2014-03-10 05:18:05 +00:00
# Author: Nic Wolfe <nic@wolfeden.ca>
# URL: http://code.google.com/p/sickbeard/
#
2014-11-12 16:43:14 +00:00
# This file is part of SickGear.
2014-03-10 05:18:05 +00:00
#
2014-11-12 16:43:14 +00:00
# SickGear is free software: you can redistribute it and/or modify
2014-03-10 05:18:05 +00: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-11-12 16:43:14 +00:00
# SickGear is distributed in the hope that it will be useful,
2014-03-10 05:18:05 +00: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-11-12 16:43:14 +00:00
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
2014-03-10 05:18:05 +00:00
from __future__ import with_statement
import datetime
import threading
import sickbeard
2015-03-12 23:23:32 +00:00
from sickbeard import db , scheduler , helpers
2014-03-10 05:18:05 +00:00
from sickbeard import search_queue
from sickbeard import logger
from sickbeard import ui
2014-05-16 03:39:46 +00:00
from sickbeard import common
2014-03-10 05:18:05 +00:00
2014-08-30 08:47:00 +00:00
2014-03-10 05:18:05 +00:00
class BacklogSearchScheduler ( scheduler . Scheduler ) :
def forceSearch ( self ) :
self . action . _set_lastBacklog ( 1 )
self . lastRun = datetime . datetime . fromordinal ( 1 )
def nextRun ( self ) :
if self . action . _lastBacklog < = 1 :
2014-09-15 13:42:24 +00:00
return datetime . date . today ( )
2015-01-04 02:26:55 +00:00
elif ( self . action . _lastBacklog + self . action . cycleTime ) < datetime . date . today ( ) . toordinal ( ) :
return datetime . date . today ( )
2014-03-10 05:18:05 +00:00
else :
2014-09-15 13:42:24 +00:00
return datetime . date . fromordinal ( self . action . _lastBacklog + self . action . cycleTime )
2014-03-10 05:18:05 +00:00
2014-08-30 08:47:00 +00:00
2014-03-25 05:57:24 +00:00
class BacklogSearcher :
2014-03-10 05:18:05 +00:00
def __init__ ( self ) :
self . _lastBacklog = self . _get_lastBacklog ( )
2014-08-30 08:47:00 +00:00
self . cycleTime = sickbeard . BACKLOG_FREQUENCY / 60 / 24
2014-03-10 05:18:05 +00:00
self . lock = threading . Lock ( )
self . amActive = False
self . amPaused = False
self . amWaiting = False
self . _resetPI ( )
def _resetPI ( self ) :
self . percentDone = 0
self . currentSearchInfo = { ' title ' : ' Initializing ' }
def getProgressIndicator ( self ) :
if self . amActive :
return ui . ProgressIndicator ( self . percentDone , self . currentSearchInfo )
else :
return None
def am_running ( self ) :
2014-03-25 05:57:24 +00:00
logger . log ( u " amWaiting: " + str ( self . amWaiting ) + " , amActive: " + str ( self . amActive ) , logger . DEBUG )
2014-03-10 05:18:05 +00:00
return ( not self . amWaiting ) and self . amActive
def searchBacklog ( self , which_shows = None ) :
2014-07-19 19:52:16 +00:00
if self . amActive :
logger . log ( u " Backlog is still running, not starting it again " , logger . DEBUG )
return
2014-03-10 05:18:05 +00:00
if which_shows :
show_list = which_shows
else :
show_list = sickbeard . showList
self . _get_lastBacklog ( )
curDate = datetime . date . today ( ) . toordinal ( )
fromDate = datetime . date . fromordinal ( 1 )
if not which_shows and not curDate - self . _lastBacklog > = self . cycleTime :
2014-11-16 02:19:15 +00:00
logger . log ( u ' Running limited backlog for episodes missed during the last %s day(s) ' % str ( sickbeard . BACKLOG_DAYS ) )
2014-09-19 08:49:37 +00:00
fromDate = datetime . date . today ( ) - datetime . timedelta ( days = sickbeard . BACKLOG_DAYS )
2014-03-10 05:18:05 +00:00
self . amActive = True
self . amPaused = False
# go through non air-by-date shows and see if they need any episodes
for curShow in show_list :
if curShow . paused :
continue
2014-05-16 03:39:46 +00:00
segments = self . _get_segments ( curShow , fromDate )
2014-03-10 05:18:05 +00:00
2014-09-07 04:36:23 +00:00
for season , segment in segments . items ( ) :
2014-09-07 05:06:11 +00:00
self . currentSearchInfo = { ' title ' : curShow . name + " Season " + str ( season ) }
2014-09-07 04:36:23 +00:00
backlog_queue_item = search_queue . BacklogQueueItem ( curShow , segment )
2014-08-30 08:47:00 +00:00
sickbeard . searchQueueScheduler . action . add_item ( backlog_queue_item ) # @UndefinedVariable
2014-05-16 04:55:56 +00:00
else :
2015-03-12 23:23:32 +00:00
logger . log ( u ' Nothing needs to be downloaded for %s , skipping ' % str ( curShow . name ) , logger . DEBUG )
2014-03-10 05:18:05 +00:00
# don't consider this an actual backlog search if we only did recent eps
# or if we only did certain shows
if fromDate == datetime . date . fromordinal ( 1 ) and not which_shows :
self . _set_lastBacklog ( curDate )
self . amActive = False
self . _resetPI ( )
def _get_lastBacklog ( self ) :
logger . log ( u " Retrieving the last check time from the DB " , logger . DEBUG )
2014-06-21 22:46:59 +00:00
myDB = db . DBConnection ( )
sqlResults = myDB . select ( " SELECT * FROM info " )
2014-03-10 05:18:05 +00:00
if len ( sqlResults ) == 0 :
lastBacklog = 1
2014-03-20 18:03:22 +00:00
elif sqlResults [ 0 ] [ " last_backlog " ] == None or sqlResults [ 0 ] [ " last_backlog " ] == " " :
2014-03-10 05:18:05 +00:00
lastBacklog = 1
else :
lastBacklog = int ( sqlResults [ 0 ] [ " last_backlog " ] )
2014-03-11 20:22:00 +00:00
if lastBacklog > datetime . date . today ( ) . toordinal ( ) :
lastBacklog = 1
2014-03-10 05:18:05 +00:00
self . _lastBacklog = lastBacklog
return self . _lastBacklog
2014-05-16 03:39:46 +00:00
def _get_segments ( self , show , fromDate ) :
2014-08-30 08:47:00 +00:00
anyQualities , bestQualities = common . Quality . splitQuality ( show . quality ) # @UnusedVariable
2014-03-10 05:18:05 +00:00
2014-06-21 22:46:59 +00:00
myDB = db . DBConnection ( )
if show . air_by_date :
sqlResults = myDB . select (
2014-08-30 08:47:00 +00:00
" 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 " ,
2014-06-21 22:46:59 +00:00
[ 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 ( ) ] )
2014-05-16 03:39:46 +00:00
# check through the list of statuses to see if we want any
wanted = { }
2015-03-12 23:23:32 +00:00
total_wanted = total_replacing = 0
2014-05-16 03:39:46 +00:00
for result in sqlResults :
curCompositeStatus = int ( result [ " status " ] )
curStatus , curQuality = common . Quality . splitCompositeStatus ( curCompositeStatus )
if bestQualities :
highestBestQuality = max ( bestQualities )
else :
highestBestQuality = 0
2014-03-10 05:18:05 +00:00
2014-05-16 03:39:46 +00:00
# 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 :
2014-03-25 05:57:24 +00:00
2015-03-12 23:23:32 +00:00
if curStatus == common . WANTED :
total_wanted + = 1
else :
total_replacing + = 1
2014-05-16 03:39:46 +00:00
epObj = show . getEpisode ( int ( result [ " season " ] ) , int ( result [ " episode " ] ) )
2014-07-21 13:29:07 +00:00
if epObj . season not in wanted :
2014-05-16 03:39:46 +00:00
wanted [ epObj . season ] = [ epObj ]
2014-07-21 13:29:07 +00:00
else :
wanted [ epObj . season ] . append ( epObj )
2014-03-10 05:18:05 +00:00
2015-03-12 23:23:32 +00:00
if 0 < total_wanted + total_replacing :
actions = [ ]
for msg , total in [ ' %d episode %s ' , total_wanted ] , [ ' to upgrade %d episode %s ' , total_replacing ] :
if 0 < total :
actions . append ( msg % ( total , helpers . maybe_plural ( total ) ) )
logger . log ( u ' We want %s for %s ' % ( ' and ' . join ( actions ) , show . name ) )
2014-05-16 03:39:46 +00:00
return wanted
2014-04-28 09:15:29 +00:00
2014-03-10 05:18:05 +00:00
def _set_lastBacklog ( self , when ) :
logger . log ( u " Setting the last backlog in the DB to " + str ( when ) , logger . DEBUG )
2014-06-21 22:46:59 +00:00
myDB = db . DBConnection ( )
sqlResults = myDB . select ( " SELECT * FROM info " )
2014-03-10 05:18:05 +00:00
2014-06-21 22:46:59 +00:00
if len ( sqlResults ) == 0 :
myDB . action ( " INSERT INTO info (last_backlog, last_indexer) VALUES (?,?) " , [ str ( when ) , 0 ] )
else :
myDB . action ( " UPDATE info SET last_backlog= " + str ( when ) )
2014-03-10 05:18:05 +00:00
2015-02-28 16:17:04 +00:00
def run ( self ) :
2014-03-10 05:18:05 +00:00
try :
self . searchBacklog ( )
except :
self . amActive = False
raise