mirror of
https://github.com/moparisthebest/SickRage
synced 2024-12-12 11:02:21 -05:00
commit
41deb957fd
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
@ -199,7 +199,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- end list view //-->
|
||||
#else:
|
||||
#else if $layout in ['banner', 'poster']:
|
||||
<!-- start non list view //-->
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
<!--
|
||||
@ -287,6 +287,7 @@
|
||||
#set $today_header = True
|
||||
#end if
|
||||
#if $runtime:
|
||||
#set $cur_ep_enddate = $cur_result["localtime"] + datetime.timedelta(minutes=$runtime)
|
||||
#if $cur_ep_enddate < $today:
|
||||
#set $show_div = "ep_listing listing_overdue"
|
||||
#elif $cur_ep_airdate >= $next_week.date():
|
||||
@ -387,6 +388,43 @@
|
||||
<!-- end non list view //-->
|
||||
#end if
|
||||
|
||||
#if $layout == 'calendar':
|
||||
|
||||
#set $today = datetime.date.today()
|
||||
#set $dates = [$today + datetime.timedelta(days=$i) for $i in range(7)]
|
||||
|
||||
<input type="hidden" id="sbRoot" value="$sbRoot" />
|
||||
#for $day in $dates
|
||||
<table class="sickbeardTable tablesorter" cellspacing="0" border="0" cellpadding="0" style="float:left;width:125px;white-space: nowrap; table-layout: fixed;">
|
||||
<thead><tr><th>$day.strftime("%A").decode($sickbeard.SYS_ENCODING).capitalize()</th></tr></thead>
|
||||
<tbody>
|
||||
|
||||
#for $cur_result in $sql_results:
|
||||
#set $cur_indexer = int($cur_result["indexer"])
|
||||
#set $runtime = $cur_result["runtime"]
|
||||
#set $airday = $cur_result["localtime"].date()
|
||||
|
||||
#if $airday == $day:
|
||||
|
||||
<tr>
|
||||
<td style="overflow: hidden; text-overflow: ellipsis; font-size: 11px; LINE-HEIGHT:12px";>
|
||||
<a href="$sbRoot/home/displayShow?show=${cur_result["showid"]}"><img alt="" src="$sbRoot/showPoster/?show=${cur_result["showid"]}&which=poster_thumb" width="125" /></a>
|
||||
<br> $cur_result["localtime"].strftime("%H:%M") on $cur_result["network"]
|
||||
#set $episodestring = "%sx%s %s" % ($cur_result["season"], $cur_result["episode"], $cur_result["name"])
|
||||
<br> $episodestring
|
||||
</td>
|
||||
</tr>
|
||||
#end if
|
||||
|
||||
<!-- end $cur_result["show_name"] //-->
|
||||
#end for
|
||||
</tbody>
|
||||
</table>
|
||||
#end for
|
||||
|
||||
<!-- end calender view //-->
|
||||
#end if
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
<!--
|
||||
window.setInterval( "location.reload(true)", 600000); // Refresh every 10 minutes
|
||||
|
@ -26,7 +26,6 @@
|
||||
<script type="text/javascript" src="$sbRoot/js/sceneExceptionsTooltip.js?$sbPID"></script>
|
||||
<script type="text/javascript" src="$sbRoot/js/ajaxEpSearch.js?$sbPID"></script>
|
||||
<script type="text/javascript" src="$sbRoot/js/ajaxEpSubtitles.js?$sbPID"></script>
|
||||
<script type="text/javascript" src="$sbRoot/js/ajaxEpRetry.js?$sbPID"></script>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
<!--
|
||||
\$(document).ready(function(){
|
||||
|
@ -1,51 +0,0 @@
|
||||
(function () {
|
||||
|
||||
$.ajaxEpRetry = {
|
||||
defaults: {
|
||||
size: 16,
|
||||
colorRow: false,
|
||||
loadingImage: 'loading16_dddddd.gif',
|
||||
noImage: 'no16.png',
|
||||
yesImage: 'yes16.png'
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.ajaxEpRetry = function (options) {
|
||||
options = $.extend({}, $.ajaxEpRetry.defaults, options);
|
||||
|
||||
$('.epRetry').click(function () {
|
||||
if ( !confirm("Mark download as bad and retry?") )
|
||||
return false;
|
||||
|
||||
var parent = $(this).parent();
|
||||
|
||||
// put the ajax spinner (for non white bg) placeholder while we wait
|
||||
parent.empty();
|
||||
parent.append($("<img/>").attr({"src": sbRoot + "/images/" + options.loadingImage, "height": options.size, "alt": "", "title": "loading"}));
|
||||
|
||||
$.getJSON($(this).attr('href'), function (data) {
|
||||
// if they failed then just put the red X
|
||||
if (data.result == 'failure') {
|
||||
img_name = options.noImage;
|
||||
img_result = 'failed';
|
||||
|
||||
// if the snatch was successful then apply the corresponding class and fill in the row appropriately
|
||||
} else {
|
||||
img_name = options.yesImage;
|
||||
img_result = 'success';
|
||||
// color the row
|
||||
if (options.colorRow) {
|
||||
parent.parent().removeClass('skipped wanted qual good unaired snatched').addClass('snatched');
|
||||
}
|
||||
}
|
||||
|
||||
// put the corresponding image as the result for the the row
|
||||
parent.empty();
|
||||
parent.append($("<img/>").attr({"src": sbRoot + "/images/" + img_name, "height": options.size, "alt": img_result, "title": img_result}));
|
||||
});
|
||||
|
||||
// don't follow the link
|
||||
return false;
|
||||
});
|
||||
};
|
||||
})();
|
@ -123,7 +123,7 @@ function disableLink(el) {
|
||||
$.fn.ajaxEpSearch = function(options){
|
||||
options = $.extend({}, $.ajaxEpSearch.defaults, options);
|
||||
|
||||
$('.epSearch').click(function(event){
|
||||
$('.epSearch, .epRetry').click(function(event){
|
||||
event.preventDefault();
|
||||
|
||||
// Check if we have disabled the click
|
||||
|
@ -267,6 +267,7 @@ $(document).ready(function(){
|
||||
function (data) {
|
||||
var devices = jQuery.parseJSON(data).devices;
|
||||
$("#pushbullet_device_list").html('');
|
||||
$("#pushbullet_device_list").append('<option value="" selected>-- All Devices --</option>')
|
||||
for (var i = 0; i < devices.length; i++) {
|
||||
if(devices[i].active == true) {
|
||||
if(current_pushbullet_device == devices[i].iden) {
|
||||
|
@ -1,7 +1,6 @@
|
||||
$(document).ready(function () {
|
||||
|
||||
$('#sbRoot').ajaxEpSearch({'colorRow': true});
|
||||
//$('#sbRoot').ajaxEpRetry({'colorRow': true});
|
||||
|
||||
$('#sbRoot').ajaxEpSubtitlesSearch();
|
||||
|
||||
|
@ -205,7 +205,8 @@ class Quality:
|
||||
else:
|
||||
return Quality.UNKNOWN
|
||||
|
||||
if checkName(["(pdtv|hdtv|dsr|tvrip).(xvid|x264|h.?264)"], all) and not checkName(["(720|1080)[pi]"], all):
|
||||
if checkName(["(pdtv|hdtv|dsr|tvrip).(xvid|x264|h.?264)"], all) and not checkName(["(720|1080)[pi]"], all) and\
|
||||
not checkName(["hr.ws.pdtv.x264"], any):
|
||||
return Quality.SDTV
|
||||
elif checkName(["web.dl|webrip", "xvid|x264|h.?264"], all) and not checkName(["(720|1080)[pi]"], all):
|
||||
return Quality.SDTV
|
||||
|
@ -50,13 +50,11 @@ class DailySearcher():
|
||||
|
||||
sql_l = []
|
||||
show = None
|
||||
wantedEp = {}
|
||||
|
||||
for sqlEp in sqlResults:
|
||||
try:
|
||||
if not show or int(sqlEp["showid"]) != show.indexerid:
|
||||
show = helpers.findCertainShow(sickbeard.showList, int(sqlEp["showid"]))
|
||||
wantedEp[show] = []
|
||||
|
||||
except exceptions.MultipleShowObjectsException:
|
||||
logger.log(u"ERROR: expected to find a single show matching " + sqlEp["showid"])
|
||||
@ -68,7 +66,6 @@ class DailySearcher():
|
||||
ep.status = common.SKIPPED
|
||||
else:
|
||||
ep.status = common.WANTED
|
||||
wantedEp[show].append(ep)
|
||||
|
||||
sql_l.append(ep.get_sql())
|
||||
else:
|
||||
@ -78,9 +75,8 @@ class DailySearcher():
|
||||
myDB = db.DBConnection()
|
||||
myDB.mass_action(sql_l)
|
||||
|
||||
for show, episode in wantedEp.items():
|
||||
# queue episode for daily search
|
||||
dailysearch_queue_item = sickbeard.search_queue.DailySearchQueueItem(show, episode)
|
||||
sickbeard.searchQueueScheduler.action.add_item(dailysearch_queue_item)
|
||||
# queue episode for daily search
|
||||
dailysearch_queue_item = sickbeard.search_queue.DailySearchQueueItem()
|
||||
sickbeard.searchQueueScheduler.action.add_item(dailysearch_queue_item)
|
||||
|
||||
self.amActive = False
|
@ -118,7 +118,7 @@ class DBConnection(object):
|
||||
else:
|
||||
return 0
|
||||
|
||||
def mass_action(self, querylist, logTransaction=False):
|
||||
def mass_action(self, querylist, logTransaction=False, fetchall=False):
|
||||
|
||||
with db_lock:
|
||||
# remove None types
|
||||
@ -136,11 +136,11 @@ class DBConnection(object):
|
||||
if len(qu) == 1:
|
||||
if logTransaction:
|
||||
logger.log(qu[0], logger.DEBUG)
|
||||
sqlResult.append(self.execute(qu[0]))
|
||||
sqlResult.append(self.execute(qu[0], fetchall=fetchall))
|
||||
elif len(qu) > 1:
|
||||
if logTransaction:
|
||||
logger.log(qu[0] + " with args " + str(qu[1]), logger.DEBUG)
|
||||
sqlResult.append(self.execute(qu[0], qu[1]))
|
||||
sqlResult.append(self.execute(qu[0], qu[1], fetchall=fetchall))
|
||||
|
||||
logger.log(u"Transaction with " + str(len(querylist)) + u" queries executed", logger.DEBUG)
|
||||
|
||||
|
@ -67,7 +67,7 @@ class FailedProcessor(object):
|
||||
for episode in parsed.episode_numbers:
|
||||
segment = parsed.show.getEpisode(parsed.season_number, episode)
|
||||
|
||||
cur_failed_queue_item = search_queue.FailedQueueItem(parsed.show, segment)
|
||||
cur_failed_queue_item = search_queue.FailedQueueItem(parsed.show, [segment])
|
||||
sickbeard.searchQueueScheduler.action.add_item(cur_failed_queue_item)
|
||||
|
||||
return True
|
||||
|
@ -79,13 +79,11 @@ class PushbulletNotifier:
|
||||
|
||||
http_handler = HTTPSConnection("api.pushbullet.com")
|
||||
|
||||
authString = base64.encodestring('%s:' % (pushbullet_api)).replace('\n', '')
|
||||
|
||||
if notificationType == None:
|
||||
testMessage = True
|
||||
try:
|
||||
logger.log(u"Testing Pushbullet authentication and retrieving the device list.", logger.DEBUG)
|
||||
http_handler.request(method, uri, None, headers={'Authorization': 'Basic %s:' % authString})
|
||||
http_handler.request(method, uri, None, headers={'Authorization': 'Bearer %s' % pushbullet_api})
|
||||
except (SSLError, HTTPException, socket.error):
|
||||
logger.log(u"Pushbullet notification failed.", logger.ERROR)
|
||||
return False
|
||||
@ -99,7 +97,7 @@ class PushbulletNotifier:
|
||||
'type': notificationType}
|
||||
data = json.dumps(data)
|
||||
http_handler.request(method, uri, body=data,
|
||||
headers={'Content-Type': 'application/json', 'Authorization': 'Basic %s' % authString})
|
||||
headers={'Content-Type': 'application/json', 'Authorization': 'Bearer %s' % pushbullet_api})
|
||||
pass
|
||||
except (SSLError, HTTPException, socket.error):
|
||||
return False
|
||||
|
@ -203,13 +203,8 @@ class GenericProvider:
|
||||
|
||||
return True
|
||||
|
||||
def searchRSS(self, episode):
|
||||
results = {}
|
||||
|
||||
for ep in episode:
|
||||
results += self.cache.findNeededEpisodes(ep)
|
||||
|
||||
return results
|
||||
def searchRSS(self, episodes):
|
||||
return self.cache.findNeededEpisodes(episodes)
|
||||
|
||||
def getQuality(self, item, anime=False):
|
||||
"""
|
||||
|
@ -194,7 +194,7 @@ class KATProvider(generic.TorrentProvider):
|
||||
if self.show.air_by_date:
|
||||
for show_name in set(allPossibleShowNames(self.show)):
|
||||
ep_string = sanitizeSceneName(show_name) + ' ' + \
|
||||
str(ep_obj.airdate).replace('-', '|')
|
||||
str(ep_obj.airdate).replace('-', ' ')
|
||||
search_string['Episode'].append(ep_string)
|
||||
elif self.show.sports:
|
||||
for show_name in set(allPossibleShowNames(self.show)):
|
||||
|
@ -189,7 +189,7 @@ class NewznabProvider(generic.NZBProvider):
|
||||
params['season'] = date_str.partition('-')[0]
|
||||
params['ep'] = date_str.partition('-')[2].replace('-', '/')
|
||||
elif ep_obj.show.anime:
|
||||
params['ep'] = "%i" % int(ep_obj.scene_absolute_number)
|
||||
params['ep'] = "%i" % int(ep_obj.scene_absolute_number if int(ep_obj.scene_absolute_number) > 0 else ep_obj.scene_episode)
|
||||
else:
|
||||
params['season'] = ep_obj.scene_season
|
||||
params['ep'] = ep_obj.scene_episode
|
||||
@ -207,7 +207,20 @@ class NewznabProvider(generic.NZBProvider):
|
||||
for cur_exception in name_exceptions:
|
||||
params['q'] = helpers.sanitizeSceneName(cur_exception)
|
||||
to_return.append(params)
|
||||
|
||||
|
||||
if ep_obj.show.anime:
|
||||
# Experimental, add a searchstring without search explicitly for the episode!
|
||||
# Remove the ?ep=e46 paramater and use add the episode number to the query paramater.
|
||||
# Can be usefull for newznab indexers that do not have the episodes 100% parsed.
|
||||
# Start with only applying the searchstring to anime shows
|
||||
params['q'] = helpers.sanitizeSceneName(cur_exception)
|
||||
paramsNoEp = params.copy()
|
||||
|
||||
paramsNoEp['q'] = paramsNoEp['q'] + " " + str(paramsNoEp['ep'])
|
||||
if "ep" in paramsNoEp:
|
||||
paramsNoEp.pop("ep")
|
||||
to_return.append(paramsNoEp)
|
||||
|
||||
return to_return
|
||||
|
||||
def _doGeneralSearch(self, search_string):
|
||||
@ -302,17 +315,27 @@ class NewznabProvider(generic.NZBProvider):
|
||||
if total == 0:
|
||||
total = int(data.feed.newznab_response['total'] or 0)
|
||||
offset = int(data.feed.newznab_response['offset'] or 0)
|
||||
|
||||
|
||||
# No items found, prevent from doing another search
|
||||
if total == 0:
|
||||
break
|
||||
|
||||
if offset != params['offset']:
|
||||
logger.log("Tell your newznab provider to fix their bloody newznab responses")
|
||||
break
|
||||
|
||||
# if there are more items available then the amount given in one call, grab some more
|
||||
|
||||
params['offset'] += params['limit']
|
||||
|
||||
logger.log(str(
|
||||
total - offset) + " more items to be fetched from provider. Fetching another " + str(
|
||||
params['limit']) + " items.", logger.DEBUG)
|
||||
if (total > int(params['offset'])):
|
||||
offset = int(params['offset'])
|
||||
# if there are more items available then the amount given in one call, grab some more
|
||||
logger.log(str(
|
||||
total - int(params['offset'])) + " more items to be fetched from provider. Fetching another " + str(
|
||||
params['limit']) + " items.", logger.DEBUG)
|
||||
else:
|
||||
logger.log(str(
|
||||
total - int(params['offset'])) + " No more searches needed, could find anything I was looking for! " + str(
|
||||
params['limit']) + " items.", logger.DEBUG)
|
||||
break
|
||||
|
||||
time.sleep(0.2)
|
||||
|
||||
|
@ -52,7 +52,7 @@ class NyaaProvider(generic.TorrentProvider):
|
||||
|
||||
def getQuality(self, item, anime=False):
|
||||
title = item.title
|
||||
quality = Quality.sceneQuality(title)
|
||||
quality = Quality.sceneQuality(title, anime)
|
||||
return quality
|
||||
|
||||
def findSearchResults(self, show, episodes, search_mode, manualSearch=False):
|
||||
|
@ -53,9 +53,14 @@ class TorrentRssProvider(generic.TorrentProvider):
|
||||
self.cookies = cookies
|
||||
|
||||
def configStr(self):
|
||||
return self.name + '|' + self.url + '|' + self.cookies + '|' + str(
|
||||
int(self.enabled)) + '|' + self.search_mode + '|' + str(int(self.search_fallback)) + '|' + str(
|
||||
int(self.enable_daily)) + '|' + str(int(self.enable_backlog))
|
||||
return "%s|%s|%s|%d|%s|%d|%d|%d" % (self.name or '',
|
||||
self.url or '',
|
||||
self.cookies or '',
|
||||
self.enabled,
|
||||
self.search_mode or '',
|
||||
self.search_fallback,
|
||||
self.enable_daily,
|
||||
self.enable_backlog)
|
||||
|
||||
def imageName(self):
|
||||
if ek.ek(os.path.isfile,
|
||||
|
@ -105,20 +105,21 @@ class TokyoToshokanProvider(generic.TorrentProvider):
|
||||
with BS4Parser(data, features=["html5lib", "permissive"]) as soup:
|
||||
torrent_table = soup.find('table', attrs={'class': 'listing'})
|
||||
torrent_rows = torrent_table.find_all('tr') if torrent_table else []
|
||||
if torrent_rows[0].find('td', attrs={'class': 'centertext'}):
|
||||
a = 1
|
||||
else:
|
||||
a = 0
|
||||
|
||||
for top, bottom in zip(torrent_rows[a::2], torrent_rows[a::2]):
|
||||
title = top.find('td', attrs={'class': 'desc-top'}).text
|
||||
url = top.find('td', attrs={'class': 'desc-top'}).find('a')['href']
|
||||
|
||||
if not title or not url:
|
||||
continue
|
||||
|
||||
item = title.lstrip(), url
|
||||
results.append(item)
|
||||
if torrent_rows:
|
||||
if torrent_rows[0].find('td', attrs={'class': 'centertext'}):
|
||||
a = 1
|
||||
else:
|
||||
a = 0
|
||||
|
||||
for top, bottom in zip(torrent_rows[a::2], torrent_rows[a::2]):
|
||||
title = top.find('td', attrs={'class': 'desc-top'}).text
|
||||
url = top.find('td', attrs={'class': 'desc-top'}).find('a')['href']
|
||||
|
||||
if not title or not url:
|
||||
continue
|
||||
|
||||
item = title.lstrip(), url
|
||||
results.append(item)
|
||||
|
||||
except Exception, e:
|
||||
logger.log(u"Failed to parsing " + self.name + " Traceback: " + traceback.format_exc(), logger.ERROR)
|
||||
|
@ -41,6 +41,7 @@ from sickbeard import failed_history
|
||||
from sickbeard.exceptions import ex
|
||||
from sickbeard.providers.generic import GenericProvider
|
||||
from sickbeard.blackandwhitelist import BlackAndWhiteList
|
||||
from sickbeard import common
|
||||
|
||||
def _downloadResult(result):
|
||||
"""
|
||||
@ -319,16 +320,60 @@ def isFirstBestMatch(result):
|
||||
|
||||
return False
|
||||
|
||||
def searchForNeededEpisodes(show, episode):
|
||||
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:
|
||||
curCompositeStatus = int(result["status"])
|
||||
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():
|
||||
foundResults = {}
|
||||
|
||||
didSearch = False
|
||||
|
||||
# build name cache for show
|
||||
sickbeard.name_cache.buildNameCache(show)
|
||||
|
||||
origThreadName = threading.currentThread().name
|
||||
|
||||
show_list = sickbeard.showList
|
||||
fromDate = datetime.date.fromordinal(1)
|
||||
episodes = []
|
||||
|
||||
for curShow in show_list:
|
||||
if curShow.paused:
|
||||
continue
|
||||
|
||||
episodes.extend(wantedEpisodes(curShow, fromDate))
|
||||
|
||||
providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive() and x.enable_daily]
|
||||
for curProvider in providers:
|
||||
|
||||
@ -336,7 +381,7 @@ def searchForNeededEpisodes(show, episode):
|
||||
|
||||
try:
|
||||
curProvider.cache.updateCache()
|
||||
curFoundResults = curProvider.searchRSS(episode)
|
||||
curFoundResults = curProvider.searchRSS(episodes)
|
||||
except exceptions.AuthException, e:
|
||||
logger.log(u"Authentication error: " + ex(e), logger.ERROR)
|
||||
continue
|
||||
|
@ -85,7 +85,7 @@ class BacklogSearcher:
|
||||
fromDate = datetime.date.fromordinal(1)
|
||||
|
||||
if not which_shows and not curDate - self._lastBacklog >= self.cycleTime:
|
||||
logger.log(u"Running limited backlog on missed episodes " + sickbeard.BACKLOG_DAYS + " day(s) and older only")
|
||||
logger.log(u"Running limited backlog on missed episodes " + str(sickbeard.BACKLOG_DAYS) + " day(s) and older only")
|
||||
fromDate = datetime.date.today() - datetime.timedelta(days=sickbeard.BACKLOG_DAYS)
|
||||
|
||||
self.amActive = True
|
||||
|
@ -84,9 +84,8 @@ class SearchQueue(generic_queue.GenericQueue):
|
||||
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
|
||||
if isinstance(self.currentItem, (ManualSearchQueueItem, FailedQueueItem)):
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_backlog_in_progress(self):
|
||||
@ -116,8 +115,11 @@ class SearchQueue(generic_queue.GenericQueue):
|
||||
|
||||
|
||||
def add_item(self, item):
|
||||
if isinstance(item, (DailySearchQueueItem, BacklogQueueItem)) and not self.is_in_queue(item.show, item.segment):
|
||||
# daily and backlog searches
|
||||
if isinstance(item, DailySearchQueueItem):
|
||||
# daily searches
|
||||
generic_queue.GenericQueue.add_item(self, item)
|
||||
elif isinstance(item, BacklogQueueItem) and not self.is_in_queue(item.show, item.segment):
|
||||
# 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
|
||||
@ -126,20 +128,18 @@ class SearchQueue(generic_queue.GenericQueue):
|
||||
logger.log(u"Not adding item, it's already in the queue", logger.DEBUG)
|
||||
|
||||
class DailySearchQueueItem(generic_queue.QueueItem):
|
||||
def __init__(self, show, segment):
|
||||
def __init__(self):
|
||||
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)
|
||||
logger.log("Beginning daily search for new episodes")
|
||||
foundResults = search.searchForNeededEpisodes()
|
||||
|
||||
if not len(foundResults):
|
||||
logger.log(u"No needed episodes found during daily search for: [" + self.show.name + "]")
|
||||
logger.log(u"No needed episodes found")
|
||||
else:
|
||||
for result in foundResults:
|
||||
# just use the first result for now
|
||||
@ -241,23 +241,28 @@ class FailedQueueItem(generic_queue.QueueItem):
|
||||
self.show = show
|
||||
self.segment = segment
|
||||
self.success = None
|
||||
self.started = None
|
||||
|
||||
def run(self):
|
||||
generic_queue.QueueItem.run(self)
|
||||
|
||||
self.started = True
|
||||
|
||||
try:
|
||||
logger.log(u"Marking episode as bad: [" + self.segment.prettyName() + "]")
|
||||
failed_history.markFailed(self.segment)
|
||||
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() + "]")
|
||||
|
||||
(release, provider) = failed_history.findRelease(self.segment)
|
||||
if release:
|
||||
failed_history.logFailed(release)
|
||||
history.logFailed(self.segment, release, provider)
|
||||
|
||||
failed_history.revertEpisode(self.segment)
|
||||
logger.log("Beginning failed download search for: [" + self.segment.prettyName() + "]")
|
||||
|
||||
searchResult = search.searchProviders(self.show, [self.segment], True)
|
||||
searchResult = search.searchProviders(self.show, self.segment, True)
|
||||
|
||||
if searchResult:
|
||||
for result in searchResult:
|
||||
@ -268,9 +273,13 @@ class FailedQueueItem(generic_queue.QueueItem):
|
||||
# give the CPU a break
|
||||
time.sleep(common.cpu_presets[sickbeard.CPU_PRESET])
|
||||
else:
|
||||
logger.log(u"No valid episode found to retry for: [" + self.segment.prettyName() + "]")
|
||||
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
|
||||
|
@ -190,7 +190,7 @@ def makeSceneSearchString(show, ep_obj):
|
||||
if (show.air_by_date or show.sports) and ep_obj.airdate != datetime.date.fromordinal(1):
|
||||
epStrings = [str(ep_obj.airdate)]
|
||||
elif show.is_anime:
|
||||
epStrings = ["%02i" % int(ep_obj.scene_absolute_number)]
|
||||
epStrings = ["%02i" % int(ep_obj.scene_absolute_number if ep_obj.scene_absolute_number > 0 else ep_obj.scene_episode)]
|
||||
else:
|
||||
epStrings = ["S%02iE%02i" % (int(ep_obj.scene_season), int(ep_obj.scene_episode)),
|
||||
"%ix%02i" % (int(ep_obj.scene_season), int(ep_obj.scene_episode))]
|
||||
|
@ -1305,6 +1305,8 @@ class TVEpisode(object):
|
||||
|
||||
self.checkForMetaFiles()
|
||||
|
||||
self.wantedQuality = []
|
||||
|
||||
name = property(lambda self: self._name, dirty_setter("_name"))
|
||||
season = property(lambda self: self._season, dirty_setter("_season"))
|
||||
episode = property(lambda self: self._episode, dirty_setter("_episode"))
|
||||
|
@ -32,6 +32,7 @@ from sickbeard.exceptions import AuthException
|
||||
from name_parser.parser import NameParser, InvalidNameException, InvalidShowException
|
||||
from sickbeard.rssfeeds import RSSFeeds
|
||||
from sickbeard import clients
|
||||
import itertools
|
||||
|
||||
class CacheDBConnection(db.DBConnection):
|
||||
def __init__(self, providerName):
|
||||
@ -279,7 +280,10 @@ class TVCache():
|
||||
|
||||
def searchCache(self, episode, manualSearch=False):
|
||||
neededEps = self.findNeededEpisodes(episode, manualSearch)
|
||||
return neededEps[episode]
|
||||
if len(neededEps) > 0:
|
||||
return neededEps[episode]
|
||||
else:
|
||||
return []
|
||||
|
||||
def listPropers(self, date=None, delimiter="."):
|
||||
myDB = self._getDB()
|
||||
@ -291,19 +295,24 @@ class TVCache():
|
||||
return filter(lambda x: x['indexerid'] != 0, myDB.select(sql))
|
||||
|
||||
|
||||
def findNeededEpisodes(self, episode=None, manualSearch=False):
|
||||
def findNeededEpisodes(self, episode, manualSearch=False):
|
||||
neededEps = {}
|
||||
|
||||
if episode:
|
||||
neededEps[episode] = []
|
||||
cl = []
|
||||
|
||||
myDB = self._getDB()
|
||||
if not episode:
|
||||
sqlResults = myDB.select("SELECT * FROM [" + self.providerID + "]")
|
||||
else:
|
||||
if type(episode) != list:
|
||||
sqlResults = myDB.select(
|
||||
"SELECT * FROM [" + self.providerID + "] WHERE indexerid = ? AND season = ? AND episodes LIKE ?",
|
||||
[episode.show.indexerid, episode.season, "%|" + str(episode.episode) + "|%"])
|
||||
else:
|
||||
for epObj in episode:
|
||||
cl.append([
|
||||
"SELECT * FROM [" + self.providerID + "] WHERE indexerid = ? AND season = ? AND episodes LIKE ? "
|
||||
"AND quality IN (" + ",".join([str(x) for x in epObj.wantedQuality]) + ")",
|
||||
[epObj.show.indexerid, epObj.season, "%|" + str(epObj.episode) + "|%"]])
|
||||
|
||||
sqlResults = myDB.mass_action(cl, fetchall=True)
|
||||
sqlResults = list(itertools.chain(*sqlResults))
|
||||
|
||||
# for each cache entry
|
||||
for curResult in sqlResults:
|
||||
@ -341,10 +350,7 @@ class TVCache():
|
||||
Quality.qualityStrings[curQuality], logger.DEBUG)
|
||||
continue
|
||||
|
||||
if episode:
|
||||
epObj = episode
|
||||
else:
|
||||
epObj = showObj.getEpisode(curSeason, curEp)
|
||||
epObj = showObj.getEpisode(curSeason, curEp)
|
||||
|
||||
# build a result object
|
||||
title = curResult["name"]
|
||||
|
@ -305,9 +305,12 @@ class MainHandler(RequestHandler):
|
||||
redirect("/home/displayShow?show=" + show)
|
||||
|
||||
def setComingEpsLayout(self, layout):
|
||||
if layout not in ('poster', 'banner', 'list'):
|
||||
if layout not in ('poster', 'banner', 'list', 'calendar'):
|
||||
layout = 'banner'
|
||||
|
||||
if layout == 'calendar':
|
||||
sickbeard.COMING_EPS_SORT = 'date'
|
||||
|
||||
sickbeard.COMING_EPS_LAYOUT = layout
|
||||
|
||||
redirect("/comingEpisodes/")
|
||||
@ -321,6 +324,9 @@ class MainHandler(RequestHandler):
|
||||
def setComingEpsSort(self, sort):
|
||||
if sort not in ('date', 'network', 'show'):
|
||||
sort = 'date'
|
||||
|
||||
if sickbeard.COMING_EPS_LAYOUT == 'calendar':
|
||||
sort = 'date'
|
||||
|
||||
sickbeard.COMING_EPS_SORT = sort
|
||||
|
||||
@ -390,6 +396,7 @@ class MainHandler(RequestHandler):
|
||||
{'title': 'Layout:', 'path': {'Banner': 'setComingEpsLayout/?layout=banner',
|
||||
'Poster': 'setComingEpsLayout/?layout=poster',
|
||||
'List': 'setComingEpsLayout/?layout=list',
|
||||
'Calendar': 'setComingEpsLayout/?layout=calendar',
|
||||
}},
|
||||
paused_item,
|
||||
]
|
||||
@ -399,7 +406,7 @@ class MainHandler(RequestHandler):
|
||||
t.sql_results = sql_results
|
||||
|
||||
# Allow local overriding of layout parameter
|
||||
if layout and layout in ('poster', 'banner', 'list'):
|
||||
if layout and layout in ('poster', 'banner', 'list','calendar'):
|
||||
t.layout = layout
|
||||
else:
|
||||
t.layout = sickbeard.COMING_EPS_LAYOUT
|
||||
@ -4197,7 +4204,7 @@ class Home(MainHandler):
|
||||
msg = "Retrying Search was automatically started for the following season of <b>" + showObj.name + "</b>:<br />"
|
||||
|
||||
for season, segment in segments.items():
|
||||
cur_failed_queue_item = search_queue.FailedQueueItem(showObj, segment)
|
||||
cur_failed_queue_item = search_queue.FailedQueueItem(showObj, [segment])
|
||||
sickbeard.searchQueueScheduler.action.add_item(cur_failed_queue_item) # @UndefinedVariable
|
||||
|
||||
msg += "<li>Season " + str(season) + "</li>"
|
||||
@ -4351,36 +4358,59 @@ class Home(MainHandler):
|
||||
if currentManualSearchThreadsQueued:
|
||||
for searchThread in currentManualSearchThreadsQueued:
|
||||
searchstatus = 'queued'
|
||||
|
||||
episodes.append({'episode': searchThread.segment.episode,
|
||||
'episodeindexid': searchThread.segment.indexerid,
|
||||
'season' : searchThread.segment.season,
|
||||
'searchstatus' : searchstatus,
|
||||
'status' : statusStrings[searchThread.segment.status],
|
||||
'quality': self.getQualityClass(searchThread.segment)})
|
||||
if isinstance(searchThread, sickbeard.search_queue.ManualSearchQueueItem):
|
||||
episodes.append({'episode': searchThread.segment.episode,
|
||||
'episodeindexid': searchThread.segment.indexerid,
|
||||
'season' : searchThread.segment.season,
|
||||
'searchstatus' : searchstatus,
|
||||
'status' : statusStrings[searchThread.segment.status],
|
||||
'quality': self.getQualityClass(searchThread.segment)})
|
||||
else:
|
||||
for epObj in searchThread.segment:
|
||||
episodes.append({'episode': epObj.episode,
|
||||
'episodeindexid': epObj.indexerid,
|
||||
'season' : epObj.season,
|
||||
'searchstatus' : searchstatus,
|
||||
'status' : statusStrings[epObj.status],
|
||||
'quality': self.getQualityClass(epObj)})
|
||||
|
||||
if currentManualSearchThreadActive:
|
||||
searchThread = currentManualSearchThreadActive
|
||||
searchstatus = 'searching'
|
||||
if searchThread.success:
|
||||
searchstatus = 'finished'
|
||||
else:
|
||||
searchstatus = 'searching'
|
||||
episodes.append({'episode': searchThread.segment.episode,
|
||||
'episodeindexid': searchThread.segment.indexerid,
|
||||
'season' : searchThread.segment.season,
|
||||
'searchstatus' : searchstatus,
|
||||
'status' : statusStrings[searchThread.segment.status],
|
||||
'quality': self.getQualityClass(searchThread.segment)})
|
||||
|
||||
if finishedManualSearchThreadItems:
|
||||
for searchThread in finishedManualSearchThreadItems:
|
||||
if str(searchThread.show.indexerid) == show and not [x for x in episodes if x['episodeindexid'] == searchThread.segment.indexerid]:
|
||||
searchstatus = 'finished'
|
||||
episodes.append({'episode': searchThread.segment.episode,
|
||||
'episodeindexid': searchThread.segment.indexerid,
|
||||
'season' : searchThread.segment.season,
|
||||
'searchstatus' : searchstatus,
|
||||
'status' : statusStrings[searchThread.segment.status],
|
||||
'quality': self.getQualityClass(searchThread.segment)})
|
||||
|
||||
if finishedManualSearchThreadItems:
|
||||
for searchThread in finishedManualSearchThreadItems:
|
||||
if isinstance(searchThread, sickbeard.search_queue.ManualSearchQueueItem):
|
||||
if str(searchThread.show.indexerid) == show and not [x for x in episodes if x['episodeindexid'] == searchThread.segment.indexerid]:
|
||||
searchstatus = 'finished'
|
||||
episodes.append({'episode': searchThread.segment.episode,
|
||||
'episodeindexid': searchThread.segment.indexerid,
|
||||
'season' : searchThread.segment.season,
|
||||
'searchstatus' : searchstatus,
|
||||
'status' : statusStrings[searchThread.segment.status],
|
||||
'quality': self.getQualityClass(searchThread.segment)})
|
||||
else:
|
||||
### These are only Failed Downloads/Retry SearchThreadItems.. lets loop through the segement/episodes
|
||||
if str(searchThread.show.indexerid) == show:
|
||||
for epObj in searchThread.segment:
|
||||
if not [x for x in episodes if x['episodeindexid'] == epObj.indexerid]:
|
||||
searchstatus = 'finished'
|
||||
episodes.append({'episode': epObj.episode,
|
||||
'episodeindexid': epObj.indexerid,
|
||||
'season' : epObj.season,
|
||||
'searchstatus' : searchstatus,
|
||||
'status' : statusStrings[epObj.status],
|
||||
'quality': self.getQualityClass(epObj)})
|
||||
|
||||
return json.dumps({'show': show, 'episodes' : episodes})
|
||||
|
||||
@ -4507,29 +4537,18 @@ class Home(MainHandler):
|
||||
return json.dumps({'result': 'failure'})
|
||||
|
||||
# make a queue item for it and put it on the queue
|
||||
ep_queue_item = search_queue.FailedQueueItem(ep_obj.show, ep_obj)
|
||||
ep_queue_item = search_queue.FailedQueueItem(ep_obj.show, [ep_obj])
|
||||
sickbeard.searchQueueScheduler.action.add_item(ep_queue_item) # @UndefinedVariable
|
||||
|
||||
# wait until the queue item tells us whether it worked or not
|
||||
while ep_queue_item.success is None: # @UndefinedVariable
|
||||
time.sleep(cpu_presets[sickbeard.CPU_PRESET])
|
||||
|
||||
# return the correct json value
|
||||
if ep_queue_item.success:
|
||||
# Find the quality class for the episode
|
||||
quality_class = Quality.qualityStrings[Quality.UNKNOWN]
|
||||
ep_status, ep_quality = Quality.splitCompositeStatus(ep_obj.status)
|
||||
for x in (SD, HD720p, HD1080p):
|
||||
if ep_quality in Quality.splitQuality(x)[0]:
|
||||
quality_class = qualityPresetStrings[x]
|
||||
break
|
||||
|
||||
return json.dumps({'result': statusStrings[ep_obj.status],
|
||||
'quality': quality_class
|
||||
})
|
||||
|
||||
return json.dumps({'result': 'failure'})
|
||||
|
||||
return returnManualSearchResult(ep_queue_item)
|
||||
if not ep_queue_item.started and ep_queue_item.success is None:
|
||||
return json.dumps({'result': 'success'}) #I Actually want to call it queued, because the search hasnt been started yet!
|
||||
if ep_queue_item.started and ep_queue_item.success is None:
|
||||
return json.dumps({'result': 'success'})
|
||||
else:
|
||||
return json.dumps({'result': 'failure'})
|
||||
|
||||
|
||||
class UI(MainHandler):
|
||||
def add_message(self):
|
||||
|
@ -100,12 +100,12 @@ class SceneExceptionTestCase(test.SickbeardTestDBCase):
|
||||
self.assertEqual(sorted(scene_exceptions.get_scene_exceptions(70726)), ['Babylon 5', 'Babylon5'])
|
||||
|
||||
def test_sceneExceptionByName(self):
|
||||
self.assertEqual(scene_exceptions.get_scene_exception_by_name('Babylon5'), 70726)
|
||||
self.assertEqual(scene_exceptions.get_scene_exception_by_name('babylon 5'), 70726)
|
||||
self.assertEqual(scene_exceptions.get_scene_exception_by_name('Carlos 2010'), 164451)
|
||||
self.assertEqual(scene_exceptions.get_scene_exception_by_name('Babylon5'), (70726, -1))
|
||||
self.assertEqual(scene_exceptions.get_scene_exception_by_name('babylon 5'), (70726, -1))
|
||||
self.assertEqual(scene_exceptions.get_scene_exception_by_name('Carlos 2010'), (164451, -1))
|
||||
|
||||
def test_sceneExceptionByNameEmpty(self):
|
||||
self.assertEqual(scene_exceptions.get_scene_exception_by_name('nothing useful'), None)
|
||||
self.assertEqual(scene_exceptions.get_scene_exception_by_name('nothing useful'), (None, None))
|
||||
|
||||
def test_sceneExceptionsResetNameCache(self):
|
||||
# clear the exceptions
|
||||
|
@ -68,15 +68,15 @@ class XEMBasicTests(test.SickbeardTestDBCase):
|
||||
name = "Game.of.Thrones.S03.720p.HDTV.x264-CtrlHD"
|
||||
release = "Game of Thrones"
|
||||
|
||||
m = re.match('(?P<ep_ab_num>(?>\d{1,3})(?![ip])).+', name)
|
||||
# m = re.match('(?P<ep_ab_num>(?>\d{1,3})(?![ip])).+', name)
|
||||
|
||||
escaped_name = re.sub('\\\\[\\s.-]', '\W+', re.escape(release))
|
||||
curRegex = '^' + escaped_name + '\W+(?:(?:S\d[\dE._ -])|(?:\d\d?x)|(?:\d{4}\W\d\d\W\d\d)|(?:(?:part|pt)[\._ -]?(\d|[ivx]))|Season\W+\d+\W+|E\d+\W+|(?:\d{1,3}.+\d{1,}[a-zA-Z]{2}\W+[a-zA-Z]{3,}\W+\d{4}.+))'
|
||||
print(u"Checking if show " + name + " matches " + curRegex)
|
||||
# print(u"Checking if show " + name + " matches " + curRegex)
|
||||
|
||||
match = re.search(curRegex, name, re.I)
|
||||
if match:
|
||||
print(u"Matched " + curRegex + " to " + name)
|
||||
# if match:
|
||||
# print(u"Matched " + curRegex + " to " + name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
Loading…
Reference in New Issue
Block a user