mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-01 08:53:37 +00:00
a4c8c53c91
Searched for other occurrences for the search_queue.FailedQueueItem() call. Changed segment to [segment] The failedDownloadQueueItem always expects a single epObj in the segment. But when checking multiple episodes as "Failed" in displayShow, an array is provided. I've changed the queueItem to always iterate over it as an array. And i've made sure that when retry a single episode, it's also send to the queueItem as an array (with a single element). I've had to adapt the queuing functionality in webserve for this.
292 lines
No EOL
11 KiB
Python
292 lines
No EOL
11 KiB
Python
# Author: Nic Wolfe <nic@wolfeden.ca>
|
|
# URL: http://code.google.com/p/sickbeard/
|
|
#
|
|
# This file is part of SickRage.
|
|
#
|
|
# SickRage 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.
|
|
#
|
|
# SickRage 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 SickRage. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from __future__ import with_statement
|
|
|
|
import time
|
|
import traceback
|
|
import threading
|
|
|
|
import sickbeard
|
|
from sickbeard import db, logger, common, exceptions, helpers
|
|
from sickbeard import generic_queue, scheduler
|
|
from sickbeard import search, failed_history, history
|
|
from sickbeard import ui
|
|
from sickbeard.exceptions import ex
|
|
from sickbeard.search import pickBestResult
|
|
|
|
search_queue_lock = threading.Lock()
|
|
|
|
BACKLOG_SEARCH = 10
|
|
DAILY_SEARCH = 20
|
|
FAILED_SEARCH = 30
|
|
MANUAL_SEARCH = 40
|
|
|
|
MANUAL_SEARCH_HISTORY = []
|
|
MANUAL_SEARCH_HISTORY_SIZE = 100
|
|
|
|
class SearchQueue(generic_queue.GenericQueue):
|
|
def __init__(self):
|
|
generic_queue.GenericQueue.__init__(self)
|
|
self.queue_name = "SEARCHQUEUE"
|
|
|
|
def is_in_queue(self, show, segment):
|
|
for cur_item in self.queue:
|
|
if isinstance(cur_item, BacklogQueueItem) and cur_item.show == show and cur_item.segment == segment:
|
|
return True
|
|
return False
|
|
|
|
def is_ep_in_queue(self, segment):
|
|
for cur_item in self.queue:
|
|
if isinstance(cur_item, (ManualSearchQueueItem, FailedQueueItem)) and cur_item.segment == segment:
|
|
return True
|
|
return False
|
|
|
|
def is_show_in_queue(self, show):
|
|
for cur_item in self.queue:
|
|
if isinstance(cur_item, (ManualSearchQueueItem, FailedQueueItem)) and cur_item.show.indexerid == show:
|
|
return True
|
|
return False
|
|
|
|
def get_all_ep_from_queue(self, show):
|
|
ep_obj_list = []
|
|
for cur_item in self.queue:
|
|
if isinstance(cur_item, (ManualSearchQueueItem, FailedQueueItem)) and str(cur_item.show.indexerid) == show:
|
|
ep_obj_list.append(cur_item)
|
|
|
|
if ep_obj_list:
|
|
return ep_obj_list
|
|
return False
|
|
|
|
def pause_backlog(self):
|
|
self.min_priority = generic_queue.QueuePriorities.HIGH
|
|
|
|
def unpause_backlog(self):
|
|
self.min_priority = 0
|
|
|
|
def is_backlog_paused(self):
|
|
# backlog priorities are NORMAL, this should be done properly somewhere
|
|
return self.min_priority >= generic_queue.QueuePriorities.NORMAL
|
|
|
|
def is_manualsearch_in_progress(self):
|
|
for cur_item in self.queue + [self.currentItem]:
|
|
if isinstance(cur_item, (ManualSearchQueueItem, FailedQueueItem)):
|
|
return True
|
|
return False
|
|
|
|
def is_backlog_in_progress(self):
|
|
for cur_item in self.queue + [self.currentItem]:
|
|
if isinstance(cur_item, BacklogQueueItem):
|
|
return True
|
|
return False
|
|
|
|
def is_dailysearch_in_progress(self):
|
|
for cur_item in self.queue + [self.currentItem]:
|
|
if isinstance(cur_item, DailySearchQueueItem):
|
|
return True
|
|
return False
|
|
|
|
def queue_length(self):
|
|
length = {'backlog': 0, 'daily': 0, 'manual': 0, 'failed': 0}
|
|
for cur_item in self.queue:
|
|
if isinstance(cur_item, DailySearchQueueItem):
|
|
length['daily'] += 1
|
|
elif isinstance(cur_item, BacklogQueueItem):
|
|
length['backlog'] += 1
|
|
elif isinstance(cur_item, ManualSearchQueueItem):
|
|
length['manual'] += 1
|
|
elif isinstance(cur_item, FailedQueueItem):
|
|
length['failed'] += 1
|
|
return length
|
|
|
|
|
|
def add_item(self, item):
|
|
if isinstance(item, (DailySearchQueueItem, BacklogQueueItem)) and not self.is_in_queue(item.show, item.segment):
|
|
# daily and backlog searches
|
|
generic_queue.GenericQueue.add_item(self, item)
|
|
elif isinstance(item, (ManualSearchQueueItem, FailedQueueItem)) and not self.is_ep_in_queue(item.segment):
|
|
# manual and failed searches
|
|
generic_queue.GenericQueue.add_item(self, item)
|
|
else:
|
|
logger.log(u"Not adding item, it's already in the queue", logger.DEBUG)
|
|
|
|
class DailySearchQueueItem(generic_queue.QueueItem):
|
|
def __init__(self, show, segment):
|
|
generic_queue.QueueItem.__init__(self, 'Daily Search', DAILY_SEARCH)
|
|
self.show = show
|
|
self.segment = segment
|
|
|
|
def run(self):
|
|
generic_queue.QueueItem.run(self)
|
|
|
|
try:
|
|
logger.log("Beginning daily search for: [" + self.show.name + "]")
|
|
foundResults = search.searchForNeededEpisodes(self.show, self.segment)
|
|
|
|
if not len(foundResults):
|
|
logger.log(u"No needed episodes found during daily search for: [" + self.show.name + "]")
|
|
else:
|
|
for result in foundResults:
|
|
# just use the first result for now
|
|
logger.log(u"Downloading " + result.name + " from " + result.provider.name)
|
|
search.snatchEpisode(result)
|
|
|
|
# give the CPU a break
|
|
time.sleep(common.cpu_presets[sickbeard.CPU_PRESET])
|
|
|
|
generic_queue.QueueItem.finish(self)
|
|
except Exception:
|
|
logger.log(traceback.format_exc(), logger.DEBUG)
|
|
|
|
self.finish()
|
|
|
|
|
|
class ManualSearchQueueItem(generic_queue.QueueItem):
|
|
def __init__(self, show, segment):
|
|
generic_queue.QueueItem.__init__(self, 'Manual Search', MANUAL_SEARCH)
|
|
self.priority = generic_queue.QueuePriorities.HIGH
|
|
self.name = 'MANUAL-' + str(show.indexerid)
|
|
self.success = None
|
|
self.show = show
|
|
self.segment = segment
|
|
self.started = None
|
|
|
|
def run(self):
|
|
generic_queue.QueueItem.run(self)
|
|
|
|
try:
|
|
logger.log("Beginning manual search for: [" + self.segment.prettyName() + "]")
|
|
self.started = True
|
|
|
|
searchResult = search.searchProviders(self.show, [self.segment], True)
|
|
|
|
if searchResult:
|
|
# just use the first result for now
|
|
logger.log(u"Downloading " + searchResult[0].name + " from " + searchResult[0].provider.name)
|
|
self.success = search.snatchEpisode(searchResult[0])
|
|
|
|
# give the CPU a break
|
|
time.sleep(common.cpu_presets[sickbeard.CPU_PRESET])
|
|
|
|
else:
|
|
ui.notifications.message('No downloads were found',
|
|
"Couldn't find a download for <i>%s</i>" % self.segment.prettyName())
|
|
|
|
logger.log(u"Unable to find a download for: [" + self.segment.prettyName() + "]")
|
|
|
|
except Exception:
|
|
logger.log(traceback.format_exc(), logger.DEBUG)
|
|
|
|
### Keep a list with the 100 last executed searches
|
|
fifo(MANUAL_SEARCH_HISTORY, self, MANUAL_SEARCH_HISTORY_SIZE)
|
|
|
|
if self.success is None:
|
|
self.success = False
|
|
|
|
self.finish()
|
|
|
|
|
|
class BacklogQueueItem(generic_queue.QueueItem):
|
|
def __init__(self, show, segment):
|
|
generic_queue.QueueItem.__init__(self, 'Backlog', BACKLOG_SEARCH)
|
|
self.priority = generic_queue.QueuePriorities.LOW
|
|
self.name = 'BACKLOG-' + str(show.indexerid)
|
|
self.success = None
|
|
self.show = show
|
|
self.segment = segment
|
|
|
|
def run(self):
|
|
generic_queue.QueueItem.run(self)
|
|
|
|
try:
|
|
logger.log("Beginning backlog search for: [" + self.show.name + "]")
|
|
searchResult = search.searchProviders(self.show, self.segment, False)
|
|
|
|
if searchResult:
|
|
for result in searchResult:
|
|
# just use the first result for now
|
|
logger.log(u"Downloading " + result.name + " from " + result.provider.name)
|
|
search.snatchEpisode(result)
|
|
|
|
# give the CPU a break
|
|
time.sleep(common.cpu_presets[sickbeard.CPU_PRESET])
|
|
else:
|
|
logger.log(u"No needed episodes found during backlog search for: [" + self.show.name + "]")
|
|
except Exception:
|
|
logger.log(traceback.format_exc(), logger.DEBUG)
|
|
|
|
self.finish()
|
|
|
|
|
|
class FailedQueueItem(generic_queue.QueueItem):
|
|
def __init__(self, show, segment):
|
|
generic_queue.QueueItem.__init__(self, 'Retry', FAILED_SEARCH)
|
|
self.priority = generic_queue.QueuePriorities.HIGH
|
|
self.name = 'RETRY-' + str(show.indexerid)
|
|
self.show = show
|
|
self.segment = segment
|
|
self.success = None
|
|
self.started = None
|
|
|
|
def run(self):
|
|
generic_queue.QueueItem.run(self)
|
|
self.started = True
|
|
|
|
try:
|
|
for epObj in self.segment:
|
|
|
|
logger.log(u"Marking episode as bad: [" + epObj.prettyName() + "]")
|
|
|
|
failed_history.markFailed(epObj)
|
|
|
|
(release, provider) = failed_history.findRelease(epObj)
|
|
if release:
|
|
failed_history.logFailed(release)
|
|
history.logFailed(epObj, release, provider)
|
|
|
|
failed_history.revertEpisode(epObj)
|
|
logger.log("Beginning failed download search for: [" + epObj.prettyName() + "]")
|
|
|
|
searchResult = search.searchProviders(self.show, self.segment, True)
|
|
|
|
if searchResult:
|
|
for result in searchResult:
|
|
# just use the first result for now
|
|
logger.log(u"Downloading " + result.name + " from " + result.provider.name)
|
|
search.snatchEpisode(result)
|
|
|
|
# give the CPU a break
|
|
time.sleep(common.cpu_presets[sickbeard.CPU_PRESET])
|
|
else:
|
|
pass
|
|
#logger.log(u"No valid episode found to retry for: [" + self.segment.prettyName() + "]")
|
|
except Exception:
|
|
logger.log(traceback.format_exc(), logger.DEBUG)
|
|
|
|
### Keep a list with the 100 last executed searches
|
|
fifo(MANUAL_SEARCH_HISTORY, self, MANUAL_SEARCH_HISTORY_SIZE)
|
|
|
|
if self.success is None:
|
|
self.success = False
|
|
|
|
self.finish()
|
|
|
|
def fifo(myList, item, maxSize = 100):
|
|
if len(myList) >= maxSize:
|
|
myList.pop(0)
|
|
myList.append(item) |