mirror of
https://github.com/sabnzbd/sabnzbd.git
synced 2026-01-05 22:20:21 -05:00
Compare commits
20 Commits
2.2.0Beta1
...
2.2.0Beta2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d5b1bf053 | ||
|
|
ea4cdba3eb | ||
|
|
d6ecebc75a | ||
|
|
b0af6a1761 | ||
|
|
6e350f30fc | ||
|
|
169137c631 | ||
|
|
6393dc0dca | ||
|
|
1a27b4824b | ||
|
|
2b59a383cf | ||
|
|
efbaaade22 | ||
|
|
cf7e7b1f62 | ||
|
|
2c1746a92d | ||
|
|
a2e57fd3d8 | ||
|
|
932f8d9176 | ||
|
|
5ffd82da89 | ||
|
|
8b3de191d9 | ||
|
|
83d8a23e2c | ||
|
|
58b107a4b5 | ||
|
|
a40609b39d | ||
|
|
0faa5d3dff |
4
PKG-INFO
4
PKG-INFO
@@ -1,7 +1,7 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: SABnzbd
|
||||
Version: 2.2.0Beta1
|
||||
Summary: SABnzbd-2.2.0Beta1
|
||||
Version: 2.2.0Beta2
|
||||
Summary: SABnzbd-2.2.0Beta2
|
||||
Home-page: https://sabnzbd.org
|
||||
Author: The SABnzbd Team
|
||||
Author-email: team@sabnzbd.org
|
||||
|
||||
13
README.mkd
13
README.mkd
@@ -1,4 +1,4 @@
|
||||
Release Notes - SABnzbd 2.2.0 Beta 1
|
||||
Release Notes - SABnzbd 2.2.0 Beta 2
|
||||
=========================================================
|
||||
|
||||
NOTE: Due to changes in this release, the queue will be converted when 2.2.0
|
||||
@@ -6,6 +6,17 @@ is started for the first time. Job order, settings and data will be
|
||||
preserved, but all jobs will be unpaused and URL's that did not finish
|
||||
fetching before the upgrade will be lost!
|
||||
|
||||
## Bugfixes and changes since Beta 1
|
||||
- Graphical overview of daily server usage on Servers page
|
||||
- New option History Retention to limit number of jobs in History
|
||||
- Add Retry All Failed button to Glitter
|
||||
- Add option to only tag a duplicate job without pausing or removing it
|
||||
- Remove video and audio rating icons from Queue
|
||||
- Show vote buttons instead of video and audio rating buttons in History
|
||||
- Direct Unpack could crash
|
||||
- Wizard was always accessible, even with username and password set
|
||||
- Several styling fixes in the interface
|
||||
|
||||
## Bugfixes since Alpha 3
|
||||
- Bugfixes and stability updates for Direct Unpack
|
||||
- Notification errors
|
||||
|
||||
@@ -32,7 +32,9 @@
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="${root}staticcfg/ico/android-192x192.png" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="${root}staticcfg/bootstrap/css/bootstrap.min.css?v=$version" />
|
||||
<link rel="stylesheet" type="text/css" href="${root}staticcfg/css/chartist.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="${root}staticcfg/css/style.css?p=$pid" />
|
||||
|
||||
<link rel="shortcut icon" href="${root}staticcfg/ico/favicon.ico?v=$version" />
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
@@ -110,6 +110,56 @@
|
||||
</div><!-- /section -->
|
||||
</form>
|
||||
|
||||
<script type="text/javascript" src="${root}staticcfg/js/chartist.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
// Define variables needed for the server-plots
|
||||
var serverData = {}
|
||||
var chartOptions = {
|
||||
fullWidth: true,
|
||||
showPoint: false,
|
||||
axisX: {
|
||||
labelOffset: {
|
||||
x: -5
|
||||
},
|
||||
showGrid: false
|
||||
},
|
||||
axisY: {
|
||||
labelOffset: {
|
||||
y: 7
|
||||
},
|
||||
scaleMinSpace: 30
|
||||
},
|
||||
chartPadding: {
|
||||
top: 9,
|
||||
bottom: 0,
|
||||
left: 30,
|
||||
right: 20
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!--
|
||||
We need to find how many months we have recorded so far, so we
|
||||
loop over all the dates to find the lowest value and then use
|
||||
the number of days passed as an estimate of the months we have.
|
||||
-->
|
||||
<!--#import json#-->
|
||||
<!--#import datetime#-->
|
||||
<!--#def show_date_selector($server, $id)#-->
|
||||
<!--#set month_names = [$T('January'), $T('February'), $T('March'), $T('April'), $T('May'), $T('June'), $T('July'), $T('August'), $T('September'), $T('October'), $T('November'), $T('December')] #-->
|
||||
<!--#set min_date = datetime.date.today()#-->
|
||||
<!--#for date in $server['amounts'][4]#-->
|
||||
<!--#set split_date = $date.split('-')#-->
|
||||
<!--#set min_date = min(min_date, datetime.date(int(split_date[0]), int(split_date[1]), int(split_date[2])))#-->
|
||||
<!--#end for#-->
|
||||
<!--#set months_recorded = int((datetime.date.today()-min_date).days / (365/12))#-->
|
||||
<select class="chart-selector" name="chart-selector-${id}" id="chart-selector-${id}" data-id="${id}">
|
||||
<!--#for $i in range(months_recorded+1)#-->
|
||||
<!--#set cur_date = (datetime.date.today() - datetime.timedelta($i*365/12))#-->
|
||||
<option value="<!--#echo '%d-%02d' % ($cur_date.year, $cur_date.month)#-->">$month_names[$cur_date.month-1] $cur_date.year</option>
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<!--#end def#-->
|
||||
|
||||
<!--#set $prio_colors = ["#59cc33", "#3366cc","#7f33cc", "#cc33a6", "#cc3333"] #-->
|
||||
<!--#set $cur_prio_color = -1 #-->
|
||||
<!--#set $last_prio = -1 #-->
|
||||
@@ -232,166 +282,282 @@
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
<div class="col2" style="display:block;">
|
||||
<!--#if 'amounts' in $server#-->
|
||||
<b>$T('srv-bandwidth'):</b><br/>
|
||||
$T('total'): $(server['amounts'][0])B<br/>
|
||||
$T('today'): $(server['amounts'][3])B<br/>
|
||||
$T('thisWeek'): $(server['amounts'][2])B<br/>
|
||||
$T('thisMonth'): $(server['amounts'][1])B
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
</div><!-- /section -->
|
||||
<div class="col1" style="display:block;">
|
||||
<!--#if 'amounts' in $server#-->
|
||||
<div class="server-amounts-text">
|
||||
<b>$T('srv-bandwidth'):</b><br/>
|
||||
$T('total'): $(server['amounts'][0])B<br/>
|
||||
$T('today'): $(server['amounts'][3])B<br/>
|
||||
$T('thisWeek'): $(server['amounts'][2])B<br/>
|
||||
$T('thisMonth'): $(server['amounts'][1])B
|
||||
</div>
|
||||
<div class="server-chart">
|
||||
$show_date_selector($server, $cur)
|
||||
<div id="server-chart-${cur}" class="ct-chart"></div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// Server data
|
||||
serverData[${cur}] = <!--#echo json.dumps($server['amounts'][4])#-->
|
||||
\$(document).ready(function() {
|
||||
showChart(${cur})
|
||||
})
|
||||
</script>
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<!--#end for#-->
|
||||
|
||||
</div><!-- /colmask -->
|
||||
|
||||
<script type="text/javascript">
|
||||
\$(document).ready(function(){
|
||||
// Exception when change of priority, reload
|
||||
\$('input[name="priority"], input[name="displayname"]').on('change', function() {
|
||||
\$('.fullform').submit(function() {
|
||||
// Skip the fancy stuff, just submit
|
||||
this.submit()
|
||||
})
|
||||
})
|
||||
function showChart(server_id, month) {
|
||||
// This month
|
||||
var thisDay = new Date()
|
||||
|
||||
/**
|
||||
Message on no Default category selected
|
||||
**/
|
||||
function checkServerCats() {
|
||||
// Now we check all of them
|
||||
var hasDefault = false;
|
||||
// Only check the active servers, not the add-server one
|
||||
\$('.section:not(#addServerContent) select[name="categories"]').each(function() {
|
||||
// See if this server is enabled
|
||||
if(!\$(this).parents('.section').find('.col2').hasClass('server-disabled') ) {
|
||||
// Is there Default?
|
||||
if(\$(this).val() && \$(this).val().indexOf('Default') > -1) {
|
||||
// Hide
|
||||
\$('.alert-no-category').hide()
|
||||
hasDefault = true
|
||||
// All good!
|
||||
return true
|
||||
}
|
||||
// What month are we doing?
|
||||
if(month) {
|
||||
var inputDate = new Date(month+'-01')
|
||||
} else {
|
||||
var inputDate = new Date()
|
||||
}
|
||||
var baseDate = new Date(inputDate.getFullYear(), inputDate.getMonth(), 1)
|
||||
var maxDaysInMonth = new Date(baseDate.getYear(), baseDate.getMonth()+1, 0).getDate()
|
||||
|
||||
// Fill the data array
|
||||
var data = {
|
||||
labels: [],
|
||||
series: [[]]
|
||||
};
|
||||
var largestVal = 0
|
||||
for(var i = 1; i < maxDaysInMonth+1; i++) {
|
||||
// Add X-label
|
||||
if(i % 3 == 1) {
|
||||
data['labels'].push(i)
|
||||
} else {
|
||||
data['labels'].push(NaN)
|
||||
}
|
||||
|
||||
// Get formatted date
|
||||
baseDate.setDate(i)
|
||||
var dateCheck = toFormattedDate(baseDate)
|
||||
|
||||
// Add data if we have it
|
||||
if(dateCheck in serverData[server_id]) {
|
||||
data['series'][0].push(serverData[server_id][dateCheck])
|
||||
largestVal = Math.max(largestVal, serverData[server_id][dateCheck])
|
||||
} else if(thisDay.getYear() == baseDate.getYear() && thisDay.getMonth() == baseDate.getMonth() && thisDay.getDate() < i) {
|
||||
data['series'][0].push(NaN)
|
||||
} else {
|
||||
data['series'][0].push(0)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we should shrink the Y-axis values
|
||||
var devideBy = 1024
|
||||
var axisLabel = 'KB'
|
||||
if(largestVal > 1024*1024) {
|
||||
devideBy = 1024*1024
|
||||
axisLabel = 'MB'
|
||||
}
|
||||
if(largestVal > 1024*1024*1024) {
|
||||
devideBy = 1024*1024*1024
|
||||
axisLabel = 'GB'
|
||||
}
|
||||
if(largestVal > 1024*1024*1024*1024) {
|
||||
devideBy = 1024*1024*1024*1024
|
||||
axisLabel = 'TB'
|
||||
}
|
||||
|
||||
// Shrink the value
|
||||
data['series'][0] = data['series'][0].map(function(num) {
|
||||
return num / devideBy;
|
||||
})
|
||||
// We found nothing.. Let's show a warning
|
||||
if(!hasDefault) \$('.alert-no-category').show()
|
||||
|
||||
// Show the chart
|
||||
chart = new Chartist.Line('#server-chart-'+server_id, data, chartOptions);
|
||||
chart.on('created', function(context) {
|
||||
context.svg.elem('rect', {
|
||||
x: context.chartRect.x1,
|
||||
y: context.chartRect.y2,
|
||||
width: context.chartRect.width(),
|
||||
height: context.chartRect.height()+2,
|
||||
fill: 'none',
|
||||
stroke: '#B9B9B9',
|
||||
'stroke-width': '1px'
|
||||
})
|
||||
\$('#server-chart-'+server_id+' .ct-label.ct-vertical').each(function(index, elmn) {
|
||||
elmn.innerHTML += axisLabel
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
\$('select[name="categories"]').on('change', checkServerCats)
|
||||
checkServerCats()
|
||||
// Need to mitigate timezone effects!
|
||||
function toFormattedDate(date) {
|
||||
var local = new Date(date);
|
||||
local.setMinutes(date.getMinutes() - date.getTimezoneOffset());
|
||||
return local.toJSON().slice(0, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
Click events
|
||||
When finished loading
|
||||
**/
|
||||
\$('.showserver').click(function () {
|
||||
if(\$(this).parent().hasClass('server-disabled')) {
|
||||
\$(this).parent().parent().toggleClass('server-disabled')
|
||||
}
|
||||
\$(this).parent().next().toggle();
|
||||
\$(this).parent().next().next().toggle();
|
||||
if (\$(this).attr("value") == "$T('showDetails')") {
|
||||
\$(this).attr("value", "$T('hideDetails')");
|
||||
} else {
|
||||
\$(this).attr("value", "$T('showDetails')");
|
||||
}
|
||||
});
|
||||
\$(document).ready(function(){
|
||||
// Exception when change of priority, reload
|
||||
\$('input[name="priority"], input[name="displayname"]').on('change', function() {
|
||||
\$('.fullform').submit(function() {
|
||||
// Skip the fancy stuff, just submit
|
||||
this.submit()
|
||||
})
|
||||
})
|
||||
|
||||
\$('#addServerButton').click(function(){
|
||||
\$('#addServer').hide();
|
||||
\$('#addServerContent').show();
|
||||
});
|
||||
/**
|
||||
Update charts when changed
|
||||
**/
|
||||
\$('.chart-selector').on('change', function(elemn) {
|
||||
showChart(\$(elemn.target).data('id'), \$(elemn.target).val())
|
||||
// Lets us leave (needs to be called after the change event)
|
||||
setTimeout(function() {
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
}, 100)
|
||||
})
|
||||
|
||||
\$('[name="ssl"]').click(function() {
|
||||
// Use CSS transitions to do some highlighting
|
||||
var portBox = \$(this).parent().parent().find('[name="port"]')
|
||||
if(this.checked) {
|
||||
// Enabled SSL change port when not already a custom port
|
||||
if(portBox.val() == '119') {
|
||||
portBox.val('563')
|
||||
portBox.addClass('port-highlight')
|
||||
/**
|
||||
Message on no Default category selected
|
||||
**/
|
||||
function checkServerCats() {
|
||||
// Now we check all of them
|
||||
var hasDefault = false;
|
||||
// Only check the active servers, not the add-server one
|
||||
\$('.section:not(#addServerContent) select[name="categories"]').each(function() {
|
||||
// See if this server is enabled
|
||||
if(!\$(this).parents('.section').find('.col2').hasClass('server-disabled') ) {
|
||||
// Is there Default?
|
||||
if(\$(this).val() && \$(this).val().indexOf('Default') > -1) {
|
||||
// Hide
|
||||
\$('.alert-no-category').hide()
|
||||
hasDefault = true
|
||||
// All good!
|
||||
return true
|
||||
}
|
||||
}
|
||||
})
|
||||
// We found nothing.. Let's show a warning
|
||||
if(!hasDefault) \$('.alert-no-category').show()
|
||||
}
|
||||
|
||||
\$('select[name="categories"]').on('change', checkServerCats)
|
||||
checkServerCats()
|
||||
|
||||
/**
|
||||
Click events
|
||||
**/
|
||||
\$('.showserver').click(function () {
|
||||
if(\$(this).parent().hasClass('server-disabled')) {
|
||||
\$(this).parent().parent().toggleClass('server-disabled')
|
||||
}
|
||||
} else {
|
||||
// Remove SSL port
|
||||
if(portBox.val() == '563') {
|
||||
portBox.val('119')
|
||||
portBox.addClass('port-highlight')
|
||||
}
|
||||
}
|
||||
setTimeout(function() { portBox.removeClass('port-highlight') }, 2000)
|
||||
})
|
||||
|
||||
\$('.testServer').click(function(event){
|
||||
removeObfuscation()
|
||||
var theButton = \$(this)
|
||||
var resultBox = theButton.parents('.col1').find('.result-box .alert');
|
||||
theButton.attr("disabled", "disabled")
|
||||
theButton.find('span').toggleClass('glyphicon-sort glyphicon-refresh spin-glyphicon')
|
||||
\$.ajax({
|
||||
type: "POST",
|
||||
url: "../../tapi",
|
||||
data: "mode=config&output=json&name=test_server&" + \$(this).parents('form:first').serialize()
|
||||
}).then(function(data) {
|
||||
// Let's replace the link
|
||||
msg = data.value.message.replace('https://sabnzbd.org/certificate-errors', '<a href="https://sabnzbd.org/certificate-errors" class="alert-link" target="_blank">https://sabnzbd.org/certificate-errors</a>')
|
||||
msg = msg.replace('-', '<br>')
|
||||
// Fill the box and enable the button
|
||||
resultBox.removeClass('alert-success alert-danger').show()
|
||||
resultBox.html(msg)
|
||||
theButton.removeAttr("disabled")
|
||||
theButton.find('span').toggleClass('glyphicon-sort glyphicon-refresh spin-glyphicon')
|
||||
|
||||
// Succes or not?
|
||||
if(data.value.result) {
|
||||
resultBox.addClass('alert-success')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-ok-sign"></span> ')
|
||||
\$(this).parent().next().toggle();
|
||||
\$(this).parent().next().next().toggle();
|
||||
if (\$(this).attr("value") == "$T('showDetails')") {
|
||||
\$(this).attr("value", "$T('hideDetails')");
|
||||
} else {
|
||||
resultBox.addClass('alert-danger')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ')
|
||||
\$(this).attr("value", "$T('showDetails')");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
\$('.delServer').click(function(){
|
||||
if( confirm("$T('Plush-confirm')") ) {
|
||||
\$(this).parents('form:first').attr('action','delServer').submit();
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
setTimeout(function() { location.reload(); }, 500)
|
||||
}
|
||||
return false;
|
||||
});
|
||||
\$('#addServerButton').click(function(){
|
||||
\$('#addServer').hide();
|
||||
\$('#addServerContent').show();
|
||||
});
|
||||
|
||||
\$('.clrServer').click(function(){
|
||||
if( confirm("$T('Plush-confirm')") ) {
|
||||
\$(this).parents('form:first').attr('action','clrServer').submit();
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
setTimeout(function() { location.reload(); }, 500)
|
||||
}
|
||||
return false;
|
||||
});
|
||||
\$('[name="ssl"]').click(function() {
|
||||
// Use CSS transitions to do some highlighting
|
||||
var portBox = \$(this).parent().parent().find('[name="port"]')
|
||||
if(this.checked) {
|
||||
// Enabled SSL change port when not already a custom port
|
||||
if(portBox.val() == '119') {
|
||||
portBox.val('563')
|
||||
portBox.addClass('port-highlight')
|
||||
}
|
||||
} else {
|
||||
// Remove SSL port
|
||||
if(portBox.val() == '563') {
|
||||
portBox.val('119')
|
||||
portBox.addClass('port-highlight')
|
||||
}
|
||||
}
|
||||
setTimeout(function() { portBox.removeClass('port-highlight') }, 2000)
|
||||
})
|
||||
|
||||
\$('.toggleServerCheckbox').click(function(){
|
||||
var whichServer = \$(this).attr("name");
|
||||
\$.ajax({
|
||||
type: "POST",
|
||||
url: "toggleServer",
|
||||
data: {server: whichServer, session: "$session" }
|
||||
}).done(function() {
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
setTimeout(function() { location.reload(); }, 100)
|
||||
\$('.testServer').click(function(event){
|
||||
removeObfuscation()
|
||||
var theButton = \$(this)
|
||||
var resultBox = theButton.parents('.col1').find('.result-box .alert');
|
||||
theButton.attr("disabled", "disabled")
|
||||
theButton.find('span').toggleClass('glyphicon-sort glyphicon-refresh spin-glyphicon')
|
||||
\$.ajax({
|
||||
type: "POST",
|
||||
url: "../../tapi",
|
||||
data: "mode=config&output=json&name=test_server&" + \$(this).parents('form:first').serialize()
|
||||
}).then(function(data) {
|
||||
// Let's replace the link
|
||||
msg = data.value.message.replace('https://sabnzbd.org/certificate-errors', '<a href="https://sabnzbd.org/certificate-errors" class="alert-link" target="_blank">https://sabnzbd.org/certificate-errors</a>')
|
||||
msg = msg.replace('-', '<br>')
|
||||
// Fill the box and enable the button
|
||||
resultBox.removeClass('alert-success alert-danger').show()
|
||||
resultBox.html(msg)
|
||||
theButton.removeAttr("disabled")
|
||||
theButton.find('span').toggleClass('glyphicon-sort glyphicon-refresh spin-glyphicon')
|
||||
|
||||
// Succes or not?
|
||||
if(data.value.result) {
|
||||
resultBox.addClass('alert-success')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-ok-sign"></span> ')
|
||||
} else {
|
||||
resultBox.addClass('alert-danger')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ')
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
\$('.delServer').click(function(){
|
||||
if( confirm("$T('Plush-confirm')") ) {
|
||||
\$(this).parents('form:first').attr('action','delServer').submit();
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
setTimeout(function() { location.reload(); }, 500)
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
\$('.clrServer').click(function(){
|
||||
if( confirm("$T('Plush-confirm')") ) {
|
||||
\$(this).parents('form:first').attr('action','clrServer').submit();
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
setTimeout(function() { location.reload(); }, 500)
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
\$('.toggleServerCheckbox').click(function(){
|
||||
var whichServer = \$(this).attr("name");
|
||||
\$.ajax({
|
||||
type: "POST",
|
||||
url: "toggleServer",
|
||||
data: {server: whichServer, session: "$session" }
|
||||
}).done(function() {
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
setTimeout(function() { location.reload(); }, 100)
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
<label class="config" for="no_dupes">$T('opt-no_dupes')</label>
|
||||
<select name="no_dupes" id="no_dupes">
|
||||
<option value="0" <!--#if int($no_dupes) == 0 then 'selected="selected"' else ""#--> >$T('nodupes-off')</option>
|
||||
<option value="4" <!--#if int($no_dupes) == 4 then 'selected="selected"' else ""#--> >$T('nodupes-tag')</option>
|
||||
<option value="2" <!--#if int($no_dupes) == 2 then 'selected="selected"' else ""#--> >$T('nodupes-pause')</option>
|
||||
<option value="3" <!--#if int($no_dupes) == 3 then 'selected="selected"' else ""#--> >$T('nodupes-fail')</option>
|
||||
<option value="1" <!--#if int($no_dupes) == 1 then 'selected="selected"' else ""#--> >$T('nodupes-ignore')</option>
|
||||
@@ -96,6 +97,7 @@
|
||||
<label class="config" for="no_series_dupes">$T('opt-no_series_dupes')</label>
|
||||
<select name="no_series_dupes" id="no_series_dupes">
|
||||
<option value="0" <!--#if int($no_series_dupes) == 0 then 'selected="selected"' else ""#--> >$T('nodupes-off')</option>
|
||||
<option value="4" <!--#if int($no_series_dupes) == 4 then 'selected="selected"' else ""#--> >$T('nodupes-tag')</option>
|
||||
<option value="2" <!--#if int($no_series_dupes) == 2 then 'selected="selected"' else ""#--> >$T('nodupes-pause')</option>
|
||||
<option value="3" <!--#if int($no_series_dupes) == 3 then 'selected="selected"' else ""#--> >$T('nodupes-fail')</option>
|
||||
<option value="1" <!--#if int($no_series_dupes) == 1 then 'selected="selected"' else ""#--> >$T('nodupes-ignore')</option>
|
||||
@@ -215,6 +217,20 @@
|
||||
<input type="text" name="cleanup_list" id="cleanup_list" value="$cleanup_list"/>
|
||||
<span class="desc">$T('explain-cleanup_list')</span>
|
||||
</div>
|
||||
|
||||
<div class="field-pair">
|
||||
<label class="config" for="history_retention_select">$T('opt-history_retention')</label>
|
||||
<input type="hidden" name="history_retention" id="history_retention" value="$history_retention">
|
||||
<select name="history_retention_select" id="history_retention_select">
|
||||
<option value="0">$T('history_retention-all')</option>
|
||||
<option value="n">$T('history_retention-number')</option>
|
||||
<option value="d">$T('history_retention-days')</option>
|
||||
<option value="-1">$T('history_retention-none')</option>
|
||||
</select>
|
||||
<input type="number" id="history_retention_number" name="history_retention_number" min="1">
|
||||
<span class="desc">$T('explain-history_retention').replace('. ', '.<br/>')</span>
|
||||
</div>
|
||||
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default restoreDefaults"><span class="glyphicon glyphicon-asterisk"></span> $T('button-restoreDefaults')</button>
|
||||
@@ -437,6 +453,53 @@
|
||||
}
|
||||
});
|
||||
|
||||
\$('#history_retention_select, #history_retention_number').on('change', updateHistoryRetention)
|
||||
function updateHistoryRetention() {
|
||||
var retention_setting = \$('#history_retention')
|
||||
var retention_select = \$('#history_retention_select').val()
|
||||
var retention_number = \$('#history_retention_number')
|
||||
// Keep all or keep none
|
||||
if(retention_select == "0" || retention_select == "-1") {
|
||||
retention_number.hide()
|
||||
retention_number.val('')
|
||||
retention_number.attr('placeholder', '')
|
||||
retention_setting.val(retention_select)
|
||||
} else {
|
||||
retention_number.show()
|
||||
// Days or number?
|
||||
if(retention_select.indexOf("d") !== -1) {
|
||||
retention_number.attr('placeholder', '$T('days')')
|
||||
if(retention_number.val()) {
|
||||
retention_setting.val(retention_number.val() + 'd')
|
||||
} else if(parseInt(retention_setting.val()) > 0) {
|
||||
retention_number.val(parseInt(retention_setting.val()))
|
||||
}
|
||||
} else {
|
||||
retention_number.attr('placeholder', '$T('history_retention-limit')')
|
||||
if(retention_number.val()) {
|
||||
retention_setting.val(retention_number.val())
|
||||
} else if(parseInt(retention_setting.val()) > 0) {
|
||||
retention_number.val(parseInt(retention_setting.val()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set the history-retention settig
|
||||
var retention_setting_value = \$('#history_retention').val()
|
||||
if(parseInt(retention_setting_value) > 0) {
|
||||
// Days or number?
|
||||
if(retention_setting_value.indexOf("d") !== -1) {
|
||||
\$('#history_retention_select').val("d")
|
||||
} else {
|
||||
\$('#history_retention_select').val("n")
|
||||
}
|
||||
\$('#history_retention_number').val(parseInt(retention_setting_value))
|
||||
} else {
|
||||
// Keep all or keep none
|
||||
\$('#history_retention_select').val(retention_setting_value)
|
||||
\$('#history_retention_number').hide()
|
||||
}
|
||||
|
||||
\$('.restoreDefaults').click(function(e) {
|
||||
// Get section name
|
||||
var sectionName = \$(this).parents('.section').find('.col2 h3').text().trim()
|
||||
|
||||
1
interfaces/Config/templates/staticcfg/css/chartist.min.css
vendored
Normal file
1
interfaces/Config/templates/staticcfg/css/chartist.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -994,6 +994,46 @@ input[type="checkbox"] {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.Servers .server-amounts-text {
|
||||
width: 20%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.Servers .server-chart {
|
||||
float: right;
|
||||
width: calc(100% - 250px - 25%);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.Servers .ct-series-a .ct-line {
|
||||
stroke: #666666;
|
||||
}
|
||||
|
||||
.Servers .ct-label {
|
||||
font-size: 1em;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.Servers .chart-selector {
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: -7px;
|
||||
left: 50%;
|
||||
width: 120px;
|
||||
margin-left: -40px;
|
||||
min-width: initial;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.Servers .chart-selector:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.Servers .ct-grid.ct-vertical:first-of-type {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.advanced-settings {
|
||||
display: none;
|
||||
}
|
||||
@@ -1171,6 +1211,15 @@ input[type="checkbox"] {
|
||||
.Servers .col2 button:first-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.Servers .server-chart {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.Servers .server-amounts-text {
|
||||
padding: 0px 15px 10px;
|
||||
width: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
|
||||
10
interfaces/Config/templates/staticcfg/js/chartist.min.js
vendored
Normal file
10
interfaces/Config/templates/staticcfg/js/chartist.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -48,8 +48,8 @@
|
||||
<!-- ko if: historyStatus.has_rating -->
|
||||
<div class="dropdown history-ratings">
|
||||
<a href="#" class="name-icons hover-button" data-toggle="dropdown" onclick="keepOpen(this)">
|
||||
<span class="glyphicon glyphicon-facetime-video"></span> <span data-bind="text: historyStatus.rating_avg_video"></span>
|
||||
<span class="glyphicon glyphicon-volume-up"></span> <span data-bind="text: historyStatus.rating_avg_audio"></span>
|
||||
<span class="glyphicon glyphicon-thumbs-up"></span> <span data-bind="text: historyStatus.rating_avg_vote_up"></span>
|
||||
<span class="glyphicon glyphicon-thumbs-down"></span> <span data-bind="text: historyStatus.rating_avg_vote_down"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu history-ratings-menu">
|
||||
<li>
|
||||
@@ -206,6 +206,7 @@
|
||||
</ul>
|
||||
|
||||
<div class="multioperations-selector" id="history-options">
|
||||
<a href="#" class="hover-button" title="$T('link-retryAll')" data-tooltip="true" data-placement="left" data-bind="click: history.retryAllFailed"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<a href="#" class="hover-button" title="$T('showAllHis') / $T('showFailedHis')" data-tooltip="true" data-placement="left" data-bind="click: history.toggleShowFailed, css: { 'history-options-show-failed': history.showFailed }"><span class="glyphicon glyphicon-exclamation-sign"></span></a>
|
||||
<a href="#modal-purge-history" class="hover-button" title="$T('purgeHist')" data-toggle="modal" data-tooltip="true" data-placement="left"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</div>
|
||||
|
||||
@@ -102,11 +102,11 @@
|
||||
<form data-bind="submit: editingNameSubmit">
|
||||
<input type="text" data-bind="value: nameForEdit, visible: editingName(), hasfocus: editingName" />
|
||||
</form>
|
||||
<div class="name-options" data-bind="visible: !editingName()">
|
||||
<a href="#" data-bind="click: \$parent.queue.moveButton" class="hover-button buttonMoveToTop" title="$T('Glitter-MoveToTop')"><span class="glyphicon glyphicon-chevron-up"></span></a>
|
||||
<a href="#" data-bind="click: \$parent.queue.moveButton" class="hover-button buttonMoveToBottom" title="$T('Glitter-MoveToBottom')"><span class="glyphicon glyphicon-chevron-down"></span></a>
|
||||
<a href="#" data-bind="click: editName, css: { disabled: isGrabbing() }" class="hover-button"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="#" data-bind="click: showFiles, css: { disabled: isGrabbing() }" class="hover-button" title="$T('nzoDetails') - $T('srv-password')"><span class="glyphicon glyphicon-folder-open"></span></a>
|
||||
<div class="name-options" data-bind="visible: !editingName(), css: { disabled: isGrabbing() }">
|
||||
<a href="#" data-bind="click: \$parent.queue.moveButton" class="hover-button buttonMoveToTop" title="$T('Glitter-top')"><span class="glyphicon glyphicon-chevron-up"></span></a>
|
||||
<a href="#" data-bind="click: \$parent.queue.moveButton" class="hover-button buttonMoveToBottom" title="$T('Glitter-bottom')"><span class="glyphicon glyphicon-chevron-down"></span></a>
|
||||
<a href="#" data-bind="click: editName" class="hover-button" title="$T('Glitter-rename')"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="#" data-bind="click: showFiles" class="hover-button" title="$T('nzoDetails') - $T('srv-password')"><span class="glyphicon glyphicon-folder-open"></span></a>
|
||||
<small data-bind="text: avg_age"></small>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
glitterTranslate.repair = "$T('explain-Repair')".replace(/<br \/>/g, "\n").replace(/"/g,'"');
|
||||
glitterTranslate.removeDown = "$T('Glitter-confirmClearDownloads')";
|
||||
glitterTranslate.removeDow1 = "$T('Glitter-confirmClear1Download')";
|
||||
glitterTranslate.retryAll = "$T('link-retryAll')?";
|
||||
glitterTranslate.encrypted = "$T('Glitter-encrypted')";
|
||||
glitterTranslate.duplicate = "$T('Glitter-duplicate')";
|
||||
glitterTranslate.tooLarge = "$T('Glitter-tooLarge')";
|
||||
|
||||
@@ -169,7 +169,6 @@ function HistoryListModel(parent) {
|
||||
|
||||
// Toggle showing failed
|
||||
self.toggleShowFailed = function(data, event) {
|
||||
|
||||
// Set the loader so it doesn't flicker and then switch
|
||||
self.isLoading(true)
|
||||
self.showFailed(!self.showFailed())
|
||||
@@ -177,7 +176,20 @@ function HistoryListModel(parent) {
|
||||
$('#history-options a').tooltip('hide')
|
||||
// Force refresh
|
||||
self.parent.refresh(true)
|
||||
}
|
||||
|
||||
// Retry all failed
|
||||
self.retryAllFailed = function(data, event) {
|
||||
// Ask to be sure
|
||||
if(confirm(glitterTranslate.retryAll)) {
|
||||
// Send the command
|
||||
callAPI({
|
||||
mode: 'retry_all'
|
||||
}).then(function() {
|
||||
// Force refresh
|
||||
self.parent.refresh(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Empty history options
|
||||
|
||||
@@ -533,9 +533,16 @@ tbody>tr>td:last-child {
|
||||
}
|
||||
|
||||
.hover-button.disabled,
|
||||
.hover-button.disabled:hover {
|
||||
.hover-button.disabled:hover,
|
||||
.name-options.disabled .hover-button,
|
||||
.name-options.disabled .hover-button:hover {
|
||||
cursor: not-allowed !important;
|
||||
opacity: 0.1 !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.name-options.disabled {
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
|
||||
.info-container {
|
||||
@@ -656,12 +663,16 @@ td.name .name-icons {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.queue-table td.name:hover .name-icons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
td.name .name-icons .glyphicon {
|
||||
margin-left: 2px;
|
||||
top: 2px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.glyphicon-chevron-down,
|
||||
.glyphicon-chevron-up {
|
||||
top: 2px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
tbody.no-downloads tr td {
|
||||
|
||||
@@ -8,14 +8,14 @@ msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
|
||||
"PO-Revision-Date: 2017-06-13 09:56+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"PO-Revision-Date: 2017-07-22 17:36+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>\n"
|
||||
"Language-Team: Hebrew <he@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
|
||||
"X-Generator: Launchpad (build 18416)\n"
|
||||
"X-Launchpad-Export-Date: 2017-07-23 06:02+0000\n"
|
||||
"X-Generator: Launchpad (build 18419)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
@@ -64,6 +64,48 @@ msgid ""
|
||||
"Sorry!\n"
|
||||
"<!--#end if#-->\n"
|
||||
msgstr ""
|
||||
"##\n"
|
||||
"## SABnzbd תבנית דוא\"ל ברירת מחדל עבור\n"
|
||||
"## זאת תבנית ברדלס\n"
|
||||
"## http://sabnzbd.wikidot.com/email-templates :תיעוד\n"
|
||||
"##\n"
|
||||
"## !שורות חדשות ורווחים לבנים הם משמעותיים\n"
|
||||
"##\n"
|
||||
"## אלו כותרות הדוא\"ל\n"
|
||||
"To: $to\n"
|
||||
"From: $from\n"
|
||||
"Date: $date\n"
|
||||
"Subject: SABnzbd has <!--#if $status then \"completed\" else \"failed\" #--> "
|
||||
"job $name\n"
|
||||
"## !אחרי זה בא הגוף, השורה הריקה דרושה\n"
|
||||
"\n"
|
||||
",היי\n"
|
||||
"<!--#if $status #-->\n"
|
||||
"SABnzbd הוריד את \"$name\" <!--#if $msgid==\"\" then \"\" else \"(newzbin "
|
||||
"#\" + $msgid + \")\"#-->\n"
|
||||
"<!--#else#-->\n"
|
||||
"SABnzbd נכשל להוריד את \"$name\" <!--#if $msgid==\"\" then \"\" else "
|
||||
"\"(newzbin #\" + $msgid + \")\"#-->\n"
|
||||
"<!--#end if#-->\n"
|
||||
"הסתיים ב $end_time\n"
|
||||
"הורדו $size\n"
|
||||
"\n"
|
||||
":תוצאות העבודה\n"
|
||||
"<!--#for $stage ב $stages #-->\n"
|
||||
"שלב $stage <!--#slurp#-->\n"
|
||||
"<!--#for $result ב $stages[$stage]#-->\n"
|
||||
" $result <!--#slurp#-->\n"
|
||||
"<!--#end for#-->\n"
|
||||
"<!--#end for#-->\n"
|
||||
"<!--#if $script!=\"\" #-->\n"
|
||||
":(קוד יציאה = $script_ret) \"$script\" פלט מתסריט משתמש\n"
|
||||
"$script_output\n"
|
||||
"<!--#end if#-->\n"
|
||||
"<!--#if $status #-->\n"
|
||||
"!תהנה\n"
|
||||
"<!--#else#-->\n"
|
||||
"!סליחה\n"
|
||||
"<!--#end if#-->\n"
|
||||
|
||||
#: email/rss.tmpl:1
|
||||
msgid ""
|
||||
@@ -93,6 +135,29 @@ msgid ""
|
||||
"\n"
|
||||
"Bye\n"
|
||||
msgstr ""
|
||||
"##\n"
|
||||
"## SABnzbd עבור RSS תבנית דוא\"ל\n"
|
||||
"## זאת תבנית ברדלס\n"
|
||||
"## http://sabnzbd.wikidot.com/email-templates :תיעוד\n"
|
||||
"##\n"
|
||||
"## !שורות חדשות ורווחים לבנים הם משמעותיים\n"
|
||||
"##\n"
|
||||
"## אלו כותרות הדוא\"ל\n"
|
||||
"To: $to\n"
|
||||
"From: $from\n"
|
||||
"Date: $date\n"
|
||||
"הוסיף $amount עבודות לתור Subject: SABnzbd\n"
|
||||
"## !אחרי זה בא הגוף, השורה הריקה דרושה\n"
|
||||
"\n"
|
||||
",היי\n"
|
||||
"\n"
|
||||
".הוסיף $amount עבודות לתור SABnzbd\n"
|
||||
".\"$feed\" בשם RSS הם מהזנת\n"
|
||||
"<!--#for $job in $jobs#-->\n"
|
||||
" $job <!--#slurp#-->\n"
|
||||
"<!--#end for#-->\n"
|
||||
"\n"
|
||||
"ביי\n"
|
||||
|
||||
#: email/badfetch.tmpl:1
|
||||
msgid ""
|
||||
@@ -119,3 +184,24 @@ msgid ""
|
||||
"\n"
|
||||
"Bye\n"
|
||||
msgstr ""
|
||||
"##\n"
|
||||
"## Bad URL Fetch Email template for SABnzbd רעה עבור URL תבנית דוא\"ל של "
|
||||
"משיכת\n"
|
||||
"## זאת תבנית ברדלס\n"
|
||||
"## http://sabnzbd.wikidot.com/email-templates :תיעוד\n"
|
||||
"##\n"
|
||||
"## !שורות חדשות ורווחים לבנים הם משמעותיים\n"
|
||||
"##\n"
|
||||
"## אלו כותרות הדוא\"ל\n"
|
||||
"To: $to\n"
|
||||
"From: $from\n"
|
||||
"Date: $date\n"
|
||||
"NZB נכשל במשיכת Subject: SABnzbd\n"
|
||||
"## !אחרי זה בא הגוף, השורה הריקה דרושה\n"
|
||||
"\n"
|
||||
",היי\n"
|
||||
"\n"
|
||||
".$url מתוך NZB-נכשל לאחזר את ה SABnzbd\n"
|
||||
"הודעת השגיאה הייתה: $msg\n"
|
||||
"\n"
|
||||
"ביי\n"
|
||||
|
||||
@@ -12,7 +12,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=ASCII\n"
|
||||
"Content-Transfer-Encoding: 7bit\n"
|
||||
"POT-Creation-Date: 2017-07-17 20:10+W. Europe Daylight Time\n"
|
||||
"POT-Creation-Date: 2017-07-24 10:07+W. Europe Daylight Time\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
#: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py
|
||||
#: sabnzbd/osxmenu.py
|
||||
#: sabnzbd/osxmenu.py # sabnzbd/wizard.py
|
||||
msgid "SABnzbd shutdown finished"
|
||||
msgstr ""
|
||||
|
||||
@@ -409,10 +409,14 @@ msgstr ""
|
||||
msgid "%s => missing from all servers, discarding"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py
|
||||
#: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py
|
||||
#: sabnzbd/newsunpack.py
|
||||
msgid "Unpacking"
|
||||
#: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py
|
||||
#: sabnzbd/directunpacker.py # sabnzbd/skintext.py
|
||||
msgid "Direct Unpack"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status]
|
||||
#: sabnzbd/skintext.py [History: job status]
|
||||
msgid "Completed"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py
|
||||
@@ -779,6 +783,11 @@ msgstr ""
|
||||
msgid "Unpacking failed, archive requires a password"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py
|
||||
#: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py
|
||||
msgid "Unpacking"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"]
|
||||
msgid "Unpack"
|
||||
msgstr ""
|
||||
@@ -944,12 +953,12 @@ msgstr ""
|
||||
|
||||
#: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py
|
||||
#: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py
|
||||
#: sabnzbd/newsunpack.py
|
||||
#: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py
|
||||
msgid "Verifying"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py
|
||||
#: sabnzbd/skintext.py [PP status]
|
||||
#: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status]
|
||||
msgid "Checking"
|
||||
msgstr ""
|
||||
|
||||
@@ -1106,7 +1115,7 @@ msgstr ""
|
||||
msgid "Failing duplicate NZB \"%s\""
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/nzbstuff.py
|
||||
#: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message]
|
||||
msgid "Duplicate NZB"
|
||||
msgstr ""
|
||||
|
||||
@@ -1213,7 +1222,7 @@ msgid "Limit Speed"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Three way switch for duplicates]
|
||||
#: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates]
|
||||
#: sabnzbd/skintext.py [Config->Scheduling]
|
||||
msgid "Pause"
|
||||
msgstr ""
|
||||
@@ -1605,10 +1614,6 @@ msgstr ""
|
||||
msgid "Failure"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [History: job status]
|
||||
msgid "Completed"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py
|
||||
msgid "Failed"
|
||||
msgstr ""
|
||||
@@ -1817,6 +1822,54 @@ msgstr ""
|
||||
msgid "Year"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "January"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "February"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "March"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "April"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "May"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "June"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "July"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "August"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "September"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "October"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "November"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "December"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Day of month"
|
||||
msgstr ""
|
||||
@@ -2595,6 +2648,34 @@ msgstr ""
|
||||
msgid "List of file extensions that should be deleted after download.<br />For example: <b>nfo</b> or <b>nfo, sfv</b>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "History Retention"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Automatically delete completed jobs from History. Beware that Duplicate Detection and some external tools rely on History information."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Keep all jobs"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Keep maximum number of completed jobs"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Keep completed jobs maximum number of days"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Do not keep any completed jobs"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "History item limit"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Save Changes"
|
||||
msgstr ""
|
||||
@@ -2871,14 +2952,18 @@ msgstr ""
|
||||
msgid "Detect identical episodes in series (based on \"name/season/episode\" of items in your History)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Three way switch for duplicates]
|
||||
#: sabnzbd/skintext.py [Four way switch for duplicates]
|
||||
msgid "Discard"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Three way switch for duplicates]
|
||||
#: sabnzbd/skintext.py [Four way switch for duplicates]
|
||||
msgid "Fail job (move to History)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Four way switch for duplicates]
|
||||
msgid "Tag job"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Three way switch for encrypted posts]
|
||||
msgid "Abort"
|
||||
msgstr ""
|
||||
@@ -2967,10 +3052,6 @@ msgstr ""
|
||||
msgid "Automatically sort items by (average) age."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Direct Unpack"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay."
|
||||
msgstr ""
|
||||
@@ -3983,10 +4064,6 @@ msgstr ""
|
||||
msgid "Queue item limit"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "History item limit"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Date format"
|
||||
msgstr ""
|
||||
@@ -4011,6 +4088,10 @@ msgstr ""
|
||||
msgid "articles"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Rename"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Queue repair"
|
||||
msgstr ""
|
||||
|
||||
@@ -906,7 +906,7 @@ def _api_server_stats(name, output, kwargs):
|
||||
|
||||
stats['servers'] = {}
|
||||
for svr in config.get_servers():
|
||||
t, m, w, d = BPSMeter.do.amounts(svr)
|
||||
t, m, w, d, _ = BPSMeter.do.amounts(svr)
|
||||
stats['servers'][svr] = {'total': t or 0, 'month': m or 0, 'week': w or 0, 'day': d or 0}
|
||||
|
||||
return report(output, keyword='', data=stats)
|
||||
|
||||
@@ -118,6 +118,9 @@ class BPSMeter(object):
|
||||
self.month_total = {}
|
||||
self.grand_total = {}
|
||||
|
||||
self.timeline_total = {}
|
||||
|
||||
self.day_label = time.strftime("%Y-%m-%d")
|
||||
self.end_of_day = tomorrow(t) # Time that current day will end
|
||||
self.end_of_week = next_week(t) # Time that current day will end
|
||||
self.end_of_month = next_month(t) # Time that current month will end
|
||||
@@ -136,7 +139,7 @@ class BPSMeter(object):
|
||||
data = (self.last_update, self.grand_total,
|
||||
self.day_total, self.week_total, self.month_total,
|
||||
self.end_of_day, self.end_of_week, self.end_of_month,
|
||||
self.quota, self.left, self.q_time
|
||||
self.quota, self.left, self.q_time, self.timeline_total
|
||||
)
|
||||
sabnzbd.save_admin(data, BYTES_FILE_NAME)
|
||||
|
||||
@@ -171,12 +174,15 @@ class BPSMeter(object):
|
||||
self.last_update, self.grand_total, \
|
||||
self.day_total, self.week_total, self.month_total, \
|
||||
self.end_of_day, self.end_of_week, self.end_of_month = data[:8]
|
||||
if len(data) == 11:
|
||||
self.quota, self.left, self.q_time = data[8:]
|
||||
if len(data) >= 11:
|
||||
self.quota, self.left, self.q_time = data[8:11]
|
||||
logging.debug('Read quota q=%s l=%s reset=%s',
|
||||
self.quota, self.left, self.q_time)
|
||||
if abs(quota - self.quota) > 0.5:
|
||||
self.change_quota()
|
||||
# Get timeline stats
|
||||
if len(data) == 12:
|
||||
self.timeline_total = data[11]
|
||||
else:
|
||||
self.quota = self.left = cfg.quota_size.get_float()
|
||||
res = self.reset_quota()
|
||||
@@ -199,6 +205,7 @@ class BPSMeter(object):
|
||||
t = time.time()
|
||||
if t > self.end_of_day:
|
||||
# current day passed. get new end of day
|
||||
self.day_label = time.strftime("%Y-%m-%d")
|
||||
self.day_total = {}
|
||||
self.end_of_day = tomorrow(t) - 1.0
|
||||
|
||||
@@ -227,6 +234,12 @@ class BPSMeter(object):
|
||||
self.grand_total[server] = 0L
|
||||
self.grand_total[server] += amount
|
||||
|
||||
if server not in self.timeline_total:
|
||||
self.timeline_total[server] = {}
|
||||
if self.day_label not in self.timeline_total[server]:
|
||||
self.timeline_total[server][self.day_label]= 0L
|
||||
self.timeline_total[server][self.day_label] += amount
|
||||
|
||||
# Quota check
|
||||
if self.have_quota and self.quota_enabled:
|
||||
self.left -= amount
|
||||
@@ -290,7 +303,8 @@ class BPSMeter(object):
|
||||
return self.grand_total.get(server, 0L), \
|
||||
self.month_total.get(server, 0L), \
|
||||
self.week_total.get(server, 0L), \
|
||||
self.day_total.get(server, 0L)
|
||||
self.day_total.get(server, 0L), \
|
||||
self.timeline_total.get(server, {})
|
||||
|
||||
def clear_server(self, server):
|
||||
""" Clean counters for specified server """
|
||||
@@ -302,6 +316,8 @@ class BPSMeter(object):
|
||||
del self.month_total[server]
|
||||
if server in self.grand_total:
|
||||
del self.grand_total[server]
|
||||
if server in self.timeline_total:
|
||||
del self.timeline_total[server]
|
||||
self.save()
|
||||
|
||||
def get_bps(self):
|
||||
|
||||
@@ -164,6 +164,7 @@ cleanup_list = OptionList('misc', 'cleanup_list')
|
||||
unwanted_extensions = OptionList('misc', 'unwanted_extensions')
|
||||
action_on_unwanted_extensions = OptionNumber('misc', 'action_on_unwanted_extensions', 0)
|
||||
new_nzb_on_failure = OptionBool('misc', 'new_nzb_on_failure', False)
|
||||
history_retention = OptionStr('misc', 'history_retention', '0')
|
||||
|
||||
quota_size = OptionStr('misc', 'quota_size')
|
||||
quota_day = OptionStr('misc', 'quota_day')
|
||||
|
||||
@@ -40,7 +40,7 @@ from sabnzbd.constants import DB_HISTORY_NAME, STAGES
|
||||
from sabnzbd.encoding import unicoder
|
||||
from sabnzbd.bpsmeter import this_week, this_month
|
||||
from sabnzbd.decorators import synchronized
|
||||
from sabnzbd.misc import get_all_passwords
|
||||
from sabnzbd.misc import get_all_passwords, int_conv
|
||||
|
||||
DB_LOCK = threading.RLock()
|
||||
|
||||
@@ -249,6 +249,30 @@ class HistoryDB(object):
|
||||
|
||||
self.save()
|
||||
|
||||
def auto_history_purge(self):
|
||||
""" Remove history items based on the configured history-retention """
|
||||
if sabnzbd.cfg.history_retention() == "0":
|
||||
return
|
||||
|
||||
if sabnzbd.cfg.history_retention() == "-1":
|
||||
# Delete all non-failed ones
|
||||
self.remove_completed()
|
||||
|
||||
if "d" in sabnzbd.cfg.history_retention():
|
||||
# How many days to keep?
|
||||
days_to_keep = int_conv(sabnzbd.cfg.history_retention().strip()[:-1])
|
||||
seconds_to_keep = int(time.time()) - days_to_keep*3600*24
|
||||
if days_to_keep > 0:
|
||||
logging.info('Removing completed jobs older than %s days from history', days_to_keep)
|
||||
return self.execute("""DELETE FROM history WHERE status = 'Completed' AND completed < ?""", (seconds_to_keep,), save=True)
|
||||
else:
|
||||
# How many to keep?
|
||||
to_keep = int_conv(sabnzbd.cfg.history_retention())
|
||||
if to_keep > 0:
|
||||
logging.info('Removing all but last %s completed jobs from history', to_keep)
|
||||
return self.execute("""DELETE FROM history WHERE id NOT IN ( SELECT id FROM history WHERE status = 'Completed' ORDER BY completed DESC LIMIT ? )""", (to_keep,), save=True)
|
||||
|
||||
|
||||
def add_history_db(self, nzo, storage, path, postproc_time, script_output, script_line):
|
||||
""" Add a new job entry to the database """
|
||||
t = build_history_info(nzo, storage, path, postproc_time, script_output, script_line)
|
||||
@@ -540,6 +564,13 @@ def unpack_history_info(item):
|
||||
return item
|
||||
|
||||
|
||||
def midnight_history_purge():
|
||||
logging.info('Scheduled history purge')
|
||||
history_db = HistoryDB()
|
||||
history_db.auto_history_purge()
|
||||
history_db.close()
|
||||
|
||||
|
||||
def decode_factory(text):
|
||||
""" Recursively looks through the supplied argument
|
||||
and converts and text to Unicode
|
||||
|
||||
@@ -177,7 +177,7 @@ class DirectUnpacker(threading.Thread):
|
||||
# Add to success
|
||||
self.success_sets.append(self.cur_setname)
|
||||
logging.info('DirectUnpack completed for %s', self.cur_setname)
|
||||
self.nzo.set_action_line(T('Unpacking'), T('Completed'))
|
||||
self.nzo.set_action_line(T('Direct Unpack'), T('Completed'))
|
||||
|
||||
# Write current log
|
||||
unrar_log.append(linebuf.strip())
|
||||
@@ -222,7 +222,7 @@ class DirectUnpacker(threading.Thread):
|
||||
if not last_volume_linebuf or last_volume_linebuf != linebuf:
|
||||
# Next volume
|
||||
self.cur_volume += 1
|
||||
self.nzo.set_action_line(T('Unpacking'), self.get_formatted_stats())
|
||||
self.nzo.set_action_line(T('Direct Unpack'), self.get_formatted_stats())
|
||||
logging.info('DirectUnpacked volume %s for %s', self.cur_volume, self.cur_setname)
|
||||
last_volume_linebuf = linebuf
|
||||
|
||||
@@ -245,17 +245,23 @@ class DirectUnpacker(threading.Thread):
|
||||
if self in ACTIVE_UNPACKERS:
|
||||
ACTIVE_UNPACKERS.remove(self)
|
||||
|
||||
# Set the thread to killed so it never gets restarted by accident
|
||||
self.killed = True
|
||||
|
||||
def have_next_volume(self):
|
||||
""" Check if next volume of set is available, start
|
||||
from the end of the list where latest completed files are """
|
||||
from the end of the list where latest completed files are
|
||||
Make sure that files are 100% written to disk by checking md5sum
|
||||
"""
|
||||
for nzf_search in reversed(self.nzo.finished_files):
|
||||
if nzf_search.setname == self.cur_setname and nzf_search.vol == (self.cur_volume+1):
|
||||
if nzf_search.setname == self.cur_setname and nzf_search.vol == (self.cur_volume+1) and nzf_search.md5sum:
|
||||
return nzf_search
|
||||
return False
|
||||
|
||||
def wait_for_next_volume(self):
|
||||
""" Wait for the correct volume to appear
|
||||
But stop if it was killed or the NZB is done """
|
||||
But stop if it was killed or the NZB is done
|
||||
"""
|
||||
while not self.have_next_volume() and not self.killed and self.nzo.files:
|
||||
with self.next_file_lock:
|
||||
self.next_file_lock.wait()
|
||||
@@ -353,7 +359,8 @@ class DirectUnpacker(threading.Thread):
|
||||
|
||||
def analyze_rar_filename(filename):
|
||||
""" Extract volume number and setname from rar-filenames
|
||||
Both ".part01.rar" and ".r01" """
|
||||
Both ".part01.rar" and ".r01"
|
||||
"""
|
||||
m = RAR_NR.search(filename)
|
||||
if m:
|
||||
if m.group(4):
|
||||
|
||||
@@ -1305,7 +1305,7 @@ SWITCH_LIST = \
|
||||
'safe_postproc', 'no_dupes', 'replace_spaces', 'replace_dots',
|
||||
'ignore_samples', 'pause_on_post_processing', 'nice', 'ionice',
|
||||
'pre_script', 'pause_on_pwrar', 'sfv_check', 'folder_rename', 'load_balancing',
|
||||
'quota_size', 'quota_day', 'quota_resume', 'quota_period',
|
||||
'quota_size', 'quota_day', 'quota_resume', 'quota_period', 'history_retention',
|
||||
'pre_check', 'max_art_tries', 'fail_hopeless_jobs', 'enable_all_par',
|
||||
'enable_recursive', 'no_series_dupes', 'script_can_fail', 'new_nzb_on_failure',
|
||||
'unwanted_extensions', 'action_on_unwanted_extensions', 'sanitize_safe',
|
||||
@@ -1384,7 +1384,7 @@ SPECIAL_BOOL_LIST = \
|
||||
)
|
||||
SPECIAL_VALUE_LIST = \
|
||||
('size_limit', 'folder_max_length', 'fsys_type', 'movie_rename_limit', 'nomedia_marker',
|
||||
'req_completion_rate', 'wait_ext_drive', 'history_limit', 'show_sysload',
|
||||
'req_completion_rate', 'wait_ext_drive', 'show_sysload',
|
||||
'direct_unpack_threads', 'ipv6_servers', 'selftest_host', 'rating_host'
|
||||
)
|
||||
SPECIAL_LIST_LIST = ('rss_odd_titles', 'quick_check_ext_ignore')
|
||||
@@ -1612,9 +1612,9 @@ class ConfigServer(object):
|
||||
server_names = sorted(servers.keys(), key=lambda svr: '%d%02d%s' % (int(not servers[svr].enable()), servers[svr].priority(), servers[svr].displayname().lower()))
|
||||
for svr in server_names:
|
||||
new.append(servers[svr].get_dict(safe=True))
|
||||
t, m, w, d = BPSMeter.do.amounts(svr)
|
||||
t, m, w, d, timeline = BPSMeter.do.amounts(svr)
|
||||
if t:
|
||||
new[-1]['amounts'] = to_units(t), to_units(m), to_units(w), to_units(d)
|
||||
new[-1]['amounts'] = to_units(t), to_units(m), to_units(w), to_units(d), timeline
|
||||
conf['servers'] = new
|
||||
conf['cats'] = list_cats(default=True)
|
||||
conf['have_ssl_context'] = sabnzbd.HAVE_SSL_CONTEXT
|
||||
|
||||
@@ -1461,7 +1461,7 @@ def starts_with_path(path, prefix):
|
||||
def set_chmod(path, permissions, report):
|
||||
""" Set 'permissions' on 'path', report any errors when 'report' is True """
|
||||
try:
|
||||
logging.debug('Applying %s to %s', permissions, path)
|
||||
logging.debug('Applying permissions %s (octal) to %s', oct(permissions), path)
|
||||
os.chmod(path, permissions)
|
||||
except:
|
||||
lpath = path.lower()
|
||||
|
||||
@@ -851,17 +851,23 @@ class NzbObject(TryList):
|
||||
if duplicate and ((not series and cfg.no_dupes() == 3) or (series and cfg.no_series_dupes() == 3)):
|
||||
if cfg.warn_dupl_jobs():
|
||||
logging.warning(T('Failing duplicate NZB "%s"'), filename)
|
||||
# Move to history, utlizing the same code as accept&fail from pre-queue script
|
||||
# Move to history, utilizing the same code as accept&fail from pre-queue script
|
||||
self.fail_msg = T('Duplicate NZB')
|
||||
accept = 2
|
||||
duplicate = False
|
||||
|
||||
if duplicate or self.priority == DUP_PRIORITY:
|
||||
if cfg.warn_dupl_jobs():
|
||||
logging.warning(T('Pausing duplicate NZB "%s"'), filename)
|
||||
self.duplicate = True
|
||||
self.pause()
|
||||
self.priority = NORMAL_PRIORITY
|
||||
if cfg.no_dupes() == 4 or cfg.no_series_dupes() == 4:
|
||||
if cfg.warn_dupl_jobs():
|
||||
logging.warning('%s: "%s"', T('Duplicate NZB'), filename)
|
||||
self.duplicate = True
|
||||
self.priority = NORMAL_PRIORITY
|
||||
else:
|
||||
if cfg.warn_dupl_jobs():
|
||||
logging.warning(T('Pausing duplicate NZB "%s"'), filename)
|
||||
self.duplicate = True
|
||||
self.pause()
|
||||
self.priority = NORMAL_PRIORITY
|
||||
|
||||
if self.priority == PAUSED_PRIORITY:
|
||||
self.pause()
|
||||
@@ -1057,9 +1063,12 @@ class NzbObject(TryList):
|
||||
if not found:
|
||||
# Add extra parfiles when there was a damaged article and not pre-checking
|
||||
if self.extrapars and not self.precheck:
|
||||
self.abort_direct_unpacker()
|
||||
self.prospective_add(nzf)
|
||||
|
||||
# Sometimes a few CRC errors are still fine, so we continue
|
||||
if self.bad_articles > 5:
|
||||
self.abort_direct_unpacker()
|
||||
|
||||
post_done = False
|
||||
if not self.files:
|
||||
post_done = True
|
||||
|
||||
@@ -547,6 +547,8 @@ def process_job(nzo):
|
||||
# Add the nzo to the database. Only the path, script and time taken is passed
|
||||
# Other information is obtained from the nzo
|
||||
history_db.add_history_db(nzo, clip_path(workdir_complete), nzo.downpath, postproc_time, script_log, script_line)
|
||||
# Purge items
|
||||
history_db.auto_history_purge()
|
||||
# The connection is only used once, so close it here
|
||||
history_db.close()
|
||||
sabnzbd.history_updated()
|
||||
|
||||
@@ -193,6 +193,11 @@ def init():
|
||||
__SCHED.add_daytime_task(action, 'quota_reset', range(1, 8), None, (hour, minute),
|
||||
kronos.method.sequential, [], None)
|
||||
|
||||
if sabnzbd.misc.int_conv(cfg.history_retention()) > 0:
|
||||
logging.info('Setting schedule for midnight auto history-purge')
|
||||
__SCHED.add_daytime_task(sabnzbd.database.midnight_history_purge, 'midnight_history_purge', range(1, 8), None, (0, 0),
|
||||
kronos.method.sequential, [], None)
|
||||
|
||||
logging.info('Setting schedule for midnight BPS reset')
|
||||
__SCHED.add_daytime_task(sabnzbd.bpsmeter.midnight_action, 'midnight_bps', range(1, 8), None, (0, 0),
|
||||
kronos.method.sequential, [], None)
|
||||
|
||||
@@ -102,6 +102,18 @@ SKIN_TEXT = {
|
||||
'week' : TT('week'),
|
||||
'month' : TT('Month'),
|
||||
'year' : TT('Year'),
|
||||
'January': TT('January'),
|
||||
'February': TT('February'),
|
||||
'March': TT('March'),
|
||||
'April': TT('April'),
|
||||
'May': TT('May'),
|
||||
'June': TT('June'),
|
||||
'July': TT('July'),
|
||||
'August': TT('August'),
|
||||
'September': TT('September'),
|
||||
'October': TT('October'),
|
||||
'November': TT('November'),
|
||||
'December': TT('December'),
|
||||
'monday' : TT('Monday'),
|
||||
'tuesday' : TT('Tuesday'),
|
||||
'wednesday' : TT('Wednesday'),
|
||||
@@ -351,6 +363,13 @@ SKIN_TEXT = {
|
||||
'explain-cache_limitstr' : TT('Cache articles in memory to reduce disk access.<br /><i>In bytes, optionally follow with K,M,G. For example: "64M" or "128M"</i>'),
|
||||
'opt-cleanup_list' : TT('Cleanup List'),
|
||||
'explain-cleanup_list' : TT('List of file extensions that should be deleted after download.<br />For example: <b>nfo</b> or <b>nfo, sfv</b>'),
|
||||
'opt-history_retention' : TT('History Retention'),
|
||||
'explain-history_retention' : TT('Automatically delete completed jobs from History. Beware that Duplicate Detection and some external tools rely on History information.'),
|
||||
'history_retention-all' : TT('Keep all jobs'),
|
||||
'history_retention-number' : TT('Keep maximum number of completed jobs'),
|
||||
'history_retention-days' : TT('Keep completed jobs maximum number of days'),
|
||||
'history_retention-none' : TT('Do not keep any completed jobs'),
|
||||
'history_retention-limit': TT('History item limit'),
|
||||
'button-saveChanges' : TT('Save Changes'),
|
||||
'button-restoreDefaults' : TT('Restore Defaults'),
|
||||
'explain-restoreDefaults' : TT('Reset'),
|
||||
@@ -425,9 +444,10 @@ SKIN_TEXT = {
|
||||
'opt-no_series_dupes' : TT('Detect duplicate episodes in series'),
|
||||
'explain-no_series_dupes' : TT('Detect identical episodes in series (based on "name/season/episode" of items in your History)'),
|
||||
'nodupes-off' : TT('Off'), #: Three way switch for duplicates
|
||||
'nodupes-ignore' : TT('Discard'), #: Three way switch for duplicates
|
||||
'nodupes-pause' : TT('Pause'), #: Three way switch for duplicates
|
||||
'nodupes-fail' : TT('Fail job (move to History)'), #: Three way switch for duplicates
|
||||
'nodupes-ignore' : TT('Discard'), #: Four way switch for duplicates
|
||||
'nodupes-pause' : TT('Pause'), #: Four way switch for duplicates
|
||||
'nodupes-fail' : TT('Fail job (move to History)'), #: Four way switch for duplicates
|
||||
'nodupes-tag' : TT('Tag job'), #: Four way switch for duplicates
|
||||
'abort' : TT('Abort'), #: Three way switch for encrypted posts
|
||||
'opt-action_on_unwanted_extensions' : TT('Action when unwanted extension detected'),
|
||||
'explain-action_on_unwanted_extensions' : TT('Action when an unwanted extension is detected in RAR files'),
|
||||
@@ -788,6 +808,7 @@ SKIN_TEXT = {
|
||||
'Glitter-page' : TT('page'),
|
||||
'Glitter-loading' : TT('Loading'),
|
||||
'Glitter-articles' : TT('articles'),
|
||||
'Glitter-rename' : TT('Rename'),
|
||||
'Glitter-repairQueue' : TT('Queue repair'),
|
||||
'Glitter-showActiveConnections' : TT('Show active connections'),
|
||||
'Glitter-unblockServer' : TT('Unblock'),
|
||||
|
||||
@@ -47,6 +47,11 @@ class Wizard(object):
|
||||
@cherrypy.expose
|
||||
def index(self, **kwargs):
|
||||
""" Show the language selection page """
|
||||
if cfg.configlock() or not sabnzbd.interface.check_access():
|
||||
return sabnzbd.interface.Protected()
|
||||
if not sabnzbd.interface.check_login():
|
||||
raise sabnzbd.interface.NeedLogin()
|
||||
|
||||
info = self.info.copy()
|
||||
lng = None
|
||||
if sabnzbd.WIN32:
|
||||
@@ -72,15 +77,25 @@ class Wizard(object):
|
||||
@cherrypy.expose
|
||||
def exit(self, **kwargs):
|
||||
""" Stop SABnzbd """
|
||||
yield "Initiating shutdown..."
|
||||
if cfg.configlock() or not sabnzbd.interface.check_access():
|
||||
return sabnzbd.interface.Protected()
|
||||
if not sabnzbd.interface.check_login():
|
||||
raise sabnzbd.interface.NeedLogin()
|
||||
|
||||
logging.info('Shutdown requested by wizard')
|
||||
sabnzbd.halt()
|
||||
yield "<br>SABnzbd-%s shutdown finished" % sabnzbd.__version__
|
||||
cherrypy.engine.exit()
|
||||
sabnzbd.SABSTOP = True
|
||||
return T('SABnzbd shutdown finished')
|
||||
|
||||
@cherrypy.expose
|
||||
def one(self, **kwargs):
|
||||
""" Accept language and show server page """
|
||||
if cfg.configlock() or not sabnzbd.interface.check_access():
|
||||
return sabnzbd.interface.Protected()
|
||||
if not sabnzbd.interface.check_login():
|
||||
raise sabnzbd.interface.NeedLogin()
|
||||
|
||||
language = kwargs.get('lang') if kwargs.get('lang') else cfg.language()
|
||||
cfg.language.set(language)
|
||||
set_language(language)
|
||||
@@ -125,6 +140,11 @@ class Wizard(object):
|
||||
@cherrypy.expose
|
||||
def two(self, **kwargs):
|
||||
""" Accept server and show the final page for restart """
|
||||
if cfg.configlock() or not sabnzbd.interface.check_access():
|
||||
return sabnzbd.interface.Protected()
|
||||
if not sabnzbd.interface.check_login():
|
||||
raise sabnzbd.interface.NeedLogin()
|
||||
|
||||
# Save server details
|
||||
if kwargs:
|
||||
kwargs['enable'] = 1
|
||||
|
||||
Reference in New Issue
Block a user