20 changed files with 499 additions and 380 deletions
@ -0,0 +1,71 @@ |
|||||
|
from couchpotato.core.event import addEvent, fireEvent |
||||
|
from couchpotato.core.helpers.variable import tryInt |
||||
|
from couchpotato.core.logger import CPLog |
||||
|
from couchpotato.core.media._base.library.base import LibraryBase |
||||
|
|
||||
|
log = CPLog(__name__) |
||||
|
|
||||
|
autoload = 'EpisodeLibraryPlugin' |
||||
|
|
||||
|
|
||||
|
class EpisodeLibraryPlugin(LibraryBase): |
||||
|
def __init__(self): |
||||
|
addEvent('library.query', self.query) |
||||
|
addEvent('library.identifier', self.identifier) |
||||
|
|
||||
|
def query(self, media, first = True, condense = True, include_identifier = True, **kwargs): |
||||
|
if media.get('type') != 'episode': |
||||
|
return |
||||
|
|
||||
|
related = fireEvent('library.related', media, single = True) |
||||
|
|
||||
|
# Get season titles |
||||
|
titles = fireEvent( |
||||
|
'library.query', related['season'], |
||||
|
|
||||
|
first = False, |
||||
|
include_identifier = include_identifier, |
||||
|
condense = condense, |
||||
|
|
||||
|
single = True |
||||
|
) |
||||
|
|
||||
|
# Add episode identifier to titles |
||||
|
if include_identifier: |
||||
|
identifier = fireEvent('library.identifier', media, single = True) |
||||
|
|
||||
|
if identifier and identifier.get('episode'): |
||||
|
titles = [title + ('E%02d' % identifier['episode']) for title in titles] |
||||
|
|
||||
|
if first: |
||||
|
return titles[0] if titles else None |
||||
|
|
||||
|
return titles |
||||
|
|
||||
|
def identifier(self, media): |
||||
|
if media.get('type') != 'episode': |
||||
|
return |
||||
|
|
||||
|
identifier = { |
||||
|
'season': None, |
||||
|
'episode': None |
||||
|
} |
||||
|
|
||||
|
# TODO identifier mapping |
||||
|
# scene_map = media['info'].get('map_episode', {}).get('scene') |
||||
|
|
||||
|
# if scene_map: |
||||
|
# # Use scene mappings if they are available |
||||
|
# identifier['season'] = scene_map.get('season_nr') |
||||
|
# identifier['episode'] = scene_map.get('episode_nr') |
||||
|
# else: |
||||
|
# Fallback to normal season/episode numbers |
||||
|
identifier['season'] = media['info'].get('season_number') |
||||
|
identifier['episode'] = media['info'].get('number') |
||||
|
|
||||
|
# Cast identifiers to integers |
||||
|
# TODO this will need changing to support identifiers with trailing 'a', 'b' characters |
||||
|
identifier['season'] = tryInt(identifier['season'], None) |
||||
|
identifier['episode'] = tryInt(identifier['episode'], None) |
||||
|
|
||||
|
return identifier |
@ -0,0 +1,52 @@ |
|||||
|
from couchpotato.core.event import addEvent, fireEvent |
||||
|
from couchpotato.core.helpers.variable import tryInt |
||||
|
from couchpotato.core.logger import CPLog |
||||
|
from couchpotato.core.media._base.library.base import LibraryBase |
||||
|
|
||||
|
log = CPLog(__name__) |
||||
|
|
||||
|
autoload = 'SeasonLibraryPlugin' |
||||
|
|
||||
|
|
||||
|
class SeasonLibraryPlugin(LibraryBase): |
||||
|
def __init__(self): |
||||
|
addEvent('library.query', self.query) |
||||
|
addEvent('library.identifier', self.identifier) |
||||
|
|
||||
|
def query(self, media, first = True, condense = True, include_identifier = True, **kwargs): |
||||
|
if media.get('type') != 'season': |
||||
|
return |
||||
|
|
||||
|
related = fireEvent('library.related', media, single = True) |
||||
|
|
||||
|
# Get show titles |
||||
|
titles = fireEvent( |
||||
|
'library.query', related['show'], |
||||
|
|
||||
|
first = False, |
||||
|
condense = condense, |
||||
|
|
||||
|
single = True |
||||
|
) |
||||
|
|
||||
|
# TODO map_names |
||||
|
|
||||
|
# Add season identifier to titles |
||||
|
if include_identifier: |
||||
|
identifier = fireEvent('library.identifier', media, single = True) |
||||
|
|
||||
|
if identifier and identifier.get('season') is not None: |
||||
|
titles = [title + (' S%02d' % identifier['season']) for title in titles] |
||||
|
|
||||
|
if first: |
||||
|
return titles[0] if titles else None |
||||
|
|
||||
|
return titles |
||||
|
|
||||
|
def identifier(self, media): |
||||
|
if media.get('type') != 'season': |
||||
|
return |
||||
|
|
||||
|
return { |
||||
|
'season': tryInt(media['info']['number'], None) |
||||
|
} |
@ -0,0 +1,38 @@ |
|||||
|
from couchpotato.core.event import addEvent |
||||
|
from couchpotato.core.helpers.encoding import simplifyString |
||||
|
from couchpotato.core.logger import CPLog |
||||
|
from couchpotato.core.media._base.library.base import LibraryBase |
||||
|
from qcond import QueryCondenser |
||||
|
|
||||
|
log = CPLog(__name__) |
||||
|
|
||||
|
autoload = 'ShowLibraryPlugin' |
||||
|
|
||||
|
|
||||
|
class ShowLibraryPlugin(LibraryBase): |
||||
|
query_condenser = QueryCondenser() |
||||
|
|
||||
|
def __init__(self): |
||||
|
addEvent('library.query', self.query) |
||||
|
|
||||
|
def query(self, media, first = True, condense = True, include_identifier = True, **kwargs): |
||||
|
if media.get('type') != 'show': |
||||
|
return |
||||
|
|
||||
|
titles = media['info']['titles'] |
||||
|
|
||||
|
if condense: |
||||
|
# Use QueryCondenser to build a list of optimal search titles |
||||
|
condensed_titles = self.query_condenser.distinct(titles) |
||||
|
|
||||
|
if condensed_titles: |
||||
|
# Use condensed titles if we got a valid result |
||||
|
titles = condensed_titles |
||||
|
else: |
||||
|
# Fallback to simplifying titles |
||||
|
titles = [simplifyString(title) for title in titles] |
||||
|
|
||||
|
if first: |
||||
|
return titles[0] if titles else None |
||||
|
|
||||
|
return titles |
@ -1,232 +0,0 @@ |
|||||
import time |
|
||||
from couchpotato import Env, get_db |
|
||||
from couchpotato.core.event import addEvent, fireEvent |
|
||||
from couchpotato.core.helpers.variable import getTitle, toIterable |
|
||||
from couchpotato.core.logger import CPLog |
|
||||
from couchpotato.core.media._base.searcher.base import SearcherBase |
|
||||
from couchpotato.core.media._base.searcher.main import SearchSetupError |
|
||||
from couchpotato.core.media.show import ShowTypeBase |
|
||||
from qcond import QueryCondenser |
|
||||
|
|
||||
log = CPLog(__name__) |
|
||||
|
|
||||
autoload = 'ShowSearcher' |
|
||||
|
|
||||
|
|
||||
class ShowSearcher(SearcherBase, ShowTypeBase): |
|
||||
|
|
||||
type = ['show', 'season', 'episode'] |
|
||||
|
|
||||
in_progress = False |
|
||||
|
|
||||
def __init__(self): |
|
||||
super(ShowSearcher, self).__init__() |
|
||||
|
|
||||
self.query_condenser = QueryCondenser() |
|
||||
|
|
||||
addEvent('season.searcher.single', self.singleSeason) |
|
||||
addEvent('episode.searcher.single', self.singleEpisode) |
|
||||
|
|
||||
addEvent('searcher.correct_release', self.correctRelease) |
|
||||
addEvent('searcher.get_search_title', self.getSearchTitle) |
|
||||
|
|
||||
|
|
||||
|
|
||||
def single(self, media, search_protocols = None, manual = False): |
|
||||
|
|
||||
# Find out search type |
|
||||
try: |
|
||||
if not search_protocols: |
|
||||
search_protocols = fireEvent('searcher.protocols', single = True) |
|
||||
except SearchSetupError: |
|
||||
return |
|
||||
|
|
||||
if not media['profile_id'] or media['status'] == 'done': |
|
||||
log.debug('Show doesn\'t have a profile or already done, assuming in manage tab.') |
|
||||
return |
|
||||
|
|
||||
show_title = fireEvent('media.search_query', media, condense = False, single = True) |
|
||||
|
|
||||
fireEvent('notify.frontend', type = 'show.searcher.started.%s' % media['_id'], data = True, message = 'Searching for "%s"' % show_title) |
|
||||
|
|
||||
media = self.extendShow(media) |
|
||||
|
|
||||
db = get_db() |
|
||||
|
|
||||
profile = db.get('id', media['profile_id']) |
|
||||
quality_order = fireEvent('quality.order', single = True) |
|
||||
|
|
||||
seasons = media.get('seasons', {}) |
|
||||
for sx in seasons: |
|
||||
|
|
||||
# Skip specials for now TODO: set status for specials to skipped by default |
|
||||
if sx == 0: continue |
|
||||
|
|
||||
season = seasons.get(sx) |
|
||||
|
|
||||
# Check if full season can be downloaded TODO: add |
|
||||
season_success = self.singleSeason(season, media, profile) |
|
||||
|
|
||||
# Do each episode seperately |
|
||||
if not season_success: |
|
||||
episodes = season.get('episodes', {}) |
|
||||
for ex in episodes: |
|
||||
episode = episodes.get(ex) |
|
||||
|
|
||||
self.singleEpisode(episode, season, media, profile, quality_order, search_protocols) |
|
||||
|
|
||||
# TODO |
|
||||
return |
|
||||
|
|
||||
# TODO |
|
||||
return |
|
||||
|
|
||||
fireEvent('notify.frontend', type = 'show.searcher.ended.%s' % media['_id'], data = True) |
|
||||
|
|
||||
def singleSeason(self, media, show, profile): |
|
||||
|
|
||||
# Check if any episode is already snatched |
|
||||
active = 0 |
|
||||
episodes = media.get('episodes', {}) |
|
||||
for ex in episodes: |
|
||||
episode = episodes.get(ex) |
|
||||
|
|
||||
if episode.get('status') in ['active']: |
|
||||
active += 1 |
|
||||
|
|
||||
if active != len(episodes): |
|
||||
return False |
|
||||
|
|
||||
# Try and search for full season |
|
||||
# TODO: |
|
||||
|
|
||||
return False |
|
||||
|
|
||||
def singleEpisode(self, media, season, show, profile, quality_order, search_protocols = None, manual = False): |
|
||||
|
|
||||
|
|
||||
# TODO: check episode status |
|
||||
|
|
||||
|
|
||||
# TODO: check air date |
|
||||
#if not self.conf('always_search') and not self.couldBeReleased(quality_type['quality']['identifier'] in pre_releases, release_dates, movie['library']['year']): |
|
||||
# too_early_to_search.append(quality_type['quality']['identifier']) |
|
||||
# return |
|
||||
|
|
||||
ret = False |
|
||||
has_better_quality = None |
|
||||
found_releases = [] |
|
||||
too_early_to_search = [] |
|
||||
|
|
||||
releases = fireEvent('release.for_media', media['_id'], single = True) |
|
||||
show_title = getTitle(show) |
|
||||
episode_identifier = '%s S%02d%s' % (show_title, season['info'].get('number', 0), "E%02d" % media['info'].get('number')) |
|
||||
|
|
||||
# Add parents |
|
||||
media['show'] = show |
|
||||
media['season'] = season |
|
||||
|
|
||||
index = 0 |
|
||||
for q_identifier in profile.get('qualities'): |
|
||||
quality_custom = { |
|
||||
'quality': q_identifier, |
|
||||
'finish': profile['finish'][index], |
|
||||
'wait_for': profile['wait_for'][index], |
|
||||
'3d': profile['3d'][index] if profile.get('3d') else False |
|
||||
} |
|
||||
|
|
||||
has_better_quality = 0 |
|
||||
|
|
||||
# See if better quality is available |
|
||||
for release in releases: |
|
||||
if quality_order.index(release['quality']) <= quality_order.index(q_identifier) and release['status'] not in ['available', 'ignored', 'failed']: |
|
||||
has_better_quality += 1 |
|
||||
|
|
||||
# Don't search for quality lower then already available. |
|
||||
if has_better_quality is 0: |
|
||||
|
|
||||
log.info('Searching for %s in %s', (episode_identifier, q_identifier)) |
|
||||
quality = fireEvent('quality.single', identifier = q_identifier, single = True) |
|
||||
quality['custom'] = quality_custom |
|
||||
|
|
||||
results = fireEvent('searcher.search', search_protocols, media, quality, single = True) |
|
||||
if len(results) == 0: |
|
||||
log.debug('Nothing found for %s in %s', (episode_identifier, q_identifier)) |
|
||||
|
|
||||
# Add them to this movie releases list |
|
||||
found_releases += fireEvent('release.create_from_search', results, media, quality, single = True) |
|
||||
|
|
||||
# Try find a valid result and download it |
|
||||
if fireEvent('release.try_download_result', results, media, quality, manual, single = True): |
|
||||
ret = True |
|
||||
|
|
||||
# Remove releases that aren't found anymore |
|
||||
for release in releases: |
|
||||
if release.get('status') == 'available' and release.get('identifier') not in found_releases: |
|
||||
fireEvent('release.delete', release.get('id'), single = True) |
|
||||
else: |
|
||||
log.info('Better quality (%s) already available or snatched for %s', (q_identifier, episode_identifier)) |
|
||||
fireEvent('media.restatus', media['_id']) |
|
||||
break |
|
||||
|
|
||||
# Break if CP wants to shut down |
|
||||
if self.shuttingDown() or ret: |
|
||||
break |
|
||||
|
|
||||
if len(too_early_to_search) > 0: |
|
||||
log.info2('Too early to search for %s, %s', (too_early_to_search, episode_identifier)) |
|
||||
|
|
||||
def correctRelease(self, release = None, media = None, quality = None, **kwargs): |
|
||||
|
|
||||
if media.get('type') not in ['season', 'episode']: return |
|
||||
|
|
||||
retention = Env.setting('retention', section = 'nzb') |
|
||||
|
|
||||
if release.get('seeders') is None and 0 < retention < release.get('age', 0): |
|
||||
log.info2('Wrong: Outside retention, age is %s, needs %s or lower: %s', (release['age'], retention, release['name'])) |
|
||||
return False |
|
||||
|
|
||||
# Check for required and ignored words |
|
||||
if not fireEvent('searcher.correct_words', release['name'], media, single = True): |
|
||||
return False |
|
||||
|
|
||||
# TODO Matching is quite costly, maybe we should be caching release matches somehow? (also look at caper optimizations) |
|
||||
match = fireEvent('matcher.match', release, media, quality, single = True) |
|
||||
if match: |
|
||||
return match.weight |
|
||||
|
|
||||
return False |
|
||||
|
|
||||
def extendShow(self, media): |
|
||||
|
|
||||
db = get_db() |
|
||||
|
|
||||
seasons = db.get_many('media_children', media['_id'], with_doc = True) |
|
||||
|
|
||||
media['seasons'] = {} |
|
||||
|
|
||||
for sx in seasons: |
|
||||
season = sx['doc'] |
|
||||
|
|
||||
# Add episode info |
|
||||
season['episodes'] = {} |
|
||||
episodes = db.get_many('media_children', sx['_id'], with_doc = True) |
|
||||
|
|
||||
for se in episodes: |
|
||||
episode = se['doc'] |
|
||||
season['episodes'][episode['info'].get('number')] = episode |
|
||||
|
|
||||
# Add season to show |
|
||||
media['seasons'][season['info'].get('number', 0)] = season |
|
||||
|
|
||||
return media |
|
||||
|
|
||||
def searchAll(self): |
|
||||
pass |
|
||||
|
|
||||
def getSearchTitle(self, media): |
|
||||
# TODO: this should be done for season and episode |
|
||||
if media['type'] == 'season': |
|
||||
return getTitle(media) |
|
||||
elif media['type'] == 'episode': |
|
||||
return getTitle(media) |
|
@ -0,0 +1,137 @@ |
|||||
|
from couchpotato import fireEvent, get_db, Env |
||||
|
from couchpotato.api import addApiView |
||||
|
from couchpotato.core.event import addEvent |
||||
|
from couchpotato.core.logger import CPLog |
||||
|
from couchpotato.core.media._base.searcher.base import SearcherBase |
||||
|
from couchpotato.core.media._base.searcher.main import SearchSetupError |
||||
|
from couchpotato.core.media.show import ShowTypeBase |
||||
|
|
||||
|
log = CPLog(__name__) |
||||
|
|
||||
|
autoload = 'EpisodeSearcher' |
||||
|
|
||||
|
|
||||
|
class EpisodeSearcher(SearcherBase, ShowTypeBase): |
||||
|
type = 'episode' |
||||
|
|
||||
|
in_progress = False |
||||
|
|
||||
|
def __init__(self): |
||||
|
super(EpisodeSearcher, self).__init__() |
||||
|
|
||||
|
addEvent('%s.searcher.single' % self.getType(), self.single) |
||||
|
addEvent('searcher.correct_release', self.correctRelease) |
||||
|
|
||||
|
addApiView('%s.searcher.single' % self.getType(), self.singleView) |
||||
|
|
||||
|
def singleView(self, media_id, **kwargs): |
||||
|
db = get_db() |
||||
|
media = db.get('id', media_id) |
||||
|
|
||||
|
return { |
||||
|
'result': fireEvent('%s.searcher.single' % self.getType(), media, single = True) |
||||
|
} |
||||
|
|
||||
|
def single(self, media, profile = None, quality_order = None, search_protocols = None, manual = False): |
||||
|
db = get_db() |
||||
|
|
||||
|
related = fireEvent('library.related', media, single = True) |
||||
|
|
||||
|
# TODO search_protocols, profile, quality_order can be moved to a base method |
||||
|
# Find out search type |
||||
|
try: |
||||
|
if not search_protocols: |
||||
|
search_protocols = fireEvent('searcher.protocols', single = True) |
||||
|
except SearchSetupError: |
||||
|
return |
||||
|
|
||||
|
if not profile and related['show']['profile_id']: |
||||
|
profile = db.get('id', related['show']['profile_id']) |
||||
|
|
||||
|
if not quality_order: |
||||
|
quality_order = fireEvent('quality.order', single = True) |
||||
|
|
||||
|
# TODO: check episode status |
||||
|
# TODO: check air date |
||||
|
#if not self.conf('always_search') and not self.couldBeReleased(quality_type['quality']['identifier'] in pre_releases, release_dates, movie['library']['year']): |
||||
|
# too_early_to_search.append(quality_type['quality']['identifier']) |
||||
|
# return |
||||
|
|
||||
|
ret = False |
||||
|
has_better_quality = None |
||||
|
found_releases = [] |
||||
|
too_early_to_search = [] |
||||
|
|
||||
|
releases = fireEvent('release.for_media', media['_id'], single = True) |
||||
|
query = fireEvent('library.query', media, condense = False, single = True) |
||||
|
|
||||
|
index = 0 |
||||
|
for q_identifier in profile.get('qualities'): |
||||
|
quality_custom = { |
||||
|
'quality': q_identifier, |
||||
|
'finish': profile['finish'][index], |
||||
|
'wait_for': profile['wait_for'][index], |
||||
|
'3d': profile['3d'][index] if profile.get('3d') else False |
||||
|
} |
||||
|
|
||||
|
has_better_quality = 0 |
||||
|
|
||||
|
# See if better quality is available |
||||
|
for release in releases: |
||||
|
if quality_order.index(release['quality']) <= quality_order.index(q_identifier) and release['status'] not in ['available', 'ignored', 'failed']: |
||||
|
has_better_quality += 1 |
||||
|
|
||||
|
# Don't search for quality lower then already available. |
||||
|
if has_better_quality is 0: |
||||
|
|
||||
|
log.info('Searching for %s in %s', (query, q_identifier)) |
||||
|
quality = fireEvent('quality.single', identifier = q_identifier, single = True) |
||||
|
quality['custom'] = quality_custom |
||||
|
|
||||
|
results = fireEvent('searcher.search', search_protocols, media, quality, single = True) |
||||
|
if len(results) == 0: |
||||
|
log.debug('Nothing found for %s in %s', (query, q_identifier)) |
||||
|
|
||||
|
# Add them to this movie releases list |
||||
|
found_releases += fireEvent('release.create_from_search', results, media, quality, single = True) |
||||
|
|
||||
|
# Try find a valid result and download it |
||||
|
if fireEvent('release.try_download_result', results, media, quality, single = True): |
||||
|
ret = True |
||||
|
|
||||
|
# Remove releases that aren't found anymore |
||||
|
for release in releases: |
||||
|
if release.get('status') == 'available' and release.get('identifier') not in found_releases: |
||||
|
fireEvent('release.delete', release.get('id'), single = True) |
||||
|
else: |
||||
|
log.info('Better quality (%s) already available or snatched for %s', (q_identifier, query)) |
||||
|
fireEvent('media.restatus', media['_id']) |
||||
|
break |
||||
|
|
||||
|
# Break if CP wants to shut down |
||||
|
if self.shuttingDown() or ret: |
||||
|
break |
||||
|
|
||||
|
if len(too_early_to_search) > 0: |
||||
|
log.info2('Too early to search for %s, %s', (too_early_to_search, query)) |
||||
|
|
||||
|
def correctRelease(self, release = None, media = None, quality = None, **kwargs): |
||||
|
if media.get('type') != 'episode': |
||||
|
return |
||||
|
|
||||
|
retention = Env.setting('retention', section = 'nzb') |
||||
|
|
||||
|
if release.get('seeders') is None and 0 < retention < release.get('age', 0): |
||||
|
log.info2('Wrong: Outside retention, age is %s, needs %s or lower: %s', (release['age'], retention, release['name'])) |
||||
|
return False |
||||
|
|
||||
|
# Check for required and ignored words |
||||
|
if not fireEvent('searcher.correct_words', release['name'], media, single = True): |
||||
|
return False |
||||
|
|
||||
|
# TODO Matching is quite costly, maybe we should be caching release matches somehow? (also look at caper optimizations) |
||||
|
match = fireEvent('matcher.match', release, media, quality, single = True) |
||||
|
if match: |
||||
|
return match.weight |
||||
|
|
||||
|
return False |
@ -0,0 +1,38 @@ |
|||||
|
from couchpotato.core.event import addEvent |
||||
|
from couchpotato.core.logger import CPLog |
||||
|
from couchpotato.core.media._base.searcher.base import SearcherBase |
||||
|
from couchpotato.core.media.show import ShowTypeBase |
||||
|
|
||||
|
log = CPLog(__name__) |
||||
|
|
||||
|
autoload = 'SeasonSearcher' |
||||
|
|
||||
|
|
||||
|
class SeasonSearcher(SearcherBase, ShowTypeBase): |
||||
|
type = 'season' |
||||
|
|
||||
|
in_progress = False |
||||
|
|
||||
|
def __init__(self): |
||||
|
super(SeasonSearcher, self).__init__() |
||||
|
|
||||
|
addEvent('%s.searcher.single' % self.getType(), self.single) |
||||
|
|
||||
|
def single(self, media, show, profile): |
||||
|
|
||||
|
# Check if any episode is already snatched |
||||
|
active = 0 |
||||
|
episodes = media.get('episodes', {}) |
||||
|
for ex in episodes: |
||||
|
episode = episodes.get(ex) |
||||
|
|
||||
|
if episode.get('status') in ['active']: |
||||
|
active += 1 |
||||
|
|
||||
|
if active != len(episodes): |
||||
|
return False |
||||
|
|
||||
|
# Try and search for full season |
||||
|
# TODO: |
||||
|
|
||||
|
return False |
@ -0,0 +1,83 @@ |
|||||
|
from couchpotato import get_db |
||||
|
from couchpotato.core.event import fireEvent, addEvent |
||||
|
from couchpotato.core.helpers.variable import getTitle |
||||
|
from couchpotato.core.logger import CPLog |
||||
|
from couchpotato.core.media._base.searcher.base import SearcherBase |
||||
|
from couchpotato.core.media._base.searcher.main import SearchSetupError |
||||
|
from couchpotato.core.media.show import ShowTypeBase |
||||
|
|
||||
|
log = CPLog(__name__) |
||||
|
|
||||
|
autoload = 'ShowSearcher' |
||||
|
|
||||
|
|
||||
|
class ShowSearcher(SearcherBase, ShowTypeBase): |
||||
|
type = 'show' |
||||
|
|
||||
|
in_progress = False |
||||
|
|
||||
|
def __init__(self): |
||||
|
super(ShowSearcher, self).__init__() |
||||
|
|
||||
|
addEvent('%s.searcher.single' % self.getType(), self.single) |
||||
|
|
||||
|
addEvent('searcher.get_search_title', self.getSearchTitle) |
||||
|
|
||||
|
def single(self, media, search_protocols = None, manual = False): |
||||
|
# Find out search type |
||||
|
try: |
||||
|
if not search_protocols: |
||||
|
search_protocols = fireEvent('searcher.protocols', single = True) |
||||
|
except SearchSetupError: |
||||
|
return |
||||
|
|
||||
|
if not media['profile_id'] or media['status'] == 'done': |
||||
|
log.debug('Show doesn\'t have a profile or already done, assuming in manage tab.') |
||||
|
return |
||||
|
|
||||
|
show_title = fireEvent('media.search_query', media, condense = False, single = True) |
||||
|
|
||||
|
fireEvent('notify.frontend', type = 'show.searcher.started.%s' % media['_id'], data = True, message = 'Searching for "%s"' % show_title) |
||||
|
|
||||
|
media = self.extendShow(media) |
||||
|
|
||||
|
db = get_db() |
||||
|
|
||||
|
profile = db.get('id', media['profile_id']) |
||||
|
quality_order = fireEvent('quality.order', single = True) |
||||
|
|
||||
|
seasons = media.get('seasons', {}) |
||||
|
for sx in seasons: |
||||
|
|
||||
|
# Skip specials for now TODO: set status for specials to skipped by default |
||||
|
if sx == 0: continue |
||||
|
|
||||
|
season = seasons.get(sx) |
||||
|
|
||||
|
# Check if full season can be downloaded TODO: add |
||||
|
season_success = fireEvent('show.season.searcher.single', season, media, profile) |
||||
|
|
||||
|
# Do each episode seperately |
||||
|
if not season_success: |
||||
|
episodes = season.get('episodes', {}) |
||||
|
for ex in episodes: |
||||
|
episode = episodes.get(ex) |
||||
|
|
||||
|
fireEvent('show.episode.searcher.single', episode, season, media, profile, quality_order, search_protocols) |
||||
|
|
||||
|
# TODO |
||||
|
return |
||||
|
|
||||
|
# TODO |
||||
|
return |
||||
|
|
||||
|
fireEvent('notify.frontend', type = 'show.searcher.ended.%s' % media['_id'], data = True) |
||||
|
|
||||
|
def getSearchTitle(self, media): |
||||
|
if media.get('type') != 'show': |
||||
|
related = fireEvent('library.related', media, single = True) |
||||
|
show = related['show'] |
||||
|
else: |
||||
|
show = media |
||||
|
|
||||
|
return getTitle(show) |
Loading…
Reference in new issue