Merge pull request #728 from JackDandy/feature/AddQBitTorrentClient

Add qBitTorrent to Search Settings/Torrent Search.
This commit is contained in:
JackDandy 2016-07-04 21:21:00 +01:00 committed by GitHub
commit 012c12ecd8
12 changed files with 399 additions and 303 deletions

View file

@ -102,6 +102,8 @@
* Change improve highlight of shows found in database in "Add New Show" results * Change improve highlight of shows found in database in "Add New Show" results
* Change use full first aired date where available in "Add New Show" results * Change use full first aired date where available in "Add New Show" results
* Change prevent duplicate results in "Add New Show" * Change prevent duplicate results in "Add New Show"
* Add qBitTorrent to Search Settings/Torrent Search
* Add "Test NZBGet" client to Search Settings/NZB Search/NZBGet
[develop changelog] [develop changelog]
* Change send nzb data to NZBGet for Anizb instead of url * Change send nzb data to NZBGet for Anizb instead of url

View file

@ -441,8 +441,8 @@
</label> </label>
</div> </div>
#end if #end if
#if $hasattr($cur_torrent_provider, '_seed_ratio') and 'blackhole' != $sickbeard.TORRENT_METHOD: #if $hasattr($cur_torrent_provider, '_seed_ratio') and $sickbeard.TORRENT_METHOD not in ('blackhole', 'qbittorrent'):
#set $torrent_method_text = {'utorrent': 'uTorrent', 'transmission': 'Transmission', 'deluge': 'Deluge', 'download_station': 'Synology DS', 'rtorrent': 'rTorrent'} #set $torrent_method_text = {'deluge': 'Deluge', 'qbittorrent': 'qBittorrent', 'rtorrent': 'rTorrent', 'download_station': 'Synology DS', 'transmission': 'Transmission', 'utorrent': 'uTorrent'}
<div class="field-pair"> <div class="field-pair">
<label for="${cur_torrent_provider.get_id()}_ratio"> <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-title" id="${cur_torrent_provider.get_id()}_ratio_desc">Seed until ratio (the goal)</span>

View file

@ -9,7 +9,11 @@
## ##
#import os.path #import os.path
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_top.tmpl') #include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_top.tmpl')
<script>
<!--
var config = {defaultHost: $clients.default_host}
//-->
</script>
<script type="text/javascript" src="$sbRoot/js/configSearch.js?v=$sbPID"></script> <script type="text/javascript" src="$sbRoot/js/configSearch.js?v=$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/config.js?v=$sbPID"></script> <script type="text/javascript" src="$sbRoot/js/config.js?v=$sbPID"></script>
@ -211,7 +215,7 @@
</label> </label>
</div> </div>
<div id="blackhole_settings"> <div id="blackhole-settings">
<div class="field-pair"> <div class="field-pair">
<label> <label>
<span class="component-title">Black hole folder location</span> <span class="component-title">Black hole folder location</span>
@ -223,7 +227,7 @@
</div> </div>
</div> </div>
<div id="sabnzbd_settings"> <div id="sabnzbd-settings">
<div class="field-pair"> <div class="field-pair">
<label> <label>
<span class="component-title">SABnzbd server URL</span> <span class="component-title">SABnzbd server URL</span>
@ -275,7 +279,7 @@
</div> </div>
</div> </div>
<div id="nzbget_settings"> <div id="nzbget-settings">
<div class="field-pair"> <div class="field-pair">
<label for="nzbget_use_https"> <label for="nzbget_use_https">
<span class="component-title">Connect using HTTPS</span> <span class="component-title">Connect using HTTPS</span>
@ -302,7 +306,7 @@
<label> <label>
<span class="component-title">NZBget username</span> <span class="component-title">NZBget username</span>
<span class="component-desc"> <span class="component-desc">
<input type="text" name="nzbget_username" value="$sickbeard.NZBGET_USERNAME" class="form-control input-sm input200"> <input type="text" name="nzbget_username" id="nzbget_username" value="$sickbeard.NZBGET_USERNAME" class="form-control input-sm input200">
<p>locate in nzbget.conf (default:nzbget)</p> <p>locate in nzbget.conf (default:nzbget)</p>
</span> </span>
</label> </label>
@ -367,8 +371,9 @@
</div> </div>
</div> </div>
<div class="testNotification" id="testSABnzbd_result">Click below to test</div> <div class="testNotification" id="test-nzb-result">Click below to test</div>
<input class="btn" type="button" value="Test SABnzbd" id="testSABnzbd" class="btn test-button"> <input type="button" value="Test SABnzbd" id="test_sabnzbd" class="btn test-button sabnzbd">
<input type="button" value="Test NZBget" id="test_nzbget" class="btn test-button nzbget">
<input type="submit" class="btn config_submitter" value="Save Changes"><br /> <input type="submit" class="btn config_submitter" value="Save Changes"><br />
</div><!-- /content_use_nzbs //--> </div><!-- /content_use_nzbs //-->
@ -402,15 +407,16 @@
<span class="component-title">Send .torrent files to:</span> <span class="component-title">Send .torrent files to:</span>
<span class="component-desc"> <span class="component-desc">
<select name="torrent_method" id="torrent_method" class="form-control input-sm"> <select name="torrent_method" id="torrent_method" class="form-control input-sm">
#set $torrent_method_text = {'blackhole': "Black hole", 'utorrent': "uTorrent", 'transmission': "Transmission", 'deluge': "Deluge", 'download_station': "Synology DS", 'rtorrent': "rTorrent"} #set $torrent_method_text = {'blackhole': "Black hole", 'utorrent': "uTorrent", 'transmission': "Transmission", 'qbittorrent': "qBittorrent", 'deluge': "Deluge", 'download_station': "Synology DS", 'rtorrent': "rTorrent"}
#for $curAction in ('blackhole', 'utorrent', 'transmission', 'deluge', 'download_station', 'rtorrent'): #for $curAction in ('blackhole', 'deluge', 'qbittorrent', 'rtorrent', 'download_station', 'transmission', 'utorrent'):
#set $selected = $html_selected if $sickbeard.TORRENT_METHOD == $curAction else '' #set $selected = $html_selected if $sickbeard.TORRENT_METHOD == $curAction else ''
<option value="$curAction"$selected>$torrent_method_text[$curAction]</option> <option value="$curAction"$selected>$torrent_method_text[$curAction]</option>
#end for #end for
</select> </select>
</span>
</label> </label>
<div id="options_torrent_blackhole"> <div id="options-torrent-blackhole">
<div class="field-pair"> <div class="field-pair">
<label> <label>
<span class="component-title">Black hole folder location</span> <span class="component-title">Black hole folder location</span>
@ -426,22 +432,22 @@
</div> </div>
</div> </div>
<div id="options_torrent_clients"> <div id="options-torrent-clients">
<div class="field-pair"> <div class="field-pair">
<label> <label>
<span class="component-title" id="host_title">Torrent host:port</span> <span class="component-title" id="host-title">Torrent host:port</span>
<span class="component-desc"> <span class="component-desc">
<input type="text" name="torrent_host" id="torrent_host" value="$sickbeard.TORRENT_HOST" class="form-control input-sm input350"> <input type="text" name="torrent_host" id="torrent_host" value="$sickbeard.TORRENT_HOST" class="form-control input-sm input350">
<p class="clear-left note"> <p class="clear-left note">
<span id="host_desc_torrent">URL to your torrent client (e.g. http://localhost:8000/)</span> <span id="host-desc-torrent">URL to your torrent client (e.g. <span class="default-host">http://localhost:8000</span>/)</span>
<span id="host_desc_rtorrent" style="display:none"><b>Note:</b> <i>rTorrent</i> client URLs use e.g. scgi://localhost:5000/</span> <span id="host-desc-deluge" style="display:none">URL to your Deluge WebUI (e.g. <span class="default-host">http://localhost:8112</span>/)</span>
<span id="host_desc_deluge" style="display:none">URL to your Deluge WebUI (e.g. http://localhost:8112/)</span> <span id="host-desc-rtorrent" style="display:none"><b>Note:</b> <i>rTorrent</i> client URLs use e.g. <span class="default-host">scgi://localhost:5000</span>/</span>
</p> </p>
</span> </span>
</label> </label>
</div> </div>
<div class="field-pair" id="torrent_verify_cert_option"> <div class="field-pair" id="torrent-verify-cert-option">
<label for="torrent_verify_cert"> <label for="torrent_verify_cert">
<span class="component-title">Verify certificate</span> <span class="component-title">Verify certificate</span>
<span class="component-desc"> <span class="component-desc">
@ -451,9 +457,9 @@
</label> </label>
</div> </div>
<div class="field-pair" id="torrent_username_option"> <div class="field-pair" id="torrent-username-option">
<label> <label>
<span class="component-title" id="username_title">Client username</span> <span class="component-title" id="username-title">Client username</span>
<span class="component-desc"> <span class="component-desc">
<input type="text" name="torrent_username" id="torrent_username" value="$sickbeard.TORRENT_USERNAME" class="form-control input-sm input200"> <input type="text" name="torrent_username" id="torrent_username" value="$sickbeard.TORRENT_USERNAME" class="form-control input-sm input200">
<p>(blank for none)</p> <p>(blank for none)</p>
@ -463,7 +469,7 @@
<div class="field-pair"> <div class="field-pair">
<label> <label>
<span class="component-title" id="password_title">Client password</span> <span class="component-title" id="password-title">Client password</span>
<span class="component-desc"> <span class="component-desc">
<input type="password" name="torrent_password" id="torrent_password" value="#echo '*' * len($sickbeard.TORRENT_PASSWORD)#" class="form-control input-sm input200"> <input type="password" name="torrent_password" id="torrent_password" value="#echo '*' * len($sickbeard.TORRENT_PASSWORD)#" class="form-control input-sm input200">
<p>(blank for none)</p> <p>(blank for none)</p>
@ -471,31 +477,36 @@
</label> </label>
</div> </div>
<div class="field-pair" id="torrent_label_option"> <div class="field-pair" id="torrent-label-option">
<label> <label>
<span class="component-title">Add label to torrent</span> <span class="component-title">Set torrent label<span class="qbittorrent">/category</span></span>
<span class="component-desc"> <span class="component-desc">
<input type="text" name="torrent_label" id="torrent_label" value="$sickbeard.TORRENT_LABEL" class="form-control input-sm input200"> <input type="text" name="torrent_label" id="torrent_label" value="$sickbeard.TORRENT_LABEL" class="form-control input-sm input200">
<span id="label_warning_deluge" style="display:none"><p>(blank spaces are not allowed)</p> <span id="label-warning-deluge" style="display:none"><p>(blank spaces are not allowed)</p>
<p class="clear-left note">note: label plugin must be enabled in Deluge clients</p> <p class="clear-left note">note: label plugin must be enabled in Deluge clients</p>
</span> </span>
<span class="qbittorrent" style="display:none"><p>(qB 3.3.1 and newer clients)</p></span>
</span> </span>
</label> </label>
</div> </div>
<div class="field-pair" id="torrent_path_option"> <div class="field-pair" id="torrent-path-option">
<label> <label>
<span class="component-title" id="directory_title">Downloaded files location</span> <span class="component-title">Downloaded files location</span>
<span class="component-desc"> <span class="component-desc">
<input type="text" name="torrent_path" id="torrent_path" value="$sickbeard.TORRENT_PATH" class="form-control input-sm input350"> <input type="text" name="torrent_path" id="torrent_path" value="$sickbeard.TORRENT_PATH" class="form-control input-sm input350">
<p class="clear-left note">where <span id="torrent_client">the torrent client</span> will save downloaded files <span id="path_blank">(blank for client default)</span> <p class="clear-left note">
<span id="path_synology"> <b>note:</b> the destination has to be a shared folder for Synology DS</span> where <span id="torrent-client">the torrent client</span> will save files
<span id="path_transmission" class="grey-text"> (v2.92 and newer should <em>not</em> be blank)</span></p> <span class="qbittorrent">(blank otherwise set will ignore label/category)</span>
<span id="path-blank">(blank for client default)</span>
<span class="synology"> <b>note:</b> the destination has to be a shared folder for Synology DS</span>
<span class="transmission grey-text"> (v2.92 and newer should <em>not</em> be blank)</span>
</p>
</span> </span>
</label> </label>
</div> </div>
<div class="field-pair" id="torrent_seed_time_option"> <div class="field-pair" id="torrent-seed-time-option">
<label> <label>
<span class="component-title">Seed time (minimum default)</span> <span class="component-title">Seed time (minimum default)</span>
<span class="component-desc"><input type="number" step="0.1" name="torrent_seed_time" id="torrent_seed_time" value="$sickbeard.TORRENT_SEED_TIME" class="form-control input-sm input100"> <span class="component-desc"><input type="number" step="0.1" name="torrent_seed_time" id="torrent_seed_time" value="$sickbeard.TORRENT_SEED_TIME" class="form-control input-sm input100">
@ -503,7 +514,7 @@
</label> </label>
</div> </div>
<div class="field-pair" id="torrent_paused_option"> <div class="field-pair" id="torrent-paused-option">
<label> <label>
<span class="component-title">Start torrent paused</span> <span class="component-title">Start torrent paused</span>
<span class="component-desc"> <span class="component-desc">
@ -513,7 +524,7 @@
</label> </label>
</div> </div>
<div class="field-pair" id="torrent_high_bandwidth_option"> <div class="field-pair" id="torrent-high-bandwidth-option">
<label> <label>
<span class="component-title">Allow high bandwidth</span> <span class="component-title">Allow high bandwidth</span>
<span class="component-desc"> <span class="component-desc">
@ -523,8 +534,8 @@
</label> </label>
</div> </div>
<div class="testNotification" id="test_torrent_result">Click below to test</div> <div class="testNotification" id="test-torrent-result">Click below to test</div>
<input class="btn" type="button" value="Test Connection" id="test_torrent" class="btn test-button"> <input type="button" value="Test Connection" id="test_torrent" class="btn test-button">
<input type="submit" class="btn config_submitter" value="Save Changes"><br /> <input type="submit" class="btn config_submitter" value="Save Changes"><br />
</div> </div>
</div><!-- /content_use_torrents //--> </div><!-- /content_use_torrents //-->

View file

@ -1,158 +1,154 @@
/** @namespace config.defaultHost */
$(document).ready(function(){ $(document).ready(function(){
var loading = '<img src="' + sbRoot + '/images/loading16' + themeSpinner + '.gif" height="16" width="16" />'; var loading = '<img src="' + sbRoot + '/images/loading16' + themeSpinner + '.gif" height="16" width="16" />';
function toggle_torrent_title(){ function toggleTorrentTitle() {
var noTorrent$ = $('#no_torrents');
if ($('#use_torrents').prop('checked')) if ($('#use_torrents').prop('checked'))
$('#no_torrents').show(); noTorrent$.show();
else else
$('#no_torrents').hide(); noTorrent$.hide();
} }
$.fn.nzb_method_handler = function() { $.fn.nzbMethodHandler = function() {
var selectedProvider = $('#nzb_method :selected').val(), var selectedProvider = $('#nzb_method').find(':selected').val(),
blackhole_settings = '#blackhole_settings', blackholeSettings = '#blackhole-settings',
sabnzbd_settings = '#sabnzbd_settings', nzbgetSettings = '#nzbget-settings, #test-nzb-result, .nzbget',
testSABnzbd = '#testSABnzbd', sabnzbdSettings = '#sabnzbd-settings, #test-nzb-result, .sabnzbd';
testSABnzbd_result = '#testSABnzbd_result',
nzbget_settings = '#nzbget_settings';
$(blackhole_settings).hide(); $('#test-sabnzbd-result').html('Click below to test');
$(sabnzbd_settings).hide(); $([blackholeSettings, nzbgetSettings, sabnzbdSettings].join(',')).hide();
$(testSABnzbd).hide();
$(testSABnzbd_result).hide();
$(nzbget_settings).hide();
if ('blackhole' == selectedProvider) { if ('blackhole' == selectedProvider) {
$(blackhole_settings).show(); $(blackholeSettings).show();
} else if ('nzbget' == selectedProvider) { } else if ('nzbget' == selectedProvider) {
$(nzbget_settings).show(); $(nzbgetSettings).show();
} else { } else {
$(sabnzbd_settings).show(); $(sabnzbdSettings).show();
$(testSABnzbd).show();
$(testSABnzbd_result).show();
}
} }
};
$('#nzb_method').change($(this).nzbMethodHandler);
$(this).nzbMethodHandler();
$.fn.torrent_method_handler = function() { $.fn.torrentMethodHandler = function() {
$('#options_torrent_clients').hide(); var selectedProvider = $('#torrent_method').find(':selected').val(),
$('#options_torrent_blackhole').hide(); host = ' host:port', username = ' username', password = ' password',
var selectedProvider = $('#torrent_method :selected').val(),
host = ' host:port',
username = ' username',
password = ' password',
label = ' label', label = ' label',
directory = ' directory', directory = ' directory',
client = '', client = '',
option_panel = '#options_torrent_blackhole'; hideHostDesc = !1, hidePausedOption = !1, hideLabelOption = !1, hidePathBlank = !1,
optionsBlackhole = '#options-torrent-blackhole',
optionsClients = '#options-torrent-clients',
optionsPanel = optionsBlackhole;
$(optionsBlackhole).hide();
$(optionsClients).hide();
$('#test-torrent-result').html('Click below to test');
$('.default-host').html(config.defaultHost[selectedProvider]);
if ('blackhole' != selectedProvider) { if ('blackhole' != selectedProvider) {
var label_warning_deluge = '#label_warning_deluge', var labelWarningDeluge = '#label-warning-deluge',
host_desc_rtorrent = '#host_desc_rtorrent', hostDesc = '#host-desc-torrent',
host_desc_torrent = '#host_desc_torrent', hostDescDeluge = '#host-desc-deluge',
torrent_verify_cert_option = '#torrent_verify_cert_option', hostDescRtorrent = '#host-desc-rtorrent',
torrent_path_option = '#torrent_path_option', usernameOption = '#torrent-username-option',
torrent_seed_time_option = '#torrent_seed_time_option', verifyCertOption = '#torrent-verify-cert-option',
torrent_high_bandwidth_option = '#torrent_high_bandwidth_option', labelOption = '#torrent-label-option',
torrent_label_option = '#torrent_label_option', qBitTorrent = '.qbittorrent',
path_blank = '#path_blank', synology = '.synology',
path_transmission = '#path_transmission', transmission = '.transmission',
path_synology = '#path_synology', pathOption = '#torrent-path-option',
torrent_paused_option = '#torrent_paused_option'; pathBlank = '#path-blank',
seedTimeOption = '#torrent-seed-time-option',
pausedOption = '#torrent-paused-option',
highBandwidthOption = '#torrent-high-bandwidth-option';
$(label_warning_deluge).hide(); $([labelWarningDeluge, hostDescDeluge, hostDescRtorrent, verifyCertOption, seedTimeOption,
$(host_desc_rtorrent).hide(); highBandwidthOption, qBitTorrent, synology, transmission].join(',')).hide();
$(host_desc_deluge).hide();
$(host_desc_torrent).show();
$(torrent_username_option).show();
$(torrent_verify_cert_option).hide();
$(torrent_path_option).show();
$(torrent_path_option).find('.fileBrowser').show();
$(torrent_seed_time_option).hide();
$(torrent_high_bandwidth_option).hide();
$(torrent_label_option).show();
$(path_blank).show();
$(path_transmission).hide();
$(path_synology).hide();
$(torrent_paused_option).show();
if ('utorrent' == selectedProvider) { $([hostDesc, usernameOption, pathOption, labelOption, pathBlank, pausedOption].join(',')).show();
$(pathOption).find('.fileBrowser').show();
switch (selectedProvider) {
case 'utorrent':
client = 'uTorrent'; client = 'uTorrent';
$(torrent_path_option).hide(); $(pathOption).hide();
$(torrent_seed_time_option).show(); $(seedTimeOption).show();
} else if ('transmission' == selectedProvider){ break;
client = 'Transmission'; case 'deluge':
$(torrent_high_bandwidth_option).show(); client = 'Deluge'; hideHostDesc = !0;
$(torrent_label_option).hide(); $(usernameOption).hide();
//$('#directory_title').text(client + directory); $([hostDescDeluge, verifyCertOption, labelWarningDeluge].join(',')).show();
$(path_blank).hide(); break;
$(path_transmission).show(); case 'transmission':
} else if ('deluge' == selectedProvider){ client = 'Transmission'; hideLabelOption = !0; hidePathBlank = !0;
client = 'Deluge'; $([transmission, highBandwidthOption].join(',')).show();
$(torrent_verify_cert_option).show(); break;
$(label_warning_deluge).show(); case 'qbittorrent':
$(host_desc_torrent).hide(); // Setting Paused is buggy on qB, remove from use
$(host_desc_deluge).show(); client = 'qBittorrent'; hidePausedOption = !0; hidePathBlank = !0;
$(torrent_username_option).hide(); $(qBitTorrent).show();
//$('#directory_title').text(client + directory); break;
} else if ('download_station' == selectedProvider){ case 'download_station':
client = 'Synology DS'; client = 'Synology DS'; hideLabelOption = !0; hidePausedOption = !0;
$(torrent_label_option).hide(); $(pathOption).find('.fileBrowser').hide();
$('#torrent_paused_option').hide(); $(synology).show();
$(torrent_path_option).find('.fileBrowser').hide(); break;
//$('#directory_title').text(client + directory); case 'rtorrent':
$(path_synology).show(); client = 'rTorrent'; hideHostDesc = !0; hidePausedOption = !0;
} else if ('rtorrent' == selectedProvider){ $(hostDescRtorrent).show();
client = 'rTorrent'; break;
$(host_desc_torrent).hide();
$(host_desc_rtorrent).show();
$(torrent_paused_option).hide();
//$('#directory_title').text(client + directory);
} }
$('#host_title').text(client + host); hideHostDesc && $(hostDesc).hide();
$('#username_title').text(client + username); hideLabelOption && $(labelOption).hide();
$('#password_title').text(client + password); hidePausedOption && $(pausedOption).hide();
$('#torrent_client').text(client); hidePathBlank && $(pathBlank).hide();
option_panel = '#options_torrent_clients'; $('#host-title').text(client + host);
} $('#username-title').text(client + username);
$(option_panel).show(); $('#password-title').text(client + password);
$('#torrent-client').text(client);
optionsPanel = optionsClients;
} }
$(optionsPanel).show();
};
$('#torrent_method').change($(this).torrentMethodHandler);
$(this).torrentMethodHandler();
$('#nzb_method').change($(this).nzb_method_handler); $('#use_torrents').click(function() {
toggleTorrentTitle();
$(this).nzb_method_handler();
$('#testSABnzbd').click(function(){
$('#testSABnzbd_result').html(loading);
var sab_host = $('#sab_host').val();
var sab_username = $('#sab_username').val();
var sab_password = $('#sab_password').val();
var sab_apiKey = $('#sab_apikey').val();
$.get(sbRoot + '/home/testSABnzbd', {'host': sab_host, 'username': sab_username, 'password': sab_password, 'apikey': sab_apiKey},
function (data){ $('#testSABnzbd_result').html(data); });
}); });
$.fn.testResult = function(data, test$) {
// endpoint changed so gracefully handle 404s until restarted
$(test$).html(/404/.test(data) ? 'Test not found, a restart should fix' : data);
};
$('#torrent_method').change($(this).torrent_method_handler); $('#test_torrent').click(function() {
$('#test-torrent-result').html(loading);
$(this).torrent_method_handler(); $.get(sbRoot + '/home/test_torrent',
{'torrent_method': $('#torrent_method').find(':selected').val(), 'host': $('#torrent_host').val(),
$('#use_torrents').click(function(){ 'username': $('#torrent_username').val(), 'password': $('#torrent_password').val()},
toggle_torrent_title(); function(data) { $(this).testResult(data, '#test-torrent-result'); });
}); });
$('#test_torrent').click(function(){ $('#test_nzbget').click(function() {
$('#test_torrent_result').html(loading); $('#test-nzb-result').html(loading);
var torrent_method = $('#torrent_method :selected').val(); $.get(sbRoot + '/home/test_nzbget',
var torrent_host = $('#torrent_host').val(); {'host': $('#nzbget_host').val(), 'use_https': $('#nzbget_use_https').prop('checked'),
var torrent_username = $('#torrent_username').val(); 'username': $('#nzbget_username').val(), 'password': $('#nzbget_password').val()},
var torrent_password = $('#torrent_password').val(); function(data) { $(this).testResult(data, '#test-nzb-result'); });
});
$.get(sbRoot + '/home/testTorrent', {'torrent_method': torrent_method, 'host': torrent_host, 'username': torrent_username, 'password': torrent_password}, $('#test_sabnzbd').click(function() {
function (data){ $('#test_torrent_result').html(data); }); $('#test-nzb-result').html(loading);
$.get(sbRoot + '/home/test_sabnzbd',
{'host': $('#sab_host').val(), 'username': $('#sab_username').val(),
'password': $('#sab_password').val(), 'apikey': $('#sab_apikey').val()},
function(data) { $(this).testResult(data, '#test-nzb-result'); });
}); });
}); });

View file

@ -721,7 +721,8 @@ def initialize(consoleLogging=True):
NZB_METHOD = 'blackhole' NZB_METHOD = 'blackhole'
TORRENT_METHOD = check_setting_str(CFG, 'General', 'torrent_method', 'blackhole') TORRENT_METHOD = check_setting_str(CFG, 'General', 'torrent_method', 'blackhole')
if TORRENT_METHOD not in ('blackhole', 'utorrent', 'transmission', 'deluge', 'download_station', 'rtorrent'): if TORRENT_METHOD not in ('blackhole', 'deluge', 'download_station', 'qbittorrent',
'rtorrent', 'transmission', 'utorrent'):
TORRENT_METHOD = 'blackhole' TORRENT_METHOD = 'blackhole'
DOWNLOAD_PROPERS = bool(check_setting_int(CFG, 'General', 'download_propers', 1)) DOWNLOAD_PROPERS = bool(check_setting_int(CFG, 'General', 'download_propers', 1))

View file

@ -1,5 +1,4 @@
# Author: Nic Wolfe <nic@wolfeden.ca> # Author: Nic Wolfe <nic@wolfeden.ca>
# URL: http://code.google.com/p/sickbeard/
# #
# This file is part of SickGear. # This file is part of SickGear.
# #
@ -16,17 +15,26 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with SickGear. If not, see <http://www.gnu.org/licenses/>. # along with SickGear. If not, see <http://www.gnu.org/licenses/>.
__all__ = ['utorrent',
'transmission',
'deluge',
'download_station',
'rtorrent'
]
import sickbeard import sickbeard
from os import sys from os import sys
__all__ = ['deluge', 'download_station', 'qbittorrent', 'rtorrent', 'transmission', 'utorrent']
default_host = {
'deluge': 'http://localhost:8112',
'download_station': 'http://localhost:5000',
'rtorrent': 'scgi://localhost:5000',
'qbittorrent': 'http://localhost:8080',
'transmission': 'http://localhost:9091',
'utorrent': 'http://localhost:8000'}
def get_client_instance(name):
module = __import__('sickbeard.clients.%s' % name.lower(), fromlist=__all__)
return getattr(module, module.api.__class__.__name__)
# Mapping error status codes to official W3C names # Mapping error status codes to official W3C names
http_error_code = { http_error_code = {
300: 'Multiple Choices', 300: 'Multiple Choices',
@ -65,26 +73,4 @@ http_error_code = {
503: 'Service Unavailable', 503: 'Service Unavailable',
504: 'Gateway Timeout', 504: 'Gateway Timeout',
505: 'HTTP Version Not Supported', 505: 'HTTP Version Not Supported',
511: 'Network Authentication Required', 511: 'Network Authentication Required'}
}
default_host = {'utorrent': 'http://localhost:8000',
'transmission': 'http://localhost:9091',
'deluge': 'http://localhost:8112',
'download_station': 'http://localhost:5000',
'rtorrent': 'scgi://localhost:5000',
}
def getClientModule(name):
name = name.lower()
prefix = "sickbeard.clients."
return __import__(prefix + name, fromlist=__all__)
def getClientIstance(name):
module = getClientModule(name)
className = module.api.__class__.__name__
return getattr(module, className)

View file

@ -0,0 +1,74 @@
#
# 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/>.
from sickbeard import helpers, TORRENT_LABEL, TORRENT_PATH
from sickbeard.clients.generic import GenericClient
class QbittorrentAPI(GenericClient):
def __init__(self, host=None, username=None, password=None):
super(QbittorrentAPI, self).__init__('qBittorrent', host, username, password)
self.url = self.host
def _get_auth(self):
self.auth = (6 < self.api_version() and
'Ok' in helpers.getURL('%slogin' % self.host, session=self.session,
post_data={'username': self.username, 'password': self.password}))
return self.auth
def api_version(self):
return helpers.tryInt(helpers.getURL('%sversion/api' % self.host, session=self.session))
def _post_api(self, cmd='', **kwargs):
return '' == helpers.getURL('%scommand/%s' % (self.host, cmd), session=self.session, **kwargs)
def _add_torrent(self, cmd, **kwargs):
label = TORRENT_LABEL.replace(' ', '_')
label_dict = {'label': label, 'category': label, 'savepath': TORRENT_PATH}
if 'post_data' in kwargs:
kwargs['post_data'].update(label_dict)
else:
kwargs.update({'post_data': label_dict})
return self._post_api(cmd, **kwargs)
def _add_torrent_uri(self, result):
return self._add_torrent('download', post_data={'urls': result.url})
def _add_torrent_file(self, result):
return self._add_torrent('upload', files={'torrents': ('%s.torrent' % result.name, result.content)})
###
# An issue in qB can lead to actions being ignored during the initial period after a file is added.
# Therefore, actions that need to be applied to existing items will be disabled unless fixed.
###
# def _set_torrent_priority(self, result):
#
# return self._post_api('%screasePrio' % ('de', 'in')[1 == result.priority], post_data={'hashes': result.hash})
# def _set_torrent_pause(self, result):
#
# return self._post_api(('resume', 'pause')[sickbeard.TORRENT_PAUSED], post_data={'hash': result.hash})
api = QbittorrentAPI()

View file

@ -1,5 +1,3 @@
# Author: Nic Wolfe <nic@wolfeden.ca>
# URL: http://code.google.com/p/sickbeard/
# #
# This file is part of SickGear. # This file is part of SickGear.
# #
@ -16,133 +14,148 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with SickGear. If not, see <http://www.gnu.org/licenses/>. # along with SickGear. If not, see <http://www.gnu.org/licenses/>.
from lib.six import moves
import datetime import datetime
import re
import sickbeard import sickbeard
import config
from lib.six import moves
from base64 import standard_b64encode from base64 import standard_b64encode
from common import Quality
from sickbeard import logger
from sickbeard.helpers import tryInt
from sickbeard.providers.generic import GenericProvider from sickbeard.providers.generic import GenericProvider
from sickbeard import logger, helpers
from common import Quality def test_nzbget(host, use_https, username, password):
result = False
if not host:
msg = 'No NZBget host found. Please configure it'
logger.log(msg, logger.ERROR)
return result, msg, None
def sendNZB(nzb, proper=False): url = 'http%(scheme)s://%(username)s:%(password)s@%(host)s/xmlrpc' % {
addToTop = False 'scheme': ('', 's')[use_https], 'host': re.sub('(?:https?://)?(.*?)/?$', r'\1', host),
nzbgetprio = 0 'username': username, 'password': password}
rpc_client = moves.xmlrpc_client.ServerProxy(url)
if sickbeard.NZBGET_USE_HTTPS:
nzbgetXMLrpc = "https://%(username)s:%(password)s@%(host)s/xmlrpc"
else:
nzbgetXMLrpc = "http://%(username)s:%(password)s@%(host)s/xmlrpc"
if sickbeard.NZBGET_HOST == None:
logger.log(u"No NZBget host found in configuration. Please configure it.", logger.ERROR)
return False
url = nzbgetXMLrpc % {"host": sickbeard.NZBGET_HOST, "username": sickbeard.NZBGET_USERNAME,
"password": sickbeard.NZBGET_PASSWORD}
nzbGetRPC = moves.xmlrpc_client.ServerProxy(url)
try: try:
if nzbGetRPC.writelog("INFO", "SickGear connected to drop off %s any moment now." % (nzb.name + ".nzb")): msg = 'Success. Connected'
logger.log(u"Successfully connected to NZBget", logger.DEBUG) if rpc_client.writelog('INFO', 'SickGear connected as a test'):
logger.log(msg, logger.DEBUG)
else: else:
logger.log(u"Successfully connected to NZBget, but unable to send a message", logger.ERROR) msg += ', but unable to send a message'
logger.log(msg, logger.ERROR)
result = True
logger.log(u'NZBGet URL: %s' % url, logger.DEBUG)
except moves.http_client.socket.error: except moves.http_client.socket.error:
logger.log( msg = 'Please check NZBget host and port (if it is running). NZBget is not responding to these values'
u"Please check your NZBget host and port (if it is running). NZBget is not responding to this combination", logger.log(msg, logger.ERROR)
logger.ERROR)
return False
except moves.xmlrpc_client.ProtocolError as e: except moves.xmlrpc_client.ProtocolError as e:
if (e.errmsg == "Unauthorized"): if 'Unauthorized' == e.errmsg:
logger.log(u"NZBget username or password is incorrect.", logger.ERROR) msg = 'NZBget username or password is incorrect'
logger.log(msg, logger.ERROR)
else: else:
logger.log(u"Protocol Error: " + e.errmsg, logger.ERROR) msg = 'Protocol Error: %s' % e.errmsg
return False logger.log(msg, logger.ERROR)
dupekey = "" return result, msg, rpc_client
def send_nzb(nzb, proper=False):
result = False
add_to_top = False
nzbget_prio = 0
authed, auth_msg, rpc_client = test_nzbget(
sickbeard.NZBGET_HOST, sickbeard.NZBGET_USE_HTTPS, sickbeard.NZBGET_USERNAME, sickbeard.NZBGET_PASSWORD)
if not authed:
return authed
dupekey = ''
dupescore = 0 dupescore = 0
# if it aired recently make it high priority and generate DupeKey/Score # if it aired recently make it high priority and generate DupeKey/Score
for curEp in nzb.episodes: for curEp in nzb.episodes:
if dupekey == "": if '' == dupekey:
if curEp.show.indexer == 1: if 1 == curEp.show.indexer:
dupekey = "SickGear-" + str(curEp.show.indexerid) dupekey = 'SickGear-%s' % curEp.show.indexerid
elif curEp.show.indexer == 2: elif 2 == curEp.show.indexer:
dupekey = "SickGear-tvr" + str(curEp.show.indexerid) dupekey = 'SickGear-tvr%s' % curEp.show.indexerid
dupekey += "-" + str(curEp.season) + "." + str(curEp.episode) dupekey += '-%s.%s' % (curEp.season, curEp.episode)
if datetime.date.today() - curEp.airdate <= datetime.timedelta(days=7):
addToTop = True
nzbgetprio = sickbeard.NZBGET_PRIORITY
if nzb.quality != Quality.UNKNOWN: if datetime.date.today() - curEp.airdate <= datetime.timedelta(days=7):
add_to_top = True
nzbget_prio = sickbeard.NZBGET_PRIORITY
if Quality.UNKNOWN != nzb.quality:
dupescore = nzb.quality * 100 dupescore = nzb.quality * 100
if proper: if proper:
dupescore += 10 dupescore += 10
nzbcontent64 = None nzbcontent64 = None
if nzb.resultType == "nzbdata": if 'nzbdata' == nzb.resultType:
data = nzb.extraInfo[0] data = nzb.extraInfo[0]
nzbcontent64 = standard_b64encode(data) nzbcontent64 = standard_b64encode(data)
elif 'Anizb' == nzb.provider.name and 'nzb' == nzb.resultType: elif 'Anizb' == nzb.provider.name and 'nzb' == nzb.resultType:
gen_provider = GenericProvider('') gen_provider = GenericProvider('')
data = gen_provider.get_url(nzb.url) data = gen_provider.get_url(nzb.url)
if None is data: if None is data:
return False return result
nzbcontent64 = standard_b64encode(data) nzbcontent64 = standard_b64encode(data)
logger.log(u"Sending NZB to NZBGet: %s" % nzb.name) logger.log(u'Sending NZB to NZBGet: %s' % nzb.name)
logger.log(u"NZBGet URL: " + url, logger.DEBUG)
try: try:
# Find out if nzbget supports priority (Version 9.0+), old versions beginning with a 0.x will use the old command # Find out if nzbget supports priority (Version 9.0+), old versions beginning with a 0.x will use the old cmd
nzbget_version_str = nzbGetRPC.version() nzbget_version_str = rpc_client.version()
nzbget_version = helpers.tryInt(nzbget_version_str[:nzbget_version_str.find(".")]) nzbget_version = tryInt(nzbget_version_str[:nzbget_version_str.find('.')])
if nzbget_version == 0:
if nzbcontent64 is not None: # v13+ has a combined append method that accepts both (url and content)
nzbget_result = nzbGetRPC.append(nzb.name + ".nzb", sickbeard.NZBGET_CATEGORY, addToTop, nzbcontent64)
else:
if nzb.resultType == "nzb":
genProvider = GenericProvider("")
data = genProvider.get_url(nzb.url)
if (data == None):
return False
nzbcontent64 = standard_b64encode(data)
nzbget_result = nzbGetRPC.append(nzb.name + ".nzb", sickbeard.NZBGET_CATEGORY, addToTop, nzbcontent64)
elif nzbget_version == 12:
if nzbcontent64 is not None:
nzbget_result = nzbGetRPC.append(nzb.name + ".nzb", sickbeard.NZBGET_CATEGORY, nzbgetprio, False,
nzbcontent64, False, dupekey, dupescore, "score")
else:
nzbget_result = nzbGetRPC.appendurl(nzb.name + ".nzb", sickbeard.NZBGET_CATEGORY, nzbgetprio, False,
nzb.url, False, dupekey, dupescore, "score")
# v13+ has a new combined append method that accepts both (url and content)
# also the return value has changed from boolean to integer # also the return value has changed from boolean to integer
# (Positive number representing NZBID of the queue item. 0 and negative numbers represent error codes.) # (Positive number representing NZBID of the queue item. 0 and negative numbers represent error codes.)
elif nzbget_version >= 13: if 13 <= nzbget_version:
nzbget_result = True if nzbGetRPC.append(nzb.name + ".nzb", nzbcontent64 if nzbcontent64 is not None else nzb.url, nzbget_result = rpc_client.append(
sickbeard.NZBGET_CATEGORY, nzbgetprio, False, False, dupekey, dupescore, '%s.nzb' % nzb.name, (nzbcontent64, nzb.url)[None is nzbcontent64], sickbeard.NZBGET_CATEGORY,
"score") > 0 else False nzbget_prio, False, False, dupekey, dupescore, 'score') > 0
elif 12 == nzbget_version:
if nzbcontent64 is not None:
nzbget_result = rpc_client.append('%s.nzb' % nzb.name, sickbeard.NZBGET_CATEGORY,
nzbget_prio, False, nzbcontent64, False, dupekey, dupescore, 'score')
else:
nzbget_result = rpc_client.appendurl('%s.nzb' % nzb.name, sickbeard.NZBGET_CATEGORY,
nzbget_prio, False, nzb.url, False, dupekey, dupescore, 'score')
elif 0 == nzbget_version:
if nzbcontent64 is not None:
nzbget_result = rpc_client.append('%s.nzb' % nzb.name, sickbeard.NZBGET_CATEGORY,
add_to_top, nzbcontent64)
else:
if 'nzb' == nzb.resultType:
gen_provider = GenericProvider('')
data = gen_provider.get_url(nzb.url)
if None is data:
return result
nzbcontent64 = standard_b64encode(data)
nzbget_result = rpc_client.append('%s.nzb' % nzb.name, sickbeard.NZBGET_CATEGORY,
add_to_top, nzbcontent64)
else: else:
if nzbcontent64 is not None: if nzbcontent64 is not None:
nzbget_result = nzbGetRPC.append(nzb.name + ".nzb", sickbeard.NZBGET_CATEGORY, nzbgetprio, False, nzbget_result = rpc_client.append('%s.nzb' % nzb.name, sickbeard.NZBGET_CATEGORY,
nzbcontent64) nzbget_prio, False, nzbcontent64)
else: else:
nzbget_result = nzbGetRPC.appendurl(nzb.name + ".nzb", sickbeard.NZBGET_CATEGORY, nzbgetprio, False, nzbget_result = rpc_client.appendurl('%s.nzb' % nzb.name, sickbeard.NZBGET_CATEGORY,
nzb.url) nzbget_prio, False, nzb.url)
if nzbget_result: if nzbget_result:
logger.log(u"NZB sent to NZBget successfully", logger.DEBUG) logger.log(u'NZB sent to NZBget successfully', logger.DEBUG)
return True result = True
else: else:
logger.log(u"NZBget could not add %s to the queue" % (nzb.name + ".nzb"), logger.ERROR) logger.log(u'NZBget could not add %s to the queue' % ('%s.nzb' % nzb.name), logger.ERROR)
return False
except: except:
logger.log(u"Connect Error to NZBget: could not add %s to the queue" % (nzb.name + ".nzb"), logger.ERROR) logger.log(u'Connect Error to NZBget: could not add %s to the queue' % ('%s.nzb' % nzb.name), logger.ERROR)
return False
return result

View file

@ -32,7 +32,7 @@ from sickbeard import history
from sickbeard.common import DOWNLOADED, SNATCHED, SNATCHED_PROPER, Quality from sickbeard.common import DOWNLOADED, SNATCHED, SNATCHED_PROPER, Quality
from name_parser.parser import NameParser from name_parser.parser import NameParser, InvalidNameException, InvalidShowException
def search_propers(): def search_propers():
@ -112,6 +112,8 @@ def _get_proper_list(aired_since_shows, recent_shows, recent_anime):
x.provider = cur_provider x.provider = cur_provider
propers[name] = x propers[name] = x
count += 1 count += 1
except (InvalidNameException, InvalidShowException):
continue
except Exception: except Exception:
continue continue

View file

@ -681,7 +681,7 @@ class TorrentProvider(object, GenericProvider):
@property @property
def url(self): def url(self):
if None is self._url: if None is self._url or (hasattr(self, 'url_tmpl') and not self.urls):
self._url = self._valid_home() self._url = self._valid_home()
self._valid_url() self._valid_url()
return self._url return self._url

View file

@ -120,7 +120,7 @@ def snatch_episode(result, end_status=SNATCHED):
dl_result = sab.send_nzb(result) dl_result = sab.send_nzb(result)
elif 'nzbget' == sickbeard.NZB_METHOD: elif 'nzbget' == sickbeard.NZB_METHOD:
is_proper = True if SNATCHED_PROPER == end_status else False is_proper = True if SNATCHED_PROPER == end_status else False
dl_result = nzbget.sendNZB(result, is_proper) dl_result = nzbget.send_nzb(result, is_proper)
else: else:
logger.log(u'Unknown NZB action specified in config: %s' % sickbeard.NZB_METHOD, logger.ERROR) logger.log(u'Unknown NZB action specified in config: %s' % sickbeard.NZB_METHOD, logger.ERROR)
dl_result = False dl_result = False
@ -138,7 +138,7 @@ def snatch_episode(result, end_status=SNATCHED):
logger.log(u'Torrent content failed to download from %s' % result.url, logger.ERROR) logger.log(u'Torrent content failed to download from %s' % result.url, logger.ERROR)
return False return False
# Snatches torrent with client # Snatches torrent with client
client = clients.getClientIstance(sickbeard.TORRENT_METHOD)() client = clients.get_client_instance(sickbeard.TORRENT_METHOD)()
dl_result = client.send_torrent(result) dl_result = client.send_torrent(result)
else: else:
logger.log(u'Unknown result type, unable to download it', logger.ERROR) logger.log(u'Unknown result type, unable to download it', logger.ERROR)

View file

@ -36,8 +36,9 @@ from Cheetah.Template import Template
from six import iteritems from six import iteritems
import sickbeard import sickbeard
from sickbeard import config, sab, clients, history, notifiers, processTV, ui, logger, helpers, exceptions, classes, \ from sickbeard import config, sab, nzbget, clients, history, notifiers, processTV, ui, logger, helpers, exceptions,\
db, search_queue, image_cache, naming, scene_exceptions, search_propers, subtitles, network_timezones, sbdatetime classes, db, search_queue, image_cache, naming, scene_exceptions, search_propers, subtitles, network_timezones,\
sbdatetime
from sickbeard import encodingKludge as ek from sickbeard import encodingKludge as ek
from sickbeard.providers import newznab, rsstorrent from sickbeard.providers import newznab, rsstorrent
from sickbeard.common import Quality, Overview, statusStrings, qualityPresetStrings from sickbeard.common import Quality, Overview, statusStrings, qualityPresetStrings
@ -649,7 +650,7 @@ class Home(MainHandler):
return t.respond() return t.respond()
def testSABnzbd(self, host=None, username=None, password=None, apikey=None): def test_sabnzbd(self, host=None, username=None, password=None, apikey=None):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store') self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
host = config.clean_url(host) host = config.clean_url(host)
@ -667,14 +668,24 @@ class Home(MainHandler):
return u'Authentication failed. %s' % auth_msg return u'Authentication failed. %s' % auth_msg
return u'Unable to connect to host' return u'Unable to connect to host'
def testTorrent(self, torrent_method=None, host=None, username=None, password=None): def test_nzbget(self, host=None, use_https=None, username=None, password=None):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
host = config.clean_url(host)
if None is not password and set('*') == set(password):
password = sickbeard.NZBGET_PASSWORD
authed, auth_msg, void = nzbget.test_nzbget(host, bool(config.checkbox_to_value(use_https)), username, password)
return auth_msg
def test_torrent(self, torrent_method=None, host=None, username=None, password=None):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store') self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
host = config.clean_url(host) host = config.clean_url(host)
if None is not password and set('*') == set(password): if None is not password and set('*') == set(password):
password = sickbeard.TORRENT_PASSWORD password = sickbeard.TORRENT_PASSWORD
client = clients.getClientIstance(torrent_method) client = clients.get_client_instance(torrent_method)
connection, accesMsg = client(host, username, password).test_authentication() connection, accesMsg = client(host, username, password).test_authentication()