1
0
mirror of https://github.com/moparisthebest/SickRage synced 2024-12-13 03:22:22 -05:00

Merge branch 'dev'

This commit is contained in:
echel0n 2014-08-31 12:57:14 -07:00
commit fc9e451f15
53 changed files with 2205 additions and 1789 deletions

View File

@ -26,6 +26,7 @@
#end if #end if
<script type="text/javascript" src="$sbRoot/js/config.js?$sbPID"></script> <script type="text/javascript" src="$sbRoot/js/config.js?$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/rootDirs.js?$sbPID"></script>
<div id="config"> <div id="config">
<div id="config-content"> <div id="config-content">
@ -167,6 +168,14 @@
</label> </label>
</div> </div>
<div class="field-pair">
<label class="clearfix">
<span class="component-title">Show Root Directories</span>
<span class="component-desc">Set root directories for where you want your shows to be.</span>
#include $os.path.join($sickbeard.PROG_DIR, "gui/slick/interfaces/default/inc_rootDirs.tmpl")
</label>
</div>
<input type="submit" class="btn config_submitter" value="Save Changes" /> <input type="submit" class="btn config_submitter" value="Save Changes" />
</fieldset> </fieldset>
</div><!-- /component-group1 //--> </div><!-- /component-group1 //-->

View File

@ -156,14 +156,24 @@ var show_nzb_providers = #if $sickbeard.USE_NZBS then "true" else "false"#;
</div> </div>
#end if #end if
#if $hasattr($curNewznabProvider, 'backlog_only'): #if $hasattr($curNewznabProvider, 'enable_daily'):
<div class="field-pair"> <div class="field-pair">
<input type="checkbox" name="${curNewznabProvider.getID()}_backlog_only" id="${curNewznabProvider.getID()}_backlog_only" #if $curNewznabProvider.backlog_only then "checked=\"checked\"" else ""#/> <input type="checkbox" name="${curNewznabProvider.getID()}_enable_daily" id="${curNewznabProvider.getID()}_enable_daily" #if $curNewznabProvider.enable_daily then "checked=\"checked\"" else ""#/>
<label class="clearfix" for="${curNewznabProvider.getID()}_backlog_only"> <label class="clearfix" for="${curNewznabProvider.getID()}_enable_daily">
<span class="component-title">Backlog Only</span> <span class="component-title">Enable Daily Searches</span>
<span class="component-desc"> <span class="component-desc">
Sets the provider to only be used for<br> Enables daily searches</span>
backlog searches.</span> </label>
</div>
#end if
#if $hasattr($curNewznabProvider, 'enable_backlog'):
<div class="field-pair">
<input type="checkbox" name="${curNewznabProvider.getID()}_enable_backlog" id="${curNewznabProvider.getID()}_enable_backlog" #if $curNewznabProvider.enable_backlog then "checked=\"checked\"" else ""#/>
<label class="clearfix" for="${curNewznabProvider.getID()}_enable_backlog">
<span class="component-title">Enable Backlog Searches</span>
<span class="component-desc">
Enables backlog searches</span>
</label> </label>
</div> </div>
#end if #end if
@ -190,7 +200,7 @@ var show_nzb_providers = #if $sickbeard.USE_NZBS then "true" else "false"#;
When searching for complete seasons<br> When searching for complete seasons<br>
you can choose to have it look for season<br> you can choose to have it look for season<br>
packs ONLY or choose to have it build a<br> packs ONLY or choose to have it build a<br>
complete season from just single episodes.</span> complete season from just single episodes.<br></span>
<span class="component-title"></span> <span class="component-title"></span>
<input type="radio" name="${curNewznabProvider.getID()}_search_mode" id="${curNewznabProvider.getID()}_search_mode_sponly" value="sponly" class="radio" #if $curNewznabProvider.search_mode=="sponly" then "checked=\"checked\"" else ""# />Season Packs ONLY!<br /> <input type="radio" name="${curNewznabProvider.getID()}_search_mode" id="${curNewznabProvider.getID()}_search_mode_sponly" value="sponly" class="radio" #if $curNewznabProvider.search_mode=="sponly" then "checked=\"checked\"" else ""# />Season Packs ONLY!<br />
@ -224,14 +234,24 @@ var show_nzb_providers = #if $sickbeard.USE_NZBS then "true" else "false"#;
</div> </div>
#end if #end if
#if $hasattr($curNzbProvider, 'backlog_only'): #if $hasattr($curNzbProvider, 'enable_daily'):
<div class="field-pair"> <div class="field-pair">
<input type="checkbox" name="${curNzbProvider.getID()}_backlog_only" id="${curNzbProvider.getID()}_backlog_only" #if $curNzbProvider.backlog_only then "checked=\"checked\"" else ""#/> <input type="checkbox" name="${curNzbProvider.getID()}_enable_daily" id="${curNzbProvider.getID()}_enable_daily" #if $curNzbProvider.enable_daily then "checked=\"checked\"" else ""#/>
<label class="clearfix" for="${curNzbProvider.getID()}_backlog_only"> <label class="clearfix" for="${curNzbProvider.getID()}_enable_daily">
<span class="component-title">Backlog Only</span> <span class="component-title">Enable Daily Searches</span>
<span class="component-desc"> <span class="component-desc">
Sets the provider to only be used for<br> Enables daily searches</span>
backlog searches.</span> </label>
</div>
#end if
#if $hasattr($curNzbProvider, 'enable_backlog'):
<div class="field-pair">
<input type="checkbox" name="${curNzbProvider.getID()}_enable_backlog" id="${curNzbProvider.getID()}_enable_backlog" #if $curNzbProvider.enable_backlog then "checked=\"checked\"" else ""#/>
<label class="clearfix" for="${curNzbProvider.getID()}_enable_backlog">
<span class="component-title">Enable Backlog Searches</span>
<span class="component-desc">
Enables backlog searches</span>
</label> </label>
</div> </div>
#end if #end if
@ -440,14 +460,24 @@ var show_nzb_providers = #if $sickbeard.USE_NZBS then "true" else "false"#;
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'backlog_only'): #if $hasattr($curTorrentProvider, 'enable_daily'):
<div class="field-pair"> <div class="field-pair">
<input type="checkbox" name="${curTorrentProvider.getID()}_backlog_only" id="${curTorrentProvider.getID()}_backlog_only" #if $curTorrentProvider.backlog_only then "checked=\"checked\"" else ""#/> <input type="checkbox" name="${curTorrentProvider.getID()}_enable_daily" id="${curTorrentProvider.getID()}_enable_daily" #if $curTorrentProvider.enable_daily then "checked=\"checked\"" else ""#/>
<label class="clearfix" for="${curTorrentProvider.getID()}_backlog_only"> <label class="clearfix" for="${curTorrentProvider.getID()}_enable_daily">
<span class="component-title">Backlog Only</span> <span class="component-title">Enable Daily Searches</span>
<span class="component-desc"> <span class="component-desc">
Sets the provider to only be used for<br> Enables daily searches</span>
backlog searches.</span> </label>
</div>
#end if
#if $hasattr($curTorrentProvider, 'enable_backlog'):
<div class="field-pair">
<input type="checkbox" name="${curTorrentProvider.getID()}_enable_backlog" id="${curTorrentProvider.getID()}_enable_backlog" #if $curTorrentProvider.enable_backlog then "checked=\"checked\"" else ""#/>
<label class="clearfix" for="${curTorrentProvider.getID()}_enable_backlog">
<span class="component-title">Enable Backlog Searches</span>
<span class="component-desc">
Enables backlog searches</span>
</label> </label>
</div> </div>
#end if #end if

View File

@ -147,6 +147,7 @@ a > i.icon-question-sign { background-image: url("$sbRoot/images/glyphicons-half
\$("#SubMenu a[href*='/home/logout/']").addClass('btn').html('<span class="ui-icon ui-icon-power pull-left"></span> Logout'); \$("#SubMenu a[href*='/home/logout/']").addClass('btn').html('<span class="ui-icon ui-icon-power pull-left"></span> Logout');
\$("#SubMenu a:contains('Edit')").addClass('btn').html('<span class="ui-icon ui-icon-pencil pull-left"></span> Edit'); \$("#SubMenu a:contains('Edit')").addClass('btn').html('<span class="ui-icon ui-icon-pencil pull-left"></span> Edit');
\$("#SubMenu a:contains('Delete')").addClass('btn').html('<span class="ui-icon ui-icon-trash pull-left"></span> Delete'); \$("#SubMenu a:contains('Delete')").addClass('btn').html('<span class="ui-icon ui-icon-trash pull-left"></span> Delete');
\$("#SubMenu a:contains('Remove')").addClass('btn').html('<span class="ui-icon ui-icon-trash pull-left"></span> Remove');
\$("#SubMenu a:contains('Clear History')").addClass('btn confirm').html('<span class="ui-icon ui-icon-trash pull-left"></span> Clear History'); \$("#SubMenu a:contains('Clear History')").addClass('btn confirm').html('<span class="ui-icon ui-icon-trash pull-left"></span> Clear History');
\$("#SubMenu a:contains('Trim History')").addClass('btn confirm').html('<span class="ui-icon ui-icon-trash pull-left"></span> Trim History'); \$("#SubMenu a:contains('Trim History')").addClass('btn confirm').html('<span class="ui-icon ui-icon-trash pull-left"></span> Trim History');
\$("#SubMenu a[href$='/errorlogs/clearerrors/']").addClass('btn').html('<span class="ui-icon ui-icon-trash pull-left"></span> Clear Errors'); \$("#SubMenu a[href$='/errorlogs/clearerrors/']").addClass('btn').html('<span class="ui-icon ui-icon-trash pull-left"></span> Clear Errors');

View File

@ -102,6 +102,7 @@
#end if #end if
<!-- <th>Force Metadata Regen <input type="checkbox" class="bulkCheck" id="metadataCheck" /></th>//--> <!-- <th>Force Metadata Regen <input type="checkbox" class="bulkCheck" id="metadataCheck" /></th>//-->
<th width="1%">Delete<br/><input type="checkbox" class="bulkCheck" id="deleteCheck" /></th> <th width="1%">Delete<br/><input type="checkbox" class="bulkCheck" id="deleteCheck" /></th>
<th width="1%">Remove<br/><input type="checkbox" class="bulkCheck" id="removeCheck" /></th>
</tr> </tr>
</thead> </thead>
<tfoot> <tfoot>
@ -120,6 +121,7 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name))
#set $curRename_disabled = "" #set $curRename_disabled = ""
#set $curSubtitle_disabled = "" #set $curSubtitle_disabled = ""
#set $curDelete_disabled = "" #set $curDelete_disabled = ""
#set $curRemove_disabled = ""
#if $sickbeard.showQueueScheduler.action.isBeingUpdated($curShow) or $sickbeard.showQueueScheduler.action.isInUpdateQueue($curShow): #if $sickbeard.showQueueScheduler.action.isBeingUpdated($curShow) or $sickbeard.showQueueScheduler.action.isInUpdateQueue($curShow):
#set $curUpdate_disabled = "disabled=\"disabled\" " #set $curUpdate_disabled = "disabled=\"disabled\" "
@ -141,6 +143,10 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name))
#set $curDelete = "disabled=\"disabled\" " #set $curDelete = "disabled=\"disabled\" "
#end if #end if
#set $curDelete = "<input type=\"checkbox\" class=\"deleteCheck\" id=\"delete-"+str($curShow.indexerid)+"\" "+$curDelete_disabled+"/>" #set $curDelete = "<input type=\"checkbox\" class=\"deleteCheck\" id=\"delete-"+str($curShow.indexerid)+"\" "+$curDelete_disabled+"/>"
#if $sickbeard.showQueueScheduler.action.isBeingRenamed($curShow) or $sickbeard.showQueueScheduler.action.isInRenameQueue($curShow) or $sickbeard.showQueueScheduler.action.isInRefreshQueue($curShow):
#set $curRemove = "disabled=\"disabled\" "
#end if
#set $curRemove = "<input type=\"checkbox\" class=\"removeCheck\" id=\"remove-"+str($curShow.indexerid)+"\" "+$curRemove_disabled+"/>"
<tr> <tr>
<td align="center"><input type="checkbox" class="editCheck" id="edit-$curShow.indexerid" /></td> <td align="center"><input type="checkbox" class="editCheck" id="edit-$curShow.indexerid" /></td>
@ -163,6 +169,7 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name))
<td align="center">$curSubtitle</td> <td align="center">$curSubtitle</td>
#end if #end if
<td align="center">$curDelete</td> <td align="center">$curDelete</td>
<td align="center">$curRemove</td>
</tr> </tr>
#end for #end for
</tbody> </tbody>

View File

@ -27,6 +27,7 @@
#set $cur_index = $root_dir_list.index($cur_dir) #set $cur_index = $root_dir_list.index($cur_dir)
<div style="padding: 6px 0 3px 25px;"> <div style="padding: 6px 0 3px 25px;">
<input class="btn edit_root_dir" type="button" class="edit_root_dir" id="edit_root_dir_$cur_index" value="Edit" /> <input class="btn edit_root_dir" type="button" class="edit_root_dir" id="edit_root_dir_$cur_index" value="Edit" />
<input class="btn delete_root_dir" type="button" class="delete_root_dir" id="delete_root_dir_$cur_index" value="Delete" />
$cur_dir => <span id="display_new_root_dir_$cur_index">$cur_dir</span> $cur_dir => <span id="display_new_root_dir_$cur_index">$cur_dir</span>
</div> </div>
<input type="hidden" name="orig_root_dir_$cur_index" value="$cur_dir" /> <input type="hidden" name="orig_root_dir_$cur_index" value="$cur_dir" />

View File

@ -63,7 +63,7 @@ $(document).ready(function(){
$('#Torrent_username').show(); $('#Torrent_username').show();
$('#Torrent_Path').show(); $('#Torrent_Path').show();
$('#Torrent_Ratio').show(); $('#Torrent_Ratio').show();
$('#Torrent_Seed_Time').hide(); $('#Torrent_Seed_Time').show();
$('#Torrent_High_Bandwidth').show(); $('#Torrent_High_Bandwidth').show();
$('#Torrent_Label').hide(); $('#Torrent_Label').hide();
$('#host_desc').html('Transmission Host'); $('#host_desc').html('Transmission Host');

View File

@ -22,4 +22,10 @@ $(document).ready(function(){
}); });
$('.delete_root_dir').click(function(){
var cur_id = find_dir_index($(this).attr('id'));
$('#new_root_dir_'+cur_id).val(null);
$('#display_new_root_dir_'+cur_id).html('<b>DELETED</b>');
});
}); });

View File

@ -24,6 +24,7 @@ $(document).ready(function(){
var renameArr = new Array() var renameArr = new Array()
var subtitleArr = new Array() var subtitleArr = new Array()
var deleteArr = new Array() var deleteArr = new Array()
var removeArr = new Array()
var metadataArr = new Array() var metadataArr = new Array()
$('.updateCheck').each(function() { $('.updateCheck').each(function() {
@ -56,6 +57,12 @@ $(document).ready(function(){
} }
}); });
$('.removeCheck').each(function() {
if (this.checked == true) {
removeArr.push($(this).attr('id').split('-')[1])
}
});
/* /*
$('.metadataCheck').each(function() { $('.metadataCheck').each(function() {
if (this.checked == true) { if (this.checked == true) {
@ -63,10 +70,10 @@ $(document).ready(function(){
} }
}); });
*/ */
if (updateArr.length+refreshArr.length+renameArr.length+subtitleArr.length+deleteArr.length+metadataArr.length == 0) if (updateArr.length+refreshArr.length+renameArr.length+subtitleArr.length+deleteArr.length+removeArr.length+metadataArr.length == 0)
return false return false
url = 'massUpdate?toUpdate='+updateArr.join('|')+'&toRefresh='+refreshArr.join('|')+'&toRename='+renameArr.join('|')+'&toSubtitle='+subtitleArr.join('|')+'&toDelete='+deleteArr.join('|')+'&toMetadata='+metadataArr.join('|') url = 'massUpdate?toUpdate='+updateArr.join('|')+'&toRefresh='+refreshArr.join('|')+'&toRename='+renameArr.join('|')+'&toSubtitle='+subtitleArr.join('|')+'&toDelete='+deleteArr.join('|')+'&toRemove='+removeArr.join('|')+'&toMetadata='+metadataArr.join('|')
window.location.href = url window.location.href = url
@ -83,7 +90,7 @@ $(document).ready(function(){
}); });
}); });
['.editCheck', '.updateCheck', '.refreshCheck', '.renameCheck', '.deleteCheck'].forEach(function(name) { ['.editCheck', '.updateCheck', '.refreshCheck', '.renameCheck', '.deleteCheck', '.removeCheck'].forEach(function(name) {
var lastCheck = null; var lastCheck = null;
$(name).click(function(event) { $(name).click(function(event) {

View File

@ -244,6 +244,23 @@ class Connection(threading.Thread):
""" """
return self.handle(PushAckCommand(nid), callback) return self.handle(PushAckCommand(nid), callback)
def notification(self, aid=None, gid=None, type=None, priority=None, callback=None):
"""
Add a notification
parameters:
aid - Anime id
gid - Group id
type - Type of notification: type=> 0=all, 1=new, 2=group, 3=complete
priority - low = 0, medium = 1, high = 2 (unconfirmed)
structure of parameters:
[aid={int}|gid={int}]&type={int}&priority={int}
"""
return self.handle(Notification(aid, gid, type, priority), callback)
def notifyadd(self, aid=None, gid=None, type=None, priority=None, callback=None): def notifyadd(self, aid=None, gid=None, type=None, priority=None, callback=None):
""" """
Add a notification Add a notification
@ -261,6 +278,22 @@ class Connection(threading.Thread):
return self.handle(NotifyAddCommand(aid, gid, type, priority), callback) return self.handle(NotifyAddCommand(aid, gid, type, priority), callback)
def notifydel(self, aid=None, gid=None, type=None, priority=None, callback=None):
"""
Add a notification
parameters:
aid - Anime id
gid - Group id
type - Type of notification: type=> 0=all, 1=new, 2=group, 3=complete
priority - low = 0, medium = 1, high = 2 (unconfirmed)
structure of parameters:
[aid={int}|gid={int}]&type={int}&priority={int}
"""
return self.handle(NotifyDelCommand(aid, gid, type, priority), callback)
def notify(self, buddy=None, callback=None): def notify(self, buddy=None, callback=None):
""" """

View File

@ -99,9 +99,18 @@ class aniDBabstractObject(object):
priority - low = 0, medium = 1, high = 2 (unconfirmed) priority - low = 0, medium = 1, high = 2 (unconfirmed)
""" """
if (self.aid): if self.aid:
self.aniDB.notifyadd(aid=self.aid, type=1, priority=1) self.aniDB.notifyadd(aid=self.aid, type=1, priority=1)
def del_notification(self):
"""
type - Type of notification: type=> 0=all, 1=new, 2=group, 3=complete
priority - low = 0, medium = 1, high = 2 (unconfirmed)
"""
if self.aid:
self.aniDB.notifydel(aid=self.aid, type=1, priority=1)
class Anime(aniDBabstractObject): class Anime(aniDBabstractObject):
def __init__(self, aniDB, name=None, aid=None, tvdbid=None, paramsA=None, autoCorrectName=False, load=False): def __init__(self, aniDB, name=None, aid=None, tvdbid=None, paramsA=None, autoCorrectName=False, load=False):

View File

@ -103,6 +103,14 @@ class PushAckCommand(Command):
Command.__init__(self, 'PUSHACK', **parameters) Command.__init__(self, 'PUSHACK', **parameters)
class Notification(Command):
def __init__(self, aid=None, gid=None, type=None, priority=None):
if not (aid or gid) or (aid and gid):
raise AniDBIncorrectParameterError, "You must provide aid OR gid for NOTIFICATION command"
parameters = {'aid': aid, "gid": gid, "type": type, "priority": priority}
Command.__init__(self, 'NOTIFICATION', **parameters)
class NotifyAddCommand(Command): class NotifyAddCommand(Command):
def __init__(self, aid=None, gid=None, type=None, priority=None): def __init__(self, aid=None, gid=None, type=None, priority=None):
if not (aid or gid) or (aid and gid): if not (aid or gid) or (aid and gid):
@ -111,6 +119,14 @@ class NotifyAddCommand(Command):
Command.__init__(self, 'NOTIFICATIONADD', **parameters) Command.__init__(self, 'NOTIFICATIONADD', **parameters)
class NotifyDelCommand(Command):
def __init__(self, aid=None, gid=None, type=None, priority=None):
if not (aid or gid) or (aid and gid):
raise AniDBIncorrectParameterError, "You must provide aid OR gid for NOTIFICATIONDEL command"
parameters = {'aid': aid, "gid": gid, "type": type, "priority": priority}
Command.__init__(self, 'NOTIFICATIONDEL', **parameters)
class NotifyCommand(Command): class NotifyCommand(Command):
def __init__(self, buddy=None): def __init__(self, buddy=None):
parameters = {'buddy': buddy} parameters = {'buddy': buddy}

View File

@ -15,23 +15,30 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with aDBa. If not, see <http://www.gnu.org/licenses/>. # along with aDBa. If not, see <http://www.gnu.org/licenses/>.
class AniDBError(Exception): class AniDBError(Exception):
pass pass
class AniDBIncorrectParameterError(AniDBError): class AniDBIncorrectParameterError(AniDBError):
pass pass
class AniDBCommandTimeoutError(AniDBError): class AniDBCommandTimeoutError(AniDBError):
pass pass
class AniDBMustAuthError(AniDBError): class AniDBMustAuthError(AniDBError):
pass pass
class AniDBPacketCorruptedError(AniDBError): class AniDBPacketCorruptedError(AniDBError):
pass pass
class AniDBBannedError(AniDBError): class AniDBBannedError(AniDBError):
pass pass
class AniDBInternalError(AniDBError): class AniDBInternalError(AniDBError):
pass pass

File diff suppressed because it is too large Load Diff

View File

@ -628,21 +628,10 @@ class Tvdb:
"""Loads a URL using caching, returns an ElementTree of the source """Loads a URL using caching, returns an ElementTree of the source
""" """
try: try:
src = self._loadUrl(url, params=params, language=language) src = self._loadUrl(url, params=params, language=language).values()[0]
src = [src[item] for item in src][0] if src else []
except:
errormsg = "There was an error with the XML retrieved from thetvdb.com:"
if self.config['cache_enabled']:
errormsg += "\nFirst try emptying the cache folder at..\n%s" % (
self.config['cache_location']
)
errormsg += "\nIf this does not resolve the issue, please try again later. If the error persists, report a bug on"
errormsg += "\nhttp://dbr.lighthouseapp.com/projects/13342-tvdb_api/overview\n"
raise tvdb_error(errormsg)
return src return src
except:
return []
def _setItem(self, sid, seas, ep, attrib, value): def _setItem(self, sid, seas, ep, attrib, value):
"""Creates a new episode, creating Show(), Season() and """Creates a new episode, creating Show(), Season() and
@ -692,8 +681,12 @@ class Tvdb:
series = series.encode("utf-8") series = series.encode("utf-8")
log().debug("Searching for show %s" % series) log().debug("Searching for show %s" % series)
self.config['params_getSeries']['seriesname'] = series self.config['params_getSeries']['seriesname'] = series
seriesEt = self._getetsrc(self.config['url_getSeries'], self.config['params_getSeries'])
return [seriesEt[item] for item in seriesEt][0] if seriesEt else [] try:
seriesFound = self._getetsrc(self.config['url_getSeries'], self.config['params_getSeries']).values()[0]
return seriesFound
except:
return []
def _getSeries(self, series): def _getSeries(self, series):
"""This searches TheTVDB.com for the series name, """This searches TheTVDB.com for the series name,

View File

@ -1,5 +1,5 @@
# !/usr/bin/env python2 # !/usr/bin/env python2
#encoding:utf-8 # encoding:utf-8
#author:echel0n #author:echel0n
#project:tvrage_api #project:tvrage_api
#repository:http://github.com/echel0n/tvrage_api #repository:http://github.com/echel0n/tvrage_api
@ -393,7 +393,6 @@ class TVRage:
except ImportError: except ImportError:
return os.path.join(tempfile.gettempdir(), "tvrage_api") return os.path.join(tempfile.gettempdir(), "tvrage_api")
return os.path.join(tempfile.gettempdir(), "tvrage_api-%s" % (uid)) return os.path.join(tempfile.gettempdir(), "tvrage_api-%s" % (uid))
#@retry(tvrage_error) #@retry(tvrage_error)
@ -455,7 +454,7 @@ class TVRage:
if key == 'genre': if key == 'genre':
value = value['genre'] value = value['genre']
if not value: if not value:
value=[] value = []
if not isinstance(value, list): if not isinstance(value, list):
value = [value] value = [value]
value = filter(None, value) value = filter(None, value)
@ -489,20 +488,10 @@ class TVRage:
""" """
try: try:
src = self._loadUrl(url, params) src = self._loadUrl(url, params).values()[0]
src = [src[item] for item in src][0] if src else []
except:
errormsg = "There was an error with the XML retrieved from tvrage.com"
if self.config['cache_enabled']:
errormsg += "\nFirst try emptying the cache folder at..\n%s" % (
self.config['cache_location']
)
errormsg += "\nIf this does not resolve the issue, please try again later. If the error persists, report a bug on\n"
raise tvrage_error(errormsg)
return src return src
except:
return []
def _setItem(self, sid, seas, ep, attrib, value): def _setItem(self, sid, seas, ep, attrib, value):
"""Creates a new episode, creating Show(), Season() and """Creates a new episode, creating Show(), Season() and
@ -557,8 +546,12 @@ class TVRage:
series = series.encode("utf-8") series = series.encode("utf-8")
log().debug("Searching for show %s" % series) log().debug("Searching for show %s" % series)
self.config['params_getSeries']['show'] = series self.config['params_getSeries']['show'] = series
seriesEt = self._getetsrc(self.config['url_getSeries'], self.config['params_getSeries'])
return [seriesEt[item] for item in seriesEt][0] if seriesEt else [] try:
seriesFound = self._getetsrc(self.config['url_getSeries'], self.config['params_getSeries']).values()[0]
return seriesFound
except:
return []
def _getSeries(self, series): def _getSeries(self, series):
"""This searches tvrage.com for the series name, """This searches tvrage.com for the series name,
@ -632,7 +625,7 @@ class TVRage:
ep_no = int(episode['episodenumber']) ep_no = int(episode['episodenumber'])
self._setItem(sid, seas_no, ep_no, 'seasonnumber', seas_no) self._setItem(sid, seas_no, ep_no, 'seasonnumber', seas_no)
for k,v in episode.items(): for k, v in episode.items():
try: try:
k = k.lower() k = k.lower()
if v is not None: if v is not None:

View File

@ -981,10 +981,16 @@ def initialize(consoleLogging=True):
curTorrentProvider.search_fallback = bool(check_setting_int(CFG, curTorrentProvider.getID().upper(), curTorrentProvider.search_fallback = bool(check_setting_int(CFG, curTorrentProvider.getID().upper(),
curTorrentProvider.getID() + '_search_fallback', curTorrentProvider.getID() + '_search_fallback',
0)) 0))
if hasattr(curTorrentProvider, 'backlog_only'):
curTorrentProvider.backlog_only = bool(check_setting_int(CFG, curTorrentProvider.getID().upper(), if hasattr(curTorrentProvider, 'enable_daily'):
curTorrentProvider.getID() + '_backlog_only', curTorrentProvider.enable_daily = bool(check_setting_int(CFG, curTorrentProvider.getID().upper(),
0)) curTorrentProvider.getID() + '_enable_daily',
1))
if hasattr(curTorrentProvider, 'enable_backlog'):
curTorrentProvider.enable_backlog = bool(check_setting_int(CFG, curTorrentProvider.getID().upper(),
curTorrentProvider.getID() + '_enable_backlog',
1))
for curNzbProvider in [curProvider for curProvider in providers.sortedProviderList() if for curNzbProvider in [curProvider for curProvider in providers.sortedProviderList() if
curProvider.providerType == GenericProvider.NZB]: curProvider.providerType == GenericProvider.NZB]:
@ -1004,10 +1010,15 @@ def initialize(consoleLogging=True):
curNzbProvider.search_fallback = bool(check_setting_int(CFG, curNzbProvider.getID().upper(), curNzbProvider.search_fallback = bool(check_setting_int(CFG, curNzbProvider.getID().upper(),
curNzbProvider.getID() + '_search_fallback', curNzbProvider.getID() + '_search_fallback',
0)) 0))
if hasattr(curNzbProvider, 'backlog_only'): if hasattr(curNzbProvider, 'enable_daily'):
curNzbProvider.backlog_only = bool(check_setting_int(CFG, curNzbProvider.getID().upper(), curNzbProvider.enable_daily = bool(check_setting_int(CFG, curNzbProvider.getID().upper(),
curNzbProvider.getID() + '_backlog_only', curNzbProvider.getID() + '_enable_daily',
0)) 1))
if hasattr(curNzbProvider, 'enable_backlog'):
curNzbProvider.enable_backlog = bool(check_setting_int(CFG, curNzbProvider.getID().upper(),
curNzbProvider.getID() + '_enable_backlog',
1))
if not os.path.isfile(CONFIG_FILE): if not os.path.isfile(CONFIG_FILE):
logger.log(u"Unable to find '" + CONFIG_FILE + "', all settings will be default!", logger.DEBUG) logger.log(u"Unable to find '" + CONFIG_FILE + "', all settings will be default!", logger.DEBUG)
@ -1124,6 +1135,7 @@ def initialize(consoleLogging=True):
__INITIALIZED__ = True __INITIALIZED__ = True
return True return True
def start(): def start():
global __INITIALIZED__, backlogSearchScheduler, \ global __INITIALIZED__, backlogSearchScheduler, \
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \ showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
@ -1278,6 +1290,7 @@ def halt():
__INITIALIZED__ = False __INITIALIZED__ = False
started = False started = False
def sig_handler(signum=None, frame=None): def sig_handler(signum=None, frame=None):
if type(signum) != type(None): if type(signum) != type(None):
logger.log(u"Signal %i caught, saving and exiting..." % int(signum)) logger.log(u"Signal %i caught, saving and exiting..." % int(signum))
@ -1462,9 +1475,12 @@ def save_config():
if hasattr(curTorrentProvider, 'search_fallback'): if hasattr(curTorrentProvider, 'search_fallback'):
new_config[curTorrentProvider.getID().upper()][curTorrentProvider.getID() + '_search_fallback'] = int( new_config[curTorrentProvider.getID().upper()][curTorrentProvider.getID() + '_search_fallback'] = int(
curTorrentProvider.search_fallback) curTorrentProvider.search_fallback)
if hasattr(curTorrentProvider, 'backlog_only'): if hasattr(curTorrentProvider, 'enable_daily'):
new_config[curTorrentProvider.getID().upper()][curTorrentProvider.getID() + '_backlog_only'] = int( new_config[curTorrentProvider.getID().upper()][curTorrentProvider.getID() + '_enable_daily'] = int(
curTorrentProvider.backlog_only) curTorrentProvider.enable_daily)
if hasattr(curTorrentProvider, 'enable_backlog'):
new_config[curTorrentProvider.getID().upper()][curTorrentProvider.getID() + '_enable_backlog'] = int(
curTorrentProvider.enable_backlog)
for curNzbProvider in [curProvider for curProvider in providers.sortedProviderList() if for curNzbProvider in [curProvider for curProvider in providers.sortedProviderList() if
curProvider.providerType == GenericProvider.NZB]: curProvider.providerType == GenericProvider.NZB]:
@ -1483,9 +1499,12 @@ def save_config():
if hasattr(curNzbProvider, 'search_fallback'): if hasattr(curNzbProvider, 'search_fallback'):
new_config[curNzbProvider.getID().upper()][curNzbProvider.getID() + '_search_fallback'] = int( new_config[curNzbProvider.getID().upper()][curNzbProvider.getID() + '_search_fallback'] = int(
curNzbProvider.search_fallback) curNzbProvider.search_fallback)
if hasattr(curNzbProvider, 'backlog_only'): if hasattr(curNzbProvider, 'enable_daily'):
new_config[curNzbProvider.getID().upper()][curNzbProvider.getID() + '_backlog_only'] = int( new_config[curNzbProvider.getID().upper()][curNzbProvider.getID() + '_enable_daily'] = int(
curNzbProvider.backlog_only) curNzbProvider.enable_daily)
if hasattr(curNzbProvider, 'enable_backlog'):
new_config[curNzbProvider.getID().upper()][curNzbProvider.getID() + '_enable_backlog'] = int(
curNzbProvider.enable_backlog)
new_config['NZBs'] = {} new_config['NZBs'] = {}
new_config['NZBs']['nzbs'] = int(NZBS) new_config['NZBs']['nzbs'] = int(NZBS)

View File

@ -22,6 +22,7 @@ import string
from tornado.httputil import HTTPHeaders from tornado.httputil import HTTPHeaders
from tornado.web import RequestHandler from tornado.web import RequestHandler
from sickbeard import encodingKludge as ek from sickbeard import encodingKludge as ek
from sickbeard import logger
# use the built-in if it's available (python 2.6), if not use the included library # use the built-in if it's available (python 2.6), if not use the included library
try: try:
@ -80,7 +81,12 @@ def foldersAtPath(path, includeParent=False, includeFiles=False):
if path == parentPath and os.name == 'nt': if path == parentPath and os.name == 'nt':
parentPath = "" parentPath = ""
try:
fileList = [{'name': filename, 'path': ek.ek(os.path.join, path, filename)} for filename in ek.ek(os.listdir, path)] fileList = [{'name': filename, 'path': ek.ek(os.path.join, path, filename)} for filename in ek.ek(os.listdir, path)]
except OSError, e:
logger.log(u"Unable to open " + path + ": " + repr(e) + " / " + str(e), logger.WARNING)
fileList = [{'name': filename, 'path': ek.ek(os.path.join, parentPath, filename)} for filename in ek.ek(os.listdir, parentPath)]
if not includeFiles: if not includeFiles:
fileList = filter(lambda entry: ek.ek(os.path.isdir, entry['path']), fileList) fileList = filter(lambda entry: ek.ek(os.path.isdir, entry['path']), fileList)

View File

@ -148,8 +148,10 @@ class TorrentSearchResult(SearchResult):
resultType = "torrent" resultType = "torrent"
# torrent hash # torrent hash
content = None
hash = None hash = None
class AllShowsListUI: class AllShowsListUI:
""" """
This class is for indexer api. Instead of prompting with a UI to pick the This class is for indexer api. Instead of prompting with a UI to pick the
@ -192,6 +194,7 @@ class AllShowsListUI:
return searchResults return searchResults
class ShowListUI: class ShowListUI:
""" """
This class is for tvdb-api. Instead of prompting with a UI to pick the This class is for tvdb-api. Instead of prompting with a UI to pick the

View File

@ -104,6 +104,24 @@ class TransmissionAPI(GenericClient):
return self.response.json()['result'] == "success" return self.response.json()['result'] == "success"
def _set_torrent_seed_time(self, result):
if sickbeard.TORRENT_SEED_TIME:
time = 60 * float(sickbeard.TORRENT_SEED_TIME)
arguments = {'ids': [result.hash],
'seedIdleLimit': time,
'seedIdleMode': 1
}
post_data = json.dumps({'arguments': arguments,
'method': 'torrent-set',
})
self._request(method='post', data=post_data)
return self.response.json()['result'] == "success"
else:
return True
def _set_torrent_priority(self, result): def _set_torrent_priority(self, result):
arguments = {'ids': [result.hash]} arguments = {'ids': [result.hash]}

View File

@ -40,34 +40,13 @@ class DailySearcher():
self.amActive = True self.amActive = True
didSearch = False
providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive() and not x.backlog_only]
for curProviderCount, curProvider in enumerate(providers):
logger.log(u"Updating [" + curProvider.name + "] RSS cache ...")
try:
curProvider.cache.updateCache()
except exceptions.AuthException, e:
logger.log(u"Authentication error: " + ex(e), logger.ERROR)
continue
except Exception, e:
logger.log(u"Error while updating cache for " + curProvider.name + ", skipping: " + ex(e), logger.ERROR)
logger.log(traceback.format_exc(), logger.DEBUG)
continue
didSearch = True
if didSearch:
logger.log(u"Searching for coming episodes and 1 weeks worth of previously WANTED episodes ...") logger.log(u"Searching for coming episodes and 1 weeks worth of previously WANTED episodes ...")
fromDate = datetime.date.today() - datetime.timedelta(weeks=1) curDate = datetime.date.today().toordinal()
curDate = datetime.date.today()
myDB = db.DBConnection() myDB = db.DBConnection()
sqlResults = myDB.select("SELECT * FROM tv_episodes WHERE status in (?,?) AND airdate >= ? AND airdate <= ?", sqlResults = myDB.select("SELECT * FROM tv_episodes WHERE status = ? AND season > 0 AND airdate <= ?",
[common.UNAIRED, common.WANTED, fromDate.toordinal(), curDate.toordinal()]) [common.UNAIRED, curDate])
sql_l = [] sql_l = []
for sqlEp in sqlResults: for sqlEp in sqlResults:
@ -81,26 +60,17 @@ class DailySearcher():
with ep.lock: with ep.lock:
if ep.show.paused: if ep.show.paused:
ep.status = common.SKIPPED ep.status = common.SKIPPED
else:
if ep.status == common.UNAIRED:
logger.log(u"New episode " + ep.prettyName() + " airs today, setting status to WANTED")
ep.status = common.WANTED ep.status = common.WANTED
sql_l.append(ep.get_sql()) sql_l.append(ep.get_sql())
if ep.status == common.WANTED:
dailysearch_queue_item = sickbeard.search_queue.DailySearchQueueItem(show, [ep])
sickbeard.searchQueueScheduler.action.add_item(dailysearch_queue_item)
else:
logger.log(u"Could not find any wanted episodes for the last 7 days to search for")
if len(sql_l) > 0: if len(sql_l) > 0:
myDB = db.DBConnection() myDB = db.DBConnection()
myDB.mass_action(sql_l) myDB.mass_action(sql_l)
else: # queue episode for daily search
logger.log( dailysearch_queue_item = sickbeard.search_queue.DailySearchQueueItem()
u"No NZB/Torrent providers found or enabled in the sickrage config. Please check your settings.", sickbeard.searchQueueScheduler.action.add_item(dailysearch_queue_item)
logger.ERROR)
self.amActive = False self.amActive = False

View File

@ -210,21 +210,17 @@ def _remove_file_failed(file):
except: except:
pass pass
def findCertainShow(showList, indexerid): def findCertainShow(showList, indexerid):
if not showList:
return None
results = [] results = []
if indexerid: if showList and indexerid:
results = filter(lambda x: int(x.indexerid) == int(indexerid), showList) results = filter(lambda x: int(x.indexerid) == int(indexerid), showList)
if len(results): if len(results) == 1:
return results[0] return results[0]
elif len(results) > 1: elif len(results) > 1:
raise MultipleShowObjectsException() raise MultipleShowObjectsException()
def makeDir(path): def makeDir(path):
if not ek.ek(os.path.isdir, path): if not ek.ek(os.path.isdir, path):
try: try:

View File

@ -63,6 +63,7 @@ def sortedProviderList():
return newList return newList
def makeProviderList(): def makeProviderList():
return [x.provider for x in [getProviderModule(y) for y in __all__] if x] return [x.provider for x in [getProviderModule(y) for y in __all__] if x]
@ -96,6 +97,8 @@ def getNewznabProviderList(data):
providerDict[curDefault.name].needs_auth = curDefault.needs_auth providerDict[curDefault.name].needs_auth = curDefault.needs_auth
providerDict[curDefault.name].search_mode = curDefault.search_mode providerDict[curDefault.name].search_mode = curDefault.search_mode
providerDict[curDefault.name].search_fallback = curDefault.search_fallback providerDict[curDefault.name].search_fallback = curDefault.search_fallback
providerDict[curDefault.name].enable_daily = curDefault.enable_daily
providerDict[curDefault.name].enable_backlog = curDefault.enable_backlog
return filter(lambda x: x, providerList) return filter(lambda x: x, providerList)
@ -106,12 +109,19 @@ def makeNewznabProvider(configString):
search_mode = 'eponly' search_mode = 'eponly'
search_fallback = 0 search_fallback = 0
enable_daily = 0
enable_backlog = 0
try: try:
name, url, key, catIDs, enabled, search_mode, search_fallback = configString.split('|') values = configString.split('|')
except ValueError: if len(values) == 9:
try: name, url, key, catIDs, enabled, search_mode, search_fallback, enable_daily, enable_backlog = values
name, url, key, catIDs, enabled = configString.split('|') else:
name = values[0]
url = values[1]
key = values[2]
catIDs = values[3]
enabled = values[4]
except ValueError: except ValueError:
logger.log(u"Skipping Newznab provider string: '" + configString + "', incorrect format", logger.ERROR) logger.log(u"Skipping Newznab provider string: '" + configString + "', incorrect format", logger.ERROR)
return None return None
@ -119,7 +129,8 @@ def makeNewznabProvider(configString):
newznab = sys.modules['sickbeard.providers.newznab'] newznab = sys.modules['sickbeard.providers.newznab']
newProvider = newznab.NewznabProvider(name, url, key=key, catIDs=catIDs, search_mode=search_mode, newProvider = newznab.NewznabProvider(name, url, key=key, catIDs=catIDs, search_mode=search_mode,
search_fallback=search_fallback) search_fallback=search_fallback, enable_daily=enable_daily,
enable_backlog=enable_backlog)
newProvider.enabled = enabled == '1' newProvider.enabled = enabled == '1'
return newProvider return newProvider
@ -146,18 +157,20 @@ def makeTorrentRssProvider(configString):
cookies = None cookies = None
search_mode = 'eponly' search_mode = 'eponly'
search_fallback = 0 search_fallback = 0
backlog_only = 0 enable_daily = 0
enable_backlog = 0
try: try:
name, url, cookies, enabled, search_mode, search_fallback, backlog_only = configString.split('|') values = configString.split('|')
if len(values) == 8:
name, url, cookies, enabled, search_mode, search_fallback, enable_daily, enable_backlog = values
else:
name = values[0]
url = values[1]
enabled = values[3]
except ValueError: except ValueError:
try: logger.log(u"Skipping RSS Torrent provider string: '" + configString + "', incorrect format",
name, url, enabled, search_mode, search_fallback, backlog_only = configString.split('|') logger.ERROR)
except ValueError:
try:
name, url, enabled = configString.split('|')
except ValueError:
logger.log(u"Skipping RSS Torrent provider string: '" + configString + "', incorrect format", logger.ERROR)
return None return None
try: try:
@ -165,14 +178,15 @@ def makeTorrentRssProvider(configString):
except: except:
return return
newProvider = torrentRss.TorrentRssProvider(name, url, cookies, search_mode, search_fallback, backlog_only) newProvider = torrentRss.TorrentRssProvider(name, url, cookies, search_mode, search_fallback, enable_daily,
enable_backlog)
newProvider.enabled = enabled == '1' newProvider.enabled = enabled == '1'
return newProvider return newProvider
def getDefaultNewznabProviders(): def getDefaultNewznabProviders():
return 'Sick Beard Index|http://lolo.sickbeard.com/|0|5030,5040|0|eponly|0!!!NZBs.org|https://nzbs.org/||5030,5040|0|eponly|0!!!Usenet-Crawler|https://www.usenet-crawler.com/||5030,5040|0|eponly|0' return 'Sick Beard Index|http://lolo.sickbeard.com/|0|5030,5040|0|eponly|0|0|0!!!NZBs.org|https://nzbs.org/|0|5030,5040|0|eponly|0|0|0!!!Usenet-Crawler|https://www.usenet-crawler.com/|0|5030,5040|0|eponly|0|0|0'
def getProviderModule(name): def getProviderModule(name):

View File

@ -133,7 +133,7 @@ class AnimezbCache(tvcache.TVCache):
# only poll Animezb every 20 minutes max # only poll Animezb every 20 minutes max
self.minTime = 20 self.minTime = 20
def _getDailyData(self): def _getRSSData(self):
params = { params = {
"cat": "anime".encode('utf-8'), "cat": "anime".encode('utf-8'),

View File

@ -274,7 +274,7 @@ class BitSoupCache(tvcache.TVCache):
# only poll TorrentBytes every 20 minutes max # only poll TorrentBytes every 20 minutes max
self.minTime = 20 self.minTime = 20
def _getDailyData(self): def _getRSSData(self):
search_params = {'RSS': ['']} search_params = {'RSS': ['']}
return self.provider._doSearch(search_params) return self.provider._doSearch(search_params)

View File

@ -297,7 +297,7 @@ class BTNCache(tvcache.TVCache):
# At least 15 minutes between queries # At least 15 minutes between queries
self.minTime = 15 self.minTime = 15
def _getDailyData(self): def _getRSSData(self):
# Get the torrents uploaded since last check. # Get the torrents uploaded since last check.
seconds_since_last_update = math.ceil(time.time() - time.mktime(self._getLastUpdate().timetuple())) seconds_since_last_update = math.ceil(time.time() - time.mktime(self._getLastUpdate().timetuple()))

View File

@ -174,7 +174,7 @@ class EZRSSCache(tvcache.TVCache):
# only poll EZRSS every 15 minutes max # only poll EZRSS every 15 minutes max
self.minTime = 15 self.minTime = 15
def _getDailyData(self): def _getRSSData(self):
rss_url = self.provider.url + 'feed/' rss_url = self.provider.url + 'feed/'
logger.log(self.provider.name + " cache update URL: " + rss_url, logger.DEBUG) logger.log(self.provider.name + " cache update URL: " + rss_url, logger.DEBUG)

View File

@ -128,7 +128,7 @@ class FanzubCache(tvcache.TVCache):
# only poll Fanzub every 20 minutes max # only poll Fanzub every 20 minutes max
self.minTime = 20 self.minTime = 20
def _getDailyData(self): def _getRSSData(self):
params = { params = {
"cat": "anime".encode('utf-8'), "cat": "anime".encode('utf-8'),

View File

@ -306,7 +306,7 @@ class FreshOnTVCache(tvcache.TVCache):
# poll delay in minutes # poll delay in minutes
self.minTime = 20 self.minTime = 20
def _getDailyData(self): def _getRSSData(self):
search_params = {'RSS': ['']} search_params = {'RSS': ['']}
return self.provider._doSearch(search_params) return self.provider._doSearch(search_params)

View File

@ -55,7 +55,8 @@ class GenericProvider:
self.search_mode = None self.search_mode = None
self.search_fallback = False self.search_fallback = False
self.backlog_only = False self.enable_daily = False
self.enable_backlog = False
self.cache = tvcache.TVCache(self) self.cache = tvcache.TVCache(self)
@ -194,8 +195,8 @@ class GenericProvider:
return True return True
def searchRSS(self, episodes): def searchRSS(self):
return self.cache.findNeededEpisodes(episodes) return self.cache.findNeededEpisodes()
def getQuality(self, item, anime=False): def getQuality(self, item, anime=False):
""" """
@ -254,10 +255,15 @@ class GenericProvider:
searched_scene_season = None searched_scene_season = None
for epObj in episodes: for epObj in episodes:
# check cache for results # search cache for episode result
cacheResult = self.cache.searchCache([epObj], manualSearch) cacheResult = self.cache.searchCache(epObj, manualSearch)
if len(cacheResult): if cacheResult:
results.update({epObj.episode: cacheResult[epObj]}) if epObj not in results:
results = [cacheResult]
else:
results.append(cacheResult)
# found result, search next episode
continue continue
# skip if season already searched # skip if season already searched

View File

@ -204,7 +204,7 @@ class HDBitsCache(tvcache.TVCache):
# only poll HDBits every 15 minutes max # only poll HDBits every 15 minutes max
self.minTime = 15 self.minTime = 15
def _getDailyData(self): def _getRSSData(self):
parsedJSON = self.provider.getURL(self.provider.rss_url, post_data=self.provider._make_post_data_JSON(), json=True) parsedJSON = self.provider.getURL(self.provider.rss_url, post_data=self.provider._make_post_data_JSON(), json=True)
if not self.provider._checkAuthFromData(parsedJSON): if not self.provider._checkAuthFromData(parsedJSON):

View File

@ -336,7 +336,7 @@ class HDTorrentsCache(tvcache.TVCache):
# only poll HDTorrents every 10 minutes max # only poll HDTorrents every 10 minutes max
self.minTime = 20 self.minTime = 20
def _getDailyData(self): def _getRSSData(self):
search_params = {'RSS': []} search_params = {'RSS': []}
return self.provider._doSearch(search_params) return self.provider._doSearch(search_params)

View File

@ -276,7 +276,7 @@ class IPTorrentsCache(tvcache.TVCache):
# Only poll IPTorrents every 10 minutes max # Only poll IPTorrents every 10 minutes max
self.minTime = 10 self.minTime = 10
def _getDailyData(self): def _getRSSData(self):
search_params = {'RSS': ['']} search_params = {'RSS': ['']}
return self.provider._doSearch(search_params) return self.provider._doSearch(search_params)

View File

@ -355,7 +355,7 @@ class KATCache(tvcache.TVCache):
# only poll ThePirateBay every 10 minutes max # only poll ThePirateBay every 10 minutes max
self.minTime = 20 self.minTime = 20
def _getDailyData(self): def _getRSSData(self):
search_params = {'RSS': ['rss']} search_params = {'RSS': ['rss']}
return self.provider._doSearch(search_params) return self.provider._doSearch(search_params)

View File

@ -33,14 +33,14 @@ from sickbeard import classes
from sickbeard import helpers from sickbeard import helpers
from sickbeard import scene_exceptions from sickbeard import scene_exceptions
from sickbeard import encodingKludge as ek from sickbeard import encodingKludge as ek
from sickbeard.common import cpu_presets
from sickbeard import logger from sickbeard import logger
from sickbeard import tvcache from sickbeard import tvcache
from sickbeard.exceptions import ex, AuthException from sickbeard.exceptions import ex, AuthException
class NewznabProvider(generic.NZBProvider): class NewznabProvider(generic.NZBProvider):
def __init__(self, name, url, key='', catIDs='5030,5040', search_mode='eponly', search_fallback=False): def __init__(self, name, url, key='', catIDs='5030,5040', search_mode='eponly', search_fallback=False,
enable_daily=False, enable_backlog=False):
generic.NZBProvider.__init__(self, name) generic.NZBProvider.__init__(self, name)
@ -52,6 +52,8 @@ class NewznabProvider(generic.NZBProvider):
self.search_mode = search_mode self.search_mode = search_mode
self.search_fallback = search_fallback self.search_fallback = search_fallback
self.enable_daily = enable_daily
self.enable_backlog = enable_backlog
# a 0 in the key spot indicates that no key is needed # a 0 in the key spot indicates that no key is needed
if self.key == '0': if self.key == '0':
@ -71,10 +73,13 @@ class NewznabProvider(generic.NZBProvider):
def configStr(self): def configStr(self):
return self.name + '|' + self.url + '|' + self.key + '|' + self.catIDs + '|' + str( return self.name + '|' + self.url + '|' + self.key + '|' + self.catIDs + '|' + str(
int(self.enabled)) + '|' + self.search_mode + '|' + str(int(self.search_fallback)) int(self.enabled)) + '|' + self.search_mode + '|' + str(int(self.search_fallback)) + '|' + str(
int(self.enable_daily)) + '|' + str(int(self.enable_backlog))
def imageName(self): def imageName(self):
if ek.ek(os.path.isfile, ek.ek(os.path.join, sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME, 'images', 'providers', self.getID() + '.png')): if ek.ek(os.path.isfile,
ek.ek(os.path.join, sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME, 'images', 'providers',
self.getID() + '.png')):
return self.getID() + '.png' return self.getID() + '.png'
return 'newznab.png' return 'newznab.png'
@ -99,9 +104,10 @@ class NewznabProvider(generic.NZBProvider):
# search # search
rid = helpers.mapIndexersToShow(ep_obj.show)[2] rid = helpers.mapIndexersToShow(ep_obj.show)[2]
if rid: if rid:
cur_params['rid'] = rid cur_return = cur_params.copy()
to_return.append(cur_params) cur_return['rid'] = rid
else: to_return.append(cur_return)
# add new query strings for exceptions # add new query strings for exceptions
name_exceptions = list( name_exceptions = list(
set(scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name])) set(scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name]))
@ -132,11 +138,13 @@ class NewznabProvider(generic.NZBProvider):
# search # search
rid = helpers.mapIndexersToShow(ep_obj.show)[2] rid = helpers.mapIndexersToShow(ep_obj.show)[2]
if rid: if rid:
params['rid'] = rid cur_return = params.copy()
to_return.append(params) cur_return['rid'] = rid
else: to_return.append(cur_return)
# add new query strings for exceptions # add new query strings for exceptions
name_exceptions = list(set(scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name])) name_exceptions = list(
set(scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name]))
for cur_exception in name_exceptions: for cur_exception in name_exceptions:
params['q'] = helpers.sanitizeSceneName(cur_exception) params['q'] = helpers.sanitizeSceneName(cur_exception)
to_return.append(params) to_return.append(params)
@ -234,7 +242,9 @@ class NewznabProvider(generic.NZBProvider):
# if there are more items available then the amount given in one call, grab some more # if there are more items available then the amount given in one call, grab some more
if (total - params['limit']) > offset == params['offset']: if (total - params['limit']) > offset == params['offset']:
params['offset'] += params['limit'] params['offset'] += params['limit']
logger.log(str(total - params['offset']) + " more items to be fetched from provider. Fetching another " + str(params['limit']) + " items.", logger.DEBUG) logger.log(str(
total - params['offset']) + " more items to be fetched from provider. Fetching another " + str(
params['limit']) + " items.", logger.DEBUG)
else: else:
break break
@ -327,21 +337,18 @@ class NewznabCache(tvcache.TVCache):
def updateCache(self): def updateCache(self):
# delete anything older then 7 days if self.shouldUpdate() and self._checkAuth(None):
self._clearCache()
if not self.shouldUpdate():
return
if self._checkAuth(None):
data = self._getRSSData() data = self._getRSSData()
# as long as the http request worked we count this as an update # as long as the http request worked we count this as an update
if data: if not data:
self.setLastUpdate()
else:
return [] return []
self.setLastUpdate()
# clear cache
self._clearCache()
if self._checkAuth(data): if self._checkAuth(data):
items = data.entries items = data.entries
cl = [] cl = []
@ -360,7 +367,6 @@ class NewznabCache(tvcache.TVCache):
return [] return []
# overwrite method with that parses the rageid from the newznab feed # overwrite method with that parses the rageid from the newznab feed
def _parseItem(self, item): def _parseItem(self, item):
title = item.title title = item.title

View File

@ -318,7 +318,7 @@ class NextGenCache(tvcache.TVCache):
# Only poll NextGen every 10 minutes max # Only poll NextGen every 10 minutes max
self.minTime = 10 self.minTime = 10
def _getDailyData(self): def _getRSSData(self):
search_params = {'RSS': ['']} search_params = {'RSS': ['']}
return self.provider._doSearch(search_params) return self.provider._doSearch(search_params)

View File

@ -126,7 +126,7 @@ class NyaaCache(tvcache.TVCache):
# only poll NyaaTorrents every 15 minutes max # only poll NyaaTorrents every 15 minutes max
self.minTime = 15 self.minTime = 15
def _getDailyData(self): def _getRSSData(self):
params = { params = {
"page": 'rss', # Use RSS page "page": 'rss', # Use RSS page
"order": '1', # Sort Descending By Date "order": '1', # Sort Descending By Date

View File

@ -174,7 +174,7 @@ class OmgwtfnzbsCache(tvcache.TVCache):
return (title, url) return (title, url)
def _getDailyData(self): def _getRSSData(self):
params = {'user': provider.username, params = {'user': provider.username,
'api': provider.api_key, 'api': provider.api_key,
'eng': 1, 'eng': 1,

View File

@ -34,8 +34,10 @@ from lib import requests
from lib.requests import exceptions from lib.requests import exceptions
from lib.bencode import bdecode from lib.bencode import bdecode
class TorrentRssProvider(generic.TorrentProvider): class TorrentRssProvider(generic.TorrentProvider):
def __init__(self, name, url, cookies='', search_mode='eponly', search_fallback=False, backlog_only=False): def __init__(self, name, url, cookies='', search_mode='eponly', search_fallback=False, enable_daily=False,
enable_backlog=False):
generic.TorrentProvider.__init__(self, name) generic.TorrentProvider.__init__(self, name)
self.cache = TorrentRssCache(self) self.cache = TorrentRssCache(self)
self.url = re.sub('\/$', '', url) self.url = re.sub('\/$', '', url)
@ -46,14 +48,19 @@ class TorrentRssProvider(generic.TorrentProvider):
self.search_mode = search_mode self.search_mode = search_mode
self.search_fallback = search_fallback self.search_fallback = search_fallback
self.backlog_only = backlog_only self.enable_daily = enable_daily
self.enable_backlog = enable_backlog
self.cookies = cookies self.cookies = cookies
def configStr(self): 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.backlog_only)) 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))
def imageName(self): def imageName(self):
if ek.ek(os.path.isfile, ek.ek(os.path.join, sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME, 'images', 'providers', self.getID() + '.png')): if ek.ek(os.path.isfile,
ek.ek(os.path.join, sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME, 'images', 'providers',
self.getID() + '.png')):
return self.getID() + '.png' return self.getID() + '.png'
return 'torrentrss.png' return 'torrentrss.png'
@ -91,11 +98,11 @@ class TorrentRssProvider(generic.TorrentProvider):
try: try:
if self.cookies: if self.cookies:
cookie_validator=re.compile("^(\w+=\w+)(;\w+=\w+)*$") cookie_validator = re.compile("^(\w+=\w+)(;\w+=\w+)*$")
if not cookie_validator.match(self.cookies): if not cookie_validator.match(self.cookies):
return (False, 'Cookie is not correctly formatted: ' + self.cookies) return (False, 'Cookie is not correctly formatted: ' + self.cookies)
items = self.cache._getDailyData() items = self.cache._getRSSData()
if not len(items) > 0: if not len(items) > 0:
return (False, 'No items found in the RSS feed ' + self.url) return (False, 'No items found in the RSS feed ' + self.url)
@ -144,17 +151,18 @@ class TorrentRssProvider(generic.TorrentProvider):
def seedRatio(self): def seedRatio(self):
return self.ratio return self.ratio
class TorrentRssCache(tvcache.TVCache): class TorrentRssCache(tvcache.TVCache):
def __init__(self, provider): def __init__(self, provider):
tvcache.TVCache.__init__(self, provider) tvcache.TVCache.__init__(self, provider)
self.minTime = 15 self.minTime = 15
def _getDailyData(self): def _getRSSData(self):
logger.log(u"TorrentRssCache cache update URL: " + self.provider.url, logger.DEBUG) logger.log(u"TorrentRssCache cache update URL: " + self.provider.url, logger.DEBUG)
request_headers = None request_headers = None
if self.provider.cookies: if self.provider.cookies:
request_headers = { 'Cookie': self.provider.cookies } request_headers = {'Cookie': self.provider.cookies}
data = self.getRSSFeed(self.provider.url, request_headers=request_headers) data = self.getRSSFeed(self.provider.url, request_headers=request_headers)

View File

@ -312,7 +312,7 @@ class SCCCache(tvcache.TVCache):
# only poll SCC every 10 minutes max # only poll SCC every 10 minutes max
self.minTime = 20 self.minTime = 20
def _getDailyData(self): def _getRSSData(self):
search_params = {'RSS': ['']} search_params = {'RSS': ['']}
return self.provider._doSearch(search_params) return self.provider._doSearch(search_params)

View File

@ -252,7 +252,7 @@ class SpeedCDCache(tvcache.TVCache):
# only poll Speedcd every 20 minutes max # only poll Speedcd every 20 minutes max
self.minTime = 20 self.minTime = 20
def _getDailyData(self): def _getRSSData(self):
search_params = {'RSS': ['']} search_params = {'RSS': ['']}
return self.provider._doSearch(search_params) return self.provider._doSearch(search_params)

View File

@ -338,7 +338,7 @@ class ThePirateBayCache(tvcache.TVCache):
# only poll ThePirateBay every 10 minutes max # only poll ThePirateBay every 10 minutes max
self.minTime = 20 self.minTime = 20
def _getDailyData(self): def _getRSSData(self):
search_params = {'RSS': ['rss']} search_params = {'RSS': ['rss']}
return self.provider._doSearch(search_params) return self.provider._doSearch(search_params)

View File

@ -274,7 +274,7 @@ class TorrentBytesCache(tvcache.TVCache):
# only poll TorrentBytes every 20 minutes max # only poll TorrentBytes every 20 minutes max
self.minTime = 20 self.minTime = 20
def _getDailyData(self): def _getRSSData(self):
search_params = {'RSS': ['']} search_params = {'RSS': ['']}
return self.provider._doSearch(search_params) return self.provider._doSearch(search_params)

View File

@ -277,7 +277,7 @@ class TorrentDayCache(tvcache.TVCache):
# Only poll IPTorrents every 10 minutes max # Only poll IPTorrents every 10 minutes max
self.minTime = 10 self.minTime = 10
def _getDailyData(self): def _getRSSData(self):
search_params = {'RSS': ['']} search_params = {'RSS': ['']}
return self.provider._doSearch(search_params) return self.provider._doSearch(search_params)

View File

@ -275,7 +275,7 @@ class TorrentLeechCache(tvcache.TVCache):
# only poll TorrentLeech every 20 minutes max # only poll TorrentLeech every 20 minutes max
self.minTime = 20 self.minTime = 20
def _getDailyData(self): def _getRSSData(self):
search_params = {'RSS': ['']} search_params = {'RSS': ['']}
return self.provider._doSearch(search_params) return self.provider._doSearch(search_params)

View File

@ -83,7 +83,7 @@ class TvTorrentsCache(tvcache.TVCache):
# only poll TvTorrents every 15 minutes max # only poll TvTorrents every 15 minutes max
self.minTime = 15 self.minTime = 15
def _getDailyData(self): def _getRSSData(self):
# These will be ignored on the serverside. # These will be ignored on the serverside.
ignore_regex = "all.month|month.of|season[\s\d]*complete" ignore_regex = "all.month|month.of|season[\s\d]*complete"

View File

@ -40,17 +40,17 @@ class RSSFeeds:
fc = cache.Cache(fs) fc = cache.Cache(fs)
feed = fc.fetch(url, False, False, request_headers) feed = fc.fetch(url, False, False, request_headers)
if not feed or not feed.entries: if feed:
logger.log(u"RSS error loading url: " + url, logger.DEBUG) if 'entries' in feed:
return return feed
elif 'error' in feed.feed: elif 'error' in feed.feed:
err_code = feed.feed['error']['code'] err_code = feed.feed['error']['code']
err_desc = feed.feed['error']['description'] err_desc = feed.feed['error']['description']
logger.log( logger.log(
u"RSS ERROR:[%s] CODE:[%s]" % (err_desc, err_code), logger.DEBUG) u"RSS ERROR:[%s] CODE:[%s]" % (err_desc, err_code), logger.DEBUG)
return
else: else:
return feed logger.log(u"RSS error loading url: " + url, logger.DEBUG)
except Exception as e: except Exception as e:
logger.log(u"RSS error: " + ex(e), logger.DEBUG) logger.log(u"RSS error: " + ex(e), logger.DEBUG)

View File

@ -53,7 +53,7 @@ def get_scene_numbering(indexer_id, indexer, season, episode, fallback_to_xem=Tr
return (season, episode) return (season, episode)
showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(indexer_id)) showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(indexer_id))
if not showObj.is_scene: if showObj and not showObj.is_scene:
return (season, episode) return (season, episode)
result = find_scene_numbering(int(indexer_id), int(indexer), season, episode) result = find_scene_numbering(int(indexer_id), int(indexer), season, episode)
@ -105,7 +105,7 @@ def get_scene_absolute_numbering(indexer_id, indexer, absolute_number, fallback_
indexer = int(indexer) indexer = int(indexer)
showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, indexer_id) showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, indexer_id)
if not showObj.is_scene: if showObj and not showObj.is_scene:
return absolute_number return absolute_number
result = find_scene_absolute_numbering(indexer_id, indexer, absolute_number) result = find_scene_absolute_numbering(indexer_id, indexer, absolute_number)

View File

@ -336,23 +336,21 @@ def filterSearchResults(show, season, results):
return foundResults return foundResults
def searchForNeededEpisodes(show, episodes): def searchForNeededEpisodes():
foundResults = {} foundResults = {}
didSearch = False didSearch = False
origThreadName = threading.currentThread().name origThreadName = threading.currentThread().name
providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive() and not x.backlog_only] providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive() and x.enable_daily]
for curProviderCount, curProvider in enumerate(providers): for curProvider in providers:
if curProvider.anime_only and not show.is_anime:
logger.log(u"" + str(show.name) + " is not an anime, skiping", logger.DEBUG)
continue
threading.currentThread().name = origThreadName + " :: [" + curProvider.name + "]" threading.currentThread().name = origThreadName + " :: [" + curProvider.name + "]"
try: try:
curFoundResults = curProvider.searchRSS(episodes) curProvider.cache.updateCache()
curFoundResults = curProvider.searchRSS()
except exceptions.AuthException, e: except exceptions.AuthException, e:
logger.log(u"Authentication error: " + ex(e), logger.ERROR) logger.log(u"Authentication error: " + ex(e), logger.ERROR)
continue continue
@ -374,6 +372,12 @@ def searchForNeededEpisodes(show, episodes):
logger.DEBUG) logger.DEBUG)
continue continue
# find the best result for the current episode
bestResult = None
for curResult in curFoundResults[curEp]:
if not bestResult or bestResult.quality < curResult.quality:
bestResult = curResult
bestResult = pickBestResult(curFoundResults[curEp], curEp.show) bestResult = pickBestResult(curFoundResults[curEp], curEp.show)
# if all results were rejected move on to the next episode # if all results were rejected move on to the next episode
@ -400,7 +404,7 @@ def searchForNeededEpisodes(show, episodes):
u"No NZB/Torrent providers found or enabled in the sickrage config for daily searches. Please check your settings.", u"No NZB/Torrent providers found or enabled in the sickrage config for daily searches. Please check your settings.",
logger.ERROR) logger.ERROR)
return foundResults.values() if len(foundResults) else {} return foundResults.values()
def searchProviders(show, season, episodes, manualSearch=False): def searchProviders(show, season, episodes, manualSearch=False):
@ -409,6 +413,9 @@ def searchProviders(show, season, episodes, manualSearch=False):
didSearch = False didSearch = False
# build name cache for show
sickbeard.name_cache.buildNameCache(show)
# check if we want to search for season packs instead of just season/episode # check if we want to search for season packs instead of just season/episode
seasonSearch = False seasonSearch = False
if not manualSearch: if not manualSearch:
@ -418,7 +425,7 @@ def searchProviders(show, season, episodes, manualSearch=False):
origThreadName = threading.currentThread().name origThreadName = threading.currentThread().name
providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive()] providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive() and x.enable_backlog]
for providerNum, curProvider in enumerate(providers): for providerNum, curProvider in enumerate(providers):
if curProvider.anime_only and not show.is_anime: if curProvider.anime_only and not show.is_anime:
logger.log(u"" + str(show.name) + " is not an anime, skiping", logger.DEBUG) logger.log(u"" + str(show.name) + " is not an anime, skiping", logger.DEBUG)
@ -442,6 +449,7 @@ def searchProviders(show, season, episodes, manualSearch=False):
logger.log(u"Searching for episodes we need from " + show.name + " Season " + str(season)) logger.log(u"Searching for episodes we need from " + show.name + " Season " + str(season))
try: try:
curProvider.cache.updateCache()
searchResults = curProvider.findSearchResults(show, season, episodes, search_mode, manualSearch) searchResults = curProvider.findSearchResults(show, season, episodes, search_mode, manualSearch)
except exceptions.AuthException, e: except exceptions.AuthException, e:
logger.log(u"Authentication error: " + ex(e), logger.ERROR) logger.log(u"Authentication error: " + ex(e), logger.ERROR)

View File

@ -29,6 +29,7 @@ from sickbeard import logger
from sickbeard import ui from sickbeard import ui
from sickbeard import common from sickbeard import common
class BacklogSearchScheduler(scheduler.Scheduler): class BacklogSearchScheduler(scheduler.Scheduler):
def forceSearch(self): def forceSearch(self):
self.action._set_lastBacklog(1) self.action._set_lastBacklog(1)
@ -40,11 +41,12 @@ class BacklogSearchScheduler(scheduler.Scheduler):
else: else:
return datetime.date.fromordinal(self.action._lastBacklog + self.action.cycleTime) return datetime.date.fromordinal(self.action._lastBacklog + self.action.cycleTime)
class BacklogSearcher: class BacklogSearcher:
def __init__(self): def __init__(self):
self._lastBacklog = self._get_lastBacklog() self._lastBacklog = self._get_lastBacklog()
self.cycleTime = sickbeard.BACKLOG_FREQUENCY/60/24 self.cycleTime = sickbeard.BACKLOG_FREQUENCY / 60 / 24
self.lock = threading.Lock() self.lock = threading.Lock()
self.amActive = False self.amActive = False
self.amPaused = False self.amPaused = False
@ -99,7 +101,7 @@ class BacklogSearcher:
if len(segments): if len(segments):
backlog_queue_item = search_queue.BacklogQueueItem(curShow, segments) backlog_queue_item = search_queue.BacklogQueueItem(curShow, segments)
sickbeard.searchQueueScheduler.action.add_item(backlog_queue_item) #@UndefinedVariable sickbeard.searchQueueScheduler.action.add_item(backlog_queue_item) # @UndefinedVariable
else: else:
logger.log(u"Nothing needs to be downloaded for " + str(curShow.name) + ", skipping this season", logger.log(u"Nothing needs to be downloaded for " + str(curShow.name) + ", skipping this season",
logger.DEBUG) logger.DEBUG)
@ -132,14 +134,14 @@ class BacklogSearcher:
return self._lastBacklog return self._lastBacklog
def _get_segments(self, show, fromDate): def _get_segments(self, show, fromDate):
anyQualities, bestQualities = common.Quality.splitQuality(show.quality) #@UnusedVariable anyQualities, bestQualities = common.Quality.splitQuality(show.quality) # @UnusedVariable
logger.log(u"Seeing if we need anything from " + show.name) logger.log(u"Seeing if we need anything from " + show.name)
myDB = db.DBConnection() myDB = db.DBConnection()
if show.air_by_date: if show.air_by_date:
sqlResults = myDB.select( 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", "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]) [fromDate.toordinal(), show.indexerid])
else: else:
sqlResults = myDB.select( sqlResults = myDB.select(

View File

@ -72,34 +72,27 @@ class SearchQueue(generic_queue.GenericQueue):
return False return False
def add_item(self, item): def add_item(self, item):
if isinstance(item, DailySearchQueueItem) or (
if isinstance(item, (DailySearchQueueItem, BacklogQueueItem, ManualSearchQueueItem, FailedQueueItem)) \ isinstance(item, (BacklogQueueItem, ManualSearchQueueItem, FailedQueueItem)) and not self.is_in_queue(
and not self.is_in_queue(item.show, item.segment): item.show, item.segment)):
sickbeard.name_cache.buildNameCache(item.show)
generic_queue.GenericQueue.add_item(self, item) generic_queue.GenericQueue.add_item(self, item)
else: else:
logger.log(u"Not adding item, it's already in the queue", logger.DEBUG) logger.log(u"Not adding item, it's already in the queue", logger.DEBUG)
class DailySearchQueueItem(generic_queue.QueueItem): class DailySearchQueueItem(generic_queue.QueueItem):
def __init__(self, show, segment): def __init__(self):
generic_queue.QueueItem.__init__(self, 'Daily Search', DAILY_SEARCH) generic_queue.QueueItem.__init__(self, 'Daily Search', DAILY_SEARCH)
self.priority = generic_queue.QueuePriorities.HIGH
self.name = 'DAILYSEARCH-' + str(show.indexerid)
self.show = show
self.segment = segment
def run(self): def run(self):
generic_queue.QueueItem.run(self) generic_queue.QueueItem.run(self)
try: try:
logger.log("Beginning daily search for new episodes")
logger.log("Beginning daily search for [" + self.show.name + "]") foundResults = search.searchForNeededEpisodes()
foundResults = search.searchForNeededEpisodes(self.show, self.segment)
if not len(foundResults): 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: else:
for result in foundResults: for result in foundResults:
# just use the first result for now # just use the first result for now
@ -115,6 +108,7 @@ class DailySearchQueueItem(generic_queue.QueueItem):
self.finish() self.finish()
class ManualSearchQueueItem(generic_queue.QueueItem): class ManualSearchQueueItem(generic_queue.QueueItem):
def __init__(self, show, segment): def __init__(self, show, segment):
generic_queue.QueueItem.__init__(self, 'Manual Search', MANUAL_SEARCH) generic_queue.QueueItem.__init__(self, 'Manual Search', MANUAL_SEARCH)

View File

@ -23,6 +23,7 @@ import datetime
import threading import threading
import re import re
import glob import glob
import stat
import traceback import traceback
import sickbeard import sickbeard
@ -962,7 +963,7 @@ class TVShow(object):
return self.nextaired return self.nextaired
def deleteShow(self): def deleteShow(self, full=False):
sql_l = [["DELETE FROM tv_episodes WHERE showid = ?", [self.indexerid]], sql_l = [["DELETE FROM tv_episodes WHERE showid = ?", [self.indexerid]],
["DELETE FROM tv_shows WHERE indexer_id = ?", [self.indexerid]], ["DELETE FROM tv_shows WHERE indexer_id = ?", [self.indexerid]],
@ -973,7 +974,6 @@ class TVShow(object):
myDB = db.DBConnection() myDB = db.DBConnection()
myDB.mass_action(sql_l) myDB.mass_action(sql_l)
# remove self from show list # remove self from show list
sickbeard.showList = [x for x in sickbeard.showList if int(x.indexerid) != self.indexerid] sickbeard.showList = [x for x in sickbeard.showList if int(x.indexerid) != self.indexerid]
@ -983,6 +983,24 @@ class TVShow(object):
logger.log(u"Deleting cache file " + cache_file) logger.log(u"Deleting cache file " + cache_file)
os.remove(cache_file) os.remove(cache_file)
# remove entire show folder
if full:
try:
logger.log(u"Deleting show folder " + self.location)
# check first the read-only attribute
file_attribute = ek.ek(os.stat, self.location)[0]
if (not file_attribute & stat.S_IWRITE):
# File is read-only, so make it writeable
logger.log('Read only mode on folder ' + self.location + ' Will try to make it writeable', logger.DEBUG)
try:
ek.ek(os.chmod, self.location, stat.S_IWRITE)
except:
logger.log(u'Cannot change permissions of ' + self.location, logger.WARNING)
ek.ek(os.rmdir, self.location)
except OSError, e:
logger.log(u"Unable to delete " + self.location + ": " + repr(e) + " / " + str(e), logger.WARNING)
def populateCache(self): def populateCache(self):
cache_inst = image_cache.ImageCache() cache_inst = image_cache.ImageCache()

View File

@ -89,26 +89,17 @@ class TVCache():
def _clearCache(self): def _clearCache(self):
if self.shouldClearCache(): if self.shouldClearCache():
logger.log(u"Clearing items older than 1 week from " + self.provider.name + " cache")
curDate = datetime.date.today() - datetime.timedelta(weeks=1)
myDB = self._getDB() myDB = self._getDB()
myDB.action("DELETE FROM [" + self.providerID + "] WHERE time < ?", [int(time.mktime(curDate.timetuple()))]) myDB.action("DELETE FROM [" + self.providerID + "] WHERE 1")
def _get_title_and_url(self, item): def _get_title_and_url(self, item):
# override this in the provider if daily search has a different data layout to backlog searches # override this in the provider if daily search has a different data layout to backlog searches
return self.provider._get_title_and_url(item) return self.provider._get_title_and_url(item)
def _getRSSData(self): def _getRSSData(self):
data = None data = None
return data return data
def _getDailyData(self):
return None
def _checkAuth(self): def _checkAuth(self):
return self.provider._checkAuth() return self.provider._checkAuth()
@ -116,10 +107,9 @@ class TVCache():
return True return True
def updateCache(self): def updateCache(self):
if self.shouldUpdate() and self._checkAuth(): if self.shouldUpdate() and self._checkAuth():
# as long as the http request worked we count this as an update # as long as the http request worked we count this as an update
data = self._getDailyData() data = self._getRSSData()
if not data: if not data:
return [] return []
@ -230,8 +220,6 @@ class TVCache():
def shouldClearCache(self): def shouldClearCache(self):
# if daily search hasn't used our previous results yet then don't clear the cache # if daily search hasn't used our previous results yet then don't clear the cache
if self.lastUpdate > self.lastSearch: if self.lastUpdate > self.lastSearch:
logger.log(
u"Daily search has not yet used our last cache results, not clearing cache ...", logger.DEBUG)
return False return False
return True return True
@ -289,9 +277,9 @@ class TVCache():
[name, season, episodeText, parse_result.show.indexerid, url, curTimestamp, quality, release_group, version]] [name, season, episodeText, parse_result.show.indexerid, url, curTimestamp, quality, release_group, version]]
def searchCache(self, episodes, manualSearch=False): def searchCache(self, episode, manualSearch=False):
neededEps = self.findNeededEpisodes(episodes, manualSearch) neededEps = self.findNeededEpisodes(episode, manualSearch)
return neededEps return neededEps[episode]
def listPropers(self, date=None, delimiter="."): def listPropers(self, date=None, delimiter="."):
myDB = self._getDB() myDB = self._getDB()
@ -303,31 +291,37 @@ class TVCache():
return filter(lambda x: x['indexerid'] != 0, myDB.select(sql)) return filter(lambda x: x['indexerid'] != 0, myDB.select(sql))
def findNeededEpisodes(self, episodes, manualSearch=False): def findNeededEpisodes(self, episode=None, manualSearch=False):
neededEps = {} neededEps = {}
for epObj in episodes: if episode:
neededEps[episode] = []
myDB = self._getDB() myDB = self._getDB()
if not episode:
sqlResults = myDB.select("SELECT * FROM [" + self.providerID + "]")
else:
sqlResults = myDB.select( sqlResults = myDB.select(
"SELECT * FROM [" + self.providerID + "] WHERE indexerid = ? AND season = ? AND episodes LIKE ?", "SELECT * FROM [" + self.providerID + "] WHERE indexerid = ? AND season = ? AND episodes LIKE ?",
[epObj.show.indexerid, epObj.season, "%|" + str(epObj.episode) + "|%"]) [episode.show.indexerid, episode.season, "%|" + str(episode.episode) + "|%"])
# for each cache entry # for each cache entry
for curResult in sqlResults: for curResult in sqlResults:
# skip non-tv crap (but allow them for Newzbin cause we assume it's filtered well) # skip non-tv crap
if self.providerID != 'newzbin' and not show_name_helpers.filterBadReleases(curResult["name"]): if not show_name_helpers.filterBadReleases(curResult["name"]):
continue continue
# get the show object, or if it's not one of our shows then ignore it # get the show object, or if it's not one of our shows then ignore it
try:
showObj = helpers.findCertainShow(sickbeard.showList, int(curResult["indexerid"])) showObj = helpers.findCertainShow(sickbeard.showList, int(curResult["indexerid"]))
except MultipleShowObjectsException:
showObj = None
if not showObj: if not showObj:
continue continue
# skip if provider is anime only and show is not anime
if self.provider.anime_only and not showObj.is_anime:
logger.log(u"" + str(showObj.name) + " is not an anime, skiping", logger.DEBUG)
continue
# get season and ep data (ignoring multi-eps for now) # get season and ep data (ignoring multi-eps for now)
curSeason = int(curResult["season"]) curSeason = int(curResult["season"])
if curSeason == -1: if curSeason == -1:
@ -336,6 +330,7 @@ class TVCache():
if not curEp: if not curEp:
continue continue
curEp = int(curEp) curEp = int(curEp)
curQuality = int(curResult["quality"]) curQuality = int(curResult["quality"])
curReleaseGroup = curResult["release_group"] curReleaseGroup = curResult["release_group"]
curVersion = curResult["version"] curVersion = curResult["version"]
@ -346,6 +341,14 @@ class TVCache():
Quality.qualityStrings[curQuality], logger.DEBUG) Quality.qualityStrings[curQuality], logger.DEBUG)
continue continue
# build name cache for show
sickbeard.name_cache.buildNameCache(showObj)
if episode:
epObj = episode
else:
epObj = showObj.getEpisode(curSeason, curEp)
# build a result object # build a result object
title = curResult["name"] title = curResult["name"]
url = curResult["url"] url = curResult["url"]

View File

@ -1036,8 +1036,10 @@ class Manage(MainHandler):
return _munge(t) return _munge(t)
def massEditSubmit(self, paused=None, anime=None, sports=None, scene=None, flatten_folders=None, quality_preset=False, def massEditSubmit(self, paused=None, anime=None, sports=None, scene=None, flatten_folders=None,
subtitles=None, air_by_date=None, anyQualities=[], bestQualities=[], toEdit=None, *args, **kwargs): quality_preset=False,
subtitles=None, air_by_date=None, anyQualities=[], bestQualities=[], toEdit=None, *args,
**kwargs):
dir_map = {} dir_map = {}
for cur_arg in kwargs: for cur_arg in kwargs:
@ -1112,7 +1114,8 @@ class Manage(MainHandler):
exceptions_list = [] exceptions_list = []
curErrors += Home(self.application, self.request).editShow(curShow, new_show_dir, anyQualities, bestQualities, exceptions_list, curErrors += Home(self.application, self.request).editShow(curShow, new_show_dir, anyQualities,
bestQualities, exceptions_list,
flatten_folders=new_flatten_folders, flatten_folders=new_flatten_folders,
paused=new_paused, sports=new_sports, paused=new_paused, sports=new_sports,
subtitles=new_subtitles, anime=new_anime, subtitles=new_subtitles, anime=new_anime,
@ -1131,7 +1134,7 @@ class Manage(MainHandler):
redirect("/manage/") redirect("/manage/")
def massUpdate(self, toUpdate=None, toRefresh=None, toRename=None, toDelete=None, toMetadata=None, toSubtitle=None): def massUpdate(self, toUpdate=None, toRefresh=None, toRename=None, toDelete=None, toRemove=None, toMetadata=None, toSubtitle=None):
if toUpdate is not None: if toUpdate is not None:
toUpdate = toUpdate.split('|') toUpdate = toUpdate.split('|')
@ -1158,6 +1161,11 @@ class Manage(MainHandler):
else: else:
toDelete = [] toDelete = []
if toRemove is not None:
toRemove = toRemove.split('|')
else:
toRemove = []
if toMetadata is not None: if toMetadata is not None:
toMetadata = toMetadata.split('|') toMetadata = toMetadata.split('|')
else: else:
@ -1169,7 +1177,7 @@ class Manage(MainHandler):
renames = [] renames = []
subtitles = [] subtitles = []
for curShowID in set(toUpdate + toRefresh + toRename + toSubtitle + toDelete + toMetadata): for curShowID in set(toUpdate + toRefresh + toRename + toSubtitle + toDelete + toRemove + toMetadata):
if curShowID == '': if curShowID == '':
continue continue
@ -1180,10 +1188,15 @@ class Manage(MainHandler):
continue continue
if curShowID in toDelete: if curShowID in toDelete:
showObj.deleteShow() showObj.deleteShow(True)
# don't do anything else if it's being deleted # don't do anything else if it's being deleted
continue continue
if curShowID in toRemove:
showObj.deleteShow()
# don't do anything else if it's being remove
continue
if curShowID in toUpdate: if curShowID in toUpdate:
try: try:
sickbeard.showQueueScheduler.action.updateShow(showObj, True) # @UndefinedVariable sickbeard.showQueueScheduler.action.updateShow(showObj, True) # @UndefinedVariable
@ -1601,7 +1614,8 @@ class ConfigSearch(MainHandler):
def saveSearch(self, use_nzbs=None, use_torrents=None, nzb_dir=None, sab_username=None, sab_password=None, def saveSearch(self, use_nzbs=None, use_torrents=None, nzb_dir=None, sab_username=None, sab_password=None,
sab_apikey=None, sab_category=None, sab_host=None, nzbget_username=None, nzbget_password=None, sab_apikey=None, sab_category=None, sab_host=None, nzbget_username=None, nzbget_password=None,
nzbget_category=None, nzbget_priority=100, nzbget_host=None, nzbget_use_https=None, dailysearch_frequency=None, nzbget_category=None, nzbget_priority=100, nzbget_host=None, nzbget_use_https=None,
dailysearch_frequency=None,
nzb_method=None, torrent_method=None, usenet_retention=None, backlog_frequency=None, nzb_method=None, torrent_method=None, usenet_retention=None, backlog_frequency=None,
download_propers=None, check_propers_interval=None, allow_high_priority=None, download_propers=None, check_propers_interval=None, allow_high_priority=None,
backlog_startup=None, dailysearch_startup=None, backlog_startup=None, dailysearch_startup=None,
@ -1992,19 +2006,42 @@ class ConfigProviders(MainHandler):
cur_url = config.clean_url(cur_url) cur_url = config.clean_url(cur_url)
newProvider = newznab.NewznabProvider(cur_name, cur_url, key=cur_key) newProvider = newznab.NewznabProvider(cur_name, cur_url, key=cur_key)
cur_id = newProvider.getID() cur_id = newProvider.getID()
# if it already exists then update it # if it already exists then update it
if cur_id in newznabProviderDict: if cur_id in newznabProviderDict:
newznabProviderDict[cur_id].name = cur_name newznabProviderDict[cur_id].name = cur_name
newznabProviderDict[cur_id].url = cur_url newznabProviderDict[cur_id].url = cur_url
newznabProviderDict[cur_id].key = cur_key newznabProviderDict[cur_id].key = cur_key
# a 0 in the key spot indicates that no key is needed # a 0 in the key spot indicates that no key is needed
if cur_key == '0': if cur_key == '0':
newznabProviderDict[cur_id].needs_auth = False newznabProviderDict[cur_id].needs_auth = False
else: else:
newznabProviderDict[cur_id].needs_auth = True newznabProviderDict[cur_id].needs_auth = True
try:
newznabProviderDict[cur_id].search_mode = str(kwargs[cur_id + '_search_mode']).strip()
except:
pass
try:
newznabProviderDict[cur_id].search_fallback = config.checkbox_to_value(
kwargs[cur_id + '_search_fallback'])
except:
pass
try:
newznabProviderDict[cur_id].enable_daily = config.checkbox_to_value(
kwargs[cur_id + '_enable_daily'])
except:
pass
try:
newznabProviderDict[cur_id].enable_backlog = config.checkbox_to_value(
kwargs[cur_id + '_enable_backlog'])
except:
pass
else: else:
sickbeard.newznabProviderList.append(newProvider) sickbeard.newznabProviderList.append(newProvider)
@ -2161,12 +2198,19 @@ class ConfigProviders(MainHandler):
except: except:
curTorrentProvider.search_fallback = 0 curTorrentProvider.search_fallback = 0
if hasattr(curTorrentProvider, 'backlog_only'): if hasattr(curTorrentProvider, 'enable_daily'):
try: try:
curTorrentProvider.backlog_only = config.checkbox_to_value( curTorrentProvider.enable_daily = config.checkbox_to_value(
kwargs[curTorrentProvider.getID() + '_backlog_only']) kwargs[curTorrentProvider.getID() + '_enable_daily'])
except: except:
curTorrentProvider.backlog_only = 0 curTorrentProvider.enable_daily = 1
if hasattr(curTorrentProvider, 'enable_backlog'):
try:
curTorrentProvider.enable_backlog = config.checkbox_to_value(
kwargs[curTorrentProvider.getID() + '_enable_backlog'])
except:
curTorrentProvider.enable_backlog = 1
for curNzbProvider in [curProvider for curProvider in sickbeard.providers.sortedProviderList() if for curNzbProvider in [curProvider for curProvider in sickbeard.providers.sortedProviderList() if
curProvider.providerType == sickbeard.GenericProvider.NZB]: curProvider.providerType == sickbeard.GenericProvider.NZB]:
@ -2196,12 +2240,19 @@ class ConfigProviders(MainHandler):
except: except:
curNzbProvider.search_fallback = 0 curNzbProvider.search_fallback = 0
if hasattr(curNzbProvider, 'backlog_only'): if hasattr(curNzbProvider, 'enable_daily'):
try: try:
curNzbProvider.backlog_only = config.checkbox_to_value( curNzbProvider.enable_daily = config.checkbox_to_value(
kwargs[curNzbProvider.getID() + '_backlog_only']) kwargs[curNzbProvider.getID() + '_enable_daily'])
except: except:
curNzbProvider.backlog_only = 0 curNzbProvider.enable_daily = 1
if hasattr(curNzbProvider, 'enable_backlog'):
try:
curNzbProvider.enable_backlog = config.checkbox_to_value(
kwargs[curNzbProvider.getID() + '_enable_backlog'])
except:
curNzbProvider.enable_backlog = 1
sickbeard.NEWZNAB_DATA = '!!!'.join([x.configStr() for x in sickbeard.newznabProviderList]) sickbeard.NEWZNAB_DATA = '!!!'.join([x.configStr() for x in sickbeard.newznabProviderList])
sickbeard.PROVIDER_ORDER = provider_list sickbeard.PROVIDER_ORDER = provider_list
@ -2796,7 +2847,8 @@ class NewHomeAddShows(MainHandler):
final_results = [] final_results = []
logger.log(u"Getting recommended shows from Trakt.tv", logger.DEBUG) logger.log(u"Getting recommended shows from Trakt.tv", logger.DEBUG)
recommendedlist = TraktCall("recommendations/shows.json/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD) recommendedlist = TraktCall("recommendations/shows.json/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME,
sickbeard.TRAKT_PASSWORD)
if recommendedlist == 'NULL': if recommendedlist == 'NULL':
logger.log(u"No shows found in your recommendedlist, aborting recommendedlist update", logger.DEBUG) logger.log(u"No shows found in your recommendedlist, aborting recommendedlist update", logger.DEBUG)
@ -2807,7 +2859,8 @@ class NewHomeAddShows(MainHandler):
return return
map(final_results.append, map(final_results.append,
([int(show['tvdb_id'] or 0) if sickbeard.TRAKT_DEFAULT_INDEXER == 1 else int(show['tvdb_id'] or 0), show['url'], show['title'], show['overview'], ([int(show['tvdb_id'] or 0) if sickbeard.TRAKT_DEFAULT_INDEXER == 1 else int(show['tvdb_id'] or 0),
show['url'], show['title'], show['overview'],
datetime.date.fromtimestamp(int(show['first_aired']) / 1000.0).strftime('%Y%m%d')] for show in datetime.date.fromtimestamp(int(show['first_aired']) / 1000.0).strftime('%Y%m%d')] for show in
recommendedlist if not helpers.findCertainShow(sickbeard.showList, indexerid=int(show['tvdb_id'])))) recommendedlist if not helpers.findCertainShow(sickbeard.showList, indexerid=int(show['tvdb_id']))))
@ -3563,7 +3616,10 @@ class Home(MainHandler):
if not sickbeard.showQueueScheduler.action.isBeingAdded(showObj): # @UndefinedVariable if not sickbeard.showQueueScheduler.action.isBeingAdded(showObj): # @UndefinedVariable
if not sickbeard.showQueueScheduler.action.isBeingUpdated(showObj): # @UndefinedVariable if not sickbeard.showQueueScheduler.action.isBeingUpdated(showObj): # @UndefinedVariable
t.submenu.append( t.submenu.append(
{'title': 'Delete', 'path': 'home/deleteShow?show=%d' % showObj.indexerid, 'confirm': True}) {'title': 'Delete', 'path': 'home/deleteShow?show=%d&amp;full=1' % showObj.indexerid,
'confirm': True})
t.submenu.append(
{'title': 'Remove', 'path': 'home/deleteShow?show=%d' % showObj.indexerid, 'confirm': True})
t.submenu.append({'title': 'Re-scan files', 'path': 'home/refreshShow?show=%d' % showObj.indexerid}) t.submenu.append({'title': 'Re-scan files', 'path': 'home/refreshShow?show=%d' % showObj.indexerid})
t.submenu.append( t.submenu.append(
{'title': 'Force Full Update', 'path': 'home/updateShow?show=%d&amp;force=1' % showObj.indexerid}) {'title': 'Force Full Update', 'path': 'home/updateShow?show=%d&amp;force=1' % showObj.indexerid})
@ -3895,7 +3951,7 @@ class Home(MainHandler):
redirect("/home/displayShow?show=" + show) redirect("/home/displayShow?show=" + show)
def deleteShow(self, show=None): def deleteShow(self, show=None, full=0):
if show is None: if show is None:
return self._genericMessage("Error", "Invalid show ID") return self._genericMessage("Error", "Invalid show ID")
@ -3913,7 +3969,7 @@ class Home(MainHandler):
# remove show from trakt.tv library # remove show from trakt.tv library
sickbeard.traktCheckerScheduler.action.removeShowFromTraktLibrary(showObj) sickbeard.traktCheckerScheduler.action.removeShowFromTraktLibrary(showObj)
showObj.deleteShow() showObj.deleteShow(bool(full))
ui.notifications.message('<b>%s</b> has been deleted' % showObj.name) ui.notifications.message('<b>%s</b> has been deleted' % showObj.name)
redirect("/home/") redirect("/home/")