@ -1,10 +1,10 @@
from couchpotato import get_session , Env
from couchpotato import Env , get_session
from couchpotato . core . event import addEvent , fireEvent
from couchpotato . core . helpers . variable import getTitle , tryInt
from couchpotato . core . helpers . variable import getTitle , tryInt , toIterable
from couchpotato . core . logger import CPLog
from couchpotato . core . media . _base . searcher . main import SearchSetupError
from couchpotato . core . plugins . base import Plugin
from couchpotato . core . settings . model import Media , Library
from couchpotato . core . settings . model import Media
from qcond import QueryCondenser
from qcond . helpers import simplify
@ -13,6 +13,8 @@ log = CPLog(__name__)
class ShowSearcher ( Plugin ) :
type = [ ' show ' , ' season ' , ' episode ' ]
in_progress = False
# TODO come back to this later, think this could be handled better
@ -29,16 +31,17 @@ class ShowSearcher(Plugin):
self . query_condenser = QueryCondenser ( )
addEvent ( ' show.searcher.single ' , self . single )
for type in toIterable ( self . type ) :
addEvent ( ' %s .searcher.single ' % type , self . single )
addEvent ( ' searcher.get_search_title ' , self . getSearchTitle )
addEvent ( ' searcher.correct_match ' , self . correctMatch )
addEvent ( ' searcher.correct_release ' , self . correctRelease )
addEvent ( ' searcher.get_media_identifier ' , self . getMediaIdentifier )
addEvent ( ' searcher.get_media_root ' , self . getMediaRoot )
def single ( self , media , search_protocols = None , manual = False ) :
show , season , episode = self . getLibraries ( media [ ' library ' ] )
if media [ ' type ' ] == ' show ' :
# TODO handle show searches (scan all seasons)
return
@ -69,8 +72,7 @@ class ShowSearcher(Plugin):
#fireEvent('episode.delete', episode['id'], single = True)
return
show , season , episode = self . getMedia ( media )
if show is None or season is None :
if not show or not season :
log . error ( ' Unable to find show or season library in database, missing required data for searching ' )
return
@ -93,7 +95,7 @@ class ShowSearcher(Plugin):
# Don't search for quality lower then already available.
if has_better_quality is 0 :
log . info ( ' Search for %s S %02d %s in %s ' , ( getTitle ( show ) , season . season_number , " E %02d " % episode . episode_number if episode else " " , quality_type [ ' quality ' ] [ ' label ' ] ) )
log . info ( ' Search for %s S %02d %s in %s ' , ( getTitle ( show ) , season [ ' season_number ' ] , " E %02d " % episode [ ' episode_number ' ] if episode else " " , quality_type [ ' quality ' ] [ ' label ' ] ) )
quality = fireEvent ( ' quality.single ' , identifier = quality_type [ ' quality ' ] [ ' identifier ' ] , single = True )
results = fireEvent ( ' searcher.search ' , search_protocols , media , quality , single = True )
@ -135,15 +137,16 @@ class ShowSearcher(Plugin):
if media [ ' type ' ] not in [ ' show ' , ' season ' , ' episode ' ] :
return
show , season , episode = self . getMedia ( media )
if show is None :
show , season , episode = self . getLibraries ( media [ ' library ' ] )
if not show :
return None
titles = [ ]
# Add season map_names if they exist
if season is not None and ' map_names ' in show . info :
season_names = show . info [ ' map_names ' ] . get ( str ( season . season_number ) , { } )
if season is not None and ' map_names ' in show [ ' info ' ] :
season_names = show [ ' info ' ] [ ' map_names ' ] . get ( str ( season [ ' season_number ' ] ) , { } )
# Add titles from all locations
# TODO only add name maps from a specific location
@ -151,7 +154,7 @@ class ShowSearcher(Plugin):
titles + = [ name for name in names if name not in titles ]
# Add show titles
titles + = [ title . title for title in show . titles if title . title not in titles ]
titles + = [ title [ ' title ' ] for title in show [ ' titles ' ] if title [ ' title ' ] not in titles ]
# Use QueryCondenser to build a list of optimal search titles
condensed_titles = self . query_condenser . distinct ( titles )
@ -170,9 +173,9 @@ class ShowSearcher(Plugin):
return None
# Add the identifier to search title
# TODO supporting other identifier formats
identifier = fireEvent ( ' searcher.get_media_identifier ' , media [ ' library ' ] , single = True )
identifier = fireEvent ( ' library.identifier ' , media [ ' library ' ] , single = True )
# TODO this needs to support other identifier formats
if identifier [ ' season ' ] :
title + = ' S %02d ' % identifier [ ' season ' ]
@ -195,11 +198,7 @@ class ShowSearcher(Plugin):
if not fireEvent ( ' searcher.correct_words ' , release [ ' name ' ] , media , single = True ) :
return False
show , season , episode = self . getMedia ( media )
if show is None or season is None :
log . error ( ' Unable to find show or season library in database, missing required data for searching ' )
return
# TODO Matching is quite costly, maybe we should be caching release matches somehow? (also look at caper optimizations)
match = fireEvent ( ' matcher.best ' , release , media , quality , single = True )
if match :
return match . weight
@ -224,68 +223,24 @@ class ShowSearcher(Plugin):
return True
# TODO move this somewhere else
def getMediaIdentifier ( self , media_library ) :
if media_library [ ' type ' ] not in [ ' show ' , ' season ' , ' episode ' ] :
return None
identifier = {
' season ' : None ,
' episode ' : None
}
def getLibraries ( self , library ) :
if ' related_libraries ' not in library :
log . warning ( " ' related_libraries ' missing from media library, unable to continue searching " )
return None , None , None
if media_library [ ' type ' ] == ' episode ' :
map_episode = media_library [ ' info ' ] . get ( ' map_episode ' )
libraries = library [ ' related_libraries ' ]
if map_episode and ' scene ' in map_episode :
identifier [ ' season ' ] = map_episode [ ' scene ' ] . get ( ' season ' )
identifier [ ' episode ' ] = map_episode [ ' scene ' ] . get ( ' episode ' )
else :
# TODO xem mapping?
identifier [ ' season ' ] = media_library . get ( ' season_number ' )
identifier [ ' episode ' ] = media_library . get ( ' episode_number ' )
# Get libraries and return lists only if there is multiple items
show = libraries . get ( ' show ' , [ ] )
if len ( show ) < = 1 :
show = show [ 0 ] if len ( show ) else None
if media_library [ ' type ' ] == ' season ' :
identifier [ ' season ' ] = media_library . get ( ' season_number ' )
season = libraries . get ( ' season ' , [ ] )
if len ( season ) < = 1 :
season = season [ 0 ] if len ( season ) else None
# Try cast identifier values to integers
identifier [ ' season ' ] = tryInt ( identifier [ ' season ' ] , None )
identifier [ ' episode ' ] = tryInt ( identifier [ ' episode ' ] , None )
return identifier
# TODO move this somewhere else
def getMediaRoot ( self , media ) :
if media [ ' type ' ] not in [ ' show ' , ' season ' , ' episode ' ] :
return None
show , season , episode = self . getMedia ( media )
if show is None or season is None :
log . error ( ' Unable to find show or season library in database, missing required data for searching ' )
return
return show . to_dict ( )
# TODO move this somewhere else
def getMedia ( self , media ) :
db = get_session ( )
media_library = db . query ( Library ) . filter_by ( id = media [ ' library_id ' ] ) . first ( )
show = None
season = None
episode = None
if media [ ' type ' ] == ' episode ' :
show = media_library . parent . parent
season = media_library . parent
episode = media_library
if media [ ' type ' ] == ' season ' :
show = media_library . parent
season = media_library
if media [ ' type ' ] == ' show ' :
show = media_library
episode = libraries . get ( ' episode ' , [ ] )
if len ( episode ) < = 1 :
episode = episode [ 0 ] if len ( episode ) else None
return show , season , episode