2014-03-10 01:18:05 -04:00
# Author: Nic Wolfe <nic@wolfeden.ca>
# URL: http://code.google.com/p/sickbeard/
#
2014-05-23 08:37:22 -04:00
# This file is part of SickRage.
2014-03-10 01:18:05 -04:00
#
2014-05-23 08:37:22 -04:00
# SickRage is free software: you can redistribute it and/or modify
2014-03-10 01:18:05 -04:00
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
2014-05-23 08:37:22 -04:00
# SickRage is distributed in the hope that it will be useful,
2014-03-10 01:18:05 -04:00
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
2014-05-23 08:37:22 -04:00
# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
2014-03-10 01:18:05 -04:00
from __future__ import with_statement
import os
2014-04-24 01:18:16 -04:00
import re
2014-05-06 07:29:25 -04:00
import threading
2014-03-10 01:18:05 -04:00
import datetime
2014-07-24 12:12:29 -04:00
import traceback
2014-03-10 01:18:05 -04:00
import sickbeard
2014-07-24 12:12:29 -04:00
from common import SNATCHED , SNATCHED_PROPER , SNATCHED_BEST , Quality , SEASON_RESULT , MULTI_EP_RESULT
2014-03-10 01:18:05 -04:00
from sickbeard import logger , db , show_name_helpers , exceptions , helpers
from sickbeard import sab
from sickbeard import nzbget
from sickbeard import clients
from sickbeard import history
from sickbeard import notifiers
from sickbeard import nzbSplitter
from sickbeard import ui
from sickbeard import encodingKludge as ek
from sickbeard import failed_history
from sickbeard . exceptions import ex
2014-07-24 12:12:29 -04:00
from sickbeard . providers . generic import GenericProvider
2014-05-27 03:44:23 -04:00
from sickbeard . blackandwhitelist import BlackAndWhiteList
2014-09-20 08:03:48 -04:00
from sickbeard import common
2014-05-13 22:19:28 -04:00
2014-03-10 01:18:05 -04:00
def _downloadResult ( result ) :
"""
Downloads a result to the appropriate black hole folder .
Returns a bool representing success .
result : SearchResult instance to download .
"""
resProvider = result . provider
2014-03-20 14:03:22 -04:00
if resProvider == None :
2014-03-10 01:18:05 -04:00
logger . log ( u " Invalid provider name - this is a coding error, report it please " , logger . ERROR )
return False
# nzbs with an URL can just be downloaded from the provider
if result . resultType == " nzb " :
newResult = resProvider . downloadResult ( result )
# if it's an nzb data result
elif result . resultType == " nzbdata " :
# get the final file path to the nzb
fileName = ek . ek ( os . path . join , sickbeard . NZB_DIR , result . name + " .nzb " )
logger . log ( u " Saving NZB to " + fileName )
newResult = True
# save the data to disk
try :
with ek . ek ( open , fileName , ' w ' ) as fileOut :
fileOut . write ( result . extraInfo [ 0 ] )
helpers . chmodAsParent ( fileName )
except EnvironmentError , e :
logger . log ( u " Error trying to save NZB to black hole: " + ex ( e ) , logger . ERROR )
newResult = False
elif resProvider . providerType == " torrent " :
newResult = resProvider . downloadResult ( result )
else :
logger . log ( u " Invalid provider type - this is a coding error, report it please " , logger . ERROR )
2014-07-27 06:59:21 -04:00
newResult = False
2014-03-10 01:18:05 -04:00
return newResult
def snatchEpisode ( result , endStatus = SNATCHED ) :
"""
Contains the internal logic necessary to actually " snatch " a result that
has been found .
Returns a bool representing success .
result : SearchResult instance to be snatched .
endStatus : the episode status that should be used for the episode object once it ' s snatched.
"""
2014-03-19 19:33:49 -04:00
2014-07-24 12:12:29 -04:00
if result is None :
return False
2014-03-19 19:33:49 -04:00
2014-03-25 01:57:24 -04:00
result . priority = 0 # -1 = low, 0 = normal, 1 = high
2014-03-10 01:18:05 -04:00
if sickbeard . ALLOW_HIGH_PRIORITY :
# if it aired recently make it high priority
for curEp in result . episodes :
if datetime . date . today ( ) - curEp . airdate < = datetime . timedelta ( days = 7 ) :
result . priority = 1
2014-05-05 18:48:28 -04:00
if re . search ( ' (^|[ \ . _-])(proper|repack)([ \ . _-]|$) ' , result . name , re . I ) != None :
endStatus = SNATCHED_PROPER
2014-03-10 01:18:05 -04:00
# NZBs can be sent straight to SAB or saved to disk
if result . resultType in ( " nzb " , " nzbdata " ) :
if sickbeard . NZB_METHOD == " blackhole " :
dlResult = _downloadResult ( result )
elif sickbeard . NZB_METHOD == " sabnzbd " :
dlResult = sab . sendNZB ( result )
elif sickbeard . NZB_METHOD == " nzbget " :
2014-05-05 18:48:28 -04:00
is_proper = True if endStatus == SNATCHED_PROPER else False
dlResult = nzbget . sendNZB ( result , is_proper )
2014-03-10 01:18:05 -04:00
else :
logger . log ( u " Unknown NZB action specified in config: " + sickbeard . NZB_METHOD , logger . ERROR )
dlResult = False
# TORRENTs can be sent to clients or saved to disk
elif result . resultType == " torrent " :
# torrents are saved to disk when blackhole mode
if sickbeard . TORRENT_METHOD == " blackhole " :
dlResult = _downloadResult ( result )
else :
2014-12-24 12:19:25 -05:00
#result.content = result.provider.getURL(result.url) if not result.url.startswith('magnet') else None
2014-03-10 01:18:05 -04:00
client = clients . getClientIstance ( sickbeard . TORRENT_METHOD ) ( )
dlResult = client . sendTORRENT ( result )
else :
logger . log ( u " Unknown result type, unable to download it " , logger . ERROR )
dlResult = False
2014-05-02 07:33:06 -04:00
if not dlResult :
2014-03-10 01:18:05 -04:00
return False
if sickbeard . USE_FAILED_DOWNLOADS :
failed_history . logSnatch ( result )
2014-05-23 02:58:29 -04:00
ui . notifications . message ( ' Episode snatched ' , result . name )
2014-03-10 01:18:05 -04:00
history . logSnatch ( result )
# don't notify when we re-download an episode
2014-05-30 06:01:49 -04:00
sql_l = [ ]
2014-03-10 01:18:05 -04:00
for curEpObj in result . episodes :
with curEpObj . lock :
2014-03-19 19:33:49 -04:00
if isFirstBestMatch ( result ) :
curEpObj . status = Quality . compositeStatus ( SNATCHED_BEST , result . quality )
else :
curEpObj . status = Quality . compositeStatus ( endStatus , result . quality )
2014-05-30 06:01:49 -04:00
sql_l . append ( curEpObj . get_sql ( ) )
2014-03-10 01:18:05 -04:00
if curEpObj . status not in Quality . DOWNLOADED :
2014-11-16 09:32:46 -05:00
notifiers . notify_snatch ( curEpObj . _format_pattern ( ' % SN - % Sx %0E - %E N - % QN ' ) + " from " + result . provider . name )
2014-03-10 01:18:05 -04:00
2014-07-14 22:00:53 -04:00
if len ( sql_l ) > 0 :
2014-06-21 18:46:59 -04:00
myDB = db . DBConnection ( )
myDB . mass_action ( sql_l )
2014-06-30 11:57:32 -04:00
2014-03-10 01:18:05 -04:00
return True
2014-05-13 22:19:28 -04:00
2014-04-24 01:18:16 -04:00
def filter_release_name ( name , filter_words ) :
"""
Filters out results based on filter_words
name : name to check
filter_words : Words to filter on , separated by comma
Returns : False if the release name is OK , True if it contains one of the filter_words
"""
if filter_words :
2014-08-09 13:00:53 -04:00
filters = [ re . compile ( ' .* %s .* ' % filter . strip ( ) , re . I ) for filter in filter_words . split ( ' , ' ) ]
2014-04-26 02:33:02 -04:00
for regfilter in filters :
if regfilter . search ( name ) :
logger . log ( u " " + name + " contains pattern: " + regfilter . pattern , logger . DEBUG )
return True
2014-03-10 01:18:05 -04:00
2014-04-24 01:18:16 -04:00
return False
2014-05-13 22:19:28 -04:00
2015-01-19 21:29:19 -05:00
def pickBestResult ( results , show , quality_list = None ) :
2014-12-21 21:26:15 -05:00
results = results if isinstance ( results , list ) else [ results ]
2014-03-10 01:18:05 -04:00
logger . log ( u " Picking the best result out of " + str ( [ x . name for x in results ] ) , logger . DEBUG )
2014-05-27 03:44:23 -04:00
bwl = None
2014-12-21 21:26:15 -05:00
bestResult = None
2014-05-27 03:44:23 -04:00
2014-03-10 01:18:05 -04:00
# find the best result for the current episode
for cur_result in results :
2014-12-21 21:26:15 -05:00
if show and cur_result . show is not show :
continue
2014-03-10 01:18:05 -04:00
2015-01-19 23:15:54 -05:00
# filter out possible bad torrents from providers such as ezrss
if isinstance ( cur_result , sickbeard . classes . SearchResult ) :
if cur_result . resultType == " torrent " and sickbeard . TORRENT_METHOD != " blackhole " :
if not cur_result . url . startswith ( ' magnet ' ) :
cur_result . content = cur_result . provider . getURL ( cur_result . url )
if not cur_result . content :
continue
else :
if not cur_result . url . startswith ( ' magnet ' ) :
cur_result . content = cur_result . provider . getURL ( cur_result . url )
if not cur_result . content :
continue
2014-12-24 12:19:25 -05:00
2014-12-21 21:26:15 -05:00
# build the black And white list
2015-01-14 21:37:17 -05:00
if cur_result . show . is_anime :
if not bwl :
bwl = BlackAndWhiteList ( cur_result . show . indexerid )
2014-05-27 03:44:23 -04:00
if not bwl . is_valid ( cur_result ) :
2014-12-16 05:24:06 -05:00
logger . log ( cur_result . name + " does not match the blacklist or the whitelist, rejecting it. Result: " + bwl . get_last_result_msg ( ) , logger . INFO )
2014-05-27 03:44:23 -04:00
continue
2014-12-21 21:26:15 -05:00
logger . log ( " Quality of " + cur_result . name + " is " + Quality . qualityStrings [ cur_result . quality ] )
2014-03-10 01:18:05 -04:00
if quality_list and cur_result . quality not in quality_list :
logger . log ( cur_result . name + " is a quality we know we don ' t want, rejecting it " , logger . DEBUG )
continue
2014-12-21 21:26:15 -05:00
if show . rls_ignore_words and filter_release_name ( cur_result . name , cur_result . show . rls_ignore_words ) :
2014-04-24 01:18:16 -04:00
logger . log ( u " Ignoring " + cur_result . name + " based on ignored words filter: " + show . rls_ignore_words ,
2014-12-16 05:24:06 -05:00
logger . INFO )
2014-04-24 01:18:16 -04:00
continue
2014-12-21 21:26:15 -05:00
if show . rls_require_words and not filter_release_name ( cur_result . name , cur_result . show . rls_require_words ) :
2014-04-24 01:18:16 -04:00
logger . log ( u " Ignoring " + cur_result . name + " based on required words filter: " + show . rls_require_words ,
2014-12-16 05:24:06 -05:00
logger . INFO )
2014-04-24 01:18:16 -04:00
continue
2014-12-21 21:26:15 -05:00
if not show_name_helpers . filterBadReleases ( cur_result . name , parse = False ) :
logger . log ( u " Ignoring " + cur_result . name + " because its not a valid scene release that we want, ignoring it " ,
logger . INFO )
continue
2015-02-03 11:30:12 -05:00
if hasattr ( cur_result , ' size ' ) :
if sickbeard . USE_FAILED_DOWNLOADS and failed_history . hasFailed ( cur_result . name , cur_result . size ,
cur_result . provider . name ) :
logger . log ( cur_result . name + u " has previously failed, rejecting it " )
continue
2014-03-10 01:18:05 -04:00
2014-03-20 14:03:22 -04:00
if not bestResult or bestResult . quality < cur_result . quality and cur_result . quality != Quality . UNKNOWN :
2014-03-10 01:18:05 -04:00
bestResult = cur_result
2014-05-13 13:11:19 -04:00
2014-03-10 01:18:05 -04:00
elif bestResult . quality == cur_result . quality :
if " proper " in cur_result . name . lower ( ) or " repack " in cur_result . name . lower ( ) :
bestResult = cur_result
elif " internal " in bestResult . name . lower ( ) and " internal " not in cur_result . name . lower ( ) :
bestResult = cur_result
2014-05-14 08:51:48 -04:00
elif " xvid " in bestResult . name . lower ( ) and " x264 " in cur_result . name . lower ( ) :
logger . log ( u " Preferring " + cur_result . name + " (x264 over xvid) " )
bestResult = cur_result
2014-03-10 01:18:05 -04:00
if bestResult :
logger . log ( u " Picked " + bestResult . name + " as the best " , logger . DEBUG )
else :
logger . log ( u " No result picked. " , logger . DEBUG )
return bestResult
2014-05-13 22:19:28 -04:00
2014-03-10 01:18:05 -04:00
def isFinalResult ( result ) :
"""
Checks if the given result is good enough quality that we can stop searching for other ones .
If the result is the highest quality in both the any / best quality lists then this function
returns True , if not then it ' s False
"""
logger . log ( u " Checking if we should keep searching after we ' ve found " + result . name , logger . DEBUG )
show_obj = result . episodes [ 0 ] . show
2014-07-14 22:00:53 -04:00
bwl = None
if show_obj . is_anime :
bwl = BlackAndWhiteList ( show_obj . indexerid )
2014-05-27 03:44:23 -04:00
2014-03-10 01:18:05 -04:00
any_qualities , best_qualities = Quality . splitQuality ( show_obj . quality )
# if there is a redownload that's higher than this then we definitely need to keep looking
if best_qualities and result . quality < max ( best_qualities ) :
return False
2014-05-27 03:44:23 -04:00
# if it does not match the shows black and white list its no good
2014-07-14 22:00:53 -04:00
elif bwl and not bwl . is_valid ( result ) :
2014-05-27 03:44:23 -04:00
return False
2014-03-10 01:18:05 -04:00
# if there's no redownload that's higher (above) and this is the highest initial download then we're good
2014-05-13 22:19:28 -04:00
elif any_qualities and result . quality in any_qualities :
2014-03-10 01:18:05 -04:00
return True
elif best_qualities and result . quality == max ( best_qualities ) :
# if this is the best redownload but we have a higher initial download then keep looking
if any_qualities and result . quality < max ( any_qualities ) :
return False
# if this is the best redownload and we don't have a higher initial download then we're done
else :
return True
# if we got here than it's either not on the lists, they're empty, or it's lower than the highest required
else :
return False
2014-03-25 01:57:24 -04:00
2014-03-19 19:33:49 -04:00
def isFirstBestMatch ( result ) :
"""
Checks if the given result is a best quality match and if we want to archive the episode on first match .
"""
2014-03-25 01:57:24 -04:00
logger . log ( u " Checking if we should archive our first best quality match for for episode " + result . name ,
logger . DEBUG )
2014-03-19 19:33:49 -04:00
show_obj = result . episodes [ 0 ] . show
any_qualities , best_qualities = Quality . splitQuality ( show_obj . quality )
# if there is a redownload that's a match to one of our best qualities and we want to archive the episode then we are done
if best_qualities and show_obj . archive_firstmatch and result . quality in best_qualities :
return True
return False
2014-03-10 01:18:05 -04:00
2014-09-20 08:03:48 -04:00
def wantedEpisodes ( show , fromDate ) :
anyQualities , bestQualities = common . Quality . splitQuality ( show . quality ) # @UnusedVariable
allQualities = list ( set ( anyQualities + bestQualities ) )
logger . log ( u " Seeing if we need anything from " + show . name )
myDB = db . DBConnection ( )
if show . air_by_date :
sqlResults = myDB . select (
" SELECT ep.status, ep.season, ep.episode FROM tv_episodes ep, tv_shows show WHERE season != 0 AND ep.showid = show.indexer_id AND show.paused = 0 AND ep.airdate > ? AND ep.showid = ? AND show.air_by_date = 1 " ,
[ fromDate . toordinal ( ) , show . indexerid ] )
else :
sqlResults = myDB . select (
" SELECT status, season, episode FROM tv_episodes WHERE showid = ? AND season > 0 and airdate > ? " ,
[ show . indexerid , fromDate . toordinal ( ) ] )
# check through the list of statuses to see if we want any
wanted = [ ]
for result in sqlResults :
2014-12-02 06:21:23 -05:00
curCompositeStatus = int ( result [ " status " ] or - 1 )
2014-09-20 08:03:48 -04:00
curStatus , curQuality = common . Quality . splitCompositeStatus ( curCompositeStatus )
if bestQualities :
highestBestQuality = max ( allQualities )
else :
highestBestQuality = 0
# if we need a better one then say yes
if ( curStatus in ( common . DOWNLOADED , common . SNATCHED , common . SNATCHED_PROPER ,
common . SNATCHED_BEST ) and curQuality < highestBestQuality ) or curStatus == common . WANTED :
epObj = show . getEpisode ( int ( result [ " season " ] ) , int ( result [ " episode " ] ) )
epObj . wantedQuality = [ i for i in allQualities if ( i > curQuality and i != common . Quality . UNKNOWN ) ]
wanted . append ( epObj )
return wanted
def searchForNeededEpisodes ( ) :
2014-05-18 08:59:42 -04:00
foundResults = { }
2014-07-24 15:05:49 -04:00
2014-05-18 08:59:42 -04:00
didSearch = False
2014-07-19 07:52:55 -04:00
origThreadName = threading . currentThread ( ) . name
2014-09-22 01:41:29 -04:00
threads = [ ]
2014-07-24 12:12:29 -04:00
2014-09-20 08:03:48 -04:00
show_list = sickbeard . showList
fromDate = datetime . date . fromordinal ( 1 )
episodes = [ ]
for curShow in show_list :
2014-12-03 09:41:51 -05:00
if not curShow . paused :
episodes . extend ( wantedEpisodes ( curShow , fromDate ) )
2014-09-20 08:03:48 -04:00
2014-12-03 09:41:51 -05:00
providers = [ x for x in sickbeard . providers . sortedProviderList ( sickbeard . RANDOMIZE_PROVIDERS ) if x . isActive ( ) and x . enable_daily ]
2014-08-30 04:47:00 -04:00
for curProvider in providers :
2014-12-03 09:41:51 -05:00
threads + = [ threading . Thread ( target = curProvider . cache . updateCache , name = origThreadName + " :: [ " + curProvider . name + " ] " ) ]
# start the thread we just created
for t in threads :
t . start ( )
2014-09-22 01:41:29 -04:00
# wait for all threads to finish
for t in threads :
t . join ( )
for curProvider in providers :
2014-07-24 12:12:29 -04:00
threading . currentThread ( ) . name = origThreadName + " :: [ " + curProvider . name + " ] "
2014-09-22 01:41:29 -04:00
curFoundResults = curProvider . searchRSS ( episodes )
2014-05-18 08:59:42 -04:00
didSearch = True
# pick a single result for each episode, respecting existing results
for curEp in curFoundResults :
bestResult = pickBestResult ( curFoundResults [ curEp ] , curEp . show )
# if all results were rejected move on to the next episode
if not bestResult :
logger . log ( u " All found results for " + curEp . prettyName ( ) + " were rejected. " , logger . DEBUG )
continue
# if it's already in the list (from another provider) and the newly found quality is no better then skip it
if curEp in foundResults and bestResult . quality < = foundResults [ curEp ] . quality :
continue
foundResults [ curEp ] = bestResult
2014-09-22 01:41:29 -04:00
threading . currentThread ( ) . name = origThreadName
2014-05-18 08:59:42 -04:00
if not didSearch :
logger . log (
2014-07-24 15:05:49 -04:00
u " No NZB/Torrent providers found or enabled in the sickrage config for daily searches. Please check your settings. " ,
2014-05-18 08:59:42 -04:00
logger . ERROR )
2014-08-30 04:47:00 -04:00
return foundResults . values ( )
2014-05-18 08:59:42 -04:00
2014-09-07 00:36:23 -04:00
def searchProviders ( show , episodes , manualSearch = False ) :
2014-05-18 11:33:31 -04:00
foundResults = { }
finalResults = [ ]
2014-07-24 15:05:49 -04:00
didSearch = False
2014-12-07 12:16:41 -05:00
threads = [ ]
2014-07-24 15:05:49 -04:00
2014-09-15 05:46:08 -04:00
# build name cache for show
sickbeard . name_cache . buildNameCache ( show )
2014-05-18 11:33:31 -04:00
origThreadName = threading . currentThread ( ) . name
2014-07-24 12:12:29 -04:00
2014-12-03 09:41:51 -05:00
providers = [ x for x in sickbeard . providers . sortedProviderList ( sickbeard . RANDOMIZE_PROVIDERS ) if x . isActive ( ) and x . enable_backlog ]
2014-12-07 12:16:41 -05:00
for curProvider in providers :
threads + = [ threading . Thread ( target = curProvider . cache . updateCache ,
name = origThreadName + " :: [ " + curProvider . name + " ] " ) ]
# start the thread we just created
for t in threads :
t . start ( )
# wait for all threads to finish
for t in threads :
t . join ( )
2014-07-24 12:12:29 -04:00
for providerNum , curProvider in enumerate ( providers ) :
if curProvider . anime_only and not show . is_anime :
logger . log ( u " " + str ( show . name ) + " is not an anime, skiping " , logger . DEBUG )
2014-05-27 03:44:23 -04:00
continue
2014-07-24 12:12:29 -04:00
threading . currentThread ( ) . name = origThreadName + " :: [ " + curProvider . name + " ] "
foundResults [ curProvider . name ] = { }
2014-05-28 17:13:29 -04:00
2014-09-07 00:36:23 -04:00
searchCount = 0
search_mode = curProvider . search_mode
2014-05-17 01:23:11 -04:00
2014-07-20 01:26:28 -04:00
while ( True ) :
2014-05-17 01:23:11 -04:00
searchCount + = 1
2014-09-07 00:36:23 -04:00
if search_mode == ' eponly ' :
logger . log ( u " Performing episode search for " + show . name )
2014-05-17 01:23:11 -04:00
else :
2014-09-07 00:36:23 -04:00
logger . log ( u " Performing season pack search for " + show . name )
2014-03-10 01:18:05 -04:00
2014-05-16 05:16:01 -04:00
try :
2014-09-07 00:36:23 -04:00
searchResults = curProvider . findSearchResults ( show , episodes , search_mode , manualSearch )
2014-05-16 05:16:01 -04:00
except exceptions . AuthException , e :
logger . log ( u " Authentication error: " + ex ( e ) , logger . ERROR )
2014-05-17 12:43:34 -04:00
break
2014-05-16 05:16:01 -04:00
except Exception , e :
2014-07-24 12:12:29 -04:00
logger . log ( u " Error while searching " + curProvider . name + " , skipping: " + ex ( e ) , logger . ERROR )
logger . log ( traceback . format_exc ( ) , logger . DEBUG )
2014-05-17 12:43:34 -04:00
break
2014-07-24 12:12:29 -04:00
finally :
threading . currentThread ( ) . name = origThreadName
2014-05-11 15:04:47 -04:00
2014-07-24 15:05:49 -04:00
didSearch = True
2014-05-17 06:01:09 -04:00
if len ( searchResults ) :
2014-05-26 02:29:22 -04:00
# make a list of all the results for this provider
for curEp in searchResults :
if curEp in foundResults :
2014-07-24 12:12:29 -04:00
foundResults [ curProvider . name ] [ curEp ] + = searchResults [ curEp ]
2014-05-26 02:29:22 -04:00
else :
2014-07-24 12:12:29 -04:00
foundResults [ curProvider . name ] [ curEp ] = searchResults [ curEp ]
2014-05-26 02:29:22 -04:00
2014-05-17 01:23:11 -04:00
break
2014-07-24 12:12:29 -04:00
elif not curProvider . search_fallback or searchCount == 2 :
2014-05-17 06:01:09 -04:00
break
2014-03-10 01:18:05 -04:00
2014-05-17 01:23:11 -04:00
if search_mode == ' sponly ' :
logger . log ( u " FALLBACK EPISODE SEARCH INITIATED ... " )
search_mode = ' eponly '
else :
logger . log ( u " FALLBACK SEASON PACK SEARCH INITIATED ... " )
2014-05-19 11:59:22 -04:00
search_mode = ' sponly '
2014-03-10 01:18:05 -04:00
2014-05-17 01:23:11 -04:00
# skip to next provider if we have no results to process
2014-07-24 12:12:29 -04:00
if not len ( foundResults [ curProvider . name ] ) :
continue
2014-05-17 12:43:34 -04:00
2014-05-17 01:23:11 -04:00
anyQualities , bestQualities = Quality . splitQuality ( show . quality )
# pick the best season NZB
2014-08-24 13:47:06 -04:00
bestSeasonResult = None
2014-07-24 12:12:29 -04:00
if SEASON_RESULT in foundResults [ curProvider . name ] :
2014-08-24 13:47:06 -04:00
bestSeasonResult = pickBestResult ( foundResults [ curProvider . name ] [ SEASON_RESULT ] , show ,
2014-05-17 01:23:11 -04:00
anyQualities + bestQualities )
highest_quality_overall = 0
2014-07-24 12:12:29 -04:00
for cur_episode in foundResults [ curProvider . name ] :
for cur_result in foundResults [ curProvider . name ] [ cur_episode ] :
2014-05-17 01:23:11 -04:00
if cur_result . quality != Quality . UNKNOWN and cur_result . quality > highest_quality_overall :
highest_quality_overall = cur_result . quality
logger . log ( u " The highest quality of any match is " + Quality . qualityStrings [ highest_quality_overall ] ,
logger . DEBUG )
# see if every episode is wanted
2014-08-24 13:47:06 -04:00
if bestSeasonResult :
2014-09-24 07:04:56 -04:00
searchedSeasons = [ str ( x . season ) for x in episodes ]
2014-12-24 12:19:25 -05:00
2014-05-17 01:23:11 -04:00
# get the quality of the season nzb
2014-08-24 13:47:06 -04:00
seasonQual = bestSeasonResult . quality
2014-05-17 01:23:11 -04:00
logger . log (
2014-08-24 13:47:06 -04:00
u " The quality of the season " + bestSeasonResult . provider . providerType + " is " + Quality . qualityStrings [
2014-05-17 01:23:11 -04:00
seasonQual ] , logger . DEBUG )
2014-06-21 18:46:59 -04:00
myDB = db . DBConnection ( )
2014-12-24 12:19:25 -05:00
allEps = [ int ( x [ " episode " ] )
for x in myDB . select ( " SELECT episode FROM tv_episodes WHERE showid = ? AND ( season IN ( " + ' , ' . join ( searchedSeasons ) + " ) ) " ,
2014-09-24 07:04:56 -04:00
[ show . indexerid ] ) ]
2014-12-24 12:19:25 -05:00
2014-09-24 07:04:56 -04:00
logger . log ( u " Executed query: [SELECT episode FROM tv_episodes WHERE showid = %s AND season in %s ] " % ( show . indexerid , ' , ' . join ( searchedSeasons ) ) )
2014-05-17 01:23:11 -04:00
logger . log ( u " Episode list: " + str ( allEps ) , logger . DEBUG )
allWanted = True
anyWanted = False
for curEpNum in allEps :
2014-09-24 07:04:56 -04:00
for season in set ( [ x . season for x in episodes ] ) :
if not show . wantEpisode ( season , curEpNum , seasonQual ) :
allWanted = False
else :
anyWanted = True
2014-03-10 01:18:05 -04:00
2014-05-17 01:23:11 -04:00
# if we need every ep in the season and there's nothing better then just download this and be done with it (unless single episodes are preferred)
2014-08-24 13:47:06 -04:00
if allWanted and bestSeasonResult . quality == highest_quality_overall :
2014-05-17 01:23:11 -04:00
logger . log (
2014-08-24 13:47:06 -04:00
u " Every ep in this season is needed, downloading the whole " + bestSeasonResult . provider . providerType + " " + bestSeasonResult . name )
2014-05-17 01:23:11 -04:00
epObjs = [ ]
for curEpNum in allEps :
2014-12-24 12:19:25 -05:00
for season in set ( [ x . season for x in episodes ] ) :
epObjs . append ( show . getEpisode ( season , curEpNum ) )
2014-08-24 13:47:06 -04:00
bestSeasonResult . episodes = epObjs
2014-05-18 11:33:31 -04:00
2014-08-24 13:47:06 -04:00
return [ bestSeasonResult ]
2014-03-10 01:18:05 -04:00
2014-05-17 01:23:11 -04:00
elif not anyWanted :
2014-05-16 05:16:01 -04:00
logger . log (
2014-08-24 13:47:06 -04:00
u " No eps from this season are wanted at this quality, ignoring the result of " + bestSeasonResult . name ,
2014-05-17 01:23:11 -04:00
logger . DEBUG )
2014-03-10 01:18:05 -04:00
2014-05-17 01:23:11 -04:00
else :
2014-03-10 01:18:05 -04:00
2014-08-24 13:47:06 -04:00
if bestSeasonResult . provider . providerType == GenericProvider . NZB :
2014-05-17 01:23:11 -04:00
logger . log ( u " Breaking apart the NZB and adding the individual ones to our results " , logger . DEBUG )
# if not, break it apart and add them as the lowest priority results
2014-08-24 13:47:06 -04:00
individualResults = nzbSplitter . splitResult ( bestSeasonResult )
2014-05-17 01:23:11 -04:00
for curResult in individualResults :
if len ( curResult . episodes ) == 1 :
epNum = curResult . episodes [ 0 ] . episode
elif len ( curResult . episodes ) > 1 :
epNum = MULTI_EP_RESULT
2014-07-24 12:12:29 -04:00
if epNum in foundResults [ curProvider . name ] :
foundResults [ curProvider . name ] [ epNum ] . append ( curResult )
2014-05-17 01:23:11 -04:00
else :
2014-07-24 12:12:29 -04:00
foundResults [ curProvider . name ] [ epNum ] = [ curResult ]
2014-05-17 01:23:11 -04:00
# If this is a torrent all we can do is leech the entire torrent, user will have to select which eps not do download in his torrent client
else :
# Season result from Torrent Provider must be a full-season torrent, creating multi-ep result for it.
2014-05-11 15:04:47 -04:00
logger . log (
2014-05-17 01:23:11 -04:00
u " Adding multi-ep result for full-season torrent. Set the episodes you don ' t want to ' don ' t download ' in your torrent client if desired! " )
2014-05-11 15:04:47 -04:00
epObjs = [ ]
for curEpNum in allEps :
2014-12-21 21:26:15 -05:00
for season in set ( [ x . season for x in episodes ] ) :
epObjs . append ( show . getEpisode ( season , curEpNum ) )
2014-08-24 13:47:06 -04:00
bestSeasonResult . episodes = epObjs
2014-05-11 15:04:47 -04:00
2014-05-17 01:23:11 -04:00
epNum = MULTI_EP_RESULT
2014-07-24 12:12:29 -04:00
if epNum in foundResults [ curProvider . name ] :
2014-08-24 13:47:06 -04:00
foundResults [ curProvider . name ] [ epNum ] . append ( bestSeasonResult )
2014-05-17 01:23:11 -04:00
else :
2014-08-24 13:47:06 -04:00
foundResults [ curProvider . name ] [ epNum ] = [ bestSeasonResult ]
2014-05-11 15:04:47 -04:00
2014-05-17 01:23:11 -04:00
# go through multi-ep results and see if we really want them or not, get rid of the rest
multiResults = { }
2014-07-24 12:12:29 -04:00
if MULTI_EP_RESULT in foundResults [ curProvider . name ] :
for multiResult in foundResults [ curProvider . name ] [ MULTI_EP_RESULT ] :
2014-05-11 15:04:47 -04:00
2014-05-17 01:23:11 -04:00
logger . log ( u " Seeing if we want to bother with multi-episode result " + multiResult . name , logger . DEBUG )
2014-05-11 15:04:47 -04:00
2014-05-17 01:23:11 -04:00
if sickbeard . USE_FAILED_DOWNLOADS and failed_history . hasFailed ( multiResult . name , multiResult . size ,
multiResult . provider . name ) :
logger . log ( multiResult . name + u " has previously failed, rejecting this multi-ep result " )
continue
2014-05-11 15:04:47 -04:00
2014-05-17 01:23:11 -04:00
# see how many of the eps that this result covers aren't covered by single results
neededEps = [ ]
notNeededEps = [ ]
for epObj in multiResult . episodes :
epNum = epObj . episode
# if we have results for the episode
2014-07-24 12:12:29 -04:00
if epNum in foundResults [ curProvider . name ] and len ( foundResults [ curProvider . name ] [ epNum ] ) > 0 :
2014-05-17 01:23:11 -04:00
neededEps . append ( epNum )
else :
2014-07-24 12:12:29 -04:00
notNeededEps . append ( epNum )
2014-03-10 01:18:05 -04:00
2014-05-17 01:23:11 -04:00
logger . log (
u " Single-ep check result is neededEps: " + str ( neededEps ) + " , notNeededEps: " + str ( notNeededEps ) ,
logger . DEBUG )
2014-03-10 01:18:05 -04:00
2014-08-17 21:36:21 -04:00
if not notNeededEps :
2014-08-17 21:32:47 -04:00
logger . log ( u " All of these episodes were covered by single episode results, ignoring this multi-episode result " , logger . DEBUG )
2014-05-17 01:23:11 -04:00
continue
2014-05-11 15:04:47 -04:00
2014-05-17 01:23:11 -04:00
# check if these eps are already covered by another multi-result
multiNeededEps = [ ]
multiNotNeededEps = [ ]
for epObj in multiResult . episodes :
epNum = epObj . episode
if epNum in multiResults :
multiNotNeededEps . append ( epNum )
2014-05-11 15:04:47 -04:00
else :
2014-05-17 01:23:11 -04:00
multiNeededEps . append ( epNum )
2014-05-11 15:04:47 -04:00
2014-05-17 01:23:11 -04:00
logger . log (
u " Multi-ep check result is multiNeededEps: " + str ( multiNeededEps ) + " , multiNotNeededEps: " + str (
multiNotNeededEps ) , logger . DEBUG )
2014-05-11 15:04:47 -04:00
2014-05-17 01:23:11 -04:00
if not multiNeededEps :
2014-05-11 15:04:47 -04:00
logger . log (
2014-05-17 01:23:11 -04:00
u " All of these episodes were covered by another multi-episode nzbs, ignoring this multi-ep result " ,
2014-05-11 15:04:47 -04:00
logger . DEBUG )
2014-05-17 01:23:11 -04:00
continue
2014-05-11 15:04:47 -04:00
2014-05-17 01:23:11 -04:00
# if we're keeping this multi-result then remember it
for epObj in multiResult . episodes :
multiResults [ epObj . episode ] = multiResult
2014-05-16 05:16:01 -04:00
2014-05-17 01:23:11 -04:00
# don't bother with the single result if we're going to get it with a multi result
for epObj in multiResult . episodes :
epNum = epObj . episode
2014-07-24 12:12:29 -04:00
if epNum in foundResults [ curProvider . name ] :
2014-05-13 22:19:28 -04:00
logger . log (
2014-05-17 01:23:11 -04:00
u " A needed multi-episode result overlaps with a single-episode result for ep # " + str (
epNum ) + " , removing the single-episode results from the list " , logger . DEBUG )
2014-07-24 12:12:29 -04:00
del foundResults [ curProvider . name ] [ epNum ]
2014-05-17 01:23:11 -04:00
# of all the single ep results narrow it down to the best one for each episode
2014-05-18 11:33:31 -04:00
finalResults + = set ( multiResults . values ( ) )
2014-07-24 12:12:29 -04:00
for curEp in foundResults [ curProvider . name ] :
2014-05-17 01:23:11 -04:00
if curEp in ( MULTI_EP_RESULT , SEASON_RESULT ) :
continue
2014-03-10 01:18:05 -04:00
2014-12-24 12:19:25 -05:00
if not len ( foundResults [ curProvider . name ] [ curEp ] ) > 0 :
2014-05-17 01:23:11 -04:00
continue
2014-03-10 01:18:05 -04:00
2014-05-17 01:23:11 -04:00
# if all results were rejected move on to the next episode
2014-12-24 12:19:25 -05:00
bestResult = pickBestResult ( foundResults [ curProvider . name ] [ curEp ] , show )
2014-05-17 01:23:11 -04:00
if not bestResult :
continue
2014-05-13 13:11:19 -04:00
2014-05-17 01:23:11 -04:00
# add result if its not a duplicate and
found = False
2014-05-18 11:33:31 -04:00
for i , result in enumerate ( finalResults ) :
2014-05-17 01:23:11 -04:00
for bestResultEp in bestResult . episodes :
if bestResultEp in result . episodes :
if result . quality < bestResult . quality :
2014-05-18 11:33:31 -04:00
finalResults . pop ( i )
2014-05-17 01:23:11 -04:00
else :
found = True
if not found :
2014-05-18 11:33:31 -04:00
finalResults + = [ bestResult ]
2014-05-15 17:43:45 -04:00
2014-05-17 01:23:11 -04:00
# check that we got all the episodes we wanted first before doing a match and snatch
wantedEpCount = 0
for wantedEp in episodes :
2014-05-18 11:33:31 -04:00
for result in finalResults :
2014-05-17 01:23:11 -04:00
if wantedEp in result . episodes and isFinalResult ( result ) :
wantedEpCount + = 1
2014-05-13 22:19:28 -04:00
2014-05-17 01:23:11 -04:00
# make sure we search every provider for results unless we found everything we wanted
2014-07-24 12:12:29 -04:00
if wantedEpCount == len ( episodes ) :
2014-05-17 12:43:34 -04:00
break
2014-03-10 01:18:05 -04:00
2014-07-24 15:05:49 -04:00
if not didSearch :
logger . log ( u " No NZB/Torrent providers found or enabled in the sickrage config for backlog searches. Please check your settings. " ,
2014-07-24 12:12:29 -04:00
logger . ERROR )
2014-05-18 11:58:04 -04:00
return finalResults