1
0
mirror of https://github.com/moparisthebest/SickRage synced 2024-08-13 16:53:54 -04:00

Merge pull request #822 from echel0n/dev

Dev
This commit is contained in:
echel0n 2014-09-21 13:19:19 -07:00
commit 41deb957fd
27 changed files with 284 additions and 198 deletions

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -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"]}&amp;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

View File

@ -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(){

View File

@ -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;
});
};
})();

View File

@ -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

View File

@ -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) {

View File

@ -1,7 +1,6 @@
$(document).ready(function () {
$('#sbRoot').ajaxEpSearch({'colorRow': true});
//$('#sbRoot').ajaxEpRetry({'colorRow': true});
$('#sbRoot').ajaxEpSubtitlesSearch();

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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):
"""

View File

@ -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)):

View File

@ -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)

View File

@ -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):

View File

@ -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,

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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))]

View File

@ -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"))

View File

@ -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"]

View File

@ -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):

View File

@ -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

View File

@ -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__":