2014-03-10 05:18:05 +00:00
# Author: Nic Wolfe <nic@wolfeden.ca>
# URL: http://code.google.com/p/sickbeard/
#
# This file is part of Sick Beard.
#
# Sick Beard is free software: you can redistribute it and/or modify
# 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.
#
# Sick Beard is distributed in the hope that it will be useful,
# 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
# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>.
from __future__ import with_statement
import datetime
import threading
import sickbeard
from sickbeard import db , scheduler
from sickbeard import search_queue
from sickbeard import logger
from sickbeard import ui
#from sickbeard.common import *
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 :
return datetime . date . today ( )
else :
return datetime . date . fromordinal ( self . action . _lastBacklog + self . action . cycleTime )
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 ( )
self . cycleTime = 7
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 ) :
if which_shows :
show_list = which_shows
else :
show_list = sickbeard . showList
2014-03-20 18:03:22 +00:00
if self . amActive == True :
2014-03-10 05:18:05 +00:00
logger . log ( u " Backlog is still running, not starting it again " , logger . DEBUG )
return
self . _get_lastBacklog ( )
curDate = datetime . date . today ( ) . toordinal ( )
fromDate = datetime . date . fromordinal ( 1 )
if not which_shows and not curDate - self . _lastBacklog > = self . cycleTime :
logger . log ( u " Running limited backlog on recently missed episodes only " )
fromDate = datetime . date . today ( ) - datetime . timedelta ( days = 7 )
self . amActive = True
self . amPaused = False
#myDB = db.DBConnection()
#numSeasonResults = myDB.select("SELECT DISTINCT(season), showid FROM tv_episodes ep, tv_shows show WHERE season != 0 AND ep.showid = show.indexer_id AND show.paused = 0 AND ep.airdate > ?", [fromDate.toordinal()])
# get separate lists of the season/date shows
#season_shows = [x for x in show_list if not x.air_by_date]
air_by_date_shows = [ x for x in show_list if x . air_by_date ]
# figure out how many segments of air by date shows we're going to do
air_by_date_segments = [ ]
for cur_id in [ x . indexerid for x in air_by_date_shows ] :
2014-03-25 05:57:24 +00:00
air_by_date_segments + = self . _get_air_by_date_segments ( cur_id , fromDate )
2014-03-10 05:18:05 +00:00
2014-03-25 05:57:24 +00:00
logger . log ( u " Air-by-date segments: " + str ( air_by_date_segments ) , logger . DEBUG )
2014-03-10 05:18:05 +00:00
#totalSeasons = float(len(numSeasonResults) + len(air_by_date_segments))
#numSeasonsDone = 0.0
# go through non air-by-date shows and see if they need any episodes
for curShow in show_list :
if curShow . paused :
continue
if curShow . air_by_date :
segments = [ x [ 1 ] for x in self . _get_air_by_date_segments ( curShow . indexerid , fromDate ) ]
else :
2014-05-03 09:23:26 +00:00
segments = self . _get_segments ( curShow . indexerid , fromDate )
2014-03-10 05:18:05 +00:00
for cur_segment in segments :
2014-03-25 05:57:24 +00:00
self . currentSearchInfo = { ' title ' : curShow . name + " Season " + str ( cur_segment ) }
2014-03-10 05:18:05 +00:00
backlog_queue_item = search_queue . BacklogQueueItem ( curShow , cur_segment )
2014-05-03 09:23:26 +00:00
if backlog_queue_item . wantedEpisodes :
sickbeard . searchQueueScheduler . action . add_item ( backlog_queue_item ) #@UndefinedVariable
else :
2014-03-25 05:57:24 +00:00
logger . log (
u " Nothing in season " + str ( cur_segment ) + " needs to be downloaded, skipping this season " ,
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 )
myDB = db . DBConnection ( )
sqlResults = myDB . select ( " SELECT * FROM info " )
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-03 09:23:26 +00:00
def _get_segments ( self , indexer_id , fromDate ) :
2014-03-10 05:18:05 +00:00
myDB = db . DBConnection ( )
2014-03-25 05:57:24 +00:00
sqlResults = myDB . select (
" SELECT DISTINCT(season) as season FROM tv_episodes WHERE showid = ? AND season > 0 and airdate > ? " ,
[ indexer_id , fromDate . toordinal ( ) ] )
2014-05-03 09:23:26 +00:00
2014-03-10 05:18:05 +00:00
return [ int ( x [ " season " ] ) for x in sqlResults ]
def _get_air_by_date_segments ( self , indexer_id , fromDate ) :
# query the DB for all dates for this show
myDB = db . DBConnection ( )
2014-03-25 05:57:24 +00:00
num_air_by_date_results = myDB . select (
2014-04-28 09:15:29 +00:00
" SELECT airdate, showid 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-03-25 05:57:24 +00:00
[ fromDate . toordinal ( ) , indexer_id ] )
2014-03-10 05:18:05 +00:00
# break them apart into month/year strings
air_by_date_segments = [ ]
for cur_result in num_air_by_date_results :
cur_date = datetime . date . fromordinal ( int ( cur_result [ " airdate " ] ) )
cur_date_str = str ( cur_date ) [ : 7 ]
cur_indexer_id = int ( cur_result [ " showid " ] )
2014-03-25 05:57:24 +00:00
2014-03-10 05:18:05 +00:00
cur_result_tuple = ( cur_indexer_id , cur_date_str )
if cur_result_tuple not in air_by_date_segments :
air_by_date_segments . append ( cur_result_tuple )
2014-03-25 05:57:24 +00:00
2014-03-10 05:18:05 +00:00
return air_by_date_segments
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 )
myDB = db . DBConnection ( )
sqlResults = myDB . select ( " SELECT * FROM info " )
if len ( sqlResults ) == 0 :
2014-03-11 19:28:44 +00:00
myDB . action ( " INSERT INTO info (last_backlog, last_indexer) VALUES (?,?) " , [ str ( when ) , 0 ] )
2014-03-10 05:18:05 +00:00
else :
myDB . action ( " UPDATE info SET last_backlog= " + str ( when ) )
def run ( self ) :
try :
self . searchBacklog ( )
except :
self . amActive = False
raise