Browse Source

[TV} Working show and season searcher, fixed season correctRelease/matcher

pull/3730/merge
Dean Gardiner 11 years ago
parent
commit
3d6ce1c2e2
  1. 3
      couchpotato/core/media/show/matcher.py
  2. 142
      couchpotato/core/media/show/searcher/season.py
  3. 32
      couchpotato/core/media/show/searcher/show.py

3
couchpotato/core/media/show/matcher.py

@ -107,6 +107,7 @@ class Episode(Base):
return True
class Season(Base):
type = 'show.season'
@ -121,7 +122,7 @@ class Season(Base):
log.info2('Wrong: releases with identifier ranges are not supported yet')
return False
required = fireEvent('media.identifier', media['library'], single = True)
required = fireEvent('library.identifier', media, single = True)
if identifier != required:
log.info2('Wrong: required identifier (%s) does not match release identifier (%s)', (required, identifier))

142
couchpotato/core/media/show/searcher/season.py

@ -1,7 +1,9 @@
from couchpotato import get_db, Env
from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEventAsync
from couchpotato.core.event import addEvent, fireEventAsync, fireEvent
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.searcher.base import SearcherBase
from couchpotato.core.media.movie.searcher import SearchSetupError
from couchpotato.core.media.show import ShowTypeBase
log = CPLog(__name__)
@ -19,6 +21,7 @@ class SeasonSearcher(SearcherBase, ShowTypeBase):
addEvent('%s.searcher.all' % self.getType(), self.searchAll)
addEvent('%s.searcher.single' % self.getType(), self.single)
addEvent('searcher.correct_release', self.correctRelease)
addApiView('%s.searcher.full_search' % self.getType(), self.searchAllView, docs = {
'desc': 'Starts a full search for all wanted seasons',
@ -34,21 +37,136 @@ class SeasonSearcher(SearcherBase, ShowTypeBase):
def searchAll(self, manual = False):
pass
def single(self, media, show, profile):
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
# Check if any episode is already snatched
active = 0
episodes = media.get('episodes', {})
for ex in episodes:
episode = episodes.get(ex)
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)
if episode.get('status') in ['active']:
active += 1
# Find 'active' episodes
episodes = media.get('episodes', [])
episodes_active = []
if active != len(episodes):
for episode in episodes:
if episode.get('status') != 'active':
continue
episodes_active.append(episode)
if len(episodes_active) == len(episodes):
# All episodes are 'active', try and search for full season
if self.search(media, profile, quality_order, search_protocols):
# Success, end season search
return True
else:
log.info('Unable to find season pack, searching for individual episodes...')
# Search for each episode individually
for episode in episodes_active:
fireEvent('show.episode.searcher.single', episode, profile, quality_order, search_protocols, manual)
# TODO (testing) only grab one episode
return True
return True
def search(self, media, profile, quality_order, search_protocols):
# 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))
return len(found_releases) > 0
def correctRelease(self, release = None, media = None, quality = None, **kwargs):
if media.get('type') != 'show.season':
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
# Try and search for full season
# TODO:
# 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

32
couchpotato/core/media/show/searcher/show.py

@ -54,36 +54,26 @@ class ShowSearcher(SearcherBase, ShowTypeBase):
fireEvent('notify.frontend', type = 'show.searcher.started.%s' % media['_id'], data = True, message = 'Searching for "%s"' % show_title)
media = self.extendShow(media)
show_tree = fireEvent('library.tree', media, single = True)
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:
for season in show_tree.get('seasons', []):
if not season.get('info'):
continue
# Skip specials for now TODO: set status for specials to skipped by default
if sx == 0: continue
# Skip specials (and seasons missing 'number') for now
# TODO: set status for specials to skipped by default
if not season['info'].get('number'):
continue
season = seasons.get(sx)
# Check if full season can be downloaded
fireEvent('show.season.searcher.single', season, profile, quality_order, search_protocols, manual)
# 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
# TODO (testing) only snatch one season
return
fireEvent('notify.frontend', type = 'show.searcher.ended.%s' % media['_id'], data = True)

Loading…
Cancel
Save