Merge pull request #673 from JackDandy/feature/ChangeValidateProv

Change validate and improve specific Torrent provider connections…
This commit is contained in:
JackDandy 2016-06-08 01:57:32 +01:00
commit c88e998b5d
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 include OSError system messages in file system failure logs during post process
* 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)

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' %>;
#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
@ -47,9 +47,9 @@
#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
@ -98,20 +98,20 @@
<ul id="provider_order_list" class="provider_order_panel">
#for $curProvider in $sickbeard.providers.sortedProviderList()
#if $curProvider.providerType == $GenericProvider.NZB and not $sickbeard.USE_NZBS
#continue
#elif $curProvider.providerType == $GenericProvider.TORRENT and not $sickbeard.USE_TORRENTS
#continue
#end if
#set $curName = $curProvider.get_id()
<li class="ui-state-default" id="$curName">
<input type="checkbox" id="enable_$curName" class="provider_enabler" <%= html_checked if curProvider.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>
<span style="vertical-align:middle">$curProvider.name</span>
<%= '*' if not curProvider.supportsBacklog else '' %>
<span class="ui-icon ui-icon-arrowthick-2-n-s pull-right" style="margin-top:3px"></span>
</li>
#for $cur_provider in [$x for $x in $sickbeard.providers.sortedProviderList()
if $x.providerType == $GenericProvider.NZB and $sickbeard.USE_NZBS or
$x.providerType == $GenericProvider.TORRENT and $sickbeard.USE_TORRENTS]
#set $cur_name = $cur_provider.get_id()
#set $cur_url = $cur_provider.url
#set $tip = ($cur_provider.name, 'Site Down')[not $cur_url]
#set $state = ('', ' <span class="red-text">(Site Down?)</span>')[not $cur_url]
<li class="ui-state-default" id="$cur_name">
<input type="checkbox" id="enable_$cur_name" class="provider_enabler" <%= html_checked if cur_provider.is_enabled() else '' %>/>
<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">$cur_provider.name$state</span>
<%= '*' if not cur_provider.supports_backlog else '' %>
<span class="ui-icon ui-icon-arrowthick-2-n-s pull-right" style="margin-top:3px"></span>
</li>
#end for
</ul>
@ -150,16 +150,13 @@
<span class="component-desc">
#set $provider_config_list_enabled = []
#set $provider_config_list = []
#for $curProvider in $sickbeard.providers.sortedProviderList()
#if $curProvider.providerType == $GenericProvider.NZB and not $sickbeard.USE_NZBS
#continue
#elif $curProvider.providerType == $GenericProvider.TORRENT and not $sickbeard.USE_TORRENTS
#continue
#end if
#if $curProvider.is_enabled()
$provider_config_list_enabled.append($curProvider)
#for $cur_provider in [$x for $x in $sickbeard.providers.sortedProviderList()
if $x.providerType == $GenericProvider.NZB and $sickbeard.USE_NZBS or
$x.providerType == $GenericProvider.TORRENT and $sickbeard.USE_TORRENTS]
#if $cur_provider.is_enabled()
$provider_config_list_enabled.append($cur_provider)
#else
$provider_config_list.append($curProvider)
$provider_config_list.append($cur_provider)
#end if
#end for
@ -188,71 +185,71 @@
</div>
<!-- start div for editing providers //-->
#for $curNewznabProvider in [$curProvider for $curProvider in $sickbeard.newznabProviderList]
<div class="providerDiv" id="${curNewznabProvider.get_id()}Div">
#if $curNewznabProvider.default and $curNewznabProvider.needs_auth
#for $cur_newznab_provider in [$cur_provider for $cur_provider in $sickbeard.newznabProviderList]
<div class="providerDiv" id="${cur_newznab_provider.get_id()}Div">
#if $cur_newznab_provider.default and $cur_newznab_provider.needs_auth
<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-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>
</label>
</div>
<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-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>
</span>
</label>
</div>
#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">
<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-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>
</span>
</label>
</div>
#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">
<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-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>
</span>
</label>
</div>
#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">
<span class="component-title">Season search mode</span>
<span class="component-title">Episode search mode</span>
<span class="component-desc">
<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>
<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>
<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>
</div>
#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">
<label for="${curNewznabProvider.get_id()}_search_fallback">
<span class="component-title">Season search fallback</span>
<label for="${cur_newznab_provider.get_id()}_search_fallback">
<span class="component-title">Episode search fallback</span>
<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 '' %>/>
<p>run the alternate season search mode when a complete season is not found</p>
<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>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>
</label>
</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]:
<div class="providerDiv" id="${curNzbProvider.get_id()}Div">
#if $hasattr($curNzbProvider, 'username'):
#for $cur_nzb_provider in [$cur_provider for $cur_provider in $sickbeard.providers.sortedProviderList()
if $cur_provider.providerType == $GenericProvider.NZB and $cur_provider not in $sickbeard.newznabProviderList]:
<div class="providerDiv" id="${cur_nzb_provider.get_id()}Div">
#if $hasattr($cur_nzb_provider, 'username'):
<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-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>
</label>
</div>
#end if
#if $hasattr($curNzbProvider, 'api_key'):
#if $hasattr($cur_nzb_provider, 'api_key'):
<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-desc">
#set $field_name = curNzbProvider.get_id() + '_api_key'
<input type="text" name="$field_name" value="<%= starify(curNzbProvider.api_key) %>" class="form-control input-sm input350" />
#if callable(getattr(curNzbProvider, 'ui_string', None))
<div class="clear-left"><p>${curNzbProvider.ui_string($field_name)}</p></div>
#set $field_name = cur_nzb_provider.get_id() + '_api_key'
<input type="text" name="$field_name" value="<%= starify(cur_nzb_provider.api_key) %>" class="form-control input-sm input350" />
#if callable(getattr(cur_nzb_provider, 'ui_string', None))
<div class="clear-left"><p>${cur_nzb_provider.ui_string($field_name)}</p></div>
#end if
</span>
</label>
</div>
#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">
<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-desc">
<input type="checkbox" name="${curNzbProvider.get_id()}_enable_recentsearch" id="${curNzbProvider.get_id()}_enable_recentsearch" <%= html_checked if curNzbProvider.enable_recentsearch else '' %>/>
<p>enable provider to perform recent searches.</p>
<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>
</span>
</label>
</div>
#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">
<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-desc">
<input type="checkbox" name="${curNzbProvider.get_id()}_enable_backlog" id="${curNzbProvider.get_id()}_enable_backlog" <%= html_checked if curNzbProvider.enable_backlog else '' %>/>
<p>enable provider to perform backlog searches.</p>
<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>
</span>
</label>
</div>
#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">
<span class="component-title">Season search mode</span>
<span class="component-title">Episode search mode</span>
<span class="component-desc">
<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>
<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>
<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>
</div>
#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">
<label for="${curNzbProvider.get_id()}_search_fallback">
<span class="component-title">Season search fallback</span>
<label for="${cur_nzb_provider.get_id()}_search_fallback">
<span class="component-title">Episode search fallback</span>
<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 '' %>/>
<p>run the alternate season search mode when a complete season is not found</p>
<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>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>
</label>
</div>
#end if
#if not $curNzbProvider.supportsBacklog:
#if not $cur_nzb_provider.supports_backlog:
<div class="field-pair">
<span class="component-desc">The latest releases are the focus of this provider, no backlog searching</span>
</div>
@ -345,233 +343,229 @@
##
##
#for $curTorrentProvider in [$curProvider for $curProvider in $sickbeard.providers.sortedProviderList() if $curProvider.providerType == $GenericProvider.TORRENT]:
<div class="providerDiv" id="${curTorrentProvider.get_id()}Div">
#if callable(getattr(curTorrentProvider, 'ui_string', None))
#set $field_name = curTorrentProvider.get_id() + '_tip'
#set $tip_text = curTorrentProvider.ui_string($field_name)
#for $cur_torrent_provider in [$cur_provider for $cur_provider in $sickbeard.providers.sortedProviderList()
if $cur_provider.providerType == $GenericProvider.TORRENT]:
<div class="providerDiv" id="${cur_torrent_provider.get_id()}Div">
#if callable(getattr(cur_torrent_provider, 'ui_string', None))
#set $field_name = cur_torrent_provider.get_id() + '_tip'
#set $tip_text = cur_torrent_provider.ui_string($field_name)
#if $tip_text
<div class="field-pair">
<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>
</div>
#end if
#end if
#if $hasattr($curTorrentProvider, 'api_key'):
#if $getattr($cur_torrent_provider, 'url_edit', None):
<div class="field-pair">
<label for="${curTorrentProvider.get_id()}_api_key">
<span class="component-title">Api key:</span>
<label for="url_base">
#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">
<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" />
</span>
</label>
</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>
#set $field_name = cur_torrent_provider.get_id() + '_url_edit'
<input type="text" name="$field_name" id="$field_name" value="<%= ', '.join(cur_torrent_provider.url_home) %>" 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($curTorrentProvider, 'hash'):
#if $hasattr($cur_torrent_provider, 'api_key'):
<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-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>
</label>
</div>
#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">
<label for="${curTorrentProvider.get_id()}_username">
<span class="component-title">Username:</span>
<label for="$prov_type">
<span class="component-title">$user_type.capitalize():</span>
<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>
</label>
</div>
#end if
#if $hasattr($curTorrentProvider, 'password'):
#break
#end if
#end for
#if $hasattr($cur_torrent_provider, 'password'):
<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-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>
</label>
</div>
#end if
#if $hasattr($curTorrentProvider, 'passkey'):
#if $hasattr($cur_torrent_provider, 'passkey'):
<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-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>
</label>
</div>
#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'}
<div class="field-pair">
<label for="${curTorrentProvider.get_id()}_ratio">
<span class="component-title" id="${curTorrentProvider.get_id()}_ratio_desc">Seed until ratio (the goal)</span>
<label for="${cur_torrent_provider.get_id()}_ratio">
<span class="component-title" id="${cur_torrent_provider.get_id()}_ratio_desc">Seed until ratio (the goal)</span>
<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>
<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>
</label>
</div>
#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 $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">
<label for="${curTorrentProvider.get_id()}_seed_time">
<span class="component-title" id="${curTorrentProvider.get_id()}_seed_time_desc">Seed time (provider default)</span>
<label for="${cur_torrent_provider.get_id()}_seed_time">
<span class="component-title" id="${cur_torrent_provider.get_id()}_seed_time_desc">Seed time (provider default)</span>
<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>
<div class="clear-left"><p>(leave blank $use_default)</p></div>
</span>
</label>
</div>
#end if
#if $hasattr($curTorrentProvider, 'minseed'):
#if $hasattr($cur_torrent_provider, 'minseed'):
<div class="field-pair">
<label for="${curTorrentProvider.get_id()}_minseed">
<span class="component-title" id="${curTorrentProvider.get_id()}_minseed_desc">Minimum seeders</span>
<label for="${cur_torrent_provider.get_id()}_minseed">
<span class="component-title" id="${cur_torrent_provider.get_id()}_minseed_desc">Minimum seeders</span>
<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>
</span>
</label>
</div>
#end if
#if $hasattr($curTorrentProvider, 'minleech'):
#if $hasattr($cur_torrent_provider, 'minleech'):
<div class="field-pair">
<label for="${curTorrentProvider.get_id()}_minleech">
<span class="component-title" id="${curTorrentProvider.get_id()}_minleech_desc">Minimum leechers</span>
<label for="${cur_torrent_provider.get_id()}_minleech">
<span class="component-title" id="${cur_torrent_provider.get_id()}_minleech_desc">Minimum leechers</span>
<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>
</span>
</label>
</div>
#end if
#if $hasattr($curTorrentProvider, 'proxy'):
#if $hasattr($cur_torrent_provider, 'confirmed'):
<div class="field-pair">
<label for="${curTorrentProvider.get_id()}_proxy">
<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">
<label for="${cur_torrent_provider.get_id()}_confirmed">
<span class="component-title">Confirmed download</span>
<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>
</span>
</label>
</div>
#end if
#if $hasattr($curTorrentProvider, 'freeleech'):
#if $hasattr($cur_torrent_provider, 'freeleech'):
<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-desc">
<input type="checkbox" name="${curTorrentProvider.get_id()}_freeleech" id="${curTorrentProvider.get_id()}_freeleech" <%= html_checked if curTorrentProvider.freeleech else '' %>/>
<p>only download <b>[FreeLeech]</b> torrents.</p>
<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>
</span>
</label>
</div>
#end if
#if $hasattr($curTorrentProvider, 'reject_m2ts'):
#if $hasattr($cur_torrent_provider, 'reject_m2ts'):
<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-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>
</span>
</label>
</div>
#end if
#if $hasattr($curTorrentProvider, 'enable_recentsearch') and $curTorrentProvider.supportsBacklog:
#if $hasattr($cur_torrent_provider, 'enable_recentsearch'):
<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-desc">
<input type="checkbox" name="${curTorrentProvider.get_id()}_enable_recentsearch" id="${curTorrentProvider.get_id()}_enable_recentsearch" <%= html_checked if curTorrentProvider.enable_recentsearch else '' %>/>
<p>enable provider to perform recent searches.</p>
<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>
</span>
</label>
</div>
#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">
<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-desc">
<input type="checkbox" name="${curTorrentProvider.get_id()}_enable_backlog" id="${curTorrentProvider.get_id()}_enable_backlog" <%= html_checked if curTorrentProvider.enable_backlog else '' %>/>
<p>enable provider to perform backlog searches.</p>
<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>
</span>
</label>
</div>
#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">
<span class="component-title">Season search mode</span>
<span class="component-title">Episode search mode</span>
<span class="component-desc">
<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>
<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>
<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>
</div>
#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">
<label for="${curTorrentProvider.get_id()}_search_fallback">
<span class="component-title">Season search fallback</span>
<label for="${cur_torrent_provider.get_id()}_search_fallback">
<span class="component-title">Episode search fallback</span>
<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 '' %>/>
<p>run the alternate season search mode when a complete season is not found</p>
<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>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>
</label>
</div>

View file

@ -73,6 +73,7 @@
<span class="component-desc">
<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><em class="grey-text">enter 4489 for experimental internal provider frequencies</em></p>
</span>
</label>
</div>

View file

@ -30,6 +30,7 @@ from threading import Lock
import sys
import os.path
import uuid
import ast
import base64
sys.path.insert(1, os.path.abspath('../lib'))
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_NAME = 'SickGear'
PROVIDER_ORDER = []
PROVIDER_HOMES = {}
NAMING_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, \
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, \
RENAME_EPISODES, AIRDATE_EPISODES, properFinderScheduler, PROVIDER_ORDER, autoPostProcesserScheduler, \
RENAME_EPISODES, AIRDATE_EPISODES, properFinderScheduler, PROVIDER_ORDER, PROVIDER_HOMES, autoPostProcesserScheduler, \
providerList, newznabProviderList, torrentRssProviderList, \
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, \
@ -580,10 +582,6 @@ def initialize(consoleLogging=True):
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
if not os.path.isabs(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))
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_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_uc = torrent_prov.get_id().upper()
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'):
torrent_prov.api_key = check_setting_str(CFG, prov_id_uc, prov_id + '_api_key', '')
if hasattr(torrent_prov, 'hash'):
torrent_prov.hash = check_setting_str(CFG, prov_id_uc, prov_id + '_hash', '')
if hasattr(torrent_prov, 'digest'):
torrent_prov.digest = check_setting_str(CFG, prov_id_uc, prov_id + '_digest', '')
if hasattr(torrent_prov, 'username'):
torrent_prov.username = check_setting_str(CFG, prov_id_uc, prov_id + '_username', '')
for user_type in ['username', 'uid']:
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'):
torrent_prov.password = check_setting_str(CFG, prov_id_uc, prov_id + '_password', '')
if hasattr(torrent_prov, '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'):
torrent_prov.confirmed = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_confirmed', 0))
if hasattr(torrent_prov, 'options'):
torrent_prov.options = check_setting_str(CFG, prov_id_uc, prov_id + '_options', '')
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'):
torrent_prov.seed_time = check_setting_int(CFG, prov_id_uc, prov_id + '_seed_time', '')
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))
if hasattr(nzb_prov, 'enable_recentsearch'):
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'):
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),
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(),
cycleTime=update_interval,
threadName='RECENTSEARCHER',
@ -1457,6 +1457,7 @@ def save_config():
new_config['General']['anime_default'] = int(ANIME_DEFAULT)
new_config['General']['scene_default'] = int(SCENE_DEFAULT)
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']['auto_update'] = int(AUTO_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']['torrent_dir'] = TORRENT_DIR
# dynamically save provider settings
for torrent_prov in [curProvider for curProvider in providers.sortedProviderList()
if GenericProvider.TORRENT == curProvider.providerType]:
prov_id = torrent_prov.get_id()
prov_id_uc = torrent_prov.get_id().upper()
new_config[prov_id_uc] = {}
new_config[prov_id_uc][prov_id] = int(torrent_prov.enabled)
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 src in [x for x in providers.sortedProviderList() if GenericProvider.TORRENT == x.providerType]:
src_id = src.get_id()
src_id_uc = src_id.upper()
new_config[src_id_uc] = {}
new_config[src_id_uc][src_id] = int(src.enabled)
if getattr(src, 'url_edit', None):
new_config[src_id_uc][src_id + '_url_home'] = src.url_home
for nzb_prov in [curProvider for curProvider in providers.sortedProviderList()
if GenericProvider.NZB == curProvider.providerType]:
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(src, 'password'):
new_config[src_id_uc][src_id + '_password'] = helpers.encrypt(src.password, ENCRYPTION_VERSION)
if hasattr(nzb_prov, 'api_key'):
new_config[prov_id_uc][prov_id + '_api_key'] = nzb_prov.api_key
if hasattr(nzb_prov, 'username'):
new_config[prov_id_uc][prov_id + '_username'] = nzb_prov.username
if hasattr(nzb_prov, 'search_mode'):
new_config[prov_id_uc][prov_id + '_search_mode'] = nzb_prov.search_mode
if hasattr(nzb_prov, 'search_fallback'):
new_config[prov_id_uc][prov_id + '_search_fallback'] = int(nzb_prov.search_fallback)
if hasattr(nzb_prov, 'enable_recentsearch'):
new_config[prov_id_uc][prov_id + '_enable_recentsearch'] = int(nzb_prov.enable_recentsearch)
if hasattr(nzb_prov, 'enable_backlog'):
new_config[prov_id_uc][prov_id + '_enable_backlog'] = int(nzb_prov.enable_backlog)
for (setting, value) in [
('%s_%s' % (src_id, k), getattr(src, k, v) if not v else helpers.tryInt(getattr(src, k, None)))
for (k, v) in [
('api_key', None), ('passkey', None), ('digest', None), ('hash', None), ('username', ''), ('uid', ''),
('minseed', 1), ('minleech', 1), ('confirmed', 1), ('freeleech', 1), ('reject_m2ts', 1),
('enable_recentsearch', 1), ('enable_backlog', 1), ('search_mode', None), ('search_fallback', 1),
('seed_time', None)] if hasattr(src, k)]:
new_config[src_id_uc][setting] = value
if hasattr(src, '_seed_ratio'):
new_config[src_id_uc][src_id + '_seed_ratio'] = src.seed_ratio()
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']['sab_username'] = SAB_USERNAME

View file

@ -213,6 +213,9 @@ class Quality:
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):
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) \
and not checkName(['(1080|2160)[pi]'], all):
return Quality.HDTV

View file

@ -420,7 +420,7 @@ def check_setting_str(config, cfg_name, item_name, def_val, log=True):
else:
logger.log('%s -> ******' % item_name, logger.DEBUG)
return my_val
return (my_val, def_val)['None' == my_val]
class ConfigMigrator():
@ -783,4 +783,4 @@ class ConfigMigrator():
old_token = check_setting_str(self.config_obj, 'Trakt', 'trakt_token', '')
old_refresh_token = check_setting_str(self.config_obj, 'Trakt', 'trakt_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:
try:
affected = 0
for qu in querylist:
cursor = self.connection.cursor()
if len(qu) == 1:
if logTransaction:
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:
if logTransaction:
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()
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
except sqlite3.OperationalError as e:
sqlResult = []

View file

@ -18,7 +18,6 @@
from __future__ import with_statement
import urllib2
import xml.etree.cElementTree as etree
import xml.etree
import re
@ -84,7 +83,7 @@ def createNZBString(fileElements, xmlns):
for curFile in fileElements:
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):
@ -158,7 +157,7 @@ def splitResult(result):
wantEp = True
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 " +
Quality.qualityStrings[result.quality], logger.DEBUG)
wantEp = False
@ -169,13 +168,14 @@ def splitResult(result):
# get all the associated episode objects
epObjList = []
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
curResult = classes.NZBDataSearchResult(epObjList)
curResult.name = newNZB
curResult.provider = result.provider
curResult.quality = result.quality
curResult.show = result.show
curResult.extraInfo = [createNZBString(separateNZBs[newNZB], xmlns)]
resultList.append(curResult)

View file

@ -18,30 +18,37 @@
from os import sys
import os.path
import sickbeard
from . import generic
from sickbeard import logger
from sickbeard import logger, encodingKludge as ek
# usenet
from . import newznab, omgwtfnzbs, womble
# torrent
from . import alpharatio, beyondhd, bitmetv, bitsoup, btn, freshontv, funfile, gftracker, grabtheinfo, \
hdbits, hdspace, iptorrents, kat, morethan, pisexy, pretome, rarbg, scc, scenetime, shazbat, speedcd, \
from . import alpharatio, beyondhd, bitmetv, btn, freshontv, funfile, gftracker, grabtheinfo, \
hd4free, hdbits, hdspace, iptorrents, kat, morethan, pisexy, pretome, rarbg, scc, scenetime, shazbat, speedcd, \
thepiratebay, torrentbytes, torrentday, torrenting, torrentleech, torrentshack, transmithe_net, tvchaosuk
# anime
from . import nyaatorrents, tokyotoshokan
# custom
try:
from . import custom01
except:
pass
__all__ = ['omgwtfnzbs',
'womble',
'alpharatio',
'beyondhd',
'bitmetv',
'bitsoup',
'btn',
'custom01',
'freshontv',
'funfile',
'gftracker',
'grabtheinfo',
'hd4free',
'hdbits',
'hdspace',
'iptorrents',
@ -208,16 +215,19 @@ def makeTorrentRssProvider(configString):
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):
name = name.lower()
prefix = "sickbeard.providers."
prefix, cprov, name = 'sickbeard.providers.', 'motsuc'[::-1], name.lower()
if name in __all__ and prefix + name in sys.modules:
return sys.modules[prefix + name]
else:
raise Exception("Can't find " + prefix + name + " in " + "Providers")
elif cprov in name:
return None
raise Exception('Can\'t find %s%s in providers' % (prefix, name))
def getProviderClass(id):

View file

@ -21,7 +21,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -31,7 +31,7 @@ class AlphaRatioProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'AlphaRatio')
generic.TorrentProvider.__init__(self, 'AlphaRatio', cache_update_freq=20)
self.url_base = 'https://alpharatio.cc/'
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.username, self.password, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = AlphaRatioCache(self)
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
def _authorised(self, **kwargs):
@ -65,7 +63,7 @@ class AlphaRatioProvider(generic.TorrentProvider):
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, ('', '&freetorrent=1')[self.freeleech])
search_url = self.urls['search'] % (search_string, ('&freetorrent=1', '')[not self.freeleech])
html = self.get_url(search_url)
@ -111,16 +109,4 @@ class AlphaRatioProvider(generic.TorrentProvider):
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()

View file

@ -19,7 +19,7 @@ import re
import time
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.exceptions import AuthException
from lib.unidecode import unidecode
@ -41,7 +41,6 @@ class BeyondHDProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri']
self.passkey, self.minseed, self.minleech = 3 * [None]
self.cache = BeyondHDCache(self)
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)
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()

View file

@ -19,7 +19,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -28,7 +28,7 @@ from lib.unidecode import unidecode
class BitmetvProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'BitMeTV')
generic.TorrentProvider.__init__(self, 'BitMeTV', cache_update_freq=7)
self.url_base = 'http://www.bitmetv.org/'
@ -42,7 +42,6 @@ class BitmetvProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri']
self.digest, self.minseed, self.minleech = 3 * [None]
self.cache = BitmetvCache(self)
def _authorised(self, **kwargs):
@ -63,9 +62,7 @@ class BitmetvProvider(generic.TorrentProvider):
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
category = 'cat=%s' % self.categories[
(mode in ['Season', 'Episode'] and self.show and self.show.is_anime) and 'anime' or 'shows']
search_url = self.urls['search'] % (category, search_string)
search_url = self.urls['search'] % (self._categories_string(mode, 'cat=%s'), search_string)
html = self.get_url(search_url)
@ -89,8 +86,8 @@ class BitmetvProvider(generic.TorrentProvider):
continue
info = tr.find('a', href=rc['info'])
title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip()
download_url = self.urls['get'] % tr.find('a', href=rc['get']).get('href')
title = info.attrs.get('title') or info.get_text().strip()
download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/')
except (AttributeError, TypeError, ValueError):
continue
@ -116,16 +113,4 @@ class BitmetvProvider(generic.TorrentProvider):
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()

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
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -28,19 +28,19 @@ from lib.unidecode import unidecode
class FreshOnTVProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'FreshOnTV')
generic.TorrentProvider.__init__(self, 'FreshOnTV', cache_update_freq=20)
self.url_base = 'https://freshon.tv/'
self.urls = {'config_provider_home_uri': self.url_base,
'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'}
self.categories = {'shows': 0, 'anime': 235}
self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = FreshOnTVCache(self)
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
def _authorised(self, **kwargs):
@ -59,16 +59,17 @@ class FreshOnTVProvider(generic.TorrentProvider):
return results
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
freeleech = (0, 3)[self.freeleech]
freeleech = (3, 0)[not self.freeleech]
rc = dict((k, re.compile('(?i)' + v))
for (k, v) in {'info': 'detail', 'get': 'download', 'name': '_name'}.items())
for mode in search_params.keys():
for search_string in search_params[mode]:
search_string, search_url = self._title_and_url((
isinstance(search_string, unicode) and unidecode(search_string) or search_string,
self.urls['search'] % (freeleech, search_string)))
search_string, void = self._title_and_url((
isinstance(search_string, unicode) and unidecode(search_string) or 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
html = self.get_url(search_url)
@ -96,7 +97,7 @@ class FreshOnTVProvider(generic.TorrentProvider):
continue
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('/')
except (AttributeError, TypeError, ValueError):
@ -117,21 +118,9 @@ class FreshOnTVProvider(generic.TorrentProvider):
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)
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()

View file

@ -19,7 +19,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -28,7 +28,7 @@ from lib.unidecode import unidecode
class FunFileProvider(generic.TorrentProvider):
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.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_timeout = 90
self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = FunFileCache(self)
def _authorised(self, **kwargs):
@ -58,10 +57,9 @@ class FunFileProvider(generic.TorrentProvider):
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download',
'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|')
}.items())
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download'}.items())
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]:
search_string = isinstance(search_string, unicode) and unidecode(search_string) or 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):
continue
title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip()
download_url = self.urls['get'] % tr.find('a', href=rc['get']).get('href')
title = info.attrs.get('title') or info.get_text().strip()
download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/')
except (AttributeError, TypeError, ValueError):
continue
@ -114,16 +112,4 @@ class FunFileProvider(generic.TorrentProvider):
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()

View file

@ -25,6 +25,8 @@ import math
import os
import re
import time
import urlparse
import zlib
from base64 import b16encode, b32decode
import sickbeard
@ -53,7 +55,7 @@ class GenericProvider:
# these need to be set in the subclass
self.providerType = None
self.name = name
self.supportsBacklog = supports_backlog
self.supports_backlog = supports_backlog
self.anime_only = anime_only
if anime_only:
self.proper_search_terms = 'v1|v2|v3|v4|v5'
@ -518,7 +520,7 @@ class GenericProvider:
if hasattr(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
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='&'):
return delimiter.join([('%s', template)[any(template)] % c for c in sorted(self.categories['shows'] + (
[], [] if 'anime' not in self.categories else self.categories['anime'])[
('Cache' == mode and helpers.has_anime()) or ((mode in ['Season', 'Episode']) and self.show and self.show.is_anime)])])
return delimiter.join([('%s', template)[any(template)] % c for c in sorted(
'shows' in self.categories and (isinstance(self.categories['shows'], type([])) and
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
def _bytesizer(size_dim=''):
@ -577,12 +583,8 @@ class NZBProvider(object, GenericProvider):
def maybe_apikey(self):
if hasattr(self, 'needs_auth') and self.needs_auth:
if hasattr(self, 'key') and 0 < len(self.key):
return self.key
if hasattr(self, 'api_key') and 0 < len(self.api_key):
return self.api_key
return None
if getattr(self, 'needs_auth', None):
return (getattr(self, 'key', '') and self.key) or (getattr(self, 'api_key', '') and self.api_key) or None
return False
def _check_auth(self):
@ -664,13 +666,32 @@ class NZBProvider(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)
self.providerType = GenericProvider.TORRENT
self._seed_ratio = 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):
@ -777,6 +798,65 @@ class TorrentProvider(object, GenericProvider):
search_params += [crop.sub(r'\1', '%s %s%s' % (name, x, detail)) for x in prefix]
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):
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():
return True
if not self._valid_home():
return False
if hasattr(self, 'digest'):
self.cookies = re.sub(r'(?i)([\s\']+|cookie\s*:)', '', self.digest)
success, msg = self._check_cookie()
@ -811,13 +894,14 @@ class TorrentProvider(object, GenericProvider):
if url:
response = helpers.getURL(url, session=self.session)
try:
action = re.findall('[<]form[\w\W]+?action="([^"]+)', response)[0]
url = (self.urls.get('login_base') or
self.urls['config_provider_home_uri']) + action.lstrip('/')
action = re.findall('[<]form[\w\W]+?action=[\'\"]([^\'\"]+)', response)[0]
url = action if action.startswith('http') else \
(self.urls.get('login_base') or self.urls['config_provider_home_uri']) + action.lstrip('/')
tags = re.findall(r'(?is)(<input.*?name="[^"]+".*?>)', response)
nv = [(tup[0]) for tup in [re.findall(r'(?is)name="([^"]+)"(?:.*?value="([^"]+)")?', x)
for x in tags]]
tags = re.findall(r'(?is)(<input.*?name=[\'\"][^\'\"]+[\'\"].*?>)', response)
nv = [(tup[0]) for tup in [
re.findall(r'(?is)name=[\'\"]([^\'\"]+)[\'\"](?:.*?value=[\'\"]([^\'\"]+)[\'\"])?', x)
for x in tags]]
for name, value in nv:
if name not in ('username', 'password'):
post_params = isinstance(post_params, type({})) and post_params or {}
@ -854,10 +938,18 @@ class TorrentProvider(object, GenericProvider):
if self.username and self.password:
return True
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'):
if self.username and self.passkey:
return True
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'):
if self.api_key:
return True
@ -899,7 +991,7 @@ class TorrentProvider(object, GenericProvider):
@staticmethod
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|' +
'nothing\sfound|' +
'no\storrents\sfound|' +
@ -907,7 +999,6 @@ class TorrentProvider(object, GenericProvider):
'.*?no\shits\.\sTry\sadding' +
')', html[0])
def cache_data(self, *args, **kwargs):
def _cache_data(self):
search_params = {'Cache': ['']}
return self._search_provider(search_params)
return self._search_provider({'Cache': ['']})

View file

@ -20,7 +20,7 @@ import time
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -29,7 +29,7 @@ from lib.unidecode import unidecode
class GFTrackerProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'GFTracker')
generic.TorrentProvider.__init__(self, 'GFTracker', cache_update_freq=17)
self.url_base = 'https://thegft.org/'
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.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = GFTrackerCache(self)
def _authorised(self, **kwargs):
@ -122,16 +121,4 @@ class GFTrackerProvider(generic.TorrentProvider):
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()

View file

@ -19,7 +19,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -28,7 +28,7 @@ from lib.unidecode import unidecode
class GrabTheInfoProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'GrabTheInfo')
generic.TorrentProvider.__init__(self, 'GrabTheInfo', cache_update_freq=20)
self.url_base = 'http://grabthe.info/'
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.username, self.password, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = GrabTheInfoCache(self)
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
def _search_provider(self, search_params, **kwargs):
@ -57,7 +55,7 @@ class GrabTheInfoProvider(generic.TorrentProvider):
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['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])
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)
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()

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
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.exceptions import AuthException
from sickbeard.helpers import tryInt
from sickbeard.indexers import indexer_config
@ -33,7 +33,7 @@ except ImportError:
class HDBitsProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'HDBits')
generic.TorrentProvider.__init__(self, 'HDBits', cache_update_freq=15)
# api_spec: https://hdbits.org/wiki/API
self.url_base = 'https://hdbits.org/'
@ -46,9 +46,7 @@ class HDBitsProvider(generic.TorrentProvider):
self.proper_search_terms = [' proper ', ' repack ']
self.url = self.urls['config_provider_home_uri']
self.username, self.passkey, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = HDBitsCache(self)
self.username, self.passkey, self.freeleech, self.minseed, self.minleech = 5 * [None]
def check_auth_from_data(self, parsed_json):
@ -148,16 +146,4 @@ class HDBitsProvider(generic.TorrentProvider):
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()

View file

@ -19,7 +19,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from lib.unidecode import unidecode
@ -27,7 +27,7 @@ from lib.unidecode import unidecode
class HDSpaceProvider(generic.TorrentProvider):
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.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.username, self.password, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = HDSpaceCache(self)
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
def _authorised(self, **kwargs):
@ -124,16 +122,4 @@ class HDSpaceProvider(generic.TorrentProvider):
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()

View file

@ -19,7 +19,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from lib.unidecode import unidecode
@ -29,24 +29,24 @@ class IPTorrentsProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'IPTorrents')
self.url_base = 'https://iptorrents.eu/'
self.urls = {'config_provider_home_uri': self.url_base,
'login': self.url_base + 'torrents/',
'search': self.url_base + 't?%s;q=%s;qf=ti%s%s#torrents',
'get': self.url_base + '%s'}
self.url_home = ['https://iptorrents.%s/' % u for u in 'eu', 'com', 'ru']
self.url_vars = {'login': 'getrss.php', 'search': 't?%s;q=%s;qf=ti%s%s#torrents', '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.categories = {'shows': [4, 5, 22, 23, 24, 25, 26, 55, 65, 66, 73, 78, 79], 'anime': [60]}
self.proper_search_terms = None
self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = IPTorrentsCache(self)
self.digest, self.freeleech, self.minseed, self.minleech = 4 * [None]
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):
@ -61,8 +61,9 @@ class IPTorrentsProvider(generic.TorrentProvider):
for search_string in search_params[mode]:
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
search_url = self.urls['search'] % (self._categories_string(mode, '%s', ';'), search_string,
('', ';free')[self.freeleech], (';o=seeders', '')['Cache' == mode])
search_url = self.urls['search'] % (
self._categories_string(mode, '%s', ';'), search_string,
(';free', '')[not self.freeleech], (';o=seeders', '')['Cache' == mode])
html = self.get_url(search_url)
@ -108,15 +109,9 @@ class IPTorrentsProvider(generic.TorrentProvider):
return results
class IPTorrentsCache(tvcache.TVCache):
def __init__(self, this_provider):
tvcache.TVCache.__init__(self, this_provider)
def _cache_data(self):
return self.provider.cache_data()
@staticmethod
def ui_string(key):
return 'iptorrents_digest' == key and 'use... \'uid=xx; pass=yy\'' or ''
provider = IPTorrentsProvider()

View file

@ -23,7 +23,7 @@ import traceback
import urllib
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.helpers import (has_anime, tryInt)
from sickbeard.common import Quality, mediaExtensions
@ -34,20 +34,22 @@ from lib.unidecode import unidecode
class KATProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'KickAssTorrents')
generic.TorrentProvider.__init__(self, 'KickAssTorrents', cache_update_freq=20)
self.url_base = 'https://kat.ph/'
self.urls = {'config_provider_home_uri': self.url_base,
'base': [self.url_base, 'http://katproxy.com/'],
'search': 'usearch/%s/',
'sorted': '?field=time_add&sorder=desc'}
self.url_home = ['https://%s/' % u for u in 'kat.ph', 'kat.cr', 'kickass.unblocked.red', 'katproxy.com']
self.url_vars = {'search': 'usearch/%s/?field=time_add&sorder=desc', 'get': '%s'}
self.url_tmpl = {'config_provider_home_uri': '%(home)s',
'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'}
self.proper_search_terms = None
self.url = self.urls['config_provider_home_uri']
self.minseed, self.minleech = 2 * [None]
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):
""" 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': []}
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():
search_show = mode in ['Season', 'Episode']
if not search_show and has_anime():
@ -145,19 +147,17 @@ class KATProvider(generic.TorrentProvider):
for enum, search_string in enumerate(search_params[mode]):
search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string
self.url = self.urls['base'][url]
search_url = self.url + (self.urls['search'] % urllib.quote('%scategory:%s' % (
search_url = self.urls['search'] % urllib.quote('%scategory:%s' % (
('', '%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})
html = self.get_url(search_url + self.urls['sorted'])
html = self.get_url(search_url)
cnt = len(items[mode])
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 html and 'kastatic' not in html:
url += (1, 0)[url == len(self.urls['base'])]
if not html or self._has_no_results(html) or \
re.search(r'(?is)<(?:h\d)[^>]*>.*?(?:did\snot\smatch)', html):
raise generic.HaltParseException
with BS4Parser(html, features=['html5lib', 'permissive']) as soup:
@ -183,11 +183,13 @@ class KATProvider(generic.TorrentProvider):
except (AttributeError, TypeError, ValueError):
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)
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:
ep_number = int(epcount / len(set(show_name_helpers.allPossibleShowNames(self.show))))
title = self._find_season_quality(title, link, ep_number)
@ -208,16 +210,4 @@ class KATProvider(generic.TorrentProvider):
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()

View file

@ -21,7 +21,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -30,19 +30,19 @@ from lib.unidecode import unidecode
class MoreThanProvider(generic.TorrentProvider):
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.urls = {'config_provider_home_uri': self.url_base,
'login': self.url_base + 'login.php',
'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'}
self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = MoreThanCache(self)
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)
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
except (AttributeError, TypeError, ValueError):
continue
@ -117,16 +117,4 @@ class MoreThanProvider(generic.TorrentProvider):
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()

View file

@ -27,14 +27,14 @@ from sickbeard.exceptions import AuthException
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):
generic.NZBProvider.__init__(self, name, True, False)
self.url = url
self.key = key
self.cat_ids = cat_ids
self.search_mode = search_mode
self.cat_ids = cat_ids or '5030,5040'
self.search_mode = search_mode or 'eponly'
self.search_fallback = search_fallback
self.enable_recentsearch = enable_recentsearch
self.enable_backlog = enable_backlog
@ -81,11 +81,11 @@ class NewznabProvider(generic.NZBProvider):
if isinstance(api_key, basestring):
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:
logger.log(u'Error getting html for [%s]' % self.session.response['url'], logger.DEBUG)
return (False, return_categories, 'Error getting html for [%s]' %
('%s/api?%s' % (self.url, '&'.join('%s=%s' % (x, y) for x, y in params.items()))))
logger.log(u'Error getting html for [%s]' % url, logger.DEBUG)
return False, return_categories, 'Error getting html for [%s]' % url
xml_categories = helpers.parse_xml(categories)
if not xml_categories:
@ -114,16 +114,20 @@ class NewznabProvider(generic.NZBProvider):
base_params = {}
# season
ep_detail = None
if ep_obj.show.air_by_date or ep_obj.show.is_sports:
date_str = str(ep_obj.airdate).split('-')[0]
base_params['season'] = date_str
base_params['q'] = date_str.replace('-', '.')
airdate = str(ep_obj.airdate).split('-')[0]
base_params['season'] = airdate
base_params['q'] = airdate
if ep_obj.show.air_by_date:
ep_detail = '+"%s"' % airdate
elif ep_obj.show.is_anime:
base_params['season'] = '%d' % ep_obj.scene_absolute_number
else:
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)
if ids[1]: # or ids[2]:
params = base_params.copy()
@ -136,7 +140,7 @@ class NewznabProvider(generic.NZBProvider):
use_id = True
use_id and search_params.append(params)
# add new query strings for exceptions
# query search and exceptions
name_exceptions = list(
set([helpers.sanitizeSceneName(a) for a in
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()
if 'q' in params:
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}]
@ -156,18 +167,25 @@ class NewznabProvider(generic.NZBProvider):
if not ep_obj:
return [base_params]
ep_detail = None
if ep_obj.show.air_by_date or ep_obj.show.is_sports:
date_str = str(ep_obj.airdate)
base_params['season'] = date_str.partition('-')[0]
base_params['ep'] = date_str.partition('-')[2].replace('-', '/')
airdate = str(ep_obj.airdate).split('-')
base_params['season'] = airdate[0]
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:
base_params['ep'] = '%i' % int(
ep_obj.scene_absolute_number if int(ep_obj.scene_absolute_number) > 0 else ep_obj.scene_episode)
base_params['ep'] = '%i' % (helpers.tryInt(ep_obj.scene_absolute_number) or
helpers.tryInt(ep_obj.scene_episode))
ep_detail = '%02d' % base_params['ep']
else:
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_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)
if ids[1]: # or ids[2]:
params = base_params.copy()
@ -181,7 +199,7 @@ class NewznabProvider(generic.NZBProvider):
use_id = True
use_id and search_params.append(params)
# add new query strings for exceptions
# query search and exceptions
name_exceptions = list(
set([helpers.sanitizeSceneName(a) for a in
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
search_params.append(params)
if ep_obj.show.is_anime:
# 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
if ep_detail:
params = base_params.copy()
params['q'] = '%s.%02d' % (cur_exception, int(params['ep']))
if 'ep' in params:
params.pop('ep')
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 [{'Episode': search_params}]
@ -229,8 +243,10 @@ class NewznabProvider(generic.NZBProvider):
# category ids
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 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.')
@ -238,18 +254,24 @@ class NewznabProvider(generic.NZBProvider):
if self.show:
if self.show.is_sports:
cat = [cat_sport]
cat = cat_sport
elif self.show.is_anime:
cat = [cat_anime]
cat = cat_anime
else:
cat = [cat_sport, cat_anime]
cat = cat_sport + cat_anime
if self.cat_ids or len(cat):
base_params['cat'] = ','.join(sorted(set(self.cat_ids.split(',') + cat)))
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)
# 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
batch_count = not 0
@ -336,18 +358,17 @@ class NewznabCache(tvcache.TVCache):
result = []
if True or self.shouldUpdate():
if 4489 != sickbeard.RECENTSEARCH_FREQUENCY or self.should_update():
try:
self._checkAuth()
items = self.provider.cache_data()
except Exception:
return result
items = None
items = self.provider.cache_data()
if items:
self._clearCache()
self.setLastUpdate()
# parse data
cl = []
for item in items:
ci = self._parseItem(item)
@ -358,6 +379,9 @@ class NewznabCache(tvcache.TVCache):
my_db = self.get_db()
my_db.mass_action(cl)
# set updated as time the attempt to fetch data is
self.setLastUpdate()
return result
# overwrite method with that parses the rageid from the newznab feed

View file

@ -17,7 +17,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -37,7 +37,6 @@ class PiSexyProvider(generic.TorrentProvider):
self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = PiSexyCache(self)
def _authorised(self, **kwargs):
@ -108,14 +107,4 @@ class PiSexyProvider(generic.TorrentProvider):
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()

View file

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

View file

@ -21,7 +21,7 @@ import datetime
import time
from . import generic
from sickbeard import helpers, logger, tvcache
from sickbeard import helpers, logger
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.confirmed = False
self.request_throttle = datetime.datetime.now()
self.cache = RarbgCache(self)
def _authorised(self, reset=False, **kwargs):
@ -178,14 +177,4 @@ class RarbgProvider(generic.TorrentProvider):
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()

View file

@ -20,7 +20,7 @@ import time
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -31,18 +31,16 @@ class SCCProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'SceneAccess')
self.url_base = 'https://sceneaccess.eu/'
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_home = ['https://sceneaccess.%s/' % u for u in 'eu', 'org']
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.cache = SCCCache(self)
def _authorised(self, **kwargs):
@ -121,16 +119,4 @@ class SCCProvider(generic.TorrentProvider):
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()

View file

@ -20,7 +20,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -29,7 +29,7 @@ from lib.unidecode import unidecode
class SceneTimeProvider(generic.TorrentProvider):
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.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.username, self.password, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = SceneTimeCache(self)
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
def _authorised(self, **kwargs):
@ -58,15 +56,16 @@ class SceneTimeProvider(generic.TorrentProvider):
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': '.*id=(\d+).*', 'fl': '\[freeleech\]',
'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|')
}.items())
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {
'info': 'detail', 'get': '.*id=(\d+).*', 'fl': '\[freeleech\]',
'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|')}.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
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:
search_string = '+'.join(search_string.split())
post_data['search'] = search_string
@ -99,10 +98,11 @@ class SceneTimeProvider(generic.TorrentProvider):
continue
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'])),
'title': str(title).replace(' ', '.')}
download_url = self.urls['get'] % {
'id': re.sub(rc['get'], r'\1', str(info.attrs['href'])),
'title': str(title).replace(' ', '.')}
except (AttributeError, TypeError, ValueError):
continue
@ -124,16 +124,4 @@ class SceneTimeProvider(generic.TorrentProvider):
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()

View file

@ -22,7 +22,7 @@ import time
import traceback
from . import generic
from sickbeard import helpers, logger, tvcache
from sickbeard import helpers, logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -32,7 +32,7 @@ class ShazbatProvider(generic.TorrentProvider):
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.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.username, self.password, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = ShazbatCache(self)
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)
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()

View file

@ -19,34 +19,32 @@ import re
import time
from . import generic
from sickbeard import tvcache
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
class SpeedCDProvider(generic.TorrentProvider):
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,
'login_action': self.url_base + 'login.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},
'Episode': {'c2': 1, 'c49': 1, 'c50': 1, 'c55': 1},
'Cache': {'c41': 1, 'c2': 1, 'c49': 1, 'c50': 1, 'c53': 1, 'c55': 1}}
self.categories = {'Season': [41, 53], 'Episode': [2, 49, 50, 55], 'anime': [30]}
self.categories['Cache'] = self.categories['Season'] + self.categories['Episode']
self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = SpeedCDCache(self)
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
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):
@ -56,37 +54,49 @@ class SpeedCDProvider(generic.TorrentProvider):
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():
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]:
search_string = '+'.join(search_string.split())
post_data = dict({'/browse.php?': None, 'cata': 'yes', 'jxt': 4, 'jxw': 'b', 'search': search_string},
**self.categories[search_mode])
if self.freeleech:
post_data['freeleech'] = 'on'
post_data = dict((x.split('=') for x in self._categories_string(mode).split('&')), search=search_string,
jxt=2, jxw='b', freeleech=('on', None)[not self.freeleech])
data_json = self.get_url(self.urls['search'], post_data=post_data, json=True)
cnt = len(items[mode])
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
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'):
continue
if 2 > len(torrent_rows):
raise generic.HaltParseException
seeders, leechers, size = [tryInt(n, n) for n in [item.get(x) for x in 'seed', 'leech', 'size']]
if self._peers_fail(mode, seeders, leechers):
continue
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 (-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'))
download_url = self.urls['get'] % item.get('id')
if title and download_url:
items[mode].append((title, download_url, seeders, self._bytesizer(size)))
info = tr.find('a', 'torrent')
title = info.attrs.get('title') or 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 Exception:
time.sleep(1.1)
@ -105,16 +115,4 @@ class SpeedCDProvider(generic.TorrentProvider):
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()

View file

@ -23,7 +23,7 @@ import traceback
import urllib
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.common import Quality, mediaExtensions
from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException
@ -33,40 +33,32 @@ from lib.unidecode import unidecode
class ThePirateBayProvider(generic.TorrentProvider):
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/',
'https://thepiratebay.mn/', 'https://thepiratebay.vg/',
'https://thepiratebay.la/'],
'search': 'search/%s/0/7/200',
'browse': 'tv/latest/'} # order by seed
self.url_home = ['https://thepiratebay.%s/' % u for u in 'se', 'org']
self.url_vars = {'search': 'search/%s/0/7/200', 'browse': 'tv/latest/'}
self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'search': '%(home)s%(vars)s',
'browse': '%(home)s%(vars)s'}
self.proper_search_terms = None
self.url = self.urls['config_provider_home_uri'][0]
self.minseed, self.minleech = 2 * [None]
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):
""" 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
file_name = None
data = None
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)
data = self.get_url('%sajax_details_filelist.php?id=%s' % (self.url, torrent_id))
if not data:
return None
@ -138,30 +130,22 @@ class ThePirateBayProvider(generic.TorrentProvider):
def _search_provider(self, search_params, search_mode='eponly', epcount=0, **kwargs):
results = []
if not self.url:
return results
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict((k, re.compile('(?i)' + v))
for (k, v) in {'info': 'detail', 'get': 'download[^"]+magnet', 'tid': r'.*/(\d{5,}).*',
'verify': '(?:helper|moderator|trusted|vip)'}.items())
has_signature = False
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
log_url = '%s %s' % (self.name, search_string) # placebo value
for idx, search_url in enumerate(self.urls['config_provider_home_uri']):
search_url += self.urls['browse'] if 'Cache' == mode\
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
search_url = self.urls['browse'] if 'Cache' == mode \
else self.urls['search'] % (urllib.quote(search_string))
html = self.get_url(search_url)
cnt = len(items[mode])
try:
@ -213,28 +197,13 @@ class ThePirateBayProvider(generic.TorrentProvider):
pass
except Exception:
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)
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
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()

View file

@ -19,7 +19,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -28,21 +28,18 @@ from lib.unidecode import unidecode
class TorrentBytesProvider(generic.TorrentProvider):
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.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.url_home = ['https://www.torrentbytes.net/']
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.freeleech = False
self.cache = TorrentBytesCache(self)
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
def _authorised(self, **kwargs):
@ -56,12 +53,12 @@ class TorrentBytesProvider(generic.TorrentProvider):
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*\]'
}.items())
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download',
'fl': '\[\W*F\W?L\W*\]'}.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())
search_url = self.urls['search'] % (search_string, self._categories_string(mode))
html = self.get_url(search_url, timeout=90)
@ -82,11 +79,11 @@ class TorrentBytesProvider(generic.TorrentProvider):
info = tr.find('a', href=rc['info'])
seeders, leechers, size = [tryInt(n, n) for n in [
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())) \
or self._peers_fail(mode, seeders, leechers):
if self.freeleech and (len(info.contents) < 2 or not rc['fl'].search(
info.contents[1].string.strip())) or self._peers_fail(mode, seeders, leechers):
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()
download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/')
except (AttributeError, TypeError, ValueError):
@ -109,16 +106,4 @@ class TorrentBytesProvider(generic.TorrentProvider):
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()

View file

@ -19,8 +19,7 @@ import re
import time
from . import generic
from sickbeard import tvcache
from sickbeard.helpers import (has_anime, tryInt)
from sickbeard.helpers import tryInt
class TorrentDayProvider(generic.TorrentProvider):
@ -28,22 +27,19 @@ class TorrentDayProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'TorrentDay')
self.url_base = 'https://torrentday.eu/'
self.urls = {'config_provider_home_uri': self.url_base,
'login': self.url_base + 'torrents/',
'search': self.url_base + 'V3/API/API.php',
'get': self.url_base + 'download.php/%s/%s'}
self.url_home = ['https://%s/' % u for u in 'torrentday.eu', 'secure.torrentday.com', 'tdonline.org',
'torrentday.it', 'www.td.af', 'www.torrentday.com']
self.categories = {'Season': {'c31': 1, 'c33': 1, 'c14': 1},
'Episode': {'c32': 1, 'c26': 1, 'c7': 1, 'c2': 1},
'Cache': {'c31': 1, 'c33': 1, 'c14': 1, 'c32': 1, 'c26': 1, 'c7': 1, 'c2': 1}}
self.url_vars = {'login': 'torrents/', 'search': 'V3/API/API.php', 'get': 'download.php/%s/%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.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.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = TorrentDayCache(self)
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
def _authorised(self, **kwargs):
@ -66,11 +62,8 @@ class TorrentDayProvider(generic.TorrentProvider):
for mode in search_params.keys():
for search_string in search_params[mode]:
search_string = '+'.join(search_string.split())
post_data = dict({'/browse.php?': None, 'cata': 'yes', 'jxt': 8, 'jxw': 'b', 'search': search_string},
**self.categories[(mode, 'Episode')['Propers' == mode]])
if ('Cache' == mode and has_anime()) or (
mode in ['Season', 'Episode'] and self.show and self.show.is_anime):
post_data.update({'c29': 1})
post_data = dict((x.split('=') for x in self._categories_string(mode).split('&')),
search=search_string, cata='yes', jxt=8, jxw='b')
if self.freeleech:
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)
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()

View file

@ -19,7 +19,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -30,25 +30,20 @@ class TorrentingProvider(generic.TorrentProvider):
def __init__(self):
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.urls = {'config_provider_home_uri': self.url_base,
'login': self.api + 'secure.php',
'search': self.api + 'browse.php?%s&search=%s',
'get': self.api + '%s'}
self.url_vars = {'login': 'rss.php', 'search': 'browse.php?%s&search=%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.categories = {'shows': [4, 5]}
self.url = self.urls['config_provider_home_uri']
self.digest, self.minseed, self.minleech = 3 * [None]
self.cache = TorrentingCache(self)
def _authorised(self, **kwargs):
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),
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': []}
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download',
'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|')
}.items())
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {
'info': 'detail', 'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|'),
'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
@ -90,8 +85,9 @@ class TorrentingProvider(generic.TorrentProvider):
continue
info = tr.find('a', href=rc['info'])
title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip()
download_url = self.urls['get'] % tr.find('a', href=rc['get']).get('href')
title = info.attrs.get('title') or info.get_text().strip()
download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/')
except (AttributeError, TypeError, ValueError):
continue
@ -117,14 +113,4 @@ class TorrentingProvider(generic.TorrentProvider):
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()

View file

@ -19,14 +19,14 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from lib.unidecode import unidecode
class TorrentLeechProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'TorrentLeech')
generic.TorrentProvider.__init__(self, 'TorrentLeech', cache_update_freq=20)
self.url_base = 'https://torrentleech.org/'
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.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = TorrentLeechCache(self)
def _authorised(self, **kwargs):
@ -111,14 +110,5 @@ class TorrentLeechProvider(generic.TorrentProvider):
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()

View file

@ -21,7 +21,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from lib.unidecode import unidecode
@ -30,13 +30,14 @@ from lib.unidecode import unidecode
class TorrentShackProvider(generic.TorrentProvider):
def __init__(self):
generic.TorrentProvider.__init__(self, 'TorrentShack')
generic.TorrentProvider.__init__(self, 'TorrentShack', cache_update_freq=20)
self.url_base = 'https://torrentshack.me/'
self.urls = {'config_provider_home_uri': self.url_base,
'login': self.url_base + 'login.php?lang=',
'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'}
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.username, self.password, self.minseed, self.minleech = 4 * [None]
self.cache = TorrentShackCache(self)
def _authorised(self, **kwargs):
@ -117,16 +117,4 @@ class TorrentShackProvider(generic.TorrentProvider):
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()

View file

@ -19,7 +19,8 @@ import re
import traceback
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 lib.unidecode import unidecode
@ -27,7 +28,7 @@ from lib.unidecode import unidecode
class TransmithenetProvider(generic.TorrentProvider):
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.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.user_authkey, self.user_passkey = 2 * [None]
self.chk_td = True
self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.freeleech = False
self.cache = TransmithenetCache(self)
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
def _authorised(self, **kwargs):
@ -88,11 +88,13 @@ class TransmithenetProvider(generic.TorrentProvider):
try:
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[1] = detail[1].strip().lower().replace('mkv', 'x264')
title = '%s.%s' % (title_parts[0].strip(), '.'.join(
(len(maybe_res) and [maybe_res[0]] or []) + [detail[0].strip(), detail[1]]))
title = '%s.%s' % (BS4Parser(title_parts[0].strip(), 'html.parser').soup.string, '.'.join(
(maybe_res and [maybe_res[0]] or []) +
[detail[0].strip(), detail[1], maybe_ext and maybe_ext[0].lower() or 'mkv']))
except (IndexError, KeyError):
title = group_name
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)
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()

View file

@ -19,7 +19,7 @@ import re
import traceback
from . import generic
from sickbeard import logger, tvcache
from sickbeard import logger
from sickbeard.bs4_parser import BS4Parser
from sickbeard.helpers import tryInt
from sickbeard.config import naming_ep_type
@ -32,9 +32,9 @@ class TVChaosUKProvider(generic.TorrentProvider):
def __init__(self):
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,
'login': self.url_base + 'takelogin.php',
'login_action': self.url_base + 'login.php',
'search': self.url_base + 'browse.php',
'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.search_fallback = True
self.cache = TVChaosUKCache(self)
def _authorised(self, **kwargs):
@ -92,8 +91,9 @@ class TVChaosUKProvider(generic.TorrentProvider):
info = tr.find('a', href=rc['info'])
title = (tr.find('div', attrs={'class': 'tooltip-content'}).get_text() or info.get_text()).strip()
title = re.findall('(?m)(^[^\r\n]+)', title)[0]
download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip(
'/').replace(self.urls['config_provider_home_uri'], '')
download_url = str(tr.find('a', href=rc['get'])['href'])
if not download_url.startswith('http'):
download_url = self.urls['get'] % download_url.lstrip('/')
except Exception:
continue
@ -134,6 +134,7 @@ class TVChaosUKProvider(generic.TorrentProvider):
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 [' ', '.']:
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:
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 ''
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()

View file

@ -17,7 +17,8 @@
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
from . import generic
from sickbeard import logger, tvcache
from sickbeard import tvcache
import time
class WombleProvider(generic.NZBProvider):
@ -34,46 +35,23 @@ class WombleCache(tvcache.TVCache):
def __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
self._clearCache()
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)
result = []
for section in ['sd', 'hd', 'x264', 'dvd']:
url = '%srss/?sec=tv-%s&fr=false' % (self.provider.url, section)
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
if not data:
return []
self.provider.log_result(count=len(result) - cnt, url=url)
# By now we know we've got data and no auth errors, all we need to do is put it in the database
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]
return result
provider = WombleProvider()

View file

@ -179,6 +179,21 @@ def snatch_episode(result, end_status=SNATCHED):
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):
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)
continue
re_extras = dict(re_prefix='.*', re_suffix='.*')
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)
if not pass_show_wordlist_checks(cur_result.name, show):
continue
cur_size = getattr(cur_result, 'size', None)
@ -427,8 +434,11 @@ def search_for_needed_episodes(episodes):
threading.currentThread().name = orig_thread_name
if not search_done:
logger.log(u'No NZB/Torrent provider enabled to do recent searches. Please check provider options.', logger.ERROR)
if not len(providers):
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()
@ -672,12 +682,39 @@ def search_providers(show, episodes, manual_search=False):
continue
# filter out possible bad torrents from providers
if 'torrent' == best_result.resultType and 'blackhole' != sickbeard.TORRENT_METHOD:
best_result.content = None
if not best_result.url.startswith('magnet'):
best_result.content = best_result.provider.get_url(best_result.url)
if not best_result.content:
if 'torrent' == best_result.resultType:
if best_result.url.startswith('magnet'):
if 'blackhole' != sickbeard.TORRENT_METHOD:
best_result.content = None
else:
td = best_result.provider.get_url(best_result.url)
if not td:
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
found = False
@ -702,8 +739,10 @@ def search_providers(show, episodes, manual_search=False):
if len(episodes) == wanted_ep_count:
break
if not search_done:
logger.log(u'No NZB/Torrent providers found or enabled in the SickGear config for backlog searches. Please check your settings.',
logger.ERROR)
if not len(provider_list):
logger.log('No NZB/Torrent sources enabled in Search Provider options to do backlog searches', logger.WARNING)
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

View file

@ -18,7 +18,6 @@
from __future__ import with_statement
import time
import traceback
import threading
import datetime
@ -288,21 +287,29 @@ class RecentSearchQueueItem(generic_queue.QueueItem):
orig_thread_name = threading.currentThread().name
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]
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,
name='%s :: [%s]' % (orig_thread_name, cur_provider.name)))
# start the thread we just created
threads[-1].start()
# wait for all threads to finish
for t in threads:
t.join()
if not len(providers):
logger.log('No NZB/Torrent sources enabled in Search Provider options for cache update', logger.WARNING)
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):
@ -427,7 +434,7 @@ class FailedQueueItem(generic_queue.QueueItem):
history.logFailed(epObj, release, provider)
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)

View file

@ -32,6 +32,7 @@ from name_parser.parser import NameParser, InvalidNameException, InvalidShowExce
from sickbeard.rssfeeds import RSSFeeds
import itertools
class CacheDBConnection(db.DBConnection):
def __init__(self, providerName):
db.DBConnection.__init__(self, 'cache.db')
@ -44,6 +45,7 @@ class CacheDBConnection(db.DBConnection):
if str(e) != 'table lastUpdate already exists':
raise
class TVCache:
def __init__(self, provider):
@ -56,7 +58,7 @@ class TVCache:
return CacheDBConnection(self.providerID)
def _clearCache(self):
if self.shouldClearCache():
if self.should_clear_cache():
myDB = self.get_db()
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)
return []
if self.shouldUpdate():
# as long as the http request worked we count this as an update
if self.should_update():
data = self._cache_data()
if not data:
return []
# clear cache
self._clearCache()
# set updated
self.setLastUpdate()
if data:
self._clearCache()
# parse data
cl = []
for item in data:
for item in data or []:
title, url = self._title_and_url(item)
ci = self._parseItem(title, url)
if ci is not None:
@ -105,6 +102,9 @@ class TVCache:
myDB = self.get_db()
myDB.mass_action(cl)
# set updated as time the attempt to fetch data is
self.setLastUpdate()
return []
def getRSSFeed(self, url, **kwargs):
@ -180,21 +180,13 @@ class TVCache:
lastUpdate = property(_getLastUpdate)
lastSearch = property(_getLastSearch)
def shouldUpdate(self):
def should_update(self):
# if we've updated recently then skip the update
if 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 datetime.datetime.today() - self.lastUpdate >= datetime.timedelta(minutes=self.update_freq)
return True
def shouldClearCache(self):
def should_clear_cache(self):
# if recent search hasn't used our previous results yet then don't clear the cache
if self.lastUpdate > self.lastSearch:
return False
return True
return self.lastSearch >= self.lastUpdate
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
# a 0 in the key spot indicates that no key is needed
if key == '0':
providerDict[name].needs_auth = False
else:
providerDict[name].needs_auth = True
providerDict[name].needs_auth = '0' != key
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):
results = []
provider_str_list = provider_order.split()
provider_list = []
newznabProviderDict = dict(
zip([x.get_id() for x in sickbeard.newznabProviderList], sickbeard.newznabProviderList))
finishedNames = []
# add all the newznab info we got into our list
# add all the newznab info we have into our list
newznab_sources = dict(zip([x.get_id() for x in sickbeard.newznabProviderList], sickbeard.newznabProviderList))
active_ids = []
if newznab_string:
for curNewznabProviderStr in newznab_string.split('!!!'):
@ -4789,282 +4781,157 @@ class ConfigProviders(Config):
if starify(cur_key, True):
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 cur_id in newznabProviderDict:
newznabProviderDict[cur_id].name = cur_name
newznabProviderDict[cur_id].url = cur_url
if cur_id in newznab_sources:
nzb_src = newznab_sources[cur_id]
nzb_src.name, nzb_src.url, nzb_src.cat_ids = cur_name, cur_url, cur_cat
if cur_key:
newznabProviderDict[cur_id].key = cur_key
newznabProviderDict[cur_id].cat_ids = cur_cat
nzb_src.key = cur_key
# a 0 in the key spot indicates that no key is needed
if cur_key == '0':
newznabProviderDict[cur_id].needs_auth = False
else:
newznabProviderDict[cur_id].needs_auth = True
nzb_src.needs_auth = '0' != cur_key
try:
newznabProviderDict[cur_id].search_mode = str(kwargs[cur_id + '_search_mode']).strip()
except:
pass
attr = 'search_mode'
if cur_id + '_' + attr in kwargs:
setattr(nzb_src, attr, str(kwargs.get(cur_id + '_' + attr)).strip())
try:
newznabProviderDict[cur_id].search_fallback = config.checkbox_to_value(
kwargs[cur_id + '_search_fallback'])
except:
newznabProviderDict[cur_id].search_fallback = 0
for attr in ['search_fallback', 'enable_recentsearch', 'enable_backlog']:
setattr(nzb_src, attr, config.checkbox_to_value(kwargs.get(cur_id + '_' + attr)))
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:
sickbeard.newznabProviderList.append(newProvider)
sickbeard.newznabProviderList.append(new_provider)
finishedNames.append(cur_id)
active_ids.append(cur_id)
# delete anything that is missing
for curProvider in sickbeard.newznabProviderList:
if curProvider.get_id() not in finishedNames:
sickbeard.newznabProviderList.remove(curProvider)
torrentRssProviderDict = dict(
zip([x.get_id() for x in sickbeard.torrentRssProviderList], sickbeard.torrentRssProviderList))
finishedNames = []
for source in [x for x in sickbeard.newznabProviderList if x.get_id() not in active_ids]:
sickbeard.newznabProviderList.remove(source)
# 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:
for curTorrentRssProviderStr in torrentrss_string.split('!!!'):
if not curTorrentRssProviderStr:
continue
curName, curURL, curCookies = curTorrentRssProviderStr.split('|')
curURL = config.clean_url(curURL, False)
cur_name, cur_url, cur_cookies = curTorrentRssProviderStr.split('|')
cur_url = config.clean_url(cur_url, False)
if starify(curCookies, True):
curCookies = ''
if starify(cur_cookies, True):
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 curID in torrentRssProviderDict:
torrentRssProviderDict[curID].name = curName
torrentRssProviderDict[curID].url = curURL
if curCookies:
torrentRssProviderDict[curID].cookies = curCookies
if cur_id in torrent_rss_sources:
torrent_rss_sources[cur_id].name = cur_name
torrent_rss_sources[cur_id].url = cur_url
if cur_cookies:
torrent_rss_sources[cur_id].cookies = cur_cookies
else:
sickbeard.torrentRssProviderList.append(newProvider)
sickbeard.torrentRssProviderList.append(new_provider)
finishedNames.append(curID)
active_ids.append(cur_id)
# delete anything that is missing
for curProvider in sickbeard.torrentRssProviderList:
if curProvider.get_id() not in finishedNames:
sickbeard.torrentRssProviderList.remove(curProvider)
for source in [x for x in sickbeard.torrentRssProviderList if x.get_id() not in active_ids]:
sickbeard.torrentRssProviderList.remove(source)
# do the enable/disable
for curProviderStr in provider_str_list:
curProvider, curEnabled = curProviderStr.split(':')
curEnabled = config.to_int(curEnabled)
# enable/disable states of source providers
provider_str_list = provider_order.split()
sources = dict(zip([x.get_id() for x in sickbeard.providers.sortedProviderList()],
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
x.get_id() == curProvider and hasattr(x, 'enabled')]
if curProvObj:
curProvObj[0].enabled = bool(curEnabled)
provider_list.append(src_name)
src_enabled = bool(config.to_int(src_enabled))
provider_list.append(curProvider)
if curProvider in newznabProviderDict:
newznabProviderDict[curProvider].enabled = bool(curEnabled)
elif curProvider in torrentRssProviderDict:
torrentRssProviderDict[curProvider].enabled = bool(curEnabled)
if src_name in sources and hasattr(sources[src_name], 'enabled'):
sources[src_name].enabled = src_enabled
# dynamically load provider settings
for curTorrentProvider in [curProvider for curProvider in sickbeard.providers.sortedProviderList() if
curProvider.providerType == sickbeard.GenericProvider.TORRENT]:
if src_name in newznab_sources:
newznab_sources[src_name].enabled = src_enabled
elif src_name in torrent_rss_sources:
torrent_rss_sources[src_name].enabled = src_enabled
if hasattr(curTorrentProvider, '_seed_ratio'):
try:
curTorrentProvider._seed_ratio = str(kwargs[curTorrentProvider.get_id() + '_ratio']).strip()
except:
curTorrentProvider._seed_ratio = None
# update torrent source settings
for torrent_src in [src for src in sickbeard.providers.sortedProviderList()
if sickbeard.GenericProvider.TORRENT == src.providerType]:
src_id_prefix = torrent_src.get_id() + '_'
if hasattr(curTorrentProvider, 'seed_time') and curTorrentProvider.get_id() + '_seed_time' in kwargs:
curTorrentProvider.seed_time = config.to_int(str(kwargs[curTorrentProvider.get_id() + '_seed_time']).strip(), 0)
attr = 'url_edit'
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'):
try:
curTorrentProvider.minseed = int(str(kwargs[curTorrentProvider.get_id() + '_minseed']).strip())
except:
curTorrentProvider.minseed = 0
for attr in [x for x in ['username', 'uid'] if hasattr(torrent_src, x)]:
setattr(torrent_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip())
if hasattr(curTorrentProvider, 'minleech'):
try:
curTorrentProvider.minleech = int(str(kwargs[curTorrentProvider.get_id() + '_minleech']).strip())
except:
curTorrentProvider.minleech = 0
for attr in [x for x in ['password', 'api_key', 'passkey', 'digest', 'hash'] if hasattr(torrent_src, x)]:
key = str(kwargs.get(src_id_prefix + attr, '')).strip()
if 'password' == attr:
set('*') != set(key) and setattr(torrent_src, attr, key)
elif not starify(key, True):
setattr(torrent_src, attr, key)
if hasattr(curTorrentProvider, 'digest'):
try:
key = str(kwargs[curTorrentProvider.get_id() + '_digest']).strip()
if not starify(key, True):
curTorrentProvider.digest = key
except:
curTorrentProvider.digest = None
attr = 'ratio'
if hasattr(torrent_src, '_seed_' + attr):
setattr(torrent_src, '_seed_' + attr, kwargs.get(src_id_prefix + attr, '').strip() or None)
if hasattr(curTorrentProvider, 'hash'):
try:
key = str(kwargs[curTorrentProvider.get_id() + '_hash']).strip()
if not starify(key, True):
curTorrentProvider.hash = key
except:
curTorrentProvider.hash = None
for attr in [x for x in ['minseed', 'minleech'] if hasattr(torrent_src, x)]:
setattr(torrent_src, attr, config.to_int(str(kwargs.get(src_id_prefix + attr)).strip()))
if hasattr(curTorrentProvider, 'api_key'):
try:
key = str(kwargs[curTorrentProvider.get_id() + '_api_key']).strip()
if not starify(key, True):
curTorrentProvider.api_key = key
except:
curTorrentProvider.api_key = None
for attr in [x for x in ['confirmed', 'freeleech', 'reject_m2ts', 'enable_recentsearch',
'enable_backlog', 'search_fallback'] if hasattr(torrent_src, x)]:
setattr(torrent_src, attr, config.checkbox_to_value(kwargs.get(src_id_prefix + attr)))
if hasattr(curTorrentProvider, 'username'):
try:
curTorrentProvider.username = str(kwargs[curTorrentProvider.get_id() + '_username']).strip()
except:
curTorrentProvider.username = None
attr = 'seed_time'
if hasattr(torrent_src, attr) and src_id_prefix + attr in kwargs:
setattr(torrent_src, attr, config.to_int(str(kwargs.get(src_id_prefix + attr)).strip()))
if hasattr(curTorrentProvider, 'password'):
try:
key = str(kwargs[curTorrentProvider.get_id() + '_password']).strip()
if set('*') != set(key):
curTorrentProvider.password = key
except:
curTorrentProvider.password = None
attr = 'search_mode'
if hasattr(torrent_src, attr):
setattr(torrent_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip() or 'eponly')
if hasattr(curTorrentProvider, 'passkey'):
try:
key = str(kwargs[curTorrentProvider.get_id() + '_passkey']).strip()
if not starify(key, True):
curTorrentProvider.passkey = key
except:
curTorrentProvider.passkey = None
# update nzb source settings
for nzb_src in [src for src in sickbeard.providers.sortedProviderList() if
sickbeard.GenericProvider.NZB == src.providerType]:
src_id_prefix = nzb_src.get_id() + '_'
if hasattr(curTorrentProvider, 'confirmed'):
try:
curTorrentProvider.confirmed = config.checkbox_to_value(
kwargs[curTorrentProvider.get_id() + '_confirmed'])
except:
curTorrentProvider.confirmed = 0
attr = 'api_key'
if hasattr(nzb_src, attr):
key = str(kwargs.get(src_id_prefix + attr, '')).strip()
if not starify(key, True):
setattr(nzb_src, attr, key)
if hasattr(curTorrentProvider, 'proxy'):
try:
curTorrentProvider.proxy.enabled = config.checkbox_to_value(
kwargs[curTorrentProvider.get_id() + '_proxy'])
except:
curTorrentProvider.proxy.enabled = 0
attr = 'username'
if hasattr(nzb_src, attr):
setattr(nzb_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip() or None)
if hasattr(curTorrentProvider.proxy, 'url'):
try:
curTorrentProvider.proxy.url = str(kwargs[curTorrentProvider.get_id() + '_proxy_url']).strip()
except:
curTorrentProvider.proxy.url = None
attr = 'search_mode'
if hasattr(nzb_src, attr):
setattr(nzb_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip() or 'eponly')
if hasattr(curTorrentProvider, 'freeleech'):
try:
curTorrentProvider.freeleech = config.checkbox_to_value(
kwargs[curTorrentProvider.get_id() + '_freeleech'])
except:
curTorrentProvider.freeleech = 0
attr = 'enable_recentsearch'
if hasattr(nzb_src, attr):
setattr(nzb_src, attr, config.checkbox_to_value(kwargs.get(src_id_prefix + attr)) or
not getattr(nzb_src, 'supports_backlog', True))
if hasattr(curTorrentProvider, 'reject_m2ts'):
try:
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
for attr in [x for x in ['search_fallback', 'enable_backlog'] if hasattr(nzb_src, x)]:
setattr(nzb_src, attr, config.checkbox_to_value(kwargs.get(src_id_prefix + attr)))
sickbeard.NEWZNAB_DATA = '!!!'.join([x.config_str() for x in sickbeard.newznabProviderList])
sickbeard.PROVIDER_ORDER = provider_list
@ -5073,11 +4940,10 @@ class ConfigProviders(Config):
sickbeard.save_config()
if len(results) > 0:
if 0 < len(results):
for x in results:
logger.log(x, logger.ERROR)
ui.notifications.error('Error(s) Saving Configuration',
'<br />\n'.join(results))
ui.notifications.error('Error(s) Saving Configuration', '<br />\n'.join(results))
else:
ui.notifications.message('Configuration Saved', ek.ek(os.path.join, sickbeard.CONFIG_FILE))