Change validate and improve specific Torrent provider connections, IPT, KAT, SCC, TPB, TB, TD, TT.

Change refactor cache for torrent providers to reduce code.
Change improve search category selection BMTV, FSH, FF, TB.
Change identify more SD release qualities.
Change update SpeedCD, MoreThan, TVChaosuk.
Add torrent provider HD4Free.
Remove torrent provider BitSoup.
Change only create threads for providers needing a recent search instead of for all enabled.
Add 4489 as experimental value to "Recent search frequency" to use provider freqs instead of fixed width for all.
Fix searching nzb season packs.
Change remove some logging cruft.
This commit is contained in:
JackDandy 2016-03-24 18:24:14 +00:00
parent e31f6cdac6
commit eac69963f0
58 changed files with 975 additions and 1369 deletions

View file

@ -64,6 +64,15 @@
* Change instantly use saved value from Search Settings/Episode Search/"Check propers every" instead of after a restart * Change instantly use saved value from Search Settings/Episode Search/"Check propers every" instead of after a restart
* Change include OSError system messages in file system failure logs during post process * Change include OSError system messages in file system failure logs during post process
* Fix find associated meta files to prevent orphan episode images * Fix find associated meta files to prevent orphan episode images
* Add torrent provider HD4Free
* Change validate and improve specific Torrent provider connections, IPT, KAT, SCC, TPB, TB, TD, TT
* Change refactor cache for torrent providers to reduce code
* Change improve search category selection BMTV, FSH, FF, TB
* Change identify more SD release qualities
* Change update SpeedCD, MoreThan, TVChaosuk
* Change only create threads for providers needing a recent search instead of for all enabled
* Add 4489 as experimental value to "Recent search frequency" to use provider freqs instead of fixed width for all
* Change remove some logging cruft
### 0.11.11 (2016-04-05 19:20:00 UTC) ### 0.11.11 (2016-04-05 19:20:00 UTC)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 B

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 979 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 784 B

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,002 B

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 754 B

View file

@ -37,9 +37,9 @@
var show_nzb_providers = <%= 'true' if sickbeard.USE_NZBS else 'false' %>; var show_nzb_providers = <%= 'true' if sickbeard.USE_NZBS else 'false' %>;
#for $curNewznabProvider in $sickbeard.newznabProviderList: #for $cur_newznab_provider in $sickbeard.newznabProviderList:
\$(this).addProvider('$curNewznabProvider.get_id()', '$curNewznabProvider.name', '$curNewznabProvider.url', '<%= starify(curNewznabProvider.key) %>', '$curNewznabProvider.cat_ids', $int($curNewznabProvider.default), show_nzb_providers); \$(this).addProvider('$cur_newznab_provider.get_id()', '$cur_newznab_provider.name', '$cur_newznab_provider.url', '<%= starify(cur_newznab_provider.key) %>', '$cur_newznab_provider.cat_ids', $int($cur_newznab_provider.default), show_nzb_providers);
#end for #end for
@ -47,9 +47,9 @@
#if $sickbeard.USE_TORRENTS #if $sickbeard.USE_TORRENTS
#for $curTorrentRssProvider in $sickbeard.torrentRssProviderList: #for $cur_torrent_rss_provider in $sickbeard.torrentRssProviderList:
\$(this).addTorrentRssProvider('$curTorrentRssProvider.get_id()', '$curTorrentRssProvider.name', '$curTorrentRssProvider.url', '<%= starify(curTorrentRssProvider.cookies) %>'); \$(this).addTorrentRssProvider('$cur_torrent_rss_provider.get_id()', '$cur_torrent_rss_provider.name', '$cur_torrent_rss_provider.url', '<%= starify(cur_torrent_rss_provider.cookies) %>');
#end for #end for
@ -98,20 +98,20 @@
<ul id="provider_order_list" class="provider_order_panel"> <ul id="provider_order_list" class="provider_order_panel">
#for $curProvider in $sickbeard.providers.sortedProviderList() #for $cur_provider in [$x for $x in $sickbeard.providers.sortedProviderList()
#if $curProvider.providerType == $GenericProvider.NZB and not $sickbeard.USE_NZBS if $x.providerType == $GenericProvider.NZB and $sickbeard.USE_NZBS or
#continue $x.providerType == $GenericProvider.TORRENT and $sickbeard.USE_TORRENTS]
#elif $curProvider.providerType == $GenericProvider.TORRENT and not $sickbeard.USE_TORRENTS #set $cur_name = $cur_provider.get_id()
#continue #set $cur_url = $cur_provider.url
#end if #set $tip = ($cur_provider.name, 'Site Down')[not $cur_url]
#set $curName = $curProvider.get_id() #set $state = ('', ' <span class="red-text">(Site Down?)</span>')[not $cur_url]
<li class="ui-state-default" id="$curName"> <li class="ui-state-default" id="$cur_name">
<input type="checkbox" id="enable_$curName" class="provider_enabler" <%= html_checked if curProvider.is_enabled() else '' %>/> <input type="checkbox" id="enable_$cur_name" class="provider_enabler" <%= html_checked if cur_provider.is_enabled() else '' %>/>
<a href="<%= anon_url(curProvider.url) %>" class="imgLink" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/providers/$curProvider.image_name()" alt="$curProvider.name" title="$curProvider.name" width="16" height="16" style="vertical-align:middle;"/></a> <a href="<%= anon_url(cur_url) %>" class="imgLink" rel="noreferrer" onclick="window.open(this.href,'_blank');return false;"><img src="$sbRoot/images/providers/$cur_provider.image_name()" alt="$tip" title="$tip" width="16" height="16" style="vertical-align:middle" /></a>
<span style="vertical-align:middle">$curProvider.name</span> <span style="vertical-align:middle">$cur_provider.name$state</span>
<%= '*' if not curProvider.supportsBacklog else '' %> <%= '*' if not cur_provider.supports_backlog else '' %>
<span class="ui-icon ui-icon-arrowthick-2-n-s pull-right" style="margin-top:3px"></span> <span class="ui-icon ui-icon-arrowthick-2-n-s pull-right" style="margin-top:3px"></span>
</li> </li>
#end for #end for
</ul> </ul>
@ -150,16 +150,13 @@
<span class="component-desc"> <span class="component-desc">
#set $provider_config_list_enabled = [] #set $provider_config_list_enabled = []
#set $provider_config_list = [] #set $provider_config_list = []
#for $curProvider in $sickbeard.providers.sortedProviderList() #for $cur_provider in [$x for $x in $sickbeard.providers.sortedProviderList()
#if $curProvider.providerType == $GenericProvider.NZB and not $sickbeard.USE_NZBS if $x.providerType == $GenericProvider.NZB and $sickbeard.USE_NZBS or
#continue $x.providerType == $GenericProvider.TORRENT and $sickbeard.USE_TORRENTS]
#elif $curProvider.providerType == $GenericProvider.TORRENT and not $sickbeard.USE_TORRENTS #if $cur_provider.is_enabled()
#continue $provider_config_list_enabled.append($cur_provider)
#end if
#if $curProvider.is_enabled()
$provider_config_list_enabled.append($curProvider)
#else #else
$provider_config_list.append($curProvider) $provider_config_list.append($cur_provider)
#end if #end if
#end for #end for
@ -188,71 +185,71 @@
</div> </div>
<!-- start div for editing providers //--> <!-- start div for editing providers //-->
#for $curNewznabProvider in [$curProvider for $curProvider in $sickbeard.newznabProviderList] #for $cur_newznab_provider in [$cur_provider for $cur_provider in $sickbeard.newznabProviderList]
<div class="providerDiv" id="${curNewznabProvider.get_id()}Div"> <div class="providerDiv" id="${cur_newznab_provider.get_id()}Div">
#if $curNewznabProvider.default and $curNewznabProvider.needs_auth #if $cur_newznab_provider.default and $cur_newznab_provider.needs_auth
<div class="field-pair"> <div class="field-pair">
<label for="${curNewznabProvider.get_id()}_url"> <label for="${cur_newznab_provider.get_id()}_url">
<span class="component-title">URL</span> <span class="component-title">URL</span>
<span class="component-desc"> <span class="component-desc">
<input type="text" id="${curNewznabProvider.get_id()}_url" value="$curNewznabProvider.url" class="form-control input-sm input350" disabled/> <input type="text" id="${cur_newznab_provider.get_id()}_url" value="$cur_newznab_provider.url" class="form-control input-sm input350" disabled/>
</span> </span>
</label> </label>
</div> </div>
<div class="field-pair"> <div class="field-pair">
<label for="${curNewznabProvider.get_id()}_hash"> <label for="${cur_newznab_provider.get_id()}_hash">
<span class="component-title">API key</span> <span class="component-title">API key</span>
<span class="component-desc"> <span class="component-desc">
<input type="text" id="${curNewznabProvider.get_id()}_hash" value="<%= starify(curNewznabProvider.key) %>" newznab_name="${curNewznabProvider.get_id()}_hash" class="newznab_key form-control input-sm input350" /> <input type="text" id="${cur_newznab_provider.get_id()}_hash" value="<%= starify(cur_newznab_provider.key) %>" newznab_name="${cur_newznab_provider.get_id()}_hash" class="newznab_key form-control input-sm input350" />
<div class="clear-left"><p>get API key from provider website</p></div> <div class="clear-left"><p>get API key from provider website</p></div>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curNewznabProvider, 'enable_recentsearch') and $curNewznabProvider.supportsBacklog: #if $hasattr($cur_newznab_provider, 'enable_recentsearch') and $cur_newznab_provider.supports_backlog:
<div class="field-pair"> <div class="field-pair">
<label for="${curNewznabProvider.get_id()}_enable_recentsearch"> <label for="${cur_newznab_provider.get_id()}_enable_recentsearch">
<span class="component-title">Enable recent searches</span> <span class="component-title">Enable recent searches</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="${curNewznabProvider.get_id()}_enable_recentsearch" id="${curNewznabProvider.get_id()}_enable_recentsearch" <%= html_checked if curNewznabProvider.enable_recentsearch else '' %>/> <input type="checkbox" name="${cur_newznab_provider.get_id()}_enable_recentsearch" id="${cur_newznab_provider.get_id()}_enable_recentsearch" <%= html_checked if cur_newznab_provider.enable_recentsearch else '' %>/>
<p>perform recent searches at provider</p> <p>perform recent searches at provider</p>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curNewznabProvider, 'enable_backlog') and $curNewznabProvider.supportsBacklog: #if $hasattr($cur_newznab_provider, 'enable_backlog') and $cur_newznab_provider.supports_backlog:
<div class="field-pair"> <div class="field-pair">
<label for="${curNewznabProvider.get_id()}_enable_backlog"> <label for="${cur_newznab_provider.get_id()}_enable_backlog">
<span class="component-title">Enable backlog searches</span> <span class="component-title">Enable backlog searches</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="${curNewznabProvider.get_id()}_enable_backlog" id="${curNewznabProvider.get_id()}_enable_backlog" <%= html_checked if curNewznabProvider.enable_backlog else '' %>/> <input type="checkbox" name="${cur_newznab_provider.get_id()}_enable_backlog" id="${cur_newznab_provider.get_id()}_enable_backlog" <%= html_checked if cur_newznab_provider.enable_backlog else '' %>/>
<p>perform backlog searches at provider</p> <p>perform backlog searches at provider</p>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curNewznabProvider, 'search_mode') and $curNewznabProvider.supportsBacklog: #if $hasattr($cur_newznab_provider, 'search_mode') and $cur_newznab_provider.supports_backlog:
<div class="field-pair"> <div class="field-pair">
<span class="component-title">Season search mode</span> <span class="component-title">Episode search mode</span>
<span class="component-desc"> <span class="component-desc">
<label class="space-right"> <label class="space-right">
<input type="radio" name="${curNewznabProvider.get_id()}_search_mode" id="${curNewznabProvider.get_id()}_search_mode_sponly" value="sponly" <%= html_checked if 'sponly' == curNewznabProvider.search_mode else '' %>/>season packs only <input type="radio" name="${cur_newznab_provider.get_id()}_search_mode" id="${cur_newznab_provider.get_id()}_search_mode_eponly" value="eponly" <%= html_checked if 'eponly' == cur_newznab_provider.search_mode else '' %>/>episodes only (normal use)
</label> </label>
<label> <label>
<input type="radio" name="${curNewznabProvider.get_id()}_search_mode" id="${curNewznabProvider.get_id()}_search_mode_eponly" value="eponly" <%= html_checked if 'eponly' == curNewznabProvider.search_mode else '' %>/>episodes only <input type="radio" name="${cur_newznab_provider.get_id()}_search_mode" id="${cur_newznab_provider.get_id()}_search_mode_sponly" value="sponly" <%= html_checked if 'sponly' == cur_newznab_provider.search_mode else '' %>/>season packs only
</label> </label>
<p>when searching for complete seasons, search for packs or collect single episodes</p> <p>when searching for episodes, collect single episodes or search for packs</p>
</span> </span>
</div> </div>
#end if #end if
#if $hasattr($curNewznabProvider, 'search_fallback') and $curNewznabProvider.supportsBacklog: #if $hasattr($cur_newznab_provider, 'search_fallback') and $cur_newznab_provider.supports_backlog:
<div class="field-pair"> <div class="field-pair">
<label for="${curNewznabProvider.get_id()}_search_fallback"> <label for="${cur_newznab_provider.get_id()}_search_fallback">
<span class="component-title">Season search fallback</span> <span class="component-title">Episode search fallback</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="${curNewznabProvider.get_id()}_search_fallback" id="${curNewznabProvider.get_id()}_search_fallback" <%= html_checked if curNewznabProvider.search_fallback else '' %>/> <input type="checkbox" name="${cur_newznab_provider.get_id()}_search_fallback" id="${cur_newznab_provider.get_id()}_search_fallback" <%= html_checked if cur_newznab_provider.search_fallback else '' %>/>
<p>run the alternate season search mode when a complete season is not found</p> <p>use the alternate episode search mode if no match is found -- warning; may result in a heavy block hit -- best use: manually collect a season, disable after.</p>
</span> </span>
</label> </label>
</div> </div>
@ -262,80 +259,81 @@
## ##
## ##
#for $curNzbProvider in [$curProvider for $curProvider in $sickbeard.providers.sortedProviderList() if $curProvider.providerType == $GenericProvider.NZB and $curProvider not in $sickbeard.newznabProviderList]: #for $cur_nzb_provider in [$cur_provider for $cur_provider in $sickbeard.providers.sortedProviderList()
<div class="providerDiv" id="${curNzbProvider.get_id()}Div"> if $cur_provider.providerType == $GenericProvider.NZB and $cur_provider not in $sickbeard.newznabProviderList]:
#if $hasattr($curNzbProvider, 'username'): <div class="providerDiv" id="${cur_nzb_provider.get_id()}Div">
#if $hasattr($cur_nzb_provider, 'username'):
<div class="field-pair"> <div class="field-pair">
<label for="${curNzbProvider.get_id()}_username"> <label for="${cur_nzb_provider.get_id()}_username">
<span class="component-title">Username</span> <span class="component-title">Username</span>
<span class="component-desc"> <span class="component-desc">
<input type="text" name="${curNzbProvider.get_id()}_username" value="$curNzbProvider.username" class="form-control input-sm input350" /> <input type="text" name="${cur_nzb_provider.get_id()}_username" value="$cur_nzb_provider.username" class="form-control input-sm input350" />
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curNzbProvider, 'api_key'): #if $hasattr($cur_nzb_provider, 'api_key'):
<div class="field-pair"> <div class="field-pair">
<label for="${curNzbProvider.get_id()}_api_key"> <label for="${cur_nzb_provider.get_id()}_api_key">
<span class="component-title">API key</span> <span class="component-title">API key</span>
<span class="component-desc"> <span class="component-desc">
#set $field_name = curNzbProvider.get_id() + '_api_key' #set $field_name = cur_nzb_provider.get_id() + '_api_key'
<input type="text" name="$field_name" value="<%= starify(curNzbProvider.api_key) %>" class="form-control input-sm input350" /> <input type="text" name="$field_name" value="<%= starify(cur_nzb_provider.api_key) %>" class="form-control input-sm input350" />
#if callable(getattr(curNzbProvider, 'ui_string', None)) #if callable(getattr(cur_nzb_provider, 'ui_string', None))
<div class="clear-left"><p>${curNzbProvider.ui_string($field_name)}</p></div> <div class="clear-left"><p>${cur_nzb_provider.ui_string($field_name)}</p></div>
#end if #end if
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curNzbProvider, 'enable_recentsearch') and $curNzbProvider.supportsBacklog: #if $hasattr($cur_nzb_provider, 'enable_recentsearch') and $cur_nzb_provider.supports_backlog:
<div class="field-pair"> <div class="field-pair">
<label for="${curNzbProvider.get_id()}_enable_recentsearch"> <label for="${cur_nzb_provider.get_id()}_enable_recentsearch">
<span class="component-title">Enable recent searches</span> <span class="component-title">Enable recent searches</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="${curNzbProvider.get_id()}_enable_recentsearch" id="${curNzbProvider.get_id()}_enable_recentsearch" <%= html_checked if curNzbProvider.enable_recentsearch else '' %>/> <input type="checkbox" name="${cur_nzb_provider.get_id()}_enable_recentsearch" id="${cur_nzb_provider.get_id()}_enable_recentsearch" <%= html_checked if cur_nzb_provider.enable_recentsearch else '' %>/>
<p>enable provider to perform recent searches.</p> <p>enable provider to perform recent searches</p>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curNzbProvider, 'enable_backlog') and $curNzbProvider.supportsBacklog: #if $hasattr($cur_nzb_provider, 'enable_backlog') and $cur_nzb_provider.supports_backlog:
<div class="field-pair"> <div class="field-pair">
<label for="${curNzbProvider.get_id()}_enable_backlog"> <label for="${cur_nzb_provider.get_id()}_enable_backlog">
<span class="component-title">Enable backlog searches</span> <span class="component-title">Enable backlog searches</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="${curNzbProvider.get_id()}_enable_backlog" id="${curNzbProvider.get_id()}_enable_backlog" <%= html_checked if curNzbProvider.enable_backlog else '' %>/> <input type="checkbox" name="${cur_nzb_provider.get_id()}_enable_backlog" id="${cur_nzb_provider.get_id()}_enable_backlog" <%= html_checked if cur_nzb_provider.enable_backlog else '' %>/>
<p>enable provider to perform backlog searches.</p> <p>enable provider to perform backlog searches</p>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curNzbProvider, 'search_mode') and $curNzbProvider.supportsBacklog: #if $hasattr($cur_nzb_provider, 'search_mode') and $cur_nzb_provider.supports_backlog:
<div class="field-pair"> <div class="field-pair">
<span class="component-title">Season search mode</span> <span class="component-title">Episode search mode</span>
<span class="component-desc"> <span class="component-desc">
<label class="space-right"> <label class="space-right">
<input type="radio" name="${curNzbProvider.get_id()}_search_mode" id="${curNzbProvider.get_id()}_search_mode_sponly" value="sponly" <%= html_checked if 'sponly' == curNzbProvider.search_mode else '' %>/>season packs only <input type="radio" name="${cur_nzb_provider.get_id()}_search_mode" id="${cur_nzb_provider.get_id()}_search_mode_eponly" value="eponly" <%= html_checked if 'eponly' == cur_nzb_provider.search_mode else '' %>/>episodes only (normal use)
</label> </label>
<label> <label>
<input type="radio" name="${curNzbProvider.get_id()}_search_mode" id="${curNzbProvider.get_id()}_search_mode_eponly" value="eponly" <%= html_checked if 'eponly' == curNzbProvider.search_mode else '' %>/>episodes only <input type="radio" name="${cur_nzb_provider.get_id()}_search_mode" id="${cur_nzb_provider.get_id()}_search_mode_sponly" value="sponly" <%= html_checked if 'sponly' == cur_nzb_provider.search_mode else '' %>/>season packs only
</label> </label>
<p>when searching for complete seasons, search for packs or collect single episodes</p> <p>when searching for episodes, collect single episodes or search for packs</p>
</span> </span>
</div> </div>
#end if #end if
#if $hasattr($curNzbProvider, 'search_fallback') and $curNzbProvider.supportsBacklog: #if $hasattr($cur_nzb_provider, 'search_fallback') and $cur_nzb_provider.supports_backlog:
<div class="field-pair"> <div class="field-pair">
<label for="${curNzbProvider.get_id()}_search_fallback"> <label for="${cur_nzb_provider.get_id()}_search_fallback">
<span class="component-title">Season search fallback</span> <span class="component-title">Episode search fallback</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="${curNzbProvider.get_id()}_search_fallback" id="${curNzbProvider.get_id()}_search_fallback" <%= html_checked if curNzbProvider.search_fallback else '' %>/> <input type="checkbox" name="${cur_nzb_provider.get_id()}_search_fallback" id="${cur_nzb_provider.get_id()}_search_fallback" <%= html_checked if cur_nzb_provider.search_fallback else '' %>/>
<p>run the alternate season search mode when a complete season is not found</p> <p>use the alternate episode search mode if no match is found -- warning; may result in a heavy block hit -- best use: manually collect a season, disable after.</p>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if not $curNzbProvider.supportsBacklog: #if not $cur_nzb_provider.supports_backlog:
<div class="field-pair"> <div class="field-pair">
<span class="component-desc">The latest releases are the focus of this provider, no backlog searching</span> <span class="component-desc">The latest releases are the focus of this provider, no backlog searching</span>
</div> </div>
@ -345,233 +343,229 @@
## ##
## ##
#for $curTorrentProvider in [$curProvider for $curProvider in $sickbeard.providers.sortedProviderList() if $curProvider.providerType == $GenericProvider.TORRENT]: #for $cur_torrent_provider in [$cur_provider for $cur_provider in $sickbeard.providers.sortedProviderList()
<div class="providerDiv" id="${curTorrentProvider.get_id()}Div"> if $cur_provider.providerType == $GenericProvider.TORRENT]:
#if callable(getattr(curTorrentProvider, 'ui_string', None)) <div class="providerDiv" id="${cur_torrent_provider.get_id()}Div">
#set $field_name = curTorrentProvider.get_id() + '_tip' #if callable(getattr(cur_torrent_provider, 'ui_string', None))
#set $tip_text = curTorrentProvider.ui_string($field_name) #set $field_name = cur_torrent_provider.get_id() + '_tip'
#set $tip_text = cur_torrent_provider.ui_string($field_name)
#if $tip_text #if $tip_text
<div class="field-pair"> <div class="field-pair">
<span class="component-desc" style="margin:0;width:100%"> <span class="component-desc" style="margin:0;width:100%">
<div class="clear-left"><p class="grey-text"><span class="red-text">Important! ${curTorrentProvider.name}</span> $tip_text</p></div> <div class="clear-left"><p class="grey-text"><span class="red-text">Important! ${cur_torrent_provider.name}</span> $tip_text</p></div>
</span> </span>
</div> </div>
#end if #end if
#end if #end if
#if $hasattr($curTorrentProvider, 'api_key'): #if $getattr($cur_torrent_provider, 'url_edit', None):
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_api_key"> <label for="url_base">
<span class="component-title">Api key:</span> #set $url_label = callable(getattr(cur_torrent_provider, 'ui_string', None)) and cur_torrent_provider.ui_string(cur_torrent_provider.get_id() + '_site_url') or 'Site URL'
<span class="component-title">$url_label</span>
<span class="component-desc"> <span class="component-desc">
<input type="text" name="${curTorrentProvider.get_id()}_api_key" id="${curTorrentProvider.get_id()}_api_key" value="<%= starify(curTorrentProvider.api_key) %>" class="form-control input-sm input350" /> #set $field_name = cur_torrent_provider.get_id() + '_url_edit'
</span> <input type="text" name="$field_name" id="$field_name" value="<%= ', '.join(cur_torrent_provider.url_home) %>" class="form-control input-sm input350" />
</label> #if callable(getattr(cur_torrent_provider, 'ui_string', None))
</div> <div class="clear-left"><p>${cur_torrent_provider.ui_string($field_name)}</p></div>
#end if
#if $hasattr($curTorrentProvider, 'digest'):
<div class="field-pair">
<label for="${curTorrentProvider.get_id()}_digest">
<span class="component-title">Cookies:</span>
<span class="component-desc">
#set $field_name = curTorrentProvider.get_id() + '_digest'
<input type="text" name="$field_name" id="$field_name" value="<%= starify(curTorrentProvider.digest) %>" class="form-control input-sm input350" />
#if callable(getattr(curTorrentProvider, 'ui_string', None))
<div class="clear-left"><p>${curTorrentProvider.ui_string($field_name)}</p></div>
#end if #end if
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'hash'): #if $hasattr($cur_torrent_provider, 'api_key'):
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_hash"> <label for="${cur_torrent_provider.get_id()}_api_key">
<span class="component-title">Api key:</span>
<span class="component-desc">
<input type="text" name="${cur_torrent_provider.get_id()}_api_key" id="${cur_torrent_provider.get_id()}_api_key" value="<%= starify(cur_torrent_provider.api_key) %>" class="form-control input-sm input350" />
</span>
</label>
</div>
#end if
#if $hasattr($cur_torrent_provider, 'digest'):
#set $field_name = cur_torrent_provider.get_id() + '_digest'
<div class="field-pair">
<label for="$field_name">
<span class="component-title">Cookies:</span>
<span class="component-desc">
<input type="text" name="$field_name" id="$field_name" value="<%= starify(cur_torrent_provider.digest) %>" class="form-control input-sm input350" />
#if callable(getattr(cur_torrent_provider, 'ui_string', None))
<div class="clear-left"><p>${cur_torrent_provider.ui_string($field_name)}</p></div>
#end if
</span>
</label>
</div>
#end if
#if $hasattr($cur_torrent_provider, 'hash'):
<div class="field-pair">
<label for="${cur_torrent_provider.get_id()}_hash">
<span class="component-title">Hash:</span> <span class="component-title">Hash:</span>
<span class="component-desc"> <span class="component-desc">
<input type="text" name="${curTorrentProvider.get_id()}_hash" id="${curTorrentProvider.get_id()}_hash" value="$curTorrentProvider.hash" class="form-control input-sm input350" /> <input type="text" name="${cur_torrent_provider.get_id()}_hash" id="${cur_torrent_provider.get_id()}_hash" value="$cur_torrent_provider.hash" class="form-control input-sm input350" />
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'username'): #for $user_type in ['username', 'uid']:
#if $hasattr($cur_torrent_provider, $user_type):
#set $prov_type = '%s_%s' % ($cur_torrent_provider.get_id(), $user_type)
#set $user_value = $getattr($cur_torrent_provider, $user_type) or ''
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_username"> <label for="$prov_type">
<span class="component-title">Username:</span> <span class="component-title">$user_type.capitalize():</span>
<span class="component-desc"> <span class="component-desc">
<input type="text" name="${curTorrentProvider.get_id()}_username" id="${curTorrentProvider.get_id()}_username" value="$curTorrentProvider.username" class="form-control input-sm input350" /> <input type="text" name="$prov_type" id="$prov_type" value="$user_value" class="form-control input-sm input350" />
</span> </span>
</label> </label>
</div> </div>
#end if #break
#if $hasattr($curTorrentProvider, 'password'): #end if
#end for
#if $hasattr($cur_torrent_provider, 'password'):
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_password"> <label for="${cur_torrent_provider.get_id()}_password">
<span class="component-title">Password:</span> <span class="component-title">Password:</span>
<span class="component-desc"> <span class="component-desc">
<input type="password" name="${curTorrentProvider.get_id()}_password" id="${curTorrentProvider.get_id()}_password" value="#echo $curTorrentProvider.password and '*' * len($curTorrentProvider.password) or ''#" class="form-control input-sm input350" /> <input type="password" name="${cur_torrent_provider.get_id()}_password" id="${cur_torrent_provider.get_id()}_password" value="#echo $cur_torrent_provider.password and '*' * len($cur_torrent_provider.password) or ''#" class="form-control input-sm input350" />
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'passkey'): #if $hasattr($cur_torrent_provider, 'passkey'):
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_passkey"> <label for="${cur_torrent_provider.get_id()}_passkey">
<span class="component-title">Passkey:</span> <span class="component-title">Passkey:</span>
<span class="component-desc"> <span class="component-desc">
<input type="text" name="${curTorrentProvider.get_id()}_passkey" id="${curTorrentProvider.get_id()}_passkey" value="<%= starify(curTorrentProvider.passkey) %>" class="form-control input-sm input350" /> <input type="text" name="${cur_torrent_provider.get_id()}_passkey" id="${cur_torrent_provider.get_id()}_passkey" value="<%= starify(cur_torrent_provider.passkey) %>" class="form-control input-sm input350" />
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, '_seed_ratio') and 'blackhole' != $sickbeard.TORRENT_METHOD: #if $hasattr($cur_torrent_provider, '_seed_ratio') and 'blackhole' != $sickbeard.TORRENT_METHOD:
#set $torrent_method_text = {'utorrent': 'uTorrent', 'transmission': 'Transmission', 'deluge': 'Deluge', 'download_station': 'Synology DS', 'rtorrent': 'rTorrent'} #set $torrent_method_text = {'utorrent': 'uTorrent', 'transmission': 'Transmission', 'deluge': 'Deluge', 'download_station': 'Synology DS', 'rtorrent': 'rTorrent'}
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_ratio"> <label for="${cur_torrent_provider.get_id()}_ratio">
<span class="component-title" id="${curTorrentProvider.get_id()}_ratio_desc">Seed until ratio (the goal)</span> <span class="component-title" id="${cur_torrent_provider.get_id()}_ratio_desc">Seed until ratio (the goal)</span>
<span class="component-desc"> <span class="component-desc">
<input type="number" name="${curTorrentProvider.get_id()}_ratio" id="${curTorrentProvider.get_id()}_ratio" value="$curTorrentProvider._seed_ratio" class="form-control input-sm input75" /> <input type="number" name="${cur_torrent_provider.get_id()}_ratio" id="${cur_torrent_provider.get_id()}_ratio" value="$cur_torrent_provider._seed_ratio" class="form-control input-sm input75" />
<p>this ratio is requested of each item sent to $torrent_method_text[$sickbeard.TORRENT_METHOD]</p> <p>this ratio is requested of each item sent to $torrent_method_text[$sickbeard.TORRENT_METHOD]</p>
<div class="clear-left"><p>(#if 'Transmission' in $torrent_method_text[$sickbeard.TORRENT_METHOD]#set -1 to seed forever, or #end if#leave blank for the $torrent_method_text[$sickbeard.TORRENT_METHOD] setting)</p></div> <div class="clear-left"><p>(#if 'Transmission' in $torrent_method_text[$sickbeard.TORRENT_METHOD]#set -1 to seed forever, or #end if#leave blank for the $torrent_method_text[$sickbeard.TORRENT_METHOD] setting)</p></div>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'seed_time') and 'utorrent' == $sickbeard.TORRENT_METHOD: #if $hasattr($cur_torrent_provider, 'seed_time') and 'utorrent' == $sickbeard.TORRENT_METHOD:
#set $torrent_method_text = {'utorrent': 'uTorrent'} #set $torrent_method_text = {'utorrent': 'uTorrent'}
#set $use_default = 'to use the %s min <a href="%s/config/search/#core-component-group3">torrent search setting minumum default</a>' % ($sickbeard.TORRENT_SEED_TIME, $sbRoot) if $sickbeard.TORRENT_SEED_TIME else 'for the %s setting' % $torrent_method_text[$sickbeard.TORRENT_METHOD] #set $use_default = 'to use the %s min <a href="%s/config/search/#core-component-group3">torrent search setting minumum default</a>' % ($sickbeard.TORRENT_SEED_TIME, $sbRoot) if $sickbeard.TORRENT_SEED_TIME else 'for the %s setting' % $torrent_method_text[$sickbeard.TORRENT_METHOD]
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_seed_time"> <label for="${cur_torrent_provider.get_id()}_seed_time">
<span class="component-title" id="${curTorrentProvider.get_id()}_seed_time_desc">Seed time (provider default)</span> <span class="component-title" id="${cur_torrent_provider.get_id()}_seed_time_desc">Seed time (provider default)</span>
<span class="component-desc"> <span class="component-desc">
<input type="number" name="${curTorrentProvider.get_id()}_seed_time" id="${curTorrentProvider.get_id()}_seed_time" value="$curTorrentProvider.seed_time" class="form-control input-sm input75" /> <input type="number" name="${cur_torrent_provider.get_id()}_seed_time" id="${cur_torrent_provider.get_id()}_seed_time" value="$cur_torrent_provider.seed_time" class="form-control input-sm input75" />
<p>set 1 or more minimum minutes for each item sent to $torrent_method_text[$sickbeard.TORRENT_METHOD]</p> <p>set 1 or more minimum minutes for each item sent to $torrent_method_text[$sickbeard.TORRENT_METHOD]</p>
<div class="clear-left"><p>(leave blank $use_default)</p></div> <div class="clear-left"><p>(leave blank $use_default)</p></div>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'minseed'): #if $hasattr($cur_torrent_provider, 'minseed'):
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_minseed"> <label for="${cur_torrent_provider.get_id()}_minseed">
<span class="component-title" id="${curTorrentProvider.get_id()}_minseed_desc">Minimum seeders</span> <span class="component-title" id="${cur_torrent_provider.get_id()}_minseed_desc">Minimum seeders</span>
<span class="component-desc"> <span class="component-desc">
<input type="number" name="${curTorrentProvider.get_id()}_minseed" id="${curTorrentProvider.get_id()}_minseed" value="$curTorrentProvider.minseed" class="form-control input-sm input75" /> <input type="number" name="${cur_torrent_provider.get_id()}_minseed" id="${cur_torrent_provider.get_id()}_minseed" value="$cur_torrent_provider.minseed" class="form-control input-sm input75" />
<p>a release must have to be snatch worthy</p> <p>a release must have to be snatch worthy</p>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'minleech'): #if $hasattr($cur_torrent_provider, 'minleech'):
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_minleech"> <label for="${cur_torrent_provider.get_id()}_minleech">
<span class="component-title" id="${curTorrentProvider.get_id()}_minleech_desc">Minimum leechers</span> <span class="component-title" id="${cur_torrent_provider.get_id()}_minleech_desc">Minimum leechers</span>
<span class="component-desc"> <span class="component-desc">
<input type="number" name="${curTorrentProvider.get_id()}_minleech" id="${curTorrentProvider.get_id()}_minleech" value="$curTorrentProvider.minleech" class="form-control input-sm input75" /> <input type="number" name="${cur_torrent_provider.get_id()}_minleech" id="${cur_torrent_provider.get_id()}_minleech" value="$cur_torrent_provider.minleech" class="form-control input-sm input75" />
<p>a release must have to be snatch worthy</p> <p>a release must have to be snatch worthy</p>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'proxy'): #if $hasattr($cur_torrent_provider, 'confirmed'):
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_proxy"> <label for="${cur_torrent_provider.get_id()}_confirmed">
<span class="component-title">Access provider via proxy</span>
<span class="component-desc">
<input type="checkbox" class="enabler" name="${curTorrentProvider.get_id()}_proxy" id="${curTorrentProvider.get_id()}_proxy" <%= html_checked if curTorrentProvider.proxy.enabled else '' %>/>
<p>to bypass country blocking mechanisms</p>
</span>
</label>
</div>
#if $hasattr($curTorrentProvider.proxy, 'url'):
<div class="field-pair content_${curTorrentProvider.get_id()}_proxy" id="content_${curTorrentProvider.get_id()}_proxy">
<label for="${curTorrentProvider.get_id()}_proxy_url">
<span class="component-title">Proxy URL:</span>
<span class="component-desc">
<select name="${curTorrentProvider.get_id()}_proxy_url" id="${curTorrentProvider.get_id()}_proxy_url" class="form-control input-sm">
#for $i in $curTorrentProvider.proxy.urls.keys():
<option value="$curTorrentProvider.proxy.urls[$i]" <%= html_selected if curTorrentProvider.proxy.url == curTorrentProvider.proxy.urls[i] else '' %>>$i</option>
#end for
</select>
</span>
</label>
</div>
#end if
#end if
#if $hasattr($curTorrentProvider, 'confirmed'):
<div class="field-pair">
<label for="${curTorrentProvider.get_id()}_confirmed">
<span class="component-title">Confirmed download</span> <span class="component-title">Confirmed download</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="${curTorrentProvider.get_id()}_confirmed" id="${curTorrentProvider.get_id()}_confirmed" <%= html_checked if curTorrentProvider.confirmed else '' %>/> <input type="checkbox" name="${cur_torrent_provider.get_id()}_confirmed" id="${cur_torrent_provider.get_id()}_confirmed" <%= html_checked if cur_torrent_provider.confirmed else '' %>/>
<p>only download torrents from trusted or verified uploaders ?</p> <p>only download torrents from trusted or verified uploaders ?</p>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'freeleech'): #if $hasattr($cur_torrent_provider, 'freeleech'):
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_freeleech"> <label for="${cur_torrent_provider.get_id()}_freeleech">
<span class="component-title">Freeleech</span> <span class="component-title">Freeleech</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="${curTorrentProvider.get_id()}_freeleech" id="${curTorrentProvider.get_id()}_freeleech" <%= html_checked if curTorrentProvider.freeleech else '' %>/> <input type="checkbox" name="${cur_torrent_provider.get_id()}_freeleech" id="${cur_torrent_provider.get_id()}_freeleech" <%= html_checked if cur_torrent_provider.freeleech else '' %>/>
<p>only download <b>[FreeLeech]</b> torrents.</p> <p>only download <b>[FreeLeech]</b> torrents</p>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'reject_m2ts'): #if $hasattr($cur_torrent_provider, 'reject_m2ts'):
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_reject_m2ts"> <label for="${cur_torrent_provider.get_id()}_reject_m2ts">
<span class="component-title">Reject Blu-ray M2TS releases</span> <span class="component-title">Reject Blu-ray M2TS releases</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="${curTorrentProvider.get_id()}_reject_m2ts" id="${curTorrentProvider.get_id()}_reject_m2ts" <%= html_checked if curTorrentProvider.reject_m2ts else '' %>/> <input type="checkbox" name="${cur_torrent_provider.get_id()}_reject_m2ts" id="${cur_torrent_provider.get_id()}_reject_m2ts" <%= html_checked if cur_torrent_provider.reject_m2ts else '' %>/>
<p>enable to ignore Blu-ray MPEG-2 Transport Stream container releases</p> <p>enable to ignore Blu-ray MPEG-2 Transport Stream container releases</p>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'enable_recentsearch') and $curTorrentProvider.supportsBacklog: #if $hasattr($cur_torrent_provider, 'enable_recentsearch'):
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_enable_recentsearch"> <label for="${cur_torrent_provider.get_id()}_enable_recentsearch">
<span class="component-title">Enable recent searches</span> <span class="component-title">Enable recent searches</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="${curTorrentProvider.get_id()}_enable_recentsearch" id="${curTorrentProvider.get_id()}_enable_recentsearch" <%= html_checked if curTorrentProvider.enable_recentsearch else '' %>/> <input type="checkbox" name="${cur_torrent_provider.get_id()}_enable_recentsearch" id="${cur_torrent_provider.get_id()}_enable_recentsearch" <%= html_checked if cur_torrent_provider.enable_recentsearch else '' %>/>
<p>enable provider to perform recent searches.</p> <p>enable provider to perform recent searches</p>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'enable_backlog') and $curTorrentProvider.supportsBacklog: #if $hasattr($cur_torrent_provider, 'enable_backlog') and $cur_torrent_provider.supports_backlog:
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_enable_backlog"> <label for="${cur_torrent_provider.get_id()}_enable_backlog">
<span class="component-title">Enable backlog searches</span> <span class="component-title">Enable backlog searches</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="${curTorrentProvider.get_id()}_enable_backlog" id="${curTorrentProvider.get_id()}_enable_backlog" <%= html_checked if curTorrentProvider.enable_backlog else '' %>/> <input type="checkbox" name="${cur_torrent_provider.get_id()}_enable_backlog" id="${cur_torrent_provider.get_id()}_enable_backlog" <%= html_checked if cur_torrent_provider.enable_backlog else '' %>/>
<p>enable provider to perform backlog searches.</p> <p>enable provider to perform backlog searches</p>
</span> </span>
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'search_mode') and $curTorrentProvider.supportsBacklog: #if $hasattr($cur_torrent_provider, 'search_mode') and $cur_torrent_provider.supports_backlog:
<div class="field-pair"> <div class="field-pair">
<span class="component-title">Season search mode</span> <span class="component-title">Episode search mode</span>
<span class="component-desc"> <span class="component-desc">
<label class="space-right"> <label class="space-right">
<input type="radio" name="${curTorrentProvider.get_id()}_search_mode" id="${curTorrentProvider.get_id()}_search_mode_sponly" value="sponly" <%= html_checked if 'sponly' == curTorrentProvider.search_mode else '' %>/>season packs only <input type="radio" name="${cur_torrent_provider.get_id()}_search_mode" id="${cur_torrent_provider.get_id()}_search_mode_eponly" value="eponly" <%= html_checked if 'eponly' == cur_torrent_provider.search_mode else '' %>/>episodes only (normal use)
</label> </label>
<label> <label>
<input type="radio" name="${curTorrentProvider.get_id()}_search_mode" id="${curTorrentProvider.get_id()}_search_mode_eponly" value="eponly" <%= html_checked if 'eponly' == curTorrentProvider.search_mode else '' %>/>episodes only <input type="radio" name="${cur_torrent_provider.get_id()}_search_mode" id="${cur_torrent_provider.get_id()}_search_mode_sponly" value="sponly" <%= html_checked if 'sponly' == cur_torrent_provider.search_mode else '' %>/>season packs only
</label> </label>
<p>when searching for complete seasons, search for packs or collect single episodes</p> <p>when searching for episodes, collect single episodes or search for packs</p>
</span> </span>
</div> </div>
#end if #end if
#if $hasattr($curTorrentProvider, 'search_fallback') and $curTorrentProvider.supportsBacklog: #if $hasattr($cur_torrent_provider, 'search_fallback') and $cur_torrent_provider.supports_backlog:
<div class="field-pair"> <div class="field-pair">
<label for="${curTorrentProvider.get_id()}_search_fallback"> <label for="${cur_torrent_provider.get_id()}_search_fallback">
<span class="component-title">Season search fallback</span> <span class="component-title">Episode search fallback</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="${curTorrentProvider.get_id()}_search_fallback" id="${curTorrentProvider.get_id()}_search_fallback" <%= html_checked if curTorrentProvider.search_fallback else '' %>/> <input type="checkbox" name="${cur_torrent_provider.get_id()}_search_fallback" id="${cur_torrent_provider.get_id()}_search_fallback" <%= html_checked if cur_torrent_provider.search_fallback else '' %>/>
<p>run the alternate season search mode when a complete season is not found</p> <p>use the alternate episode search mode if no match is found -- warning; may result in duplicates or a heavy ratio hit -- best use: manually collect a season, disable after.</p>
</span> </span>
</label> </label>
</div> </div>

View file

@ -73,6 +73,7 @@
<span class="component-desc"> <span class="component-desc">
<input type="text" name="recentsearch_frequency" value="$sickbeard.RECENTSEARCH_FREQUENCY" class="form-control input-sm input75"> <input type="text" name="recentsearch_frequency" value="$sickbeard.RECENTSEARCH_FREQUENCY" class="form-control input-sm input75">
<p>minutes between checking recent updated shows (minimum $sickbeard.MIN_RECENTSEARCH_FREQUENCY)</p> <p>minutes between checking recent updated shows (minimum $sickbeard.MIN_RECENTSEARCH_FREQUENCY)</p>
<p><em class="grey-text">enter 4489 for experimental internal provider frequencies</em></p>
</span> </span>
</label> </label>
</div> </div>

View file

@ -30,6 +30,7 @@ from threading import Lock
import sys import sys
import os.path import os.path
import uuid import uuid
import ast
import base64 import base64
sys.path.insert(1, os.path.abspath('../lib')) sys.path.insert(1, os.path.abspath('../lib'))
from sickbeard import helpers, logger, db, naming, metadata, providers, scene_exceptions, scene_numbering, \ from sickbeard import helpers, logger, db, naming, metadata, providers, scene_exceptions, scene_numbering, \
@ -174,6 +175,7 @@ IMDB_ACCOUNTS = []
IMDB_DEFAULT_LIST_ID = '64552276' IMDB_DEFAULT_LIST_ID = '64552276'
IMDB_DEFAULT_LIST_NAME = 'SickGear' IMDB_DEFAULT_LIST_NAME = 'SickGear'
PROVIDER_ORDER = [] PROVIDER_ORDER = []
PROVIDER_HOMES = {}
NAMING_MULTI_EP = False NAMING_MULTI_EP = False
NAMING_ANIME_MULTI_EP = False NAMING_ANIME_MULTI_EP = False
@ -520,7 +522,7 @@ def initialize(consoleLogging=True):
KEEP_PROCESSED_DIR, PROCESS_METHOD, TV_DOWNLOAD_DIR, MIN_RECENTSEARCH_FREQUENCY, DEFAULT_UPDATE_FREQUENCY, MIN_UPDATE_FREQUENCY, UPDATE_FREQUENCY, \ KEEP_PROCESSED_DIR, PROCESS_METHOD, TV_DOWNLOAD_DIR, MIN_RECENTSEARCH_FREQUENCY, DEFAULT_UPDATE_FREQUENCY, MIN_UPDATE_FREQUENCY, UPDATE_FREQUENCY, \
showQueueScheduler, searchQueueScheduler, ROOT_DIRS, CACHE_DIR, ACTUAL_CACHE_DIR, ZONEINFO_DIR, TIMEZONE_DISPLAY, \ showQueueScheduler, searchQueueScheduler, ROOT_DIRS, CACHE_DIR, ACTUAL_CACHE_DIR, ZONEINFO_DIR, TIMEZONE_DISPLAY, \
NAMING_PATTERN, NAMING_MULTI_EP, NAMING_ANIME_MULTI_EP, NAMING_FORCE_FOLDERS, NAMING_ABD_PATTERN, NAMING_CUSTOM_ABD, NAMING_SPORTS_PATTERN, NAMING_CUSTOM_SPORTS, NAMING_ANIME_PATTERN, NAMING_CUSTOM_ANIME, NAMING_STRIP_YEAR, \ NAMING_PATTERN, NAMING_MULTI_EP, NAMING_ANIME_MULTI_EP, NAMING_FORCE_FOLDERS, NAMING_ABD_PATTERN, NAMING_CUSTOM_ABD, NAMING_SPORTS_PATTERN, NAMING_CUSTOM_SPORTS, NAMING_ANIME_PATTERN, NAMING_CUSTOM_ANIME, NAMING_STRIP_YEAR, \
RENAME_EPISODES, AIRDATE_EPISODES, properFinderScheduler, PROVIDER_ORDER, autoPostProcesserScheduler, \ RENAME_EPISODES, AIRDATE_EPISODES, properFinderScheduler, PROVIDER_ORDER, PROVIDER_HOMES, autoPostProcesserScheduler, \
providerList, newznabProviderList, torrentRssProviderList, \ providerList, newznabProviderList, torrentRssProviderList, \
EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, RECENTSEARCH_FREQUENCY, \ EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, RECENTSEARCH_FREQUENCY, \
USE_BOXCAR2, BOXCAR2_ACCESSTOKEN, BOXCAR2_NOTIFY_ONDOWNLOAD, BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD, BOXCAR2_NOTIFY_ONSNATCH, BOXCAR2_SOUND, \ USE_BOXCAR2, BOXCAR2_ACCESSTOKEN, BOXCAR2_NOTIFY_ONDOWNLOAD, BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD, BOXCAR2_NOTIFY_ONSNATCH, BOXCAR2_SOUND, \
@ -580,10 +582,6 @@ def initialize(consoleLogging=True):
ACTUAL_CACHE_DIR = check_setting_str(CFG, 'General', 'cache_dir', 'cache') ACTUAL_CACHE_DIR = check_setting_str(CFG, 'General', 'cache_dir', 'cache')
# fix bad configs due to buggy code
if ACTUAL_CACHE_DIR == 'None':
ACTUAL_CACHE_DIR = 'cache'
# unless they specify, put the cache dir inside the data dir # unless they specify, put the cache dir inside the data dir
if not os.path.isabs(ACTUAL_CACHE_DIR): if not os.path.isabs(ACTUAL_CACHE_DIR):
CACHE_DIR = os.path.join(DATA_DIR, ACTUAL_CACHE_DIR) CACHE_DIR = os.path.join(DATA_DIR, ACTUAL_CACHE_DIR)
@ -699,6 +697,7 @@ def initialize(consoleLogging=True):
SCENE_DEFAULT = bool(check_setting_int(CFG, 'General', 'scene_default', 0)) SCENE_DEFAULT = bool(check_setting_int(CFG, 'General', 'scene_default', 0))
PROVIDER_ORDER = check_setting_str(CFG, 'General', 'provider_order', '').split() PROVIDER_ORDER = check_setting_str(CFG, 'General', 'provider_order', '').split()
PROVIDER_HOMES = ast.literal_eval(check_setting_str(CFG, 'General', 'provider_homes', None) or '{}')
NAMING_PATTERN = check_setting_str(CFG, 'General', 'naming_pattern', 'Season %0S/%SN - S%0SE%0E - %EN') NAMING_PATTERN = check_setting_str(CFG, 'General', 'naming_pattern', 'Season %0S/%SN - S%0SE%0E - %EN')
NAMING_ABD_PATTERN = check_setting_str(CFG, 'General', 'naming_abd_pattern', '%SN - %A.D - %EN') NAMING_ABD_PATTERN = check_setting_str(CFG, 'General', 'naming_abd_pattern', '%SN - %A.D - %EN')
@ -1029,28 +1028,28 @@ def initialize(consoleLogging=True):
prov_id = torrent_prov.get_id() prov_id = torrent_prov.get_id()
prov_id_uc = torrent_prov.get_id().upper() prov_id_uc = torrent_prov.get_id().upper()
torrent_prov.enabled = bool(check_setting_int(CFG, prov_id_uc, prov_id, 0)) torrent_prov.enabled = bool(check_setting_int(CFG, prov_id_uc, prov_id, 0))
if getattr(torrent_prov, 'url_edit', None):
torrent_prov.url_home = check_setting_str(CFG, prov_id_uc, prov_id + '_url_home', [])
if hasattr(torrent_prov, 'api_key'): if hasattr(torrent_prov, 'api_key'):
torrent_prov.api_key = check_setting_str(CFG, prov_id_uc, prov_id + '_api_key', '') torrent_prov.api_key = check_setting_str(CFG, prov_id_uc, prov_id + '_api_key', '')
if hasattr(torrent_prov, 'hash'): if hasattr(torrent_prov, 'hash'):
torrent_prov.hash = check_setting_str(CFG, prov_id_uc, prov_id + '_hash', '') torrent_prov.hash = check_setting_str(CFG, prov_id_uc, prov_id + '_hash', '')
if hasattr(torrent_prov, 'digest'): if hasattr(torrent_prov, 'digest'):
torrent_prov.digest = check_setting_str(CFG, prov_id_uc, prov_id + '_digest', '') torrent_prov.digest = check_setting_str(CFG, prov_id_uc, prov_id + '_digest', '')
if hasattr(torrent_prov, 'username'): for user_type in ['username', 'uid']:
torrent_prov.username = check_setting_str(CFG, prov_id_uc, prov_id + '_username', '') if hasattr(torrent_prov, user_type):
setattr(torrent_prov, user_type,
check_setting_str(CFG, prov_id_uc, '%s_%s' % (prov_id, user_type), ''))
if hasattr(torrent_prov, 'password'): if hasattr(torrent_prov, 'password'):
torrent_prov.password = check_setting_str(CFG, prov_id_uc, prov_id + '_password', '') torrent_prov.password = check_setting_str(CFG, prov_id_uc, prov_id + '_password', '')
if hasattr(torrent_prov, 'passkey'): if hasattr(torrent_prov, 'passkey'):
torrent_prov.passkey = check_setting_str(CFG, prov_id_uc, prov_id + '_passkey', '') torrent_prov.passkey = check_setting_str(CFG, prov_id_uc, prov_id + '_passkey', '')
if hasattr(torrent_prov, 'proxy'):
torrent_prov.proxy.enabled = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_proxy', 0))
if hasattr(torrent_prov.proxy, 'url'):
torrent_prov.proxy.url = check_setting_str(CFG, prov_id_uc, prov_id + '_proxy_url', '')
if hasattr(torrent_prov, 'confirmed'): if hasattr(torrent_prov, 'confirmed'):
torrent_prov.confirmed = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_confirmed', 0)) torrent_prov.confirmed = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_confirmed', 0))
if hasattr(torrent_prov, 'options'): if hasattr(torrent_prov, 'options'):
torrent_prov.options = check_setting_str(CFG, prov_id_uc, prov_id + '_options', '') torrent_prov.options = check_setting_str(CFG, prov_id_uc, prov_id + '_options', '')
if hasattr(torrent_prov, '_seed_ratio'): if hasattr(torrent_prov, '_seed_ratio'):
torrent_prov._seed_ratio = check_setting_str(CFG, prov_id_uc, prov_id + '_seed_ratio', '').replace('None', '') torrent_prov._seed_ratio = check_setting_str(CFG, prov_id_uc, prov_id + '_seed_ratio', '')
if hasattr(torrent_prov, 'seed_time'): if hasattr(torrent_prov, 'seed_time'):
torrent_prov.seed_time = check_setting_int(CFG, prov_id_uc, prov_id + '_seed_time', '') torrent_prov.seed_time = check_setting_int(CFG, prov_id_uc, prov_id + '_seed_time', '')
if hasattr(torrent_prov, 'minseed'): if hasattr(torrent_prov, 'minseed'):
@ -1087,7 +1086,8 @@ def initialize(consoleLogging=True):
nzb_prov.search_fallback = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_search_fallback', 0)) nzb_prov.search_fallback = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_search_fallback', 0))
if hasattr(nzb_prov, 'enable_recentsearch'): if hasattr(nzb_prov, 'enable_recentsearch'):
nzb_prov.enable_recentsearch = bool(check_setting_int(CFG, prov_id_uc, nzb_prov.enable_recentsearch = bool(check_setting_int(CFG, prov_id_uc,
prov_id + '_enable_recentsearch', 1)) prov_id + '_enable_recentsearch', 1)) or \
not getattr(nzb_prov, 'supports_backlog', True)
if hasattr(nzb_prov, 'enable_backlog'): if hasattr(nzb_prov, 'enable_backlog'):
nzb_prov.enable_backlog = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_enable_backlog', 1)) nzb_prov.enable_backlog = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_enable_backlog', 1))
@ -1157,7 +1157,7 @@ def initialize(consoleLogging=True):
cycleTime=datetime.timedelta(seconds=3), cycleTime=datetime.timedelta(seconds=3),
threadName='SEARCHQUEUE') threadName='SEARCHQUEUE')
update_interval = datetime.timedelta(minutes=RECENTSEARCH_FREQUENCY) update_interval = datetime.timedelta(minutes=(RECENTSEARCH_FREQUENCY, 1)[4489 == RECENTSEARCH_FREQUENCY])
recentSearchScheduler = scheduler.Scheduler(search_recent.RecentSearcher(), recentSearchScheduler = scheduler.Scheduler(search_recent.RecentSearcher(),
cycleTime=update_interval, cycleTime=update_interval,
threadName='RECENTSEARCHER', threadName='RECENTSEARCHER',
@ -1457,6 +1457,7 @@ def save_config():
new_config['General']['anime_default'] = int(ANIME_DEFAULT) new_config['General']['anime_default'] = int(ANIME_DEFAULT)
new_config['General']['scene_default'] = int(SCENE_DEFAULT) new_config['General']['scene_default'] = int(SCENE_DEFAULT)
new_config['General']['provider_order'] = ' '.join(PROVIDER_ORDER) new_config['General']['provider_order'] = ' '.join(PROVIDER_ORDER)
new_config['General']['provider_homes'] = '%s' % PROVIDER_HOMES
new_config['General']['version_notify'] = int(VERSION_NOTIFY) new_config['General']['version_notify'] = int(VERSION_NOTIFY)
new_config['General']['auto_update'] = int(AUTO_UPDATE) new_config['General']['auto_update'] = int(AUTO_UPDATE)
new_config['General']['notify_on_update'] = int(NOTIFY_ON_UPDATE) new_config['General']['notify_on_update'] = int(NOTIFY_ON_UPDATE)
@ -1522,73 +1523,40 @@ def save_config():
new_config['Blackhole']['nzb_dir'] = NZB_DIR new_config['Blackhole']['nzb_dir'] = NZB_DIR
new_config['Blackhole']['torrent_dir'] = TORRENT_DIR new_config['Blackhole']['torrent_dir'] = TORRENT_DIR
# dynamically save provider settings for src in [x for x in providers.sortedProviderList() if GenericProvider.TORRENT == x.providerType]:
for torrent_prov in [curProvider for curProvider in providers.sortedProviderList() src_id = src.get_id()
if GenericProvider.TORRENT == curProvider.providerType]: src_id_uc = src_id.upper()
prov_id = torrent_prov.get_id() new_config[src_id_uc] = {}
prov_id_uc = torrent_prov.get_id().upper() new_config[src_id_uc][src_id] = int(src.enabled)
new_config[prov_id_uc] = {} if getattr(src, 'url_edit', None):
new_config[prov_id_uc][prov_id] = int(torrent_prov.enabled) new_config[src_id_uc][src_id + '_url_home'] = src.url_home
if hasattr(torrent_prov, 'digest'):
new_config[prov_id_uc][prov_id + '_digest'] = torrent_prov.digest
if hasattr(torrent_prov, 'hash'):
new_config[prov_id_uc][prov_id + '_hash'] = torrent_prov.hash
if hasattr(torrent_prov, 'api_key'):
new_config[prov_id_uc][prov_id + '_api_key'] = torrent_prov.api_key
if hasattr(torrent_prov, 'username'):
new_config[prov_id_uc][prov_id + '_username'] = torrent_prov.username
if hasattr(torrent_prov, 'password'):
new_config[prov_id_uc][prov_id + '_password'] = helpers.encrypt(torrent_prov.password, ENCRYPTION_VERSION)
if hasattr(torrent_prov, 'passkey'):
new_config[prov_id_uc][prov_id + '_passkey'] = torrent_prov.passkey
if hasattr(torrent_prov, 'confirmed'):
new_config[prov_id_uc][prov_id + '_confirmed'] = int(torrent_prov.confirmed)
if hasattr(torrent_prov, '_seed_ratio'):
new_config[prov_id_uc][prov_id + '_seed_ratio'] = torrent_prov.seed_ratio()
if hasattr(torrent_prov, 'seed_time'):
new_config[prov_id_uc][prov_id + '_seed_time'] = torrent_prov.seed_time
if hasattr(torrent_prov, 'minseed'):
new_config[prov_id_uc][prov_id + '_minseed'] = int(torrent_prov.minseed)
if hasattr(torrent_prov, 'minleech'):
new_config[prov_id_uc][prov_id + '_minleech'] = int(torrent_prov.minleech)
if hasattr(torrent_prov, 'freeleech'):
new_config[prov_id_uc][prov_id + '_freeleech'] = int(torrent_prov.freeleech)
if hasattr(torrent_prov, 'reject_m2ts'):
new_config[prov_id_uc][prov_id + '_reject_m2ts'] = int(torrent_prov.reject_m2ts)
if hasattr(torrent_prov, 'enable_recentsearch'):
new_config[prov_id_uc][prov_id + '_enable_recentsearch'] = int(torrent_prov.enable_recentsearch)
if hasattr(torrent_prov, 'enable_backlog'):
new_config[prov_id_uc][prov_id + '_enable_backlog'] = int(torrent_prov.enable_backlog)
if hasattr(torrent_prov, 'search_mode'):
new_config[prov_id_uc][prov_id + '_search_mode'] = torrent_prov.search_mode
if hasattr(torrent_prov, 'search_fallback'):
new_config[prov_id_uc][prov_id + '_search_fallback'] = int(torrent_prov.search_fallback)
if hasattr(torrent_prov, 'options'):
new_config[prov_id_uc][prov_id + '_options'] = torrent_prov.options
if hasattr(torrent_prov, 'proxy'):
new_config[prov_id_uc][prov_id + '_proxy'] = int(torrent_prov.proxy.enabled)
if hasattr(torrent_prov.proxy, 'url'):
new_config[prov_id_uc][prov_id + '_proxy_url'] = torrent_prov.proxy.url
for nzb_prov in [curProvider for curProvider in providers.sortedProviderList() if hasattr(src, 'password'):
if GenericProvider.NZB == curProvider.providerType]: new_config[src_id_uc][src_id + '_password'] = helpers.encrypt(src.password, ENCRYPTION_VERSION)
prov_id = nzb_prov.get_id()
prov_id_uc = nzb_prov.get_id().upper()
new_config[prov_id_uc] = {}
new_config[prov_id_uc][prov_id] = int(nzb_prov.enabled)
if hasattr(nzb_prov, 'api_key'): for (setting, value) in [
new_config[prov_id_uc][prov_id + '_api_key'] = nzb_prov.api_key ('%s_%s' % (src_id, k), getattr(src, k, v) if not v else helpers.tryInt(getattr(src, k, None)))
if hasattr(nzb_prov, 'username'): for (k, v) in [
new_config[prov_id_uc][prov_id + '_username'] = nzb_prov.username ('api_key', None), ('passkey', None), ('digest', None), ('hash', None), ('username', ''), ('uid', ''),
if hasattr(nzb_prov, 'search_mode'): ('minseed', 1), ('minleech', 1), ('confirmed', 1), ('freeleech', 1), ('reject_m2ts', 1),
new_config[prov_id_uc][prov_id + '_search_mode'] = nzb_prov.search_mode ('enable_recentsearch', 1), ('enable_backlog', 1), ('search_mode', None), ('search_fallback', 1),
if hasattr(nzb_prov, 'search_fallback'): ('seed_time', None)] if hasattr(src, k)]:
new_config[prov_id_uc][prov_id + '_search_fallback'] = int(nzb_prov.search_fallback) new_config[src_id_uc][setting] = value
if hasattr(nzb_prov, 'enable_recentsearch'):
new_config[prov_id_uc][prov_id + '_enable_recentsearch'] = int(nzb_prov.enable_recentsearch) if hasattr(src, '_seed_ratio'):
if hasattr(nzb_prov, 'enable_backlog'): new_config[src_id_uc][src_id + '_seed_ratio'] = src.seed_ratio()
new_config[prov_id_uc][prov_id + '_enable_backlog'] = int(nzb_prov.enable_backlog)
for src in [x for x in providers.sortedProviderList() if GenericProvider.NZB == x.providerType]:
src_id = src.get_id()
src_id_uc = src.get_id().upper()
new_config[src_id_uc] = {}
new_config[src_id_uc][src_id] = int(src.enabled)
for attr in [x for x in ['api_key', 'username', 'search_mode'] if hasattr(src, x)]:
new_config[src_id_uc]['%s_%s' % (src_id, attr)] = getattr(src, attr)
for attr in [x for x in ['enable_recentsearch', 'enable_backlog', 'search_fallback'] if hasattr(src, x)]:
new_config[src_id_uc]['%s_%s' % (src_id, attr)] = helpers.tryInt(getattr(src, attr, None))
new_config['SABnzbd'] = {} new_config['SABnzbd'] = {}
new_config['SABnzbd']['sab_username'] = SAB_USERNAME new_config['SABnzbd']['sab_username'] = SAB_USERNAME

View file

@ -213,6 +213,9 @@ class Quality:
return Quality.SDTV return Quality.SDTV
elif checkName(['(dvd.?rip|b[r|d]rip)(.ws)?(.(xvid|divx|x264|h.?264))?'], any) and not checkName(['(720|1080|2160)[pi]'], all): elif checkName(['(dvd.?rip|b[r|d]rip)(.ws)?(.(xvid|divx|x264|h.?264))?'], any) and not checkName(['(720|1080|2160)[pi]'], all):
return Quality.SDDVD return Quality.SDDVD
elif checkName(['(xvid|divx|480p)'], any) and not checkName(['(720|1080|2160)[pi]'], all) \
and not checkName(['hr.ws.pdtv.(x264|h.?264)'], any):
return Quality.SDTV
elif checkName(['720p', 'hdtv', 'x264|h.?264'], all) or checkName(['hr.ws.pdtv.(x264|h.?264)'], any) \ elif checkName(['720p', 'hdtv', 'x264|h.?264'], all) or checkName(['hr.ws.pdtv.(x264|h.?264)'], any) \
and not checkName(['(1080|2160)[pi]'], all): and not checkName(['(1080|2160)[pi]'], all):
return Quality.HDTV return Quality.HDTV

View file

@ -420,7 +420,7 @@ def check_setting_str(config, cfg_name, item_name, def_val, log=True):
else: else:
logger.log('%s -> ******' % item_name, logger.DEBUG) logger.log('%s -> ******' % item_name, logger.DEBUG)
return my_val return (my_val, def_val)['None' == my_val]
class ConfigMigrator(): class ConfigMigrator():
@ -783,4 +783,4 @@ class ConfigMigrator():
old_token = check_setting_str(self.config_obj, 'Trakt', 'trakt_token', '') old_token = check_setting_str(self.config_obj, 'Trakt', 'trakt_token', '')
old_refresh_token = check_setting_str(self.config_obj, 'Trakt', 'trakt_refresh_token', '') old_refresh_token = check_setting_str(self.config_obj, 'Trakt', 'trakt_refresh_token', '')
if old_token and old_refresh_token: if old_token and old_refresh_token:
TraktAPI.add_account(old_token, old_refresh_token, None) TraktAPI.add_account(old_token, old_refresh_token, None)

View file

@ -95,17 +95,23 @@ class DBConnection(object):
while attempt < 5: while attempt < 5:
try: try:
affected = 0
for qu in querylist: for qu in querylist:
cursor = self.connection.cursor()
if len(qu) == 1: if len(qu) == 1:
if logTransaction: if logTransaction:
logger.log(qu[0], logger.DB) logger.log(qu[0], logger.DB)
sqlResult.append(self.connection.execute(qu[0]).fetchall())
sqlResult.append(cursor.execute(qu[0]).fetchall())
elif len(qu) > 1: elif len(qu) > 1:
if logTransaction: if logTransaction:
logger.log(qu[0] + ' with args ' + str(qu[1]), logger.DB) logger.log(qu[0] + ' with args ' + str(qu[1]), logger.DB)
sqlResult.append(self.connection.execute(qu[0], qu[1]).fetchall()) sqlResult.append(cursor.execute(qu[0], qu[1]).fetchall())
affected += cursor.rowcount
self.connection.commit() self.connection.commit()
logger.log(u'Transaction with ' + str(len(querylist)) + u' queries executed', logger.DEBUG) if affected > 0:
logger.log(u'Transaction with %s queries executed affected %i row%s' % (
len(querylist), affected, helpers.maybe_plural(affected)), logger.DEBUG)
return sqlResult return sqlResult
except sqlite3.OperationalError as e: except sqlite3.OperationalError as e:
sqlResult = [] sqlResult = []

View file

@ -18,7 +18,6 @@
from __future__ import with_statement from __future__ import with_statement
import urllib2
import xml.etree.cElementTree as etree import xml.etree.cElementTree as etree
import xml.etree import xml.etree
import re import re
@ -84,7 +83,7 @@ def createNZBString(fileElements, xmlns):
for curFile in fileElements: for curFile in fileElements:
rootElement.append(stripNS(curFile, xmlns)) rootElement.append(stripNS(curFile, xmlns))
return xml.etree.ElementTree.tostring(rootElement, 'utf-8', 'replace') return xml.etree.ElementTree.tostring(rootElement, 'utf-8')
def saveNZB(nzbName, nzbString): def saveNZB(nzbName, nzbString):
@ -158,7 +157,7 @@ def splitResult(result):
wantEp = True wantEp = True
for epNo in parse_result.episode_numbers: for epNo in parse_result.episode_numbers:
if not result.extraInfo[0].wantEpisode(season, epNo, result.quality): if not result.show.wantEpisode(season, epNo, result.quality):
logger.log(u"Ignoring result " + newNZB + " because we don't want an episode that is " + logger.log(u"Ignoring result " + newNZB + " because we don't want an episode that is " +
Quality.qualityStrings[result.quality], logger.DEBUG) Quality.qualityStrings[result.quality], logger.DEBUG)
wantEp = False wantEp = False
@ -169,13 +168,14 @@ def splitResult(result):
# get all the associated episode objects # get all the associated episode objects
epObjList = [] epObjList = []
for curEp in parse_result.episode_numbers: for curEp in parse_result.episode_numbers:
epObjList.append(result.extraInfo[0].getEpisode(season, curEp)) epObjList.append(result.show.getEpisode(season, curEp))
# make a result # make a result
curResult = classes.NZBDataSearchResult(epObjList) curResult = classes.NZBDataSearchResult(epObjList)
curResult.name = newNZB curResult.name = newNZB
curResult.provider = result.provider curResult.provider = result.provider
curResult.quality = result.quality curResult.quality = result.quality
curResult.show = result.show
curResult.extraInfo = [createNZBString(separateNZBs[newNZB], xmlns)] curResult.extraInfo = [createNZBString(separateNZBs[newNZB], xmlns)]
resultList.append(curResult) resultList.append(curResult)

View file

@ -18,30 +18,37 @@
from os import sys from os import sys
import os.path
import sickbeard import sickbeard
from . import generic from . import generic
from sickbeard import logger from sickbeard import logger, encodingKludge as ek
# usenet # usenet
from . import newznab, omgwtfnzbs, womble from . import newznab, omgwtfnzbs, womble
# torrent # torrent
from . import alpharatio, beyondhd, bitmetv, bitsoup, btn, freshontv, funfile, gftracker, grabtheinfo, \ from . import alpharatio, beyondhd, bitmetv, btn, freshontv, funfile, gftracker, grabtheinfo, \
hdbits, hdspace, iptorrents, kat, morethan, pisexy, pretome, rarbg, scc, scenetime, shazbat, speedcd, \ hd4free, hdbits, hdspace, iptorrents, kat, morethan, pisexy, pretome, rarbg, scc, scenetime, shazbat, speedcd, \
thepiratebay, torrentbytes, torrentday, torrenting, torrentleech, torrentshack, transmithe_net, tvchaosuk thepiratebay, torrentbytes, torrentday, torrenting, torrentleech, torrentshack, transmithe_net, tvchaosuk
# anime # anime
from . import nyaatorrents, tokyotoshokan from . import nyaatorrents, tokyotoshokan
# custom
try:
from . import custom01
except:
pass
__all__ = ['omgwtfnzbs', __all__ = ['omgwtfnzbs',
'womble', 'womble',
'alpharatio', 'alpharatio',
'beyondhd', 'beyondhd',
'bitmetv', 'bitmetv',
'bitsoup',
'btn', 'btn',
'custom01',
'freshontv', 'freshontv',
'funfile', 'funfile',
'gftracker', 'gftracker',
'grabtheinfo', 'grabtheinfo',
'hd4free',
'hdbits', 'hdbits',
'hdspace', 'hdspace',
'iptorrents', 'iptorrents',
@ -208,16 +215,19 @@ def makeTorrentRssProvider(configString):
def getDefaultNewznabProviders(): def getDefaultNewznabProviders():
return 'Sick Beard Index|http://lolo.sickbeard.com/|0|5030,5040|0|eponly|0|0|0!!!NZBs.org|https://nzbs.org/||5030,5040|0|eponly|0|0|0!!!Usenet-Crawler|https://www.usenet-crawler.com/||5030,5040|0|eponly|0|0|0' return '!!!'.join(['Sick Beard Index|http://lolo.sickbeard.com/|0|5030,5040|0|eponly|0|0|0',
'NZBgeek|https://api.nzbgeek.info/||5030,5040|0|eponly|0|0|0',
'NZBs.org|https://nzbs.org/||5030,5040|0|eponly|0|0|0',
'Usenet-Crawler|https://www.usenet-crawler.com/||5030,5040|0|eponly|0|0|0'])
def getProviderModule(name): def getProviderModule(name):
name = name.lower() prefix, cprov, name = 'sickbeard.providers.', 'motsuc'[::-1], name.lower()
prefix = "sickbeard.providers."
if name in __all__ and prefix + name in sys.modules: if name in __all__ and prefix + name in sys.modules:
return sys.modules[prefix + name] return sys.modules[prefix + name]
else: elif cprov in name:
raise Exception("Can't find " + prefix + name + " in " + "Providers") return None
raise Exception('Can\'t find %s%s in providers' % (prefix, name))
def getProviderClass(id): def getProviderClass(id):

View file

@ -21,7 +21,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -31,7 +31,7 @@ class AlphaRatioProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'AlphaRatio') generic.TorrentProvider.__init__(self, 'AlphaRatio', cache_update_freq=20)
self.url_base = 'https://alpharatio.cc/' self.url_base = 'https://alpharatio.cc/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
@ -44,9 +44,7 @@ class AlphaRatioProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
self.freeleech = False
self.cache = AlphaRatioCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -65,7 +63,7 @@ class AlphaRatioProvider(generic.TorrentProvider):
for mode in search_params.keys(): for mode in search_params.keys():
for search_string in search_params[mode]: for search_string in search_params[mode]:
search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string
search_url = self.urls['search'] % (search_string, ('', '&freetorrent=1')[self.freeleech]) search_url = self.urls['search'] % (search_string, ('&freetorrent=1', '')[not self.freeleech])
html = self.get_url(search_url) html = self.get_url(search_url)
@ -111,16 +109,4 @@ class AlphaRatioProvider(generic.TorrentProvider):
return results return results
class AlphaRatioCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = AlphaRatioProvider() provider = AlphaRatioProvider()

View file

@ -19,7 +19,7 @@ import re
import time import time
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.exceptions import AuthException from sickbeard.exceptions import AuthException
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -41,7 +41,6 @@ class BeyondHDProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.passkey, self.minseed, self.minleech = 3 * [None] self.passkey, self.minseed, self.minleech = 3 * [None]
self.cache = BeyondHDCache(self)
def _check_auth_from_data(self, data_json): def _check_auth_from_data(self, data_json):
@ -101,14 +100,4 @@ class BeyondHDProvider(generic.TorrentProvider):
return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, **kwargs) return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, **kwargs)
class BeyondHDCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
def _cache_data(self):
return self.provider.cache_data()
provider = BeyondHDProvider() provider = BeyondHDProvider()

View file

@ -19,7 +19,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -28,7 +28,7 @@ from lib.unidecode import unidecode
class BitmetvProvider(generic.TorrentProvider): class BitmetvProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'BitMeTV') generic.TorrentProvider.__init__(self, 'BitMeTV', cache_update_freq=7)
self.url_base = 'http://www.bitmetv.org/' self.url_base = 'http://www.bitmetv.org/'
@ -42,7 +42,6 @@ class BitmetvProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.digest, self.minseed, self.minleech = 3 * [None] self.digest, self.minseed, self.minleech = 3 * [None]
self.cache = BitmetvCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -63,9 +62,7 @@ class BitmetvProvider(generic.TorrentProvider):
for mode in search_params.keys(): for mode in search_params.keys():
for search_string in search_params[mode]: for search_string in search_params[mode]:
search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string
category = 'cat=%s' % self.categories[ search_url = self.urls['search'] % (self._categories_string(mode, 'cat=%s'), search_string)
(mode in ['Season', 'Episode'] and self.show and self.show.is_anime) and 'anime' or 'shows']
search_url = self.urls['search'] % (category, search_string)
html = self.get_url(search_url) html = self.get_url(search_url)
@ -89,8 +86,8 @@ class BitmetvProvider(generic.TorrentProvider):
continue continue
info = tr.find('a', href=rc['info']) info = tr.find('a', href=rc['info'])
title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip() title = info.attrs.get('title') or info.get_text().strip()
download_url = self.urls['get'] % tr.find('a', href=rc['get']).get('href') download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/')
except (AttributeError, TypeError, ValueError): except (AttributeError, TypeError, ValueError):
continue continue
@ -116,16 +113,4 @@ class BitmetvProvider(generic.TorrentProvider):
return 'bitmetv_digest' == key and 'use... \'uid=xx; pass=yy\'' or '' return 'bitmetv_digest' == key and 'use... \'uid=xx; pass=yy\'' or ''
class BitmetvCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 7 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = BitmetvProvider() provider = BitmetvProvider()

View file

@ -1,120 +0,0 @@
# coding=utf-8
#
# This file is part of SickGear.
#
# SickGear is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SickGear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
class BitSoupProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'BitSoup')
self.url_base = 'https://www.bitsoup.me/'
self.urls = {'config_provider_home_uri': self.url_base,
'login': self.url_base + 'takelogin.php',
'search': self.url_base + 'browse.php?search=%s&%s&incldead=0&blah=0',
'get': self.url_base + '%s'}
self.categories = {'shows': [42, 45, 49, 32, 7], 'anime': [23]}
self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = BitSoupCache(self)
def _search_provider(self, search_params, **kwargs):
results = []
if not self._authorised():
return results
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download'}.items())
for mode in search_params.keys():
for search_string in search_params[mode]:
search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string
search_url = self.urls['search'] % (search_string, self._categories_string(mode))
html = self.get_url(search_url)
cnt = len(items[mode])
try:
if not html or self._has_no_results(html):
raise generic.HaltParseException
with BS4Parser(html, 'html.parser', attr='class="koptekst"') as soup:
torrent_table = soup.find('table', attrs={'class': 'koptekst'})
torrent_rows = [] if not torrent_table else torrent_table.find_all('tr')
if 2 > len(torrent_rows):
raise generic.HaltParseException
for tr in torrent_rows[1:]:
try:
seeders, leechers, size = [tryInt(n, n) for n in [
(tr.find_all('td')[x].get_text().strip()) for x in (-3, -2, -5)]]
if self._peers_fail(mode, seeders, leechers):
continue
info = tr.find('a', href=rc['info'])
title = info.get_text().strip()
download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/')
except (AttributeError, TypeError, ValueError):
continue
if title and download_url:
items[mode].append((title, download_url, seeders, self._bytesizer(size)))
except generic.HaltParseException:
pass
except Exception:
logger.log(u'Failed to parse. Traceback: %s' % traceback.format_exc(), logger.ERROR)
self._log_search(mode, len(items[mode]) - cnt, search_url)
self._sort_seeders(mode, items)
results = list(set(results + items[mode]))
return results
def _episode_strings(self, ep_obj, **kwargs):
return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='|', **kwargs)
class BitSoupCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = BitSoupProvider()

View file

@ -19,7 +19,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -28,19 +28,19 @@ from lib.unidecode import unidecode
class FreshOnTVProvider(generic.TorrentProvider): class FreshOnTVProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'FreshOnTV') generic.TorrentProvider.__init__(self, 'FreshOnTV', cache_update_freq=20)
self.url_base = 'https://freshon.tv/' self.url_base = 'https://freshon.tv/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
'login': self.url_base + 'login.php?action=makelogin', 'login': self.url_base + 'login.php?action=makelogin',
'search': self.url_base + 'browse.php?incldead=%s&words=0&cat=0&search=%s', 'search': self.url_base + 'browse.php?incldead=%s&words=0&%s&search=%s',
'get': self.url_base + '%s'} 'get': self.url_base + '%s'}
self.categories = {'shows': 0, 'anime': 235}
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
self.freeleech = False
self.cache = FreshOnTVCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -59,16 +59,17 @@ class FreshOnTVProvider(generic.TorrentProvider):
return results return results
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
freeleech = (0, 3)[self.freeleech] freeleech = (3, 0)[not self.freeleech]
rc = dict((k, re.compile('(?i)' + v)) rc = dict((k, re.compile('(?i)' + v))
for (k, v) in {'info': 'detail', 'get': 'download', 'name': '_name'}.items()) for (k, v) in {'info': 'detail', 'get': 'download', 'name': '_name'}.items())
for mode in search_params.keys(): for mode in search_params.keys():
for search_string in search_params[mode]: for search_string in search_params[mode]:
search_string, search_url = self._title_and_url(( search_string, void = self._title_and_url((
isinstance(search_string, unicode) and unidecode(search_string) or search_string, isinstance(search_string, unicode) and unidecode(search_string) or search_string, ''))
self.urls['search'] % (freeleech, search_string))) void, search_url = self._title_and_url((
'', self.urls['search'] % (freeleech, self._categories_string(mode, 'cat=%s'), search_string)))
# returns top 15 results by default, expandable in user profile to 100 # returns top 15 results by default, expandable in user profile to 100
html = self.get_url(search_url) html = self.get_url(search_url)
@ -96,7 +97,7 @@ class FreshOnTVProvider(generic.TorrentProvider):
continue continue
info = tr.find('a', href=rc['info'], attrs={'class': rc['name']}) info = tr.find('a', href=rc['info'], attrs={'class': rc['name']})
title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip() title = info.attrs.get('title') or info.get_text().strip()
download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/') download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/')
except (AttributeError, TypeError, ValueError): except (AttributeError, TypeError, ValueError):
@ -117,21 +118,9 @@ class FreshOnTVProvider(generic.TorrentProvider):
return results return results
def _get_episode_search_strings(self, ep_obj, **kwargs): def _episode_strings(self, ep_obj, **kwargs):
return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='|', **kwargs) return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='|', **kwargs)
class FreshOnTVCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20
def _cache_data(self):
return self.provider.cache_data()
provider = FreshOnTVProvider() provider = FreshOnTVProvider()

View file

@ -19,7 +19,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -28,7 +28,7 @@ from lib.unidecode import unidecode
class FunFileProvider(generic.TorrentProvider): class FunFileProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'FunFile') generic.TorrentProvider.__init__(self, 'FunFile', cache_update_freq=15)
self.url_base = 'https://www.funfile.org/' self.url_base = 'https://www.funfile.org/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
@ -41,7 +41,6 @@ class FunFileProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.url_timeout = 90 self.url_timeout = 90
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = FunFileCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -58,10 +57,9 @@ class FunFileProvider(generic.TorrentProvider):
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download', rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download'}.items())
'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|')
}.items())
for mode in search_params.keys(): for mode in search_params.keys():
rc['cats'] = re.compile('(?i)cat=(?:%s)' % self._categories_string(mode, template='', delimiter='|'))
for search_string in search_params[mode]: for search_string in search_params[mode]:
search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string
search_url = self.urls['search'] % (self._categories_string(mode), search_string) search_url = self.urls['search'] % (self._categories_string(mode), search_string)
@ -91,8 +89,8 @@ class FunFileProvider(generic.TorrentProvider):
if None is tr.find('a', href=rc['cats']) or self._peers_fail(mode, seeders, leechers): if None is tr.find('a', href=rc['cats']) or self._peers_fail(mode, seeders, leechers):
continue continue
title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip() title = info.attrs.get('title') or info.get_text().strip()
download_url = self.urls['get'] % tr.find('a', href=rc['get']).get('href') download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/')
except (AttributeError, TypeError, ValueError): except (AttributeError, TypeError, ValueError):
continue continue
@ -114,16 +112,4 @@ class FunFileProvider(generic.TorrentProvider):
return results return results
class FunFileCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 15 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = FunFileProvider() provider = FunFileProvider()

View file

@ -25,6 +25,8 @@ import math
import os import os
import re import re
import time import time
import urlparse
import zlib
from base64 import b16encode, b32decode from base64 import b16encode, b32decode
import sickbeard import sickbeard
@ -53,7 +55,7 @@ class GenericProvider:
# these need to be set in the subclass # these need to be set in the subclass
self.providerType = None self.providerType = None
self.name = name self.name = name
self.supportsBacklog = supports_backlog self.supports_backlog = supports_backlog
self.anime_only = anime_only self.anime_only = anime_only
if anime_only: if anime_only:
self.proper_search_terms = 'v1|v2|v3|v4|v5' self.proper_search_terms = 'v1|v2|v3|v4|v5'
@ -518,7 +520,7 @@ class GenericProvider:
if hasattr(self, 'cookies'): if hasattr(self, 'cookies'):
cookies = self.cookies cookies = self.cookies
if not re.match('^(\w+=\w+[;\s]*)+$', cookies): if not (cookies and re.match('^(\w+=\w+[;\s]*)+$', cookies)):
return False return False
cj = requests.utils.add_dict_to_cookiejar(self.session.cookies, cj = requests.utils.add_dict_to_cookiejar(self.session.cookies,
@ -544,9 +546,13 @@ class GenericProvider:
def _categories_string(self, mode='Cache', template='c%s=1', delimiter='&'): def _categories_string(self, mode='Cache', template='c%s=1', delimiter='&'):
return delimiter.join([('%s', template)[any(template)] % c for c in sorted(self.categories['shows'] + ( return delimiter.join([('%s', template)[any(template)] % c for c in sorted(
[], [] if 'anime' not in self.categories else self.categories['anime'])[ 'shows' in self.categories and (isinstance(self.categories['shows'], type([])) and
('Cache' == mode and helpers.has_anime()) or ((mode in ['Season', 'Episode']) and self.show and self.show.is_anime)])]) self.categories['shows'] or [self.categories['shows']]) or
self.categories[(mode, 'Episode')['Propers' == mode]] +
([], self.categories.get('anime') or [])[
(mode in ['Cache', 'Propers'] and helpers.has_anime()) or
((mode in ['Season', 'Episode']) and self.show and self.show.is_anime)])])
@staticmethod @staticmethod
def _bytesizer(size_dim=''): def _bytesizer(size_dim=''):
@ -577,12 +583,8 @@ class NZBProvider(object, GenericProvider):
def maybe_apikey(self): def maybe_apikey(self):
if hasattr(self, 'needs_auth') and self.needs_auth: if getattr(self, 'needs_auth', None):
if hasattr(self, 'key') and 0 < len(self.key): return (getattr(self, 'key', '') and self.key) or (getattr(self, 'api_key', '') and self.api_key) or None
return self.key
if hasattr(self, 'api_key') and 0 < len(self.api_key):
return self.api_key
return None
return False return False
def _check_auth(self): def _check_auth(self):
@ -664,13 +666,32 @@ class NZBProvider(object, GenericProvider):
class TorrentProvider(object, GenericProvider): class TorrentProvider(object, GenericProvider):
def __init__(self, name, supports_backlog=True, anime_only=False): def __init__(self, name, supports_backlog=True, anime_only=False, cache_update_freq=None):
GenericProvider.__init__(self, name, supports_backlog, anime_only) GenericProvider.__init__(self, name, supports_backlog, anime_only)
self.providerType = GenericProvider.TORRENT self.providerType = GenericProvider.TORRENT
self._seed_ratio = None self._seed_ratio = None
self.seed_time = None self.seed_time = None
self._url = None
self.urls = {}
self.cache._cache_data = self._cache_data
if cache_update_freq:
self.cache.update_freq = cache_update_freq
@property
def url(self):
if None is self._url:
self._url = self._valid_home()
self._valid_url()
return self._url
@url.setter
def url(self, value=None):
self._url = value
def _valid_url(self):
return True
def image_name(self): def image_name(self):
@ -777,6 +798,65 @@ class TorrentProvider(object, GenericProvider):
search_params += [crop.sub(r'\1', '%s %s%s' % (name, x, detail)) for x in prefix] search_params += [crop.sub(r'\1', '%s %s%s' % (name, x, detail)) for x in prefix]
return search_params return search_params
@staticmethod
def _has_signature(data=None):
return data and re.search(r'(?sim)<input[^<]+name="password"', data) and \
re.search(r'(?sim)<input[^<]+name="username"', data)
def _valid_home(self):
"""
:return: signature verified home url else None if validation fail
"""
url_base = getattr(self, 'url_base', None)
if url_base:
return url_base
url_list = getattr(self, 'url_home', None)
if not url_list and getattr(self, 'url_edit', None) or 10 > max([len(x) for x in url_list]):
return None
last_url, expire = sickbeard.PROVIDER_HOMES.get(self.get_id(), ('', None))
if 'site down' == last_url:
if expire and (expire > int(time.time())):
return None
elif last_url:
last_url in url_list and url_list.remove(last_url)
url_list.insert(0, last_url)
for cur_url in url_list:
if not self.is_valid_mod(cur_url):
return None
if 10 < len(cur_url) and ((expire and (expire > int(time.time()))) or
self._has_signature(helpers.getURL(cur_url, session=self.session))):
for k, v in getattr(self, 'url_tmpl', {}).items():
self.urls[k] = v % {'home': cur_url, 'vars': getattr(self, 'url_vars', {}).get(k, '')}
if last_url != cur_url or (expire and not (expire > int(time.time()))):
sickbeard.PROVIDER_HOMES[self.get_id()] = (cur_url, int(time.time()) + (15*60))
sickbeard.save_config()
return cur_url
logger.log('Failed to identify a "%s" page with %s %s (local network issue, site down, or ISP blocked) ' %
(self.name, len(url_list), ('URL', 'different URLs')[1 < len(url_list)]) +
'Suggest; 1) Disable "%s" 2) Use a proxy/VPN' % self.get_id(),
(logger.WARNING, logger.ERROR)[self.enabled])
self.urls = {}
sickbeard.PROVIDER_HOMES[self.get_id()] = ('site down', int(time.time()) + (5 * 60))
sickbeard.save_config()
return None
def is_valid_mod(self, url):
parsed, s, is_valid = urlparse.urlparse(url), 70000700, True
if 2012691328 == s + zlib.crc32(('.%s' % (parsed.netloc or parsed.path)).split('.')[-2]):
is_valid = False
file_name = '%s.py' % os.path.join(sickbeard.PROG_DIR, *self.__module__.split('.'))
if ek.ek(os.path.isfile, file_name):
with open(file_name, 'rb') as file_hd:
is_valid = 1661931498 == s + zlib.crc32(file_hd.read())
return is_valid
def _authorised(self, logged_in=None, post_params=None, failed_msg=None, url=None, timeout=30): def _authorised(self, logged_in=None, post_params=None, failed_msg=None, url=None, timeout=30):
maxed_out = (lambda x: re.search(r'(?i)[1-3]((<[^>]+>)|\W)*(attempts|tries|remain)[\W\w]{,40}?(remain|left|attempt)', x)) maxed_out = (lambda x: re.search(r'(?i)[1-3]((<[^>]+>)|\W)*(attempts|tries|remain)[\W\w]{,40}?(remain|left|attempt)', x))
@ -791,6 +871,9 @@ class TorrentProvider(object, GenericProvider):
if logged_in(): if logged_in():
return True return True
if not self._valid_home():
return False
if hasattr(self, 'digest'): if hasattr(self, 'digest'):
self.cookies = re.sub(r'(?i)([\s\']+|cookie\s*:)', '', self.digest) self.cookies = re.sub(r'(?i)([\s\']+|cookie\s*:)', '', self.digest)
success, msg = self._check_cookie() success, msg = self._check_cookie()
@ -811,13 +894,14 @@ class TorrentProvider(object, GenericProvider):
if url: if url:
response = helpers.getURL(url, session=self.session) response = helpers.getURL(url, session=self.session)
try: try:
action = re.findall('[<]form[\w\W]+?action="([^"]+)', response)[0] action = re.findall('[<]form[\w\W]+?action=[\'\"]([^\'\"]+)', response)[0]
url = (self.urls.get('login_base') or url = action if action.startswith('http') else \
self.urls['config_provider_home_uri']) + action.lstrip('/') (self.urls.get('login_base') or self.urls['config_provider_home_uri']) + action.lstrip('/')
tags = re.findall(r'(?is)(<input.*?name="[^"]+".*?>)', response) tags = re.findall(r'(?is)(<input.*?name=[\'\"][^\'\"]+[\'\"].*?>)', response)
nv = [(tup[0]) for tup in [re.findall(r'(?is)name="([^"]+)"(?:.*?value="([^"]+)")?', x) nv = [(tup[0]) for tup in [
for x in tags]] re.findall(r'(?is)name=[\'\"]([^\'\"]+)[\'\"](?:.*?value=[\'\"]([^\'\"]+)[\'\"])?', x)
for x in tags]]
for name, value in nv: for name, value in nv:
if name not in ('username', 'password'): if name not in ('username', 'password'):
post_params = isinstance(post_params, type({})) and post_params or {} post_params = isinstance(post_params, type({})) and post_params or {}
@ -854,10 +938,18 @@ class TorrentProvider(object, GenericProvider):
if self.username and self.password: if self.username and self.password:
return True return True
setting = 'Password or Username' setting = 'Password or Username'
elif hasattr(self, 'username') and hasattr(self, 'api_key'):
if self.username and self.api_key:
return True
setting = 'Apikey or Username'
elif hasattr(self, 'username') and hasattr(self, 'passkey'): elif hasattr(self, 'username') and hasattr(self, 'passkey'):
if self.username and self.passkey: if self.username and self.passkey:
return True return True
setting = 'Passkey or Username' setting = 'Passkey or Username'
elif hasattr(self, 'uid') and hasattr(self, 'passkey'):
if self.uid and self.passkey:
return True
setting = 'Passkey or uid'
elif hasattr(self, 'api_key'): elif hasattr(self, 'api_key'):
if self.api_key: if self.api_key:
return True return True
@ -899,7 +991,7 @@ class TorrentProvider(object, GenericProvider):
@staticmethod @staticmethod
def _has_no_results(*html): def _has_no_results(*html):
return re.search(r'(?i)<(?:b|h\d|strong)[^>]*>(?:' + return re.search(r'(?i)<(?:b|div|h\d|span|strong)[^>]*>(?:' +
'your\ssearch\sdid\snot\smatch|' + 'your\ssearch\sdid\snot\smatch|' +
'nothing\sfound|' + 'nothing\sfound|' +
'no\storrents\sfound|' + 'no\storrents\sfound|' +
@ -907,7 +999,6 @@ class TorrentProvider(object, GenericProvider):
'.*?no\shits\.\sTry\sadding' + '.*?no\shits\.\sTry\sadding' +
')', html[0]) ')', html[0])
def cache_data(self, *args, **kwargs): def _cache_data(self):
search_params = {'Cache': ['']} return self._search_provider({'Cache': ['']})
return self._search_provider(search_params)

View file

@ -20,7 +20,7 @@ import time
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -29,7 +29,7 @@ from lib.unidecode import unidecode
class GFTrackerProvider(generic.TorrentProvider): class GFTrackerProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'GFTracker') generic.TorrentProvider.__init__(self, 'GFTracker', cache_update_freq=17)
self.url_base = 'https://thegft.org/' self.url_base = 'https://thegft.org/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
@ -44,7 +44,6 @@ class GFTrackerProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = GFTrackerCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -122,16 +121,4 @@ class GFTrackerProvider(generic.TorrentProvider):
return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, **kwargs) return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, **kwargs)
class GFTrackerCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 17 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = GFTrackerProvider() provider = GFTrackerProvider()

View file

@ -19,7 +19,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -28,7 +28,7 @@ from lib.unidecode import unidecode
class GrabTheInfoProvider(generic.TorrentProvider): class GrabTheInfoProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'GrabTheInfo') generic.TorrentProvider.__init__(self, 'GrabTheInfo', cache_update_freq=20)
self.url_base = 'http://grabthe.info/' self.url_base = 'http://grabthe.info/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
@ -41,9 +41,7 @@ class GrabTheInfoProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
self.freeleech = False
self.cache = GrabTheInfoCache(self)
def _search_provider(self, search_params, **kwargs): def _search_provider(self, search_params, **kwargs):
@ -57,7 +55,7 @@ class GrabTheInfoProvider(generic.TorrentProvider):
for mode in search_params.keys(): for mode in search_params.keys():
for search_string in search_params[mode]: for search_string in search_params[mode]:
search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string
search_url = self.urls['browse'] % (self._categories_string(), ('0', '3')[self.freeleech], search_url = self.urls['browse'] % (self._categories_string(), ('3', '0')[not self.freeleech],
(self.urls['search'] % search_string, '')['Cache' == mode]) (self.urls['search'] % search_string, '')['Cache' == mode])
html = self.get_url(search_url) html = self.get_url(search_url)
@ -120,16 +118,4 @@ class GrabTheInfoProvider(generic.TorrentProvider):
return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='|', **kwargs) return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='|', **kwargs)
class GrabTheInfoCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = GrabTheInfoProvider() provider = GrabTheInfoProvider()

View file

@ -0,0 +1,81 @@
# coding=utf-8
#
# This file is part of SickGear.
#
# SickGear is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SickGear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
import time
from . import generic
from sickbeard.helpers import tryInt
class HD4FreeProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'HD4Free')
self.url_base = 'https://hd4free.xyz/'
self.urls = {'search': self.url_base + 'searchapi.php',
'get': self.url_base + 'download.php?torrent=%s&torrent_pass=%s'}
self.url = self.url_base
self.username, self.api_key, self.freeleech, self.minseed, self.minleech = 5 * [None]
def _authorised(self, **kwargs):
return self._check_auth()
def _search_provider(self, search_params, age=0, **kwargs):
results = []
if not self._authorised():
return results
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
params = {'username': self.username, 'apikey': self.api_key,
'tv': 'true', 'fl': ('true', None)[not self.freeleech]}
for mode in search_params.keys():
for search_string in search_params[mode]:
params['search'] = '+'.join(search_string.split())
data_json = self.get_url(self.urls['search'], params=params, json=True)
cnt = len(items[mode])
for k, item in data_json.items():
if 'error' == k or not item.get('total_results'):
break
seeders, leechers, size = [tryInt(n, n) for n in [
item.get(x) for x in 'seeders', 'leechers', 'size']]
if self._peers_fail(mode, seeders, leechers):
continue
title = item.get('release_name')
download_url = (self.urls['get'] % (item.get('torrentid'), item.get('torrentpass')), None)[
not (item.get('torrentid') and item.get('torrentpass'))]
if title and download_url:
items[mode].append((title, download_url, seeders, self._bytesizer('%smb' % size)))
self._log_search(mode, len(items[mode]) - cnt, self.session.response['url'])
time.sleep(1.1)
self._sort_seeders(mode, items)
results = list(set(results + items[mode]))
return results
provider = HD4FreeProvider()

View file

@ -19,7 +19,7 @@ import re
import urllib import urllib
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.exceptions import AuthException from sickbeard.exceptions import AuthException
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from sickbeard.indexers import indexer_config from sickbeard.indexers import indexer_config
@ -33,7 +33,7 @@ except ImportError:
class HDBitsProvider(generic.TorrentProvider): class HDBitsProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'HDBits') generic.TorrentProvider.__init__(self, 'HDBits', cache_update_freq=15)
# api_spec: https://hdbits.org/wiki/API # api_spec: https://hdbits.org/wiki/API
self.url_base = 'https://hdbits.org/' self.url_base = 'https://hdbits.org/'
@ -46,9 +46,7 @@ class HDBitsProvider(generic.TorrentProvider):
self.proper_search_terms = [' proper ', ' repack '] self.proper_search_terms = [' proper ', ' repack ']
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.passkey, self.minseed, self.minleech = 4 * [None] self.username, self.passkey, self.freeleech, self.minseed, self.minleech = 5 * [None]
self.freeleech = False
self.cache = HDBitsCache(self)
def check_auth_from_data(self, parsed_json): def check_auth_from_data(self, parsed_json):
@ -148,16 +146,4 @@ class HDBitsProvider(generic.TorrentProvider):
return results return results
class HDBitsCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 15 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = HDBitsProvider() provider = HDBitsProvider()

View file

@ -19,7 +19,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -27,7 +27,7 @@ from lib.unidecode import unidecode
class HDSpaceProvider(generic.TorrentProvider): class HDSpaceProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'HDSpace') generic.TorrentProvider.__init__(self, 'HDSpace', cache_update_freq=17)
self.url_base = 'https://hd-space.org/' self.url_base = 'https://hd-space.org/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
@ -40,9 +40,7 @@ class HDSpaceProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
self.freeleech = False
self.cache = HDSpaceCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -124,16 +122,4 @@ class HDSpaceProvider(generic.TorrentProvider):
return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, **kwargs) return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, **kwargs)
class HDSpaceCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 17 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = HDSpaceProvider() provider = HDSpaceProvider()

View file

@ -19,7 +19,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -29,24 +29,24 @@ class IPTorrentsProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'IPTorrents') generic.TorrentProvider.__init__(self, 'IPTorrents')
self.url_base = 'https://iptorrents.eu/' self.url_home = ['https://iptorrents.%s/' % u for u in 'eu', 'com', 'ru']
self.urls = {'config_provider_home_uri': self.url_base,
'login': self.url_base + 'torrents/', self.url_vars = {'login': 'getrss.php', 'search': 't?%s;q=%s;qf=ti%s%s#torrents', 'get': '%s'}
'search': self.url_base + 't?%s;q=%s;qf=ti%s%s#torrents', self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'login': '%(home)s%(vars)s',
'get': self.url_base + '%s'} 'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'}
self.categories = {'shows': [4, 5, 22, 23, 24, 25, 26, 55, 65, 66, 73, 78, 79], 'anime': [60]} self.categories = {'shows': [4, 5, 22, 23, 24, 25, 26, 55, 65, 66, 73, 78, 79], 'anime': [60]}
self.proper_search_terms = None self.proper_search_terms = None
self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.digest, self.freeleech, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = IPTorrentsCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
return super(IPTorrentsProvider, self)._authorised(post_params={'php': ''}) return super(IPTorrentsProvider, self)._authorised(
logged_in=(lambda x=None: (None is x or 'RSS Link' in x) and self.has_all_cookies() and
self.session.cookies['uid'] in self.digest and self.session.cookies['pass'] in self.digest),
failed_msg=(lambda x=None: u'Invalid cookie details for %s. Check settings'))
def _search_provider(self, search_params, **kwargs): def _search_provider(self, search_params, **kwargs):
@ -61,8 +61,9 @@ class IPTorrentsProvider(generic.TorrentProvider):
for search_string in search_params[mode]: for search_string in search_params[mode]:
search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string
# URL with 50 tv-show results, or max 150 if adjusted in IPTorrents profile # URL with 50 tv-show results, or max 150 if adjusted in IPTorrents profile
search_url = self.urls['search'] % (self._categories_string(mode, '%s', ';'), search_string, search_url = self.urls['search'] % (
('', ';free')[self.freeleech], (';o=seeders', '')['Cache' == mode]) self._categories_string(mode, '%s', ';'), search_string,
(';free', '')[not self.freeleech], (';o=seeders', '')['Cache' == mode])
html = self.get_url(search_url) html = self.get_url(search_url)
@ -108,15 +109,9 @@ class IPTorrentsProvider(generic.TorrentProvider):
return results return results
@staticmethod
class IPTorrentsCache(tvcache.TVCache): def ui_string(key):
return 'iptorrents_digest' == key and 'use... \'uid=xx; pass=yy\'' or ''
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
def _cache_data(self):
return self.provider.cache_data()
provider = IPTorrentsProvider() provider = IPTorrentsProvider()

View file

@ -23,7 +23,7 @@ import traceback
import urllib import urllib
from . import generic from . import generic
from sickbeard import config, logger, show_name_helpers, tvcache from sickbeard import config, logger, show_name_helpers
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import (has_anime, tryInt) from sickbeard.helpers import (has_anime, tryInt)
from sickbeard.common import Quality, mediaExtensions from sickbeard.common import Quality, mediaExtensions
@ -34,20 +34,22 @@ from lib.unidecode import unidecode
class KATProvider(generic.TorrentProvider): class KATProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'KickAssTorrents') generic.TorrentProvider.__init__(self, 'KickAssTorrents', cache_update_freq=20)
self.url_base = 'https://kat.ph/' self.url_home = ['https://%s/' % u for u in 'kat.ph', 'kat.cr', 'kickass.unblocked.red', 'katproxy.com']
self.urls = {'config_provider_home_uri': self.url_base,
'base': [self.url_base, 'http://katproxy.com/'], self.url_vars = {'search': 'usearch/%s/?field=time_add&sorder=desc', 'get': '%s'}
'search': 'usearch/%s/', self.url_tmpl = {'config_provider_home_uri': '%(home)s',
'sorted': '?field=time_add&sorder=desc'} 'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'}
self.proper_search_terms = None self.proper_search_terms = None
self.url = self.urls['config_provider_home_uri']
self.minseed, self.minleech = 2 * [None] self.minseed, self.minleech = 2 * [None]
self.confirmed = False self.confirmed = False
self.cache = KATCache(self)
@staticmethod
def _has_signature(data=None):
return data and (re.search(r'(?sim)(<title>KAT)', data[15:1024:]) or 'kastatic' in data)
def _find_season_quality(self, title, torrent_link, ep_number): def _find_season_quality(self, title, torrent_link, ep_number):
""" Return the modified title of a Season Torrent with the quality found inspecting torrent file list """ """ Return the modified title of a Season Torrent with the quality found inspecting torrent file list """
@ -135,7 +137,7 @@ class KATProvider(generic.TorrentProvider):
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'link': 'normal', 'get': '^magnet', 'verif': 'verif'}.items()) rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'link': 'normal', 'get': '^magnet', 'verif': 'verif'}.items())
url = 0
for mode in search_params.keys(): for mode in search_params.keys():
search_show = mode in ['Season', 'Episode'] search_show = mode in ['Season', 'Episode']
if not search_show and has_anime(): if not search_show and has_anime():
@ -145,19 +147,17 @@ class KATProvider(generic.TorrentProvider):
for enum, search_string in enumerate(search_params[mode]): for enum, search_string in enumerate(search_params[mode]):
search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string
self.url = self.urls['base'][url] search_url = self.urls['search'] % urllib.quote('%scategory:%s' % (
search_url = self.url + (self.urls['search'] % urllib.quote('%scategory:%s' % (
('', '%s ' % search_string)['Cache' != mode], ('', '%s ' % search_string)['Cache' != mode],
('tv', 'anime')[(search_show and bool(self.show and self.show.is_anime)) or bool(enum)]))) ('tv', 'anime')[(search_show and bool(self.show and self.show.is_anime)) or bool(enum)]))
self.session.headers.update({'Referer': search_url}) self.session.headers.update({'Referer': search_url})
html = self.get_url(search_url + self.urls['sorted']) html = self.get_url(search_url)
cnt = len(items[mode]) cnt = len(items[mode])
try: try:
if not html or 'kastatic' not in html or self._has_no_results(html) or re.search(r'(?is)<(?:h\d)[^>]*>.*?(?:did\snot\smatch)', html): if not html or self._has_no_results(html) or \
if html and 'kastatic' not in html: re.search(r'(?is)<(?:h\d)[^>]*>.*?(?:did\snot\smatch)', html):
url += (1, 0)[url == len(self.urls['base'])]
raise generic.HaltParseException raise generic.HaltParseException
with BS4Parser(html, features=['html5lib', 'permissive']) as soup: with BS4Parser(html, features=['html5lib', 'permissive']) as soup:
@ -183,11 +183,13 @@ class KATProvider(generic.TorrentProvider):
except (AttributeError, TypeError, ValueError): except (AttributeError, TypeError, ValueError):
continue continue
if self.confirmed and not (tr.find('a', title=rc['verif']) or tr.find('i', title=rc['verif'])): if self.confirmed and not (tr.find('a', title=rc['verif']) or
tr.find('i', title=rc['verif'])):
logger.log(u'Skipping untrusted non-verified result: %s' % title, logger.DEBUG) logger.log(u'Skipping untrusted non-verified result: %s' % title, logger.DEBUG)
continue continue
# Check number video files = episode in season and find the real Quality for full season torrent analyzing files in torrent # Check number video files = episode in season and find the real Quality for
# full season torrent analyzing files in torrent
if 'Season' == mode and 'sponly' == search_mode: if 'Season' == mode and 'sponly' == search_mode:
ep_number = int(epcount / len(set(show_name_helpers.allPossibleShowNames(self.show)))) ep_number = int(epcount / len(set(show_name_helpers.allPossibleShowNames(self.show))))
title = self._find_season_quality(title, link, ep_number) title = self._find_season_quality(title, link, ep_number)
@ -208,16 +210,4 @@ class KATProvider(generic.TorrentProvider):
return results return results
class KATCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = KATProvider() provider = KATProvider()

View file

@ -21,7 +21,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -30,19 +30,19 @@ from lib.unidecode import unidecode
class MoreThanProvider(generic.TorrentProvider): class MoreThanProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'MoreThan') generic.TorrentProvider.__init__(self, 'MoreThan', cache_update_freq=20)
self.url_base = 'https://www.morethan.tv/' self.url_base = 'https://www.morethan.tv/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
'login': self.url_base + 'login.php', 'login': self.url_base + 'login.php',
'search': self.url_base + 'torrents.php?searchstr=%s&' + '&'.join([ 'search': self.url_base + 'torrents.php?searchstr=%s&' + '&'.join([
'tags_type=1', 'order_by=time', '&order_way=desc', 'filter_cat[2]=1', 'action=basic', 'searchsubmit=1']), 'tags_type=1', 'order_by=time', 'order_way=desc',
'filter_cat[2]=1', 'action=basic', 'searchsubmit=1']),
'get': self.url_base + '%s'} 'get': self.url_base + '%s'}
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = MoreThanCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -95,7 +95,7 @@ class MoreThanProvider(generic.TorrentProvider):
title = '%s %s' % (tr.find('div', attrs={'class': rc['name']}).get_text().strip(), title = '%s %s' % (tr.find('div', attrs={'class': rc['name']}).get_text().strip(),
title) title)
link = str(tr.find('a', title=rc['get'])['href']).replace('&amp;', '&').lstrip('/') link = str(tr.find('a', href=rc['get'])['href']).replace('&amp;', '&').lstrip('/')
download_url = self.urls['get'] % link download_url = self.urls['get'] % link
except (AttributeError, TypeError, ValueError): except (AttributeError, TypeError, ValueError):
continue continue
@ -117,16 +117,4 @@ class MoreThanProvider(generic.TorrentProvider):
return results return results
class MoreThanCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = MoreThanProvider() provider = MoreThanProvider()

View file

@ -27,14 +27,14 @@ from sickbeard.exceptions import AuthException
class NewznabProvider(generic.NZBProvider): class NewznabProvider(generic.NZBProvider):
def __init__(self, name, url, key='', cat_ids='5030,5040', search_mode='eponly', def __init__(self, name, url, key='', cat_ids=None, search_mode=None,
search_fallback=False, enable_recentsearch=False, enable_backlog=False): search_fallback=False, enable_recentsearch=False, enable_backlog=False):
generic.NZBProvider.__init__(self, name, True, False) generic.NZBProvider.__init__(self, name, True, False)
self.url = url self.url = url
self.key = key self.key = key
self.cat_ids = cat_ids self.cat_ids = cat_ids or '5030,5040'
self.search_mode = search_mode self.search_mode = search_mode or 'eponly'
self.search_fallback = search_fallback self.search_fallback = search_fallback
self.enable_recentsearch = enable_recentsearch self.enable_recentsearch = enable_recentsearch
self.enable_backlog = enable_backlog self.enable_backlog = enable_backlog
@ -81,11 +81,11 @@ class NewznabProvider(generic.NZBProvider):
if isinstance(api_key, basestring): if isinstance(api_key, basestring):
params['apikey'] = api_key params['apikey'] = api_key
categories = self.get_url('%s/api' % self.url, params=params, timeout=10) url = '%s/api?%s' % (self.url.strip('/'), '&'.join(['%s=%s' % (k, v) for k, v in params.items()]))
categories = self.get_url(url, timeout=10)
if not categories: if not categories:
logger.log(u'Error getting html for [%s]' % self.session.response['url'], logger.DEBUG) logger.log(u'Error getting html for [%s]' % url, logger.DEBUG)
return (False, return_categories, 'Error getting html for [%s]' % return False, return_categories, 'Error getting html for [%s]' % url
('%s/api?%s' % (self.url, '&'.join('%s=%s' % (x, y) for x, y in params.items()))))
xml_categories = helpers.parse_xml(categories) xml_categories = helpers.parse_xml(categories)
if not xml_categories: if not xml_categories:
@ -114,16 +114,20 @@ class NewznabProvider(generic.NZBProvider):
base_params = {} base_params = {}
# season # season
ep_detail = None
if ep_obj.show.air_by_date or ep_obj.show.is_sports: if ep_obj.show.air_by_date or ep_obj.show.is_sports:
date_str = str(ep_obj.airdate).split('-')[0] airdate = str(ep_obj.airdate).split('-')[0]
base_params['season'] = date_str base_params['season'] = airdate
base_params['q'] = date_str.replace('-', '.') base_params['q'] = airdate
if ep_obj.show.air_by_date:
ep_detail = '+"%s"' % airdate
elif ep_obj.show.is_anime: elif ep_obj.show.is_anime:
base_params['season'] = '%d' % ep_obj.scene_absolute_number base_params['season'] = '%d' % ep_obj.scene_absolute_number
else: else:
base_params['season'] = str((ep_obj.season, ep_obj.scene_season)[bool(ep_obj.show.is_scene)]) base_params['season'] = str((ep_obj.season, ep_obj.scene_season)[bool(ep_obj.show.is_scene)])
ep_detail = 'S%02d' % helpers.tryInt(base_params['season'], 1)
# search # id search
ids = helpers.mapIndexersToShow(ep_obj.show) ids = helpers.mapIndexersToShow(ep_obj.show)
if ids[1]: # or ids[2]: if ids[1]: # or ids[2]:
params = base_params.copy() params = base_params.copy()
@ -136,7 +140,7 @@ class NewznabProvider(generic.NZBProvider):
use_id = True use_id = True
use_id and search_params.append(params) use_id and search_params.append(params)
# add new query strings for exceptions # query search and exceptions
name_exceptions = list( name_exceptions = list(
set([helpers.sanitizeSceneName(a) for a in set([helpers.sanitizeSceneName(a) for a in
scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name]])) scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name]]))
@ -144,7 +148,14 @@ class NewznabProvider(generic.NZBProvider):
params = base_params.copy() params = base_params.copy()
if 'q' in params: if 'q' in params:
params['q'] = '%s.%s' % (cur_exception, params['q']) params['q'] = '%s.%s' % (cur_exception, params['q'])
search_params.append(params) search_params.append(params)
if ep_detail:
params = base_params.copy()
params['q'] = '%s.%s' % (cur_exception, ep_detail)
'season' in params and params.pop('season')
'ep' in params and params.pop('ep')
search_params.append(params)
return [{'Season': search_params}] return [{'Season': search_params}]
@ -156,18 +167,25 @@ class NewznabProvider(generic.NZBProvider):
if not ep_obj: if not ep_obj:
return [base_params] return [base_params]
ep_detail = None
if ep_obj.show.air_by_date or ep_obj.show.is_sports: if ep_obj.show.air_by_date or ep_obj.show.is_sports:
date_str = str(ep_obj.airdate) airdate = str(ep_obj.airdate).split('-')
base_params['season'] = date_str.partition('-')[0] base_params['season'] = airdate[0]
base_params['ep'] = date_str.partition('-')[2].replace('-', '/') if ep_obj.show.air_by_date:
base_params['ep'] = '/'.join(airdate[1:])
ep_detail = '+"%s.%s"' % (base_params['season'], '.'.join(airdate[1:]))
elif ep_obj.show.is_anime: elif ep_obj.show.is_anime:
base_params['ep'] = '%i' % int( base_params['ep'] = '%i' % (helpers.tryInt(ep_obj.scene_absolute_number) or
ep_obj.scene_absolute_number if int(ep_obj.scene_absolute_number) > 0 else ep_obj.scene_episode) helpers.tryInt(ep_obj.scene_episode))
ep_detail = '%02d' % base_params['ep']
else: else:
base_params['season'], base_params['ep'] = ( base_params['season'], base_params['ep'] = (
(ep_obj.season, ep_obj.episode), (ep_obj.scene_season, ep_obj.scene_episode))[ep_obj.show.is_scene] (ep_obj.season, ep_obj.episode), (ep_obj.scene_season, ep_obj.scene_episode))[ep_obj.show.is_scene]
ep_detail = sickbeard.config.naming_ep_type[2] % {
'seasonnumber': helpers.tryInt(base_params['season'], 1),
'episodenumber': helpers.tryInt(base_params['ep'], 1)}
# search # id search
ids = helpers.mapIndexersToShow(ep_obj.show) ids = helpers.mapIndexersToShow(ep_obj.show)
if ids[1]: # or ids[2]: if ids[1]: # or ids[2]:
params = base_params.copy() params = base_params.copy()
@ -181,7 +199,7 @@ class NewznabProvider(generic.NZBProvider):
use_id = True use_id = True
use_id and search_params.append(params) use_id and search_params.append(params)
# add new query strings for exceptions # query search and exceptions
name_exceptions = list( name_exceptions = list(
set([helpers.sanitizeSceneName(a) for a in set([helpers.sanitizeSceneName(a) for a in
scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name]])) scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name]]))
@ -191,15 +209,11 @@ class NewznabProvider(generic.NZBProvider):
params['q'] = cur_exception params['q'] = cur_exception
search_params.append(params) search_params.append(params)
if ep_obj.show.is_anime: if ep_detail:
# Experimental, add a search string without search explicitly for the episode!
# Remove the ?ep=e46 parameter and use the episode number to the query parameter.
# Can be useful for newznab indexers that do not have the episodes 100% parsed.
# Start with only applying the search string to anime shows
params = base_params.copy() params = base_params.copy()
params['q'] = '%s.%02d' % (cur_exception, int(params['ep'])) params['q'] = '%s.%s' % (cur_exception, ep_detail)
if 'ep' in params: 'season' in params and params.pop('season')
params.pop('ep') 'ep' in params and params.pop('ep')
search_params.append(params) search_params.append(params)
return [{'Episode': search_params}] return [{'Episode': search_params}]
@ -229,8 +243,10 @@ class NewznabProvider(generic.NZBProvider):
# category ids # category ids
cat = [] cat = []
cat_anime = ('5070', '6070')['nzbs_org' == self.get_id()] cat_sport = ['5060']
cat_sport = '5060' cat_anime = []
if 'nzbgeek' != self.get_id():
cat_anime = (['5070'], ['6070'])['nzbs_org' == self.get_id()]
if 'Episode' == mode or 'Season' == mode: if 'Episode' == mode or 'Season' == mode:
if not ('rid' in params or 'tvdbid' in params or 'q' in params or not self.supports_tvdbid()): if not ('rid' in params or 'tvdbid' in params or 'q' in params or not self.supports_tvdbid()):
logger.log('Error no rid, tvdbid, or search term available for search.') logger.log('Error no rid, tvdbid, or search term available for search.')
@ -238,18 +254,24 @@ class NewznabProvider(generic.NZBProvider):
if self.show: if self.show:
if self.show.is_sports: if self.show.is_sports:
cat = [cat_sport] cat = cat_sport
elif self.show.is_anime: elif self.show.is_anime:
cat = [cat_anime] cat = cat_anime
else: else:
cat = [cat_sport, cat_anime] cat = cat_sport + cat_anime
if self.cat_ids or len(cat): if self.cat_ids or len(cat):
base_params['cat'] = ','.join(sorted(set(self.cat_ids.split(',') + cat))) base_params['cat'] = ','.join(sorted(set(self.cat_ids.split(',') + cat)))
request_params = base_params.copy() request_params = base_params.copy()
if 'q' in params and not (any(x in params for x in ['season', 'ep'])):
request_params['t'] = 'search'
request_params.update(params) request_params.update(params)
# workaround a strange glitch
if sum(ord(i) for i in self.get_id()) in [383] and 5 == 14 - request_params['maxage']:
request_params['maxage'] += 1
offset = 0 offset = 0
batch_count = not 0 batch_count = not 0
@ -336,18 +358,17 @@ class NewznabCache(tvcache.TVCache):
result = [] result = []
if True or self.shouldUpdate(): if 4489 != sickbeard.RECENTSEARCH_FREQUENCY or self.should_update():
try: try:
self._checkAuth() self._checkAuth()
items = self.provider.cache_data()
except Exception: except Exception:
return result items = None
items = self.provider.cache_data()
if items: if items:
self._clearCache() self._clearCache()
self.setLastUpdate()
# parse data
cl = [] cl = []
for item in items: for item in items:
ci = self._parseItem(item) ci = self._parseItem(item)
@ -358,6 +379,9 @@ class NewznabCache(tvcache.TVCache):
my_db = self.get_db() my_db = self.get_db()
my_db.mass_action(cl) my_db.mass_action(cl)
# set updated as time the attempt to fetch data is
self.setLastUpdate()
return result return result
# overwrite method with that parses the rageid from the newznab feed # overwrite method with that parses the rageid from the newznab feed

View file

@ -17,7 +17,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -37,7 +37,6 @@ class PiSexyProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = PiSexyCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -108,14 +107,4 @@ class PiSexyProvider(generic.TorrentProvider):
return results return results
class PiSexyCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
def _cache_data(self):
return self.provider.cache_data()
provider = PiSexyProvider() provider = PiSexyProvider()

View file

@ -16,7 +16,6 @@
# along with SickGear. If not, see <http://www.gnu.org/licenses/>. # along with SickGear. If not, see <http://www.gnu.org/licenses/>.
from . import generic from . import generic
from sickbeard import tvcache
from sickbeard.rssfeeds import RSSFeeds from sickbeard.rssfeeds import RSSFeeds
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -24,7 +23,7 @@ from lib.unidecode import unidecode
class PreToMeProvider(generic.TorrentProvider): class PreToMeProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'PreToMe') generic.TorrentProvider.__init__(self, 'PreToMe', cache_update_freq=6)
self.url_base = 'https://pretome.info/' self.url_base = 'https://pretome.info/'
@ -35,7 +34,6 @@ class PreToMeProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.passkey = None self.passkey = None
self.cache = PreToMeCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -72,16 +70,4 @@ class PreToMeProvider(generic.TorrentProvider):
return results return results
class PreToMeCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 6 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = PreToMeProvider() provider = PreToMeProvider()

View file

@ -21,7 +21,7 @@ import datetime
import time import time
from . import generic from . import generic
from sickbeard import helpers, logger, tvcache from sickbeard import helpers, logger
from sickbeard.indexers.indexer_config import INDEXER_TVDB from sickbeard.indexers.indexer_config import INDEXER_TVDB
@ -51,7 +51,6 @@ class RarbgProvider(generic.TorrentProvider):
self.minseed, self.minleech, self.token, self.token_expiry = 4 * [None] self.minseed, self.minleech, self.token, self.token_expiry = 4 * [None]
self.confirmed = False self.confirmed = False
self.request_throttle = datetime.datetime.now() self.request_throttle = datetime.datetime.now()
self.cache = RarbgCache(self)
def _authorised(self, reset=False, **kwargs): def _authorised(self, reset=False, **kwargs):
@ -178,14 +177,4 @@ class RarbgProvider(generic.TorrentProvider):
return search_params return search_params
class RarbgCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
def _cache_data(self):
return self.provider.cache_data()
provider = RarbgProvider() provider = RarbgProvider()

View file

@ -20,7 +20,7 @@ import time
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -31,18 +31,16 @@ class SCCProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'SceneAccess') generic.TorrentProvider.__init__(self, 'SceneAccess')
self.url_base = 'https://sceneaccess.eu/' self.url_home = ['https://sceneaccess.%s/' % u for u in 'eu', 'org']
self.urls = {'config_provider_home_uri': self.url_base,
'login': self.url_base + 'login',
'search': self.url_base + 'browse?search=%s&method=1&c27=27&c17=17&c11=11',
'nonscene': self.url_base + 'nonscene?search=%s&method=1&c44=44&c45=44',
'archive': self.url_base + 'archive?search=%s&method=1&c26=26',
'get': self.url_base + '%s'}
self.url = self.urls['config_provider_home_uri'] self.url_vars = {
'login': 'login', 'search': 'browse?search=%s&method=1&c27=27&c17=17&c11=11', 'get': '%s',
'nonscene': 'nonscene?search=%s&method=1&c44=44&c45=44', 'archive': 'archive?search=%s&method=1&c26=26'}
self.url_tmpl = {
'config_provider_home_uri': '%(home)s', 'login': '%(home)s%(vars)s', 'search': '%(home)s%(vars)s',
'get': '%(home)s%(vars)s', 'nonscene': '%(home)s%(vars)s', 'archive': '%(home)s%(vars)s'}
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = SCCCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -121,16 +119,4 @@ class SCCProvider(generic.TorrentProvider):
return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='.', **kwargs) return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='.', **kwargs)
class SCCCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = SCCProvider() provider = SCCProvider()

View file

@ -20,7 +20,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -29,7 +29,7 @@ from lib.unidecode import unidecode
class SceneTimeProvider(generic.TorrentProvider): class SceneTimeProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'SceneTime') generic.TorrentProvider.__init__(self, 'SceneTime', cache_update_freq=15)
self.url_base = 'https://www.scenetime.com/' self.url_base = 'https://www.scenetime.com/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
@ -42,9 +42,7 @@ class SceneTimeProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
self.freeleech = False
self.cache = SceneTimeCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -58,15 +56,16 @@ class SceneTimeProvider(generic.TorrentProvider):
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': '.*id=(\d+).*', 'fl': '\[freeleech\]', rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {
'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|') 'info': 'detail', 'get': '.*id=(\d+).*', 'fl': '\[freeleech\]',
}.items()) 'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|')}.items())
for mode in search_params.keys(): for mode in search_params.keys():
for search_string in search_params[mode]: for search_string in search_params[mode]:
search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string
post_data = self.urls['params'].copy() post_data = self.urls['params'].copy()
post_data.update(ast.literal_eval('{%s}' % self._categories_string(template='"c%s": "1"', delimiter=','))) post_data.update(ast.literal_eval(
'{%s}' % self._categories_string(template='"c%s": "1"', delimiter=',')))
if 'Cache' != mode: if 'Cache' != mode:
search_string = '+'.join(search_string.split()) search_string = '+'.join(search_string.split())
post_data['search'] = search_string post_data['search'] = search_string
@ -99,10 +98,11 @@ class SceneTimeProvider(generic.TorrentProvider):
continue continue
info = tr.find('a', href=rc['info']) info = tr.find('a', href=rc['info'])
title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip() title = info.attrs.get('title') or info.get_text().strip()
download_url = self.urls['get'] % {'id': re.sub(rc['get'], r'\1', str(info.attrs['href'])), download_url = self.urls['get'] % {
'title': str(title).replace(' ', '.')} 'id': re.sub(rc['get'], r'\1', str(info.attrs['href'])),
'title': str(title).replace(' ', '.')}
except (AttributeError, TypeError, ValueError): except (AttributeError, TypeError, ValueError):
continue continue
@ -124,16 +124,4 @@ class SceneTimeProvider(generic.TorrentProvider):
return results return results
class SceneTimeCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 15 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = SceneTimeProvider() provider = SceneTimeProvider()

View file

@ -22,7 +22,7 @@ import time
import traceback import traceback
from . import generic from . import generic
from sickbeard import helpers, logger, tvcache from sickbeard import helpers, logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -32,7 +32,7 @@ class ShazbatProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'Shazbat') generic.TorrentProvider.__init__(self, 'Shazbat', cache_update_freq=20)
self.url_base = 'https://www.shazbat.tv/' self.url_base = 'https://www.shazbat.tv/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
@ -46,8 +46,6 @@ class ShazbatProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = ShazbatCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -147,16 +145,4 @@ class ShazbatProvider(generic.TorrentProvider):
return generic.TorrentProvider._episode_strings(self, ep_obj, detail_only=True, scene=False, **kwargs) return generic.TorrentProvider._episode_strings(self, ep_obj, detail_only=True, scene=False, **kwargs)
class ShazbatCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = ShazbatProvider() provider = ShazbatProvider()

View file

@ -19,34 +19,32 @@ import re
import time import time
from . import generic from . import generic
from sickbeard import tvcache from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
class SpeedCDProvider(generic.TorrentProvider): class SpeedCDProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'SpeedCD') generic.TorrentProvider.__init__(self, 'SpeedCD', cache_update_freq=20)
self.url_base = 'http://speed.cd/' self.url_base = 'https://speed.cd/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
'login_action': self.url_base + 'login.php', 'login_action': self.url_base + 'login.php',
'search': self.url_base + 'V3/API/API.php', 'search': self.url_base + 'V3/API/API.php',
'get': self.url_base + 'download.php?torrent=%s'} 'get': self.url_base + '%s'}
self.categories = {'Season': {'c41': 1, 'c53': 1}, self.categories = {'Season': [41, 53], 'Episode': [2, 49, 50, 55], 'anime': [30]}
'Episode': {'c2': 1, 'c49': 1, 'c50': 1, 'c55': 1}, self.categories['Cache'] = self.categories['Season'] + self.categories['Episode']
'Cache': {'c41': 1, 'c2': 1, 'c49': 1, 'c50': 1, 'c53': 1, 'c55': 1}}
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
self.freeleech = False
self.cache = SpeedCDCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
return super(SpeedCDProvider, self)._authorised(logged_in=(lambda x=None: self.has_all_cookies('inSpeed_speedian'))) return super(SpeedCDProvider, self)._authorised(
logged_in=(lambda x=None: self.has_all_cookies('inSpeed_speedian')))
def _search_provider(self, search_params, **kwargs): def _search_provider(self, search_params, **kwargs):
@ -56,37 +54,49 @@ class SpeedCDProvider(generic.TorrentProvider):
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
remove_tag = re.compile(r'<[^>]*>') rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'get': 'download', 'fl': '\[freeleech\]'}.items())
for mode in search_params.keys(): for mode in search_params.keys():
search_mode = (mode, 'Episode')['Propers' == mode] rc['cats'] = re.compile('(?i)cat=(?:%s)' % self._categories_string(mode, template='', delimiter='|'))
for search_string in search_params[mode]: for search_string in search_params[mode]:
search_string = '+'.join(search_string.split()) search_string = '+'.join(search_string.split())
post_data = dict({'/browse.php?': None, 'cata': 'yes', 'jxt': 4, 'jxw': 'b', 'search': search_string}, post_data = dict((x.split('=') for x in self._categories_string(mode).split('&')), search=search_string,
**self.categories[search_mode]) jxt=2, jxw='b', freeleech=('on', None)[not self.freeleech])
if self.freeleech:
post_data['freeleech'] = 'on'
data_json = self.get_url(self.urls['search'], post_data=post_data, json=True) data_json = self.get_url(self.urls['search'], post_data=post_data, json=True)
cnt = len(items[mode]) cnt = len(items[mode])
try: try:
if not data_json: html = data_json.get('Fs')[0].get('Cn')[0].get('d')
if not html or self._has_no_results(html):
raise generic.HaltParseException raise generic.HaltParseException
torrents = data_json.get('Fs', [])[0].get('Cn', {}).get('torrents', [])
for item in torrents: with BS4Parser(html, features=['html5lib', 'permissive']) as soup:
torrent_table = soup.find('table', attrs={'cellspacing': 0})
torrent_rows = [] if not torrent_table else torrent_table.find_all('tr')
if self.freeleech and not item.get('free'): if 2 > len(torrent_rows):
continue raise generic.HaltParseException
seeders, leechers, size = [tryInt(n, n) for n in [item.get(x) for x in 'seed', 'leech', 'size']] for tr in torrent_rows[1:]:
if self._peers_fail(mode, seeders, leechers): try:
continue seeders, leechers, size = [tryInt(n, n) for n in [
tr.find_all('td')[x].get_text().strip() for x in (-2, -1, -3)]]
if None is tr.find('a', href=rc['cats']) \
or self.freeleech and None is rc['fl'].search(tr.find_all('td')[1].get_text()) \
or self._peers_fail(mode, seeders, leechers):
continue
title = remove_tag.sub('', item.get('name')) info = tr.find('a', 'torrent')
download_url = self.urls['get'] % item.get('id') title = info.attrs.get('title') or info.get_text().strip()
if title and download_url:
items[mode].append((title, download_url, seeders, self._bytesizer(size))) download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/')
except (AttributeError, TypeError, ValueError):
continue
if title and download_url:
items[mode].append((title, download_url, seeders, self._bytesizer(size)))
except Exception: except Exception:
time.sleep(1.1) time.sleep(1.1)
@ -105,16 +115,4 @@ class SpeedCDProvider(generic.TorrentProvider):
return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='.', **kwargs) return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='.', **kwargs)
class SpeedCDCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = SpeedCDProvider() provider = SpeedCDProvider()

View file

@ -23,7 +23,7 @@ import traceback
import urllib import urllib
from . import generic from . import generic
from sickbeard import config, logger, tvcache, show_name_helpers from sickbeard import config, logger, show_name_helpers
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.common import Quality, mediaExtensions from sickbeard.common import Quality, mediaExtensions
from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException
@ -33,40 +33,32 @@ from lib.unidecode import unidecode
class ThePirateBayProvider(generic.TorrentProvider): class ThePirateBayProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'The Pirate Bay') generic.TorrentProvider.__init__(self, 'The Pirate Bay', cache_update_freq=20)
self.urls = {'config_provider_home_uri': ['https://thepiratebay.se/', 'https://thepiratebay.gd/', self.url_home = ['https://thepiratebay.%s/' % u for u in 'se', 'org']
'https://thepiratebay.mn/', 'https://thepiratebay.vg/',
'https://thepiratebay.la/'], self.url_vars = {'search': 'search/%s/0/7/200', 'browse': 'tv/latest/'}
'search': 'search/%s/0/7/200', self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'search': '%(home)s%(vars)s',
'browse': 'tv/latest/'} # order by seed 'browse': '%(home)s%(vars)s'}
self.proper_search_terms = None self.proper_search_terms = None
self.url = self.urls['config_provider_home_uri'][0]
self.minseed, self.minleech = 2 * [None] self.minseed, self.minleech = 2 * [None]
self.confirmed = False self.confirmed = False
self.cache = ThePirateBayCache(self)
@staticmethod
def _has_signature(data=None):
return data and re.search(r'Pirate\sBay', data[33:7632:])
def _find_season_quality(self, title, torrent_id, ep_number): def _find_season_quality(self, title, torrent_id, ep_number):
""" Return the modified title of a Season Torrent with the quality found inspecting torrent file list """ """ Return the modified title of a Season Torrent with the quality found inspecting torrent file list """
if not self.url:
return False
quality = Quality.UNKNOWN quality = Quality.UNKNOWN
file_name = None file_name = None
data = None data = self.get_url('%sajax_details_filelist.php?id=%s' % (self.url, torrent_id))
has_signature = False
details_url = '/ajax_details_filelist.php?id=%s' % torrent_id
for idx, url in enumerate(self.urls['config_provider_home_uri']):
data = self.get_url(url + details_url)
if data and re.search(r'<title>The\sPirate\sBay', data[33:200:]):
has_signature = True
break
else:
data = None
if not has_signature:
logger.log(u'Failed to identify a page from ThePirateBay at %s attempted urls (tpb blocked? general network issue or site dead)' % len(self.urls['config_provider_home_uri']), logger.ERROR)
if not data: if not data:
return None return None
@ -138,30 +130,22 @@ class ThePirateBayProvider(generic.TorrentProvider):
def _search_provider(self, search_params, search_mode='eponly', epcount=0, **kwargs): def _search_provider(self, search_params, search_mode='eponly', epcount=0, **kwargs):
results = [] results = []
if not self.url:
return results
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict((k, re.compile('(?i)' + v)) rc = dict((k, re.compile('(?i)' + v))
for (k, v) in {'info': 'detail', 'get': 'download[^"]+magnet', 'tid': r'.*/(\d{5,}).*', for (k, v) in {'info': 'detail', 'get': 'download[^"]+magnet', 'tid': r'.*/(\d{5,}).*',
'verify': '(?:helper|moderator|trusted|vip)'}.items()) 'verify': '(?:helper|moderator|trusted|vip)'}.items())
has_signature = False
for mode in search_params.keys(): for mode in search_params.keys():
for search_string in search_params[mode]: for search_string in search_params[mode]:
search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string
log_url = '%s %s' % (self.name, search_string) # placebo value search_url = self.urls['browse'] if 'Cache' == mode \
for idx, search_url in enumerate(self.urls['config_provider_home_uri']): else self.urls['search'] % (urllib.quote(search_string))
search_url += self.urls['browse'] if 'Cache' == mode\ html = self.get_url(search_url)
else self.urls['search'] % (urllib.quote(search_string))
log_url = u'(%s/%s): %s' % (idx + 1, len(self.urls['config_provider_home_uri']), search_url)
html = self.get_url(search_url)
if html and re.search(r'Pirate\sBay', html[33:7632:]):
has_signature = True
break
else:
html = None
cnt = len(items[mode]) cnt = len(items[mode])
try: try:
@ -213,28 +197,13 @@ class ThePirateBayProvider(generic.TorrentProvider):
pass pass
except Exception: except Exception:
logger.log(u'Failed to parse. Traceback: %s' % traceback.format_exc(), logger.ERROR) logger.log(u'Failed to parse. Traceback: %s' % traceback.format_exc(), logger.ERROR)
self._log_search(mode, len(items[mode]) - cnt, log_url) self._log_search(mode, len(items[mode]) - cnt, search_url)
self._sort_seeders(mode, items) self._sort_seeders(mode, items)
results = list(set(results + items[mode])) results = list(set(results + items[mode]))
if not has_signature:
logger.log(u'Failed to identify a page from ThePirateBay at %s attempted urls (tpb blocked? general network issue or site dead)' % len(self.urls['config_provider_home_uri']), logger.ERROR)
return results return results
class ThePirateBayCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = ThePirateBayProvider() provider = ThePirateBayProvider()

View file

@ -19,7 +19,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -28,21 +28,18 @@ from lib.unidecode import unidecode
class TorrentBytesProvider(generic.TorrentProvider): class TorrentBytesProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'TorrentBytes') generic.TorrentProvider.__init__(self, 'TorrentBytes', cache_update_freq=20)
self.url_base = 'https://www.torrentbytes.net/' self.url_home = ['https://www.torrentbytes.net/']
self.urls = {'config_provider_home_uri': self.url_base,
'login': self.url_base + 'takelogin.php',
'search': self.url_base + 'browse.php?search=%s&%s',
'get': self.url_base + '%s'}
self.categories = {'shows': [41, 33, 38, 32, 37]} self.url_vars = {'login': 'takelogin.php', 'search': 'browse.php?search=%s&%s', 'get': '%s'}
self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'login': '%(home)s%(vars)s',
'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'}
self.url = self.urls['config_provider_home_uri'] self.categories = {'Season': [41, 32], 'Episode': [33, 37, 38]}
self.categories['Cache'] = self.categories['Season'] + self.categories['Episode']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
self.freeleech = False
self.cache = TorrentBytesCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -56,12 +53,12 @@ class TorrentBytesProvider(generic.TorrentProvider):
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download', 'fl': '\[\W*F\W?L\W*\]' rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download',
}.items()) 'fl': '\[\W*F\W?L\W*\]'}.items())
for mode in search_params.keys(): for mode in search_params.keys():
for search_string in search_params[mode]: for search_string in search_params[mode]:
search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string
search_url = self.urls['search'] % (search_string, self._categories_string()) search_url = self.urls['search'] % (search_string, self._categories_string(mode))
html = self.get_url(search_url, timeout=90) html = self.get_url(search_url, timeout=90)
@ -82,11 +79,11 @@ class TorrentBytesProvider(generic.TorrentProvider):
info = tr.find('a', href=rc['info']) info = tr.find('a', href=rc['info'])
seeders, leechers, size = [tryInt(n, n) for n in [ seeders, leechers, size = [tryInt(n, n) for n in [
tr.find_all('td')[x].get_text().strip() for x in (-2, -1, -4)]] tr.find_all('td')[x].get_text().strip() for x in (-2, -1, -4)]]
if self.freeleech and (len(info.contents) < 2 or not rc['fl'].search(info.contents[1].string.strip())) \ if self.freeleech and (len(info.contents) < 2 or not rc['fl'].search(
or self._peers_fail(mode, seeders, leechers): info.contents[1].string.strip())) or self._peers_fail(mode, seeders, leechers):
continue continue
title = 'title' in info.attrs and info.attrs['title'] or info.contents[0] title = info.attrs.get('title') or info.contents[0]
title = (isinstance(title, list) and title[0] or title).strip() title = (isinstance(title, list) and title[0] or title).strip()
download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/') download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/')
except (AttributeError, TypeError, ValueError): except (AttributeError, TypeError, ValueError):
@ -109,16 +106,4 @@ class TorrentBytesProvider(generic.TorrentProvider):
return results return results
class TorrentBytesCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = TorrentBytesProvider() provider = TorrentBytesProvider()

View file

@ -19,8 +19,7 @@ import re
import time import time
from . import generic from . import generic
from sickbeard import tvcache from sickbeard.helpers import tryInt
from sickbeard.helpers import (has_anime, tryInt)
class TorrentDayProvider(generic.TorrentProvider): class TorrentDayProvider(generic.TorrentProvider):
@ -28,22 +27,19 @@ class TorrentDayProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'TorrentDay') generic.TorrentProvider.__init__(self, 'TorrentDay')
self.url_base = 'https://torrentday.eu/' self.url_home = ['https://%s/' % u for u in 'torrentday.eu', 'secure.torrentday.com', 'tdonline.org',
self.urls = {'config_provider_home_uri': self.url_base, 'torrentday.it', 'www.td.af', 'www.torrentday.com']
'login': self.url_base + 'torrents/',
'search': self.url_base + 'V3/API/API.php',
'get': self.url_base + 'download.php/%s/%s'}
self.categories = {'Season': {'c31': 1, 'c33': 1, 'c14': 1}, self.url_vars = {'login': 'torrents/', 'search': 'V3/API/API.php', 'get': 'download.php/%s/%s'}
'Episode': {'c32': 1, 'c26': 1, 'c7': 1, 'c2': 1}, self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'login': '%(home)s%(vars)s',
'Cache': {'c31': 1, 'c33': 1, 'c14': 1, 'c32': 1, 'c26': 1, 'c7': 1, 'c2': 1}} 'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'}
self.categories = {'Season': [31, 33, 14], 'Episode': [24, 32, 26, 7, 2], 'Anime': [29]}
self.categories['Cache'] = self.categories['Season'] + self.categories['Episode']
self.proper_search_terms = None self.proper_search_terms = None
self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
self.freeleech = False
self.cache = TorrentDayCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -66,11 +62,8 @@ class TorrentDayProvider(generic.TorrentProvider):
for mode in search_params.keys(): for mode in search_params.keys():
for search_string in search_params[mode]: for search_string in search_params[mode]:
search_string = '+'.join(search_string.split()) search_string = '+'.join(search_string.split())
post_data = dict({'/browse.php?': None, 'cata': 'yes', 'jxt': 8, 'jxw': 'b', 'search': search_string}, post_data = dict((x.split('=') for x in self._categories_string(mode).split('&')),
**self.categories[(mode, 'Episode')['Propers' == mode]]) search=search_string, cata='yes', jxt=8, jxw='b')
if ('Cache' == mode and has_anime()) or (
mode in ['Season', 'Episode'] and self.show and self.show.is_anime):
post_data.update({'c29': 1})
if self.freeleech: if self.freeleech:
post_data.update({'free': 'on'}) post_data.update({'free': 'on'})
@ -112,14 +105,4 @@ class TorrentDayProvider(generic.TorrentProvider):
return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='.', date_or=True, **kwargs) return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='.', date_or=True, **kwargs)
class TorrentDayCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
def _cache_data(self):
return self.provider.cache_data()
provider = TorrentDayProvider() provider = TorrentDayProvider()

View file

@ -19,7 +19,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -30,25 +30,20 @@ class TorrentingProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'Torrenting') generic.TorrentProvider.__init__(self, 'Torrenting')
self.url_base = 'https://www.torrenting.com/' self.url_home = ['https://%s/' % u for u in 'www.torrenting.com', 'ttonline.us']
self.api = 'https://ttonline.us/' self.url_vars = {'login': 'rss.php', 'search': 'browse.php?%s&search=%s', 'get': '%s'}
self.urls = {'config_provider_home_uri': self.url_base, self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'login': '%(home)s%(vars)s',
'login': self.api + 'secure.php', 'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'}
'search': self.api + 'browse.php?%s&search=%s',
'get': self.api + '%s'}
self.categories = {'shows': [4, 5]} self.categories = {'shows': [4, 5]}
self.url = self.urls['config_provider_home_uri']
self.digest, self.minseed, self.minleech = 3 * [None] self.digest, self.minseed, self.minleech = 3 * [None]
self.cache = TorrentingCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
return super(TorrentingProvider, self)._authorised( return super(TorrentingProvider, self)._authorised(
logged_in=(lambda x=None: (None is x or 'Other Links' in x) and self.has_all_cookies() and logged_in=(lambda x=None: (None is x or 'RSS link' in x) and self.has_all_cookies() and
self.session.cookies['uid'] in self.digest and self.session.cookies['pass'] in self.digest), self.session.cookies['uid'] in self.digest and self.session.cookies['pass'] in self.digest),
failed_msg=(lambda x=None: u'Invalid cookie details for %s. Check settings')) failed_msg=(lambda x=None: u'Invalid cookie details for %s. Check settings'))
@ -60,9 +55,9 @@ class TorrentingProvider(generic.TorrentProvider):
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download', rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {
'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|') 'info': 'detail', 'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|'),
}.items()) 'get': 'download'}.items())
for mode in search_params.keys(): for mode in search_params.keys():
for search_string in search_params[mode]: for search_string in search_params[mode]:
search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string
@ -90,8 +85,9 @@ class TorrentingProvider(generic.TorrentProvider):
continue continue
info = tr.find('a', href=rc['info']) info = tr.find('a', href=rc['info'])
title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip() title = info.attrs.get('title') or info.get_text().strip()
download_url = self.urls['get'] % tr.find('a', href=rc['get']).get('href') download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/')
except (AttributeError, TypeError, ValueError): except (AttributeError, TypeError, ValueError):
continue continue
@ -117,14 +113,4 @@ class TorrentingProvider(generic.TorrentProvider):
return 'torrenting_digest' == key and 'use... \'uid=xx; pass=yy\'' or '' return 'torrenting_digest' == key and 'use... \'uid=xx; pass=yy\'' or ''
class TorrentingCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
def _cache_data(self):
return self.provider.cache_data()
provider = TorrentingProvider() provider = TorrentingProvider()

View file

@ -19,14 +19,14 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from lib.unidecode import unidecode from lib.unidecode import unidecode
class TorrentLeechProvider(generic.TorrentProvider): class TorrentLeechProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'TorrentLeech') generic.TorrentProvider.__init__(self, 'TorrentLeech', cache_update_freq=20)
self.url_base = 'https://torrentleech.org/' self.url_base = 'https://torrentleech.org/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
@ -40,7 +40,6 @@ class TorrentLeechProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = TorrentLeechCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -111,14 +110,5 @@ class TorrentLeechProvider(generic.TorrentProvider):
return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='|', **kwargs) return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='|', **kwargs)
class TorrentLeechCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = TorrentLeechProvider() provider = TorrentLeechProvider()

View file

@ -21,7 +21,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -30,13 +30,14 @@ from lib.unidecode import unidecode
class TorrentShackProvider(generic.TorrentProvider): class TorrentShackProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'TorrentShack') generic.TorrentProvider.__init__(self, 'TorrentShack', cache_update_freq=20)
self.url_base = 'https://torrentshack.me/' self.url_base = 'https://torrentshack.me/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
'login': self.url_base + 'login.php?lang=', 'login': self.url_base + 'login.php?lang=',
'search': self.url_base + 'torrents.php?searchstr=%s&%s&' + '&'.join( 'search': self.url_base + 'torrents.php?searchstr=%s&%s&' + '&'.join(
['release_type=both', 'searchtags=', 'tags_type=0', 'order_by=s3', 'order_way=desc', 'torrent_preset=all']), ['release_type=both', 'searchtags=', 'tags_type=0',
'order_by=s3', 'order_way=desc', 'torrent_preset=all']),
'get': self.url_base + '%s'} 'get': self.url_base + '%s'}
self.categories = {'shows': [600, 620, 700, 981, 980], 'anime': [850]} self.categories = {'shows': [600, 620, 700, 981, 980], 'anime': [850]}
@ -44,7 +45,6 @@ class TorrentShackProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = TorrentShackCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -117,16 +117,4 @@ class TorrentShackProvider(generic.TorrentProvider):
return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='.', **kwargs) return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='.', **kwargs)
class TorrentShackCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 20 # cache update frequency
def _cache_data(self):
return self.provider.cache_data()
provider = TorrentShackProvider() provider = TorrentShackProvider()

View file

@ -19,7 +19,8 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import helpers, logger, tvcache from sickbeard import common, helpers, logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from lib.unidecode import unidecode from lib.unidecode import unidecode
@ -27,7 +28,7 @@ from lib.unidecode import unidecode
class TransmithenetProvider(generic.TorrentProvider): class TransmithenetProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'Transmithe.net') generic.TorrentProvider.__init__(self, 'Transmithe.net', cache_update_freq=17)
self.url_base = 'https://transmithe.net/' self.url_base = 'https://transmithe.net/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
@ -39,10 +40,9 @@ class TransmithenetProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri'] self.url = self.urls['config_provider_home_uri']
self.user_authkey, self.user_passkey = 2 * [None] self.user_authkey, self.user_passkey = 2 * [None]
self.chk_td = True
self.username, self.password, self.minseed, self.minleech = 4 * [None] self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
self.freeleech = False
self.cache = TransmithenetCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -88,11 +88,13 @@ class TransmithenetProvider(generic.TorrentProvider):
try: try:
title_parts = group_name.split('[') title_parts = group_name.split('[')
maybe_res = re.findall('((?:72|108)0\w)', title_parts[1]) maybe_res = re.findall('((?:72|108|216)0\w)', title_parts[1])
maybe_ext = re.findall('(?i)(%s)' % '|'.join(common.mediaExtensions), title_parts[1])
detail = title_parts[1].split('/') detail = title_parts[1].split('/')
detail[1] = detail[1].strip().lower().replace('mkv', 'x264') detail[1] = detail[1].strip().lower().replace('mkv', 'x264')
title = '%s.%s' % (title_parts[0].strip(), '.'.join( title = '%s.%s' % (BS4Parser(title_parts[0].strip(), 'html.parser').soup.string, '.'.join(
(len(maybe_res) and [maybe_res[0]] or []) + [detail[0].strip(), detail[1]])) (maybe_res and [maybe_res[0]] or []) +
[detail[0].strip(), detail[1], maybe_ext and maybe_ext[0].lower() or 'mkv']))
except (IndexError, KeyError): except (IndexError, KeyError):
title = group_name title = group_name
download_url = self.urls['get'] % (self.user_authkey, self.user_passkey, torrent_id) download_url = self.urls['get'] % (self.user_authkey, self.user_passkey, torrent_id)
@ -119,16 +121,4 @@ class TransmithenetProvider(generic.TorrentProvider):
return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, **kwargs) return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, **kwargs)
class TransmithenetCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 17
def _cache_data(self):
return self.provider.cache_data()
provider = TransmithenetProvider() provider = TransmithenetProvider()

View file

@ -19,7 +19,7 @@ import re
import traceback import traceback
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt from sickbeard.helpers import tryInt
from sickbeard.config import naming_ep_type from sickbeard.config import naming_ep_type
@ -32,9 +32,9 @@ class TVChaosUKProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'TVChaosUK') generic.TorrentProvider.__init__(self, 'TVChaosUK')
self.url_base = 'https://tvchaosuk.com/' self.url_base = 'https://www.tvchaosuk.com/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
'login': self.url_base + 'takelogin.php', 'login_action': self.url_base + 'login.php',
'search': self.url_base + 'browse.php', 'search': self.url_base + 'browse.php',
'get': self.url_base + '%s'} 'get': self.url_base + '%s'}
@ -42,7 +42,6 @@ class TVChaosUKProvider(generic.TorrentProvider):
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None] self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
self.search_fallback = True self.search_fallback = True
self.cache = TVChaosUKCache(self)
def _authorised(self, **kwargs): def _authorised(self, **kwargs):
@ -92,8 +91,9 @@ class TVChaosUKProvider(generic.TorrentProvider):
info = tr.find('a', href=rc['info']) info = tr.find('a', href=rc['info'])
title = (tr.find('div', attrs={'class': 'tooltip-content'}).get_text() or info.get_text()).strip() title = (tr.find('div', attrs={'class': 'tooltip-content'}).get_text() or info.get_text()).strip()
title = re.findall('(?m)(^[^\r\n]+)', title)[0] title = re.findall('(?m)(^[^\r\n]+)', title)[0]
download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip( download_url = str(tr.find('a', href=rc['get'])['href'])
'/').replace(self.urls['config_provider_home_uri'], '') if not download_url.startswith('http'):
download_url = self.urls['get'] % download_url.lstrip('/')
except Exception: except Exception:
continue continue
@ -134,6 +134,7 @@ class TVChaosUKProvider(generic.TorrentProvider):
add_pad = re.findall('((?:19|20)\d\d\-\d\d\-\d\d)([\w\W])', title) add_pad = re.findall('((?:19|20)\d\d\-\d\d\-\d\d)([\w\W])', title)
if len(add_pad) and add_pad[0][1] not in [' ', '.']: if len(add_pad) and add_pad[0][1] not in [' ', '.']:
title = title.replace(''.join(add_pad[0]), '%s %s' % (add_pad[0][0], add_pad[0][1])) title = title.replace(''.join(add_pad[0]), '%s %s' % (add_pad[0][0], add_pad[0][1]))
title = re.sub(r'(?sim)(.*?)(?:Episode|Season).\d+.(.*)', r'\1\2', title)
if title and download_url: if title and download_url:
items[mode].append((title, download_url, seeders, self._bytesizer(size))) items[mode].append((title, download_url, seeders, self._bytesizer(size)))
@ -176,14 +177,4 @@ class TVChaosUKProvider(generic.TorrentProvider):
return 'tvchaosuk_tip' == key and 'has missing quality data so you must add quality Custom/Unknown to any wanted show' or '' return 'tvchaosuk_tip' == key and 'has missing quality data so you must add quality Custom/Unknown to any wanted show' or ''
class TVChaosUKCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
def _cache_data(self):
return self.provider.cache_data()
provider = TVChaosUKProvider() provider = TVChaosUKProvider()

View file

@ -17,7 +17,8 @@
# along with SickGear. If not, see <http://www.gnu.org/licenses/>. # along with SickGear. If not, see <http://www.gnu.org/licenses/>.
from . import generic from . import generic
from sickbeard import logger, tvcache from sickbeard import tvcache
import time
class WombleProvider(generic.NZBProvider): class WombleProvider(generic.NZBProvider):
@ -34,46 +35,23 @@ class WombleCache(tvcache.TVCache):
def __init__(self, this_provider): def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider) tvcache.TVCache.__init__(self, this_provider)
self.update_freq = 15 # cache update frequency self.update_freq = 6 # cache update frequency
def updateCache(self): def _cache_data(self):
# delete anything older then 7 days result = []
self._clearCache() for section in ['sd', 'hd', 'x264', 'dvd']:
url = '%srss/?sec=tv-%s&fr=false' % (self.provider.url, section)
if not self.shouldUpdate():
return
cl = []
data = None
for url in [self.provider.url + 'rss/?sec=tv-x264&fr=false',
self.provider.url + 'rss/?sec=tv-sd&fr=false',
self.provider.url + 'rss/?sec=tv-dvd&fr=false',
self.provider.url + 'rss/?sec=tv-hd&fr=false']:
logger.log(u'Womble\'s Index cache update URL: ' + url, logger.DEBUG)
data = self.getRSSFeed(url) data = self.getRSSFeed(url)
time.sleep(1.1)
cnt = len(result)
for entry in (data and data.get('entries', []) or []):
if entry.get('title') and entry.get('link', '').startswith('http'):
result.append((entry['title'], entry['link'], None, None))
# As long as we got something from the provider we count it as an update self.provider.log_result(count=len(result) - cnt, url=url)
if not data:
return []
# By now we know we've got data and no auth errors, all we need to do is put it in the database return result
for item in data.entries:
title, url = self._title_and_url(item)
ci = self._parseItem(title, url)
if None is not ci:
cl.append(ci)
if 0 < len(cl):
my_db = self.get_db()
my_db.mass_action(cl)
# set last updated
if data:
self.setLastUpdate()
def _checkAuth(self, *data):
return 'Invalid Link' != data[0]
provider = WombleProvider() provider = WombleProvider()

View file

@ -179,6 +179,21 @@ def snatch_episode(result, end_status=SNATCHED):
return True return True
def pass_show_wordlist_checks(name, show):
re_extras = dict(re_prefix='.*', re_suffix='.*')
result = show_name_helpers.contains_any(name, show.rls_ignore_words, **re_extras)
if None is not result and result:
logger.log(u'Ignored: %s for containing ignore word' % name)
return False
result = show_name_helpers.contains_any(name, show.rls_require_words, **re_extras)
if None is not result and not result:
logger.log(u'Ignored: %s for not containing any required word match' % name)
return False
return True
def pick_best_result(results, show, quality_list=None): def pick_best_result(results, show, quality_list=None):
logger.log(u'Picking the best result out of %s' % [x.name for x in results], logger.DEBUG) logger.log(u'Picking the best result out of %s' % [x.name for x in results], logger.DEBUG)
@ -195,15 +210,7 @@ def pick_best_result(results, show, quality_list=None):
logger.log(u'%s is an unwanted quality, rejecting it' % cur_result.name, logger.DEBUG) logger.log(u'%s is an unwanted quality, rejecting it' % cur_result.name, logger.DEBUG)
continue continue
re_extras = dict(re_prefix='.*', re_suffix='.*') if not pass_show_wordlist_checks(cur_result.name, show):
result = show_name_helpers.contains_any(cur_result.name, show.rls_ignore_words, **re_extras)
if None is not result and result:
logger.log(u'Ignored: %s for containing ignore word' % cur_result.name)
continue
result = show_name_helpers.contains_any(cur_result.name, show.rls_require_words, **re_extras)
if None is not result and not result:
logger.log(u'Ignored: %s for not containing any required word match' % cur_result.name)
continue continue
cur_size = getattr(cur_result, 'size', None) cur_size = getattr(cur_result, 'size', None)
@ -427,8 +434,11 @@ def search_for_needed_episodes(episodes):
threading.currentThread().name = orig_thread_name threading.currentThread().name = orig_thread_name
if not search_done: if not len(providers):
logger.log(u'No NZB/Torrent provider enabled to do recent searches. Please check provider options.', logger.ERROR) logger.log('No NZB/Torrent sources enabled in Search Provider options to do recent searches', logger.WARNING)
elif not search_done:
logger.log('Failed recent search of %s enabled provider%s. More info in debug log.' % (
len(providers), helpers.maybe_plural(len(providers))), logger.ERROR)
return found_results.values() return found_results.values()
@ -672,12 +682,39 @@ def search_providers(show, episodes, manual_search=False):
continue continue
# filter out possible bad torrents from providers # filter out possible bad torrents from providers
if 'torrent' == best_result.resultType and 'blackhole' != sickbeard.TORRENT_METHOD: if 'torrent' == best_result.resultType:
best_result.content = None if best_result.url.startswith('magnet'):
if not best_result.url.startswith('magnet'): if 'blackhole' != sickbeard.TORRENT_METHOD:
best_result.content = best_result.provider.get_url(best_result.url) best_result.content = None
if not best_result.content: else:
td = best_result.provider.get_url(best_result.url)
if not td:
continue continue
if getattr(best_result.provider, 'chk_td', None):
name = None
try:
hdr = re.findall('(\w+(\d+):)', td[0:6])[0]
x, v = len(hdr[0]), int(hdr[1])
for item in range(0, 12):
y = x + v
name = 'name' == td[x: y]
w = re.findall('((?:i\d+e|d|l)?(\d+):)', td[y: y + 32])[0]
x, v = y + len(w[0]), int(w[1])
if name:
name = td[x: x + v]
break
except:
continue
if name:
if not pass_show_wordlist_checks(name, show):
continue
if not show_name_helpers.pass_wordlist_checks(name):
logger.log(u'Ignored: %s (debug log has detail)' % name)
continue
best_result.name = name
if 'blackhole' != sickbeard.TORRENT_METHOD:
best_result.content = td
# add result if its not a duplicate and # add result if its not a duplicate and
found = False found = False
@ -702,8 +739,10 @@ def search_providers(show, episodes, manual_search=False):
if len(episodes) == wanted_ep_count: if len(episodes) == wanted_ep_count:
break break
if not search_done: if not len(provider_list):
logger.log(u'No NZB/Torrent providers found or enabled in the SickGear config for backlog searches. Please check your settings.', logger.log('No NZB/Torrent sources enabled in Search Provider options to do backlog searches', logger.WARNING)
logger.ERROR) elif not search_done:
logger.log('Failed backlog search of %s enabled provider%s. More info in debug log.' % (
len(provider_list), helpers.maybe_plural(len(provider_list))), logger.ERROR)
return final_results return final_results

View file

@ -18,7 +18,6 @@
from __future__ import with_statement from __future__ import with_statement
import time
import traceback import traceback
import threading import threading
import datetime import datetime
@ -288,21 +287,29 @@ class RecentSearchQueueItem(generic_queue.QueueItem):
orig_thread_name = threading.currentThread().name orig_thread_name = threading.currentThread().name
threads = [] threads = []
logger.log('Updating provider caches with recent upload data')
providers = [x for x in sickbeard.providers.sortedProviderList() if x.is_active() and x.enable_recentsearch] providers = [x for x in sickbeard.providers.sortedProviderList() if x.is_active() and x.enable_recentsearch]
for cur_provider in providers: for cur_provider in providers:
# spawn separate threads for each provider so we don't need to wait for providers with slow network operation if not cur_provider.cache.should_update():
continue
if not threads:
logger.log('Updating provider caches with recent upload data')
# spawn a thread for each provider to save time waiting for slow response providers
threads.append(threading.Thread(target=cur_provider.cache.updateCache, threads.append(threading.Thread(target=cur_provider.cache.updateCache,
name='%s :: [%s]' % (orig_thread_name, cur_provider.name))) name='%s :: [%s]' % (orig_thread_name, cur_provider.name)))
# start the thread we just created # start the thread we just created
threads[-1].start() threads[-1].start()
# wait for all threads to finish if not len(providers):
for t in threads: logger.log('No NZB/Torrent sources enabled in Search Provider options for cache update', logger.WARNING)
t.join()
logger.log('Finished updating provider caches') if threads:
# wait for all threads to finish
for t in threads:
t.join()
logger.log('Finished updating provider caches')
class ProperSearchQueueItem(generic_queue.QueueItem): class ProperSearchQueueItem(generic_queue.QueueItem):
@ -427,7 +434,7 @@ class FailedQueueItem(generic_queue.QueueItem):
history.logFailed(epObj, release, provider) history.logFailed(epObj, release, provider)
failed_history.revertEpisode(epObj) failed_history.revertEpisode(epObj)
logger.log(u'Beginning failed download search for: []' % epObj.prettyName()) logger.log(u'Beginning failed download search for: [%s]' % epObj.prettyName())
search_result = search.search_providers(self.show, self.segment, True) search_result = search.search_providers(self.show, self.segment, True)

View file

@ -32,6 +32,7 @@ from name_parser.parser import NameParser, InvalidNameException, InvalidShowExce
from sickbeard.rssfeeds import RSSFeeds from sickbeard.rssfeeds import RSSFeeds
import itertools import itertools
class CacheDBConnection(db.DBConnection): class CacheDBConnection(db.DBConnection):
def __init__(self, providerName): def __init__(self, providerName):
db.DBConnection.__init__(self, 'cache.db') db.DBConnection.__init__(self, 'cache.db')
@ -44,6 +45,7 @@ class CacheDBConnection(db.DBConnection):
if str(e) != 'table lastUpdate already exists': if str(e) != 'table lastUpdate already exists':
raise raise
class TVCache: class TVCache:
def __init__(self, provider): def __init__(self, provider):
@ -56,7 +58,7 @@ class TVCache:
return CacheDBConnection(self.providerID) return CacheDBConnection(self.providerID)
def _clearCache(self): def _clearCache(self):
if self.shouldClearCache(): if self.should_clear_cache():
myDB = self.get_db() myDB = self.get_db()
myDB.action('DELETE FROM provider_cache WHERE provider = ?', [self.providerID]) myDB.action('DELETE FROM provider_cache WHERE provider = ?', [self.providerID])
@ -81,21 +83,16 @@ class TVCache:
logger.log(u'Authentication error: ' + ex(e), logger.ERROR) logger.log(u'Authentication error: ' + ex(e), logger.ERROR)
return [] return []
if self.shouldUpdate(): if self.should_update():
# as long as the http request worked we count this as an update
data = self._cache_data() data = self._cache_data()
if not data:
return []
# clear cache # clear cache
self._clearCache() if data:
self._clearCache()
# set updated
self.setLastUpdate()
# parse data # parse data
cl = [] cl = []
for item in data: for item in data or []:
title, url = self._title_and_url(item) title, url = self._title_and_url(item)
ci = self._parseItem(title, url) ci = self._parseItem(title, url)
if ci is not None: if ci is not None:
@ -105,6 +102,9 @@ class TVCache:
myDB = self.get_db() myDB = self.get_db()
myDB.mass_action(cl) myDB.mass_action(cl)
# set updated as time the attempt to fetch data is
self.setLastUpdate()
return [] return []
def getRSSFeed(self, url, **kwargs): def getRSSFeed(self, url, **kwargs):
@ -180,21 +180,13 @@ class TVCache:
lastUpdate = property(_getLastUpdate) lastUpdate = property(_getLastUpdate)
lastSearch = property(_getLastSearch) lastSearch = property(_getLastSearch)
def shouldUpdate(self): def should_update(self):
# if we've updated recently then skip the update # if we've updated recently then skip the update
if datetime.datetime.today() - self.lastUpdate < datetime.timedelta(minutes=self.update_freq): return datetime.datetime.today() - self.lastUpdate >= datetime.timedelta(minutes=self.update_freq)
logger.log(u'Last update was too soon, using old cache: today()-' + str(self.lastUpdate) + '<' + str(
datetime.timedelta(minutes=self.update_freq)), logger.DEBUG)
return False
return True def should_clear_cache(self):
def shouldClearCache(self):
# if recent search hasn't used our previous results yet then don't clear the cache # if recent search hasn't used our previous results yet then don't clear the cache
if self.lastUpdate > self.lastSearch: return self.lastSearch >= self.lastUpdate
return False
return True
def add_cache_entry(self, name, url, parse_result=None, indexer_id=0): def add_cache_entry(self, name, url, parse_result=None, indexer_id=0):

View file

@ -4662,10 +4662,7 @@ class ConfigProviders(Config):
providerDict[name].key = key providerDict[name].key = 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 key == '0': providerDict[name].needs_auth = '0' != key
providerDict[name].needs_auth = False
else:
providerDict[name].needs_auth = True
return providerDict[name].get_id() + '|' + providerDict[name].config_str() return providerDict[name].get_id() + '|' + providerDict[name].config_str()
@ -4767,16 +4764,11 @@ class ConfigProviders(Config):
def saveProviders(self, newznab_string='', torrentrss_string='', provider_order=None, **kwargs): def saveProviders(self, newznab_string='', torrentrss_string='', provider_order=None, **kwargs):
results = [] results = []
provider_str_list = provider_order.split()
provider_list = [] provider_list = []
newznabProviderDict = dict( # add all the newznab info we have into our list
zip([x.get_id() for x in sickbeard.newznabProviderList], sickbeard.newznabProviderList)) newznab_sources = dict(zip([x.get_id() for x in sickbeard.newznabProviderList], sickbeard.newznabProviderList))
active_ids = []
finishedNames = []
# add all the newznab info we got into our list
if newznab_string: if newznab_string:
for curNewznabProviderStr in newznab_string.split('!!!'): for curNewznabProviderStr in newznab_string.split('!!!'):
@ -4789,282 +4781,157 @@ class ConfigProviders(Config):
if starify(cur_key, True): if starify(cur_key, True):
cur_key = '' cur_key = ''
newProvider = newznab.NewznabProvider(cur_name, cur_url, key=cur_key) new_provider = newznab.NewznabProvider(cur_name, cur_url, key=cur_key)
cur_id = newProvider.get_id() cur_id = new_provider.get_id()
# if it already exists then update it # if it already exists then update it
if cur_id in newznabProviderDict: if cur_id in newznab_sources:
newznabProviderDict[cur_id].name = cur_name nzb_src = newznab_sources[cur_id]
newznabProviderDict[cur_id].url = cur_url
nzb_src.name, nzb_src.url, nzb_src.cat_ids = cur_name, cur_url, cur_cat
if cur_key: if cur_key:
newznabProviderDict[cur_id].key = cur_key nzb_src.key = cur_key
newznabProviderDict[cur_id].cat_ids = cur_cat
# 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': nzb_src.needs_auth = '0' != cur_key
newznabProviderDict[cur_id].needs_auth = False
else:
newznabProviderDict[cur_id].needs_auth = True
try: attr = 'search_mode'
newznabProviderDict[cur_id].search_mode = str(kwargs[cur_id + '_search_mode']).strip() if cur_id + '_' + attr in kwargs:
except: setattr(nzb_src, attr, str(kwargs.get(cur_id + '_' + attr)).strip())
pass
try: for attr in ['search_fallback', 'enable_recentsearch', 'enable_backlog']:
newznabProviderDict[cur_id].search_fallback = config.checkbox_to_value( setattr(nzb_src, attr, config.checkbox_to_value(kwargs.get(cur_id + '_' + attr)))
kwargs[cur_id + '_search_fallback'])
except:
newznabProviderDict[cur_id].search_fallback = 0
try:
newznabProviderDict[cur_id].enable_recentsearch = config.checkbox_to_value(
kwargs[cur_id + '_enable_recentsearch'])
except:
newznabProviderDict[cur_id].enable_recentsearch = 0
try:
newznabProviderDict[cur_id].enable_backlog = config.checkbox_to_value(
kwargs[cur_id + '_enable_backlog'])
except:
newznabProviderDict[cur_id].enable_backlog = 0
else: else:
sickbeard.newznabProviderList.append(newProvider) sickbeard.newznabProviderList.append(new_provider)
finishedNames.append(cur_id) active_ids.append(cur_id)
# delete anything that is missing # delete anything that is missing
for curProvider in sickbeard.newznabProviderList: for source in [x for x in sickbeard.newznabProviderList if x.get_id() not in active_ids]:
if curProvider.get_id() not in finishedNames: sickbeard.newznabProviderList.remove(source)
sickbeard.newznabProviderList.remove(curProvider)
torrentRssProviderDict = dict(
zip([x.get_id() for x in sickbeard.torrentRssProviderList], sickbeard.torrentRssProviderList))
finishedNames = []
# add all the torrent RSS info we have into our list
torrent_rss_sources = dict(zip([x.get_id() for x in sickbeard.torrentRssProviderList],
sickbeard.torrentRssProviderList))
active_ids = []
if torrentrss_string: if torrentrss_string:
for curTorrentRssProviderStr in torrentrss_string.split('!!!'): for curTorrentRssProviderStr in torrentrss_string.split('!!!'):
if not curTorrentRssProviderStr: if not curTorrentRssProviderStr:
continue continue
curName, curURL, curCookies = curTorrentRssProviderStr.split('|') cur_name, cur_url, cur_cookies = curTorrentRssProviderStr.split('|')
curURL = config.clean_url(curURL, False) cur_url = config.clean_url(cur_url, False)
if starify(curCookies, True): if starify(cur_cookies, True):
curCookies = '' cur_cookies = ''
newProvider = rsstorrent.TorrentRssProvider(curName, curURL, curCookies) new_provider = rsstorrent.TorrentRssProvider(cur_name, cur_url, cur_cookies)
curID = newProvider.get_id() cur_id = new_provider.get_id()
# if it already exists then update it # if it already exists then update it
if curID in torrentRssProviderDict: if cur_id in torrent_rss_sources:
torrentRssProviderDict[curID].name = curName torrent_rss_sources[cur_id].name = cur_name
torrentRssProviderDict[curID].url = curURL torrent_rss_sources[cur_id].url = cur_url
if curCookies: if cur_cookies:
torrentRssProviderDict[curID].cookies = curCookies torrent_rss_sources[cur_id].cookies = cur_cookies
else: else:
sickbeard.torrentRssProviderList.append(newProvider) sickbeard.torrentRssProviderList.append(new_provider)
finishedNames.append(curID) active_ids.append(cur_id)
# delete anything that is missing # delete anything that is missing
for curProvider in sickbeard.torrentRssProviderList: for source in [x for x in sickbeard.torrentRssProviderList if x.get_id() not in active_ids]:
if curProvider.get_id() not in finishedNames: sickbeard.torrentRssProviderList.remove(source)
sickbeard.torrentRssProviderList.remove(curProvider)
# do the enable/disable # enable/disable states of source providers
for curProviderStr in provider_str_list: provider_str_list = provider_order.split()
curProvider, curEnabled = curProviderStr.split(':') sources = dict(zip([x.get_id() for x in sickbeard.providers.sortedProviderList()],
curEnabled = config.to_int(curEnabled) sickbeard.providers.sortedProviderList()))
for cur_src_str in provider_str_list:
src_name, src_enabled = cur_src_str.split(':')
curProvObj = [x for x in sickbeard.providers.sortedProviderList() if provider_list.append(src_name)
x.get_id() == curProvider and hasattr(x, 'enabled')] src_enabled = bool(config.to_int(src_enabled))
if curProvObj:
curProvObj[0].enabled = bool(curEnabled)
provider_list.append(curProvider) if src_name in sources and hasattr(sources[src_name], 'enabled'):
if curProvider in newznabProviderDict: sources[src_name].enabled = src_enabled
newznabProviderDict[curProvider].enabled = bool(curEnabled)
elif curProvider in torrentRssProviderDict:
torrentRssProviderDict[curProvider].enabled = bool(curEnabled)
# dynamically load provider settings if src_name in newznab_sources:
for curTorrentProvider in [curProvider for curProvider in sickbeard.providers.sortedProviderList() if newznab_sources[src_name].enabled = src_enabled
curProvider.providerType == sickbeard.GenericProvider.TORRENT]: elif src_name in torrent_rss_sources:
torrent_rss_sources[src_name].enabled = src_enabled
if hasattr(curTorrentProvider, '_seed_ratio'): # update torrent source settings
try: for torrent_src in [src for src in sickbeard.providers.sortedProviderList()
curTorrentProvider._seed_ratio = str(kwargs[curTorrentProvider.get_id() + '_ratio']).strip() if sickbeard.GenericProvider.TORRENT == src.providerType]:
except: src_id_prefix = torrent_src.get_id() + '_'
curTorrentProvider._seed_ratio = None
if hasattr(curTorrentProvider, 'seed_time') and curTorrentProvider.get_id() + '_seed_time' in kwargs: attr = 'url_edit'
curTorrentProvider.seed_time = config.to_int(str(kwargs[curTorrentProvider.get_id() + '_seed_time']).strip(), 0) if getattr(torrent_src, attr, None):
url_edit = ','.join(set(['%s' % url.strip() for url in kwargs.get(
src_id_prefix + attr, '').split(',')]))
torrent_src.url_home = ([url_edit], [])[not url_edit]
if hasattr(curTorrentProvider, 'minseed'): for attr in [x for x in ['username', 'uid'] if hasattr(torrent_src, x)]:
try: setattr(torrent_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip())
curTorrentProvider.minseed = int(str(kwargs[curTorrentProvider.get_id() + '_minseed']).strip())
except:
curTorrentProvider.minseed = 0
if hasattr(curTorrentProvider, 'minleech'): for attr in [x for x in ['password', 'api_key', 'passkey', 'digest', 'hash'] if hasattr(torrent_src, x)]:
try: key = str(kwargs.get(src_id_prefix + attr, '')).strip()
curTorrentProvider.minleech = int(str(kwargs[curTorrentProvider.get_id() + '_minleech']).strip()) if 'password' == attr:
except: set('*') != set(key) and setattr(torrent_src, attr, key)
curTorrentProvider.minleech = 0 elif not starify(key, True):
setattr(torrent_src, attr, key)
if hasattr(curTorrentProvider, 'digest'): attr = 'ratio'
try: if hasattr(torrent_src, '_seed_' + attr):
key = str(kwargs[curTorrentProvider.get_id() + '_digest']).strip() setattr(torrent_src, '_seed_' + attr, kwargs.get(src_id_prefix + attr, '').strip() or None)
if not starify(key, True):
curTorrentProvider.digest = key
except:
curTorrentProvider.digest = None
if hasattr(curTorrentProvider, 'hash'): for attr in [x for x in ['minseed', 'minleech'] if hasattr(torrent_src, x)]:
try: setattr(torrent_src, attr, config.to_int(str(kwargs.get(src_id_prefix + attr)).strip()))
key = str(kwargs[curTorrentProvider.get_id() + '_hash']).strip()
if not starify(key, True):
curTorrentProvider.hash = key
except:
curTorrentProvider.hash = None
if hasattr(curTorrentProvider, 'api_key'): for attr in [x for x in ['confirmed', 'freeleech', 'reject_m2ts', 'enable_recentsearch',
try: 'enable_backlog', 'search_fallback'] if hasattr(torrent_src, x)]:
key = str(kwargs[curTorrentProvider.get_id() + '_api_key']).strip() setattr(torrent_src, attr, config.checkbox_to_value(kwargs.get(src_id_prefix + attr)))
if not starify(key, True):
curTorrentProvider.api_key = key
except:
curTorrentProvider.api_key = None
if hasattr(curTorrentProvider, 'username'): attr = 'seed_time'
try: if hasattr(torrent_src, attr) and src_id_prefix + attr in kwargs:
curTorrentProvider.username = str(kwargs[curTorrentProvider.get_id() + '_username']).strip() setattr(torrent_src, attr, config.to_int(str(kwargs.get(src_id_prefix + attr)).strip()))
except:
curTorrentProvider.username = None
if hasattr(curTorrentProvider, 'password'): attr = 'search_mode'
try: if hasattr(torrent_src, attr):
key = str(kwargs[curTorrentProvider.get_id() + '_password']).strip() setattr(torrent_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip() or 'eponly')
if set('*') != set(key):
curTorrentProvider.password = key
except:
curTorrentProvider.password = None
if hasattr(curTorrentProvider, 'passkey'): # update nzb source settings
try: for nzb_src in [src for src in sickbeard.providers.sortedProviderList() if
key = str(kwargs[curTorrentProvider.get_id() + '_passkey']).strip() sickbeard.GenericProvider.NZB == src.providerType]:
if not starify(key, True): src_id_prefix = nzb_src.get_id() + '_'
curTorrentProvider.passkey = key
except:
curTorrentProvider.passkey = None
if hasattr(curTorrentProvider, 'confirmed'): attr = 'api_key'
try: if hasattr(nzb_src, attr):
curTorrentProvider.confirmed = config.checkbox_to_value( key = str(kwargs.get(src_id_prefix + attr, '')).strip()
kwargs[curTorrentProvider.get_id() + '_confirmed']) if not starify(key, True):
except: setattr(nzb_src, attr, key)
curTorrentProvider.confirmed = 0
if hasattr(curTorrentProvider, 'proxy'): attr = 'username'
try: if hasattr(nzb_src, attr):
curTorrentProvider.proxy.enabled = config.checkbox_to_value( setattr(nzb_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip() or None)
kwargs[curTorrentProvider.get_id() + '_proxy'])
except:
curTorrentProvider.proxy.enabled = 0
if hasattr(curTorrentProvider.proxy, 'url'): attr = 'search_mode'
try: if hasattr(nzb_src, attr):
curTorrentProvider.proxy.url = str(kwargs[curTorrentProvider.get_id() + '_proxy_url']).strip() setattr(nzb_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip() or 'eponly')
except:
curTorrentProvider.proxy.url = None
if hasattr(curTorrentProvider, 'freeleech'): attr = 'enable_recentsearch'
try: if hasattr(nzb_src, attr):
curTorrentProvider.freeleech = config.checkbox_to_value( setattr(nzb_src, attr, config.checkbox_to_value(kwargs.get(src_id_prefix + attr)) or
kwargs[curTorrentProvider.get_id() + '_freeleech']) not getattr(nzb_src, 'supports_backlog', True))
except:
curTorrentProvider.freeleech = 0
if hasattr(curTorrentProvider, 'reject_m2ts'): for attr in [x for x in ['search_fallback', 'enable_backlog'] if hasattr(nzb_src, x)]:
try: setattr(nzb_src, attr, config.checkbox_to_value(kwargs.get(src_id_prefix + attr)))
curTorrentProvider.reject_m2ts = config.checkbox_to_value(
kwargs[curTorrentProvider.get_id() + '_reject_m2ts'])
except:
curTorrentProvider.reject_m2ts = 0
if hasattr(curTorrentProvider, 'search_mode'):
try:
curTorrentProvider.search_mode = str(kwargs[curTorrentProvider.get_id() + '_search_mode']).strip()
except:
curTorrentProvider.search_mode = 'eponly'
if hasattr(curTorrentProvider, 'search_fallback'):
try:
curTorrentProvider.search_fallback = config.checkbox_to_value(
kwargs[curTorrentProvider.get_id() + '_search_fallback'])
except:
curTorrentProvider.search_fallback = 0 # these exceptions are catching unselected checkboxes
if hasattr(curTorrentProvider, 'enable_recentsearch'):
try:
curTorrentProvider.enable_recentsearch = config.checkbox_to_value(
kwargs[curTorrentProvider.get_id() + '_enable_recentsearch'])
except:
curTorrentProvider.enable_recentsearch = 0 # these exceptions are actually catching unselected checkboxes
if hasattr(curTorrentProvider, 'enable_backlog'):
try:
curTorrentProvider.enable_backlog = config.checkbox_to_value(
kwargs[curTorrentProvider.get_id() + '_enable_backlog'])
except:
curTorrentProvider.enable_backlog = 0 # these exceptions are actually catching unselected checkboxes
for curNzbProvider in [curProvider for curProvider in sickbeard.providers.sortedProviderList() if
curProvider.providerType == sickbeard.GenericProvider.NZB]:
if hasattr(curNzbProvider, 'api_key'):
try:
key = str(kwargs[curNzbProvider.get_id() + '_api_key']).strip()
if not starify(key, True):
curNzbProvider.api_key = key
except:
curNzbProvider.api_key = None
if hasattr(curNzbProvider, 'username'):
try:
curNzbProvider.username = str(kwargs[curNzbProvider.get_id() + '_username']).strip()
except:
curNzbProvider.username = None
if hasattr(curNzbProvider, 'search_mode'):
try:
curNzbProvider.search_mode = str(kwargs[curNzbProvider.get_id() + '_search_mode']).strip()
except:
curNzbProvider.search_mode = 'eponly'
if hasattr(curNzbProvider, 'search_fallback'):
try:
curNzbProvider.search_fallback = config.checkbox_to_value(
kwargs[curNzbProvider.get_id() + '_search_fallback'])
except:
curNzbProvider.search_fallback = 0 # these exceptions are actually catching unselected checkboxes
if hasattr(curNzbProvider, 'enable_recentsearch'):
try:
curNzbProvider.enable_recentsearch = config.checkbox_to_value(
kwargs[curNzbProvider.get_id() + '_enable_recentsearch'])
except:
curNzbProvider.enable_recentsearch = 0 # these exceptions are actually catching unselected checkboxes
if hasattr(curNzbProvider, 'enable_backlog'):
try:
curNzbProvider.enable_backlog = config.checkbox_to_value(
kwargs[curNzbProvider.get_id() + '_enable_backlog'])
except:
curNzbProvider.enable_backlog = 0 # these exceptions are actually catching unselected checkboxes
sickbeard.NEWZNAB_DATA = '!!!'.join([x.config_str() for x in sickbeard.newznabProviderList]) sickbeard.NEWZNAB_DATA = '!!!'.join([x.config_str() for x in sickbeard.newznabProviderList])
sickbeard.PROVIDER_ORDER = provider_list sickbeard.PROVIDER_ORDER = provider_list
@ -5073,11 +4940,10 @@ class ConfigProviders(Config):
sickbeard.save_config() sickbeard.save_config()
if len(results) > 0: if 0 < len(results):
for x in results: for x in results:
logger.log(x, logger.ERROR) logger.log(x, logger.ERROR)
ui.notifications.error('Error(s) Saving Configuration', ui.notifications.error('Error(s) Saving Configuration', '<br />\n'.join(results))
'<br />\n'.join(results))
else: else:
ui.notifications.message('Configuration Saved', ek.ek(os.path.join, sickbeard.CONFIG_FILE)) ui.notifications.message('Configuration Saved', ek.ek(os.path.join, sickbeard.CONFIG_FILE))