@ -27,8 +27,10 @@ import sickbeard
from sickbeard import db , exceptions , helpers , history , logger , search , show_name_helpers
from sickbeard import encodingKludge as ek
from sickbeard . common import DOWNLOADED , SNATCHED , SNATCHED_PROPER , Quality , ARCHIVED , SNATCHED_BEST
from sickbeard . exceptions import ex
from sickbeard . common import DOWNLOADED , SNATCHED , SNATCHED_PROPER , Quality , ARCHIVED , SNATCHED_BEST , FAILED
from sickbeard . exceptions import ex , MultipleShowObjectsException
from sickbeard import failed_history
from sickbeard . history import dateFormat
from name_parser . parser import NameParser , InvalidNameException , InvalidShowException
@ -70,13 +72,56 @@ def search_propers():
logger . log ( u ' Completed the search for new propers %s ' % run_at )
def get_old_proper_level ( showObj , indexer , indexerid , season , episodes , old_status , new_quality ,
extra_no_name , version , is_anime = False ) :
level = 0
is_internal = False
codec = ' '
if old_status not in ( SNATCHED , SNATCHED_BEST , SNATCHED_PROPER ) :
level = Quality . get_proper_level ( extra_no_name , version , is_anime )
elif showObj :
myDB = db . DBConnection ( )
np = NameParser ( False , showObj = showObj )
for episode in episodes :
result = myDB . select ( ' SELECT resource FROM history WHERE showid = ? AND season = ? AND episode = ? AND '
' ( ' + ' OR ' . join ( " action LIKE ' %% %02d ' " %
x for x in ( SNATCHED , SNATCHED_PROPER , SNATCHED_BEST ) ) + ' ) '
' ORDER BY date DESC LIMIT 1 ' ,
[ indexerid , season , episode ] )
if not result or not isinstance ( result [ 0 ] [ ' resource ' ] , basestring ) or not result [ 0 ] [ ' resource ' ] :
continue
nq = Quality . sceneQuality ( result [ 0 ] [ ' resource ' ] , showObj . is_anime )
if nq != new_quality :
continue
try :
p = np . parse ( result [ 0 ] [ ' resource ' ] )
except ( StandardError , Exception ) :
continue
level = Quality . get_proper_level ( p . extra_info_no_name , p . version , showObj . is_anime )
is_internal = p . extra_info_no_name and re . search ( r ' \ binternal \ b ' , p . extra_info_no_name , flags = re . I )
codec = _get_codec ( p . extra_info_no_name )
break
return level , is_internal , codec
def _get_codec ( extra_info_no_name ) :
if not extra_info_no_name :
return ' '
if re . search ( r ' \ b[xh]264 \ b ' , extra_info_no_name , flags = re . I ) :
return ' 264 '
elif re . search ( r ' \ bxvid \ b ' , extra_info_no_name , flags = re . I ) :
return ' xvid '
elif re . search ( r ' \ b[xh]265|hevc \ b ' , extra_info_no_name , flags = re . I ) :
return ' hevc '
return ' '
def _get_proper_list ( aired_since_shows , recent_shows , recent_anime ) :
propers = { }
# for each provider get a list of the
orig_thread_name = threading . currentThread ( ) . name
providers = [ x for x in sickbeard . providers . sortedProviderList ( ) if x . is_active ( ) ]
np = NameParser ( False , try_scene_exceptions = True , indexer_lookup = False )
for cur_provider in providers :
if not recent_anime and cur_provider . anime_only :
continue
@ -106,10 +151,20 @@ def _get_proper_list(aired_since_shows, recent_shows, recent_anime):
np = NameParser ( False , try_scene_exceptions = True , showObj = x . parsed_show , indexer_lookup = False )
parse_result = np . parse ( x . name )
if parse_result . series_name and parse_result . episode_numbers and \
parse_result . show . indexerid in recent_shows + recent_anime :
( parse_result . show . indexer , parse_result . show . indexerid ) in recent_shows + recent_anime :
cur_size = getattr ( x , ' size ' , None )
if failed_history . has_failed ( x . name , cur_size , cur_provider . name ) :
continue
logger . log ( u ' Found new proper: ' + x . name , logger . DEBUG )
x . show = parse_result . show . indexerid
x . provider = cur_provider
x . is_repack , x . properlevel = Quality . get_proper_level ( parse_result . extra_info_no_name ,
parse_result . version ,
parse_result . is_anime ,
check_is_repack = True )
x . is_internal = parse_result . extra_info_no_name and \
re . search ( r ' \ binternal \ b ' , parse_result . extra_info_no_name , flags = re . I )
x . codec = _get_codec ( parse_result . extra_info_no_name )
propers [ name ] = x
count + = 1
except ( InvalidNameException , InvalidShowException ) :
@ -120,12 +175,16 @@ def _get_proper_list(aired_since_shows, recent_shows, recent_anime):
cur_provider . log_result ( ' Propers ' , count , ' %s ' % cur_provider . name )
# take the list of unique propers and get it sorted by
sorted_propers = sorted ( propers . values ( ) , key = operator . attrgetter ( ' date ' ) , reverse = True )
verified_propers = [ ]
sorted_propers = sorted ( propers . values ( ) , key = operator . attrgetter ( ' properlevel ' , ' date' ) , reverse = True )
verified_propers = set ( )
for cur_proper in sorted_propers :
parse_result = np . parse ( cur_proper . name )
np = NameParser ( False , try_scene_exceptions = True , showObj = cur_proper . parsed_show , indexer_lookup = False )
try :
parse_result = np . parse ( cur_proper . name )
except ( StandardError , Exception ) :
continue
# set the indexerid in the db to the show's indexerid
cur_proper . indexerid = parse_result . show . indexerid
@ -138,7 +197,10 @@ def _get_proper_list(aired_since_shows, recent_shows, recent_anime):
cur_proper . episode = parse_result . episode_numbers [ 0 ]
cur_proper . release_group = parse_result . release_group
cur_proper . version = parse_result . version
cur_proper . extra_info = parse_result . extra_info
cur_proper . extra_info_no_name = parse_result . extra_info_no_name
cur_proper . quality = Quality . nameQuality ( cur_proper . name , parse_result . is_anime )
cur_proper . is_anime = parse_result . is_anime
# only get anime proper if it has release group and version
if parse_result . is_anime :
@ -166,25 +228,56 @@ def _get_proper_list(aired_since_shows, recent_shows, recent_anime):
# check if we actually want this proper (if it's the right quality)
my_db = db . DBConnection ( )
sql_results = my_db . select (
' SELECT release_group, status, version, release_name FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ? ' ,
[ cur_proper . indexerid , cur_proper . season , cur_proper . episode ] )
' SELECT release_group, status, version, release_name FROM tv_episodes WHERE showid = ? AND indexer = ? ' +
' AND season = ? AND episode = ? ' ,
[ cur_proper . indexerid , cur_proper . indexer , cur_proper . season , cur_proper . episode ] )
if not sql_results :
continue
# only keep the proper if we have already retrieved the same quality ep (don't get better/worse ones)
# don't take proper of the same level we already downloaded
old_status , old_quality = Quality . splitCompositeStatus ( int ( sql_results [ 0 ] [ ' status ' ] ) )
if old_status not in ( DOWNLOADED , SNATCHED , SNATCHED_BEST , ARCHIVED ) \
or cur_proper . quality != old_quality :
continue
cur_proper . is_repack , cur_proper . proper_level = Quality . get_proper_level ( cur_proper . extra_info_no_name ,
cur_proper . version ,
cur_proper . is_anime ,
check_is_repack = True )
old_release_group = sql_results [ 0 ] [ ' release_group ' ]
# check if we want this release: same quality as current, current has correct status
# restrict other release group releases to proper's
if old_status not in ( DOWNLOADED , SNATCHED , SNATCHED_BEST , SNATCHED_PROPER , ARCHIVED ) \
or cur_proper . quality != old_quality \
or ( cur_proper . is_repack and cur_proper . release_group != old_release_group ) :
continue
np = NameParser ( False , try_scene_exceptions = True , showObj = parse_result . show , indexer_lookup = False )
try :
extra_info = np . parse ( sql_results [ 0 ] [ ' release_name ' ] ) . extra_info_no_name
except ( StandardError , Exception ) :
extra_info = None
old_proper_level , old_is_internal , old_codec = get_old_proper_level ( parse_result . show , cur_proper . indexer ,
cur_proper . indexerid , cur_proper . season ,
parse_result . episode_numbers , old_status ,
cur_proper . quality , extra_info ,
cur_proper . version , cur_proper . is_anime )
if cur_proper . proper_level < old_proper_level :
continue
elif cur_proper . proper_level == old_proper_level :
if ' 264 ' == cur_proper . codec and ' xvid ' == old_codec :
pass
elif old_is_internal and not cur_proper . is_internal :
pass
else :
continue
log_same_grp = ' Skipping proper from release group: [ %s ], does not match existing release group: [ %s ] for [ %s ] ' \
% ( cur_proper . release_group , old_release_group , cur_proper . name )
# for webldls, prevent propers from different groups
if sickbeard . PROPERS_WEBDL_ONEGRP and \
( old_quality in ( Quality . HDWEBDL , Quality . FULLHDWEBDL , Quality . UHD4KWEB ) or
( old_quality == Quality . SDTV and re . search ( r ' \ Wweb.?(dl|rip|.[hx]26[45]) \ W ' , str ( sql_results [ 0 ] [ ' release_name ' ] ) , re . I ) ) ) and \
( old_quality == Quality . SDTV and re . search ( r ' \ Wweb.?(dl|rip|.[hx]26[45]) \ W ' , str ( sql_results [ 0 ] [ ' release_name ' ] ) , re . I ) ) ) and \
cur_proper . release_group != old_release_group :
logger . log ( log_same_grp , logger . DEBUG )
continue
@ -204,12 +297,24 @@ def _get_proper_list(aired_since_shows, recent_shows, recent_anime):
# if the show is in our list and there hasn't been a proper already added for that particular episode
# then add it to our list of propers
if cur_proper . indexerid != - 1 and ( cur_proper . indexerid , cur_proper . season , cur_proper . episode ) not in map (
operator . attrgetter ( ' indexerid ' , ' season ' , ' episode ' ) , verified_propers ) :
logger . log ( u ' Found a proper that may be useful: %s ' % cur_proper . name )
verified_propers . append ( cur_proper )
if cur_proper . indexerid != - 1 :
if ( cur_proper . indexerid , cur_proper . indexer , cur_proper . season , cur_proper . episode ) not in map (
operator . attrgetter ( ' indexerid ' , ' indexer ' , ' season ' , ' episode ' ) , verified_propers ) :
logger . log ( u ' Found a proper that may be useful: %s ' % cur_proper . name )
verified_propers . add ( cur_proper )
else :
rp = set ( )
for vp in verified_propers :
if vp . indexer == cur_proper . indexer and vp . indexerid == cur_proper . indexerid and \
vp . season == cur_proper . season and vp . episode == cur_proper . episode and \
vp . proper_level < cur_proper . proper_level :
rp . add ( vp )
if rp :
verified_propers = verified_propers - rp
logger . log ( u ' Found a proper that may be useful: %s ' % cur_proper . name )
verified_propers . add ( cur_proper )
return verified_propers
return list ( verified_propers )
def _download_propers ( proper_list ) :
@ -264,6 +369,9 @@ def _download_propers(proper_list):
result . name = cur_proper . name
result . quality = cur_proper . quality
result . version = cur_proper . version
result . properlevel = cur_proper . proper_level
result . is_repack = cur_proper . is_repack
result . puid = cur_proper . puid
# snatch it
search . snatch_episode ( result , SNATCHED_PROPER )
@ -273,24 +381,29 @@ def _recent_history(aired_since_shows, aired_since_anime):
recent_shows , recent_anime = [ ] , [ ]
aired_since_shows = aired_since_shows . toordinal ( )
aired_since_anime = aired_since_anime . toordinal ( )
my_db = db . DBConnection ( )
sql_results = my_db . select (
' SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e ' +
' SELECT DISTINCT s.indexer, s.indexer_id FROM history as h ' +
' INNER JOIN tv_episodes AS e ON (h.showid == e.showid AND h.season == e.season AND h.episode == e.episode) ' +
' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id) ' +
' WHERE e.airdate >= %s ' % min ( aired_since_shows , aired_since_anime ) +
' AND (e.status IN ( %s )) ' % ' , ' . join ( [ str ( x ) for x in Quality . DOWNLOADED + Quality . SNATCHED ] )
' WHERE h.date >= %s ' % min ( aired_since_shows , aired_since_anime ) . strftime ( dateFormat ) +
' AND ( %s ) ' % ' OR ' . join ( [ ' h.action LIKE " %% %02d " ' % x for x in ( DOWNLOADED , SNATCHED , SNATCHED_PROPER ,
SNATCHED_BEST , FAILED ) ] )
)
for sqlshow in sql_results :
show = helpers . findCertainShow ( sickbeard . showList , sqlshow [ ' showid ' ] )
try :
show = helpers . find_show_by_id ( sickbeard . showList , { int ( sqlshow [ ' indexer ' ] ) : int ( sqlshow [ ' indexer_id ' ] ) } )
except MultipleShowObjectsException :
continue
if show :
if sqlshow [ ' airdate ' ] > = aired_since_shows and not show . is_anime :
sqlshow [ ' showid ' ] not in recent_shows and recent_shows . append ( sqlshow [ ' showid ' ] )
if not show . is_anime :
( sqlshow [ ' indexer ' ] , sqlshow [ ' indexer_id ' ] ) not in recent_shows and \
recent_shows . append ( ( sqlshow [ ' indexer ' ] , sqlshow [ ' indexer_id ' ] ) )
else :
sqlshow [ ' showid ' ] not in recent_anime and show . is_anime and recent_anime . append ( sqlshow [ ' showid ' ] )
( sqlshow [ ' indexer ' ] , sqlshow [ ' indexer_id ' ] ) not in recent_anime and show . is_anime and \
recent_anime . append ( ( sqlshow [ ' indexer ' ] , sqlshow [ ' indexer_id ' ] ) )
return recent_shows , recent_anime