Compare commits

..

2 Commits

Author SHA1 Message Date
Safihre
b62b38b5af Update text files for 4.3.3RC1 2024-08-13 10:29:25 +02:00
renovate[bot]
14b1d4630c Update all dependencies 2024-08-13 10:16:28 +02:00
107 changed files with 545 additions and 807 deletions

View File

@@ -15,7 +15,6 @@
"builder/release-requirements.txt"
]
},
"ignorePaths": [],
"ignoreDeps": [
"jaraco.text",
"jaraco.context",

View File

@@ -69,8 +69,8 @@ jobs:
# We need the official Python, because the GA ones only support newer macOS versions
# The deployment target is picked up by the Python build tools automatically
# If updated, make sure to also set LSMinimumSystemVersion in SABnzbd.spec
PYTHON_VERSION: "3.12.6"
MACOSX_DEPLOYMENT_TARGET: "10.13"
PYTHON_VERSION: "3.12.5"
MACOSX_DEPLOYMENT_TARGET: "10.9"
# We need to force compile for universal2 support
CFLAGS: -arch x86_64 -arch arm64
ARCHFLAGS: -arch x86_64 -arch arm64
@@ -95,12 +95,14 @@ jobs:
- name: Install Python
run: sudo installer -pkg ~/python.pkg -target /
- name: Install Python dependencies
# We have to manually compile some modules as they don't automatically fetch universal2 binaries
# We have to manually take a few steps:
# 1. We need to build the PyInstaller bootloader:
# https://github.com/pyinstaller/pyinstaller/issues/6235
run: |
python3 --version
pip3 install --upgrade pip wheel
pip3 install --upgrade -r requirements.txt --no-binary cffi,CT3,PyYAML,charset_normalizer --no-dependencies
pip3 install --upgrade -r builder/requirements.txt --no-dependencies
PYINSTALLER_COMPILE_BOOTLOADER=1 pip3 install --upgrade -r builder/requirements.txt --no-binary pyinstaller --no-dependencies
- name: Import macOS codesign certificates
# Taken from https://github.com/Apple-Actions/import-codesign-certs/pull/27 (comments)
env:

View File

@@ -31,18 +31,18 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-architecture: ["x64"]
name: ["Linux"]
os: [ubuntu-latest]
os: [ubuntu-20.04]
include:
- name: macOS
os: macos-latest
python-version: "3.13"
python-version: "3.12"
python-architecture: "x64"
- name: Windows
os: windows-latest
python-version: "3.13"
python-version: "3.12"
python-architecture: "x64"
- name: Windows (32bit)
os: windows-latest
@@ -60,7 +60,7 @@ jobs:
cache-dependency-path: "**/requirements.txt"
- name: Install system dependencies
if: runner.os == 'Linux'
run: sudo apt-get install unrar 7zip par2
run: sudo apt-get install unrar p7zip-full par2
- name: Install Python dependencies
run: |
python --version

View File

@@ -1,17 +1,57 @@
Release Notes - SABnzbd 4.4.0 Alpha 2
Release Notes - SABnzbd 4.3.3 Release Candidate 2
=========================================================
This is the first test release of SABnzbd 4.4.0.
This is the third bug fix release of SABnzbd 4.3.0.
## New features since 4.3.0
## Bug fixes and changes since 4.3.2
* Reduced chance of jobs getting stuck at 99%.
* Correct handling of empty or `Default` category when adding a job.
* History API-output could contain inconsistent variable types.
* Skip external IPv6 check if only link local addresses are available.
* Shortened timeouts when resolving addresses during checks.
* Windows: Could not repair or extract on ARM platforms.
* Windows: Add file version information to installer.
* Subtitle files will be deobfuscated if required.
* macOS: Dropped support for macOS 10.12 and below.
## Bug fixes and changes since 4.3.1
## Bug fixes since 4.3.0
* Added Special option `disable_archive` for jobs to always be permanently deleted.
* Specific AppRise notifications could fail to send.
* Update of the article decoder core (`rapidyenc`).
* Windows: After some time the interface would no longer load.
* Windows: Custom shortcuts would be removed by the installer.
* Windows/macOS: Updated Unrar to 7.01 and 7zip to 24.05.
* Toggling of Servers could result in jobs being stuck at 99%.
* Config restart would always determine redirect URL instead of using current.
## Key changes since 4.2.0
* **Archive:**
* When jobs are removed from the History, they are moved to the Archive.
* Keep your History clean and still be able to reliably use Duplicate Detection.
* **Apprise Integrated:**
* Send notifications using Apprise to almost any notification service.
* Supported notifications: https://github.com/caronc/apprise/wiki
* Notification Script `SABnzbd-notify.py` is no longer needed.
* **Added IPv6-staging option:**
* Enable `ipv6_staging` in Config - Specials to get additional IPv6 features:
* Add IPv6 hostnames during address selection.
* Internet Bandwidth is measured separately for IPv4 and IPv6.
* **Other:**
* The `text` output format is removed from the API, `json` is the default.
* Handling of multiple inputs to several API methods was improved.
* File browser dialog is available to select file paths in the Config.
* Users will be warned if they configure an Indexer as a Server.
* Added `SAB_API_KEY` and `SAB_API_URL` to script environment variables.
* Windows/macOS: Updated Python to 3.12.3, Multipar to v1.3.3.2,
Unrar to 7.00 and 7zip to 24.03.
## Bug fixes since 4.2.0
* Incorrect warnings of unknown status codes could be thrown.
* Watched Folder would not work if Socks5 proxy was active.
* Prevent crash on invalid Server Expiration Date.
* Windows: Installer could create duplicate shortcuts.
## Upgrade notices

View File

@@ -165,7 +165,7 @@ if sys.platform == "darwin":
"NSPersistentStoreTypeKey": "Binary",
}
],
"LSMinimumSystemVersion": "10.13",
"LSMinimumSystemVersion": "10.9",
"LSEnvironment": {"LANG": "en_US.UTF-8", "LC_ALL": "en_US.UTF-8"},
}

View File

@@ -1,2 +1,2 @@
PyGithub==2.4.0
PyGithub==2.3.0
praw==7.7.1

View File

@@ -5,19 +5,19 @@ packaging==24.1
pyinstaller-hooks-contrib==2024.8
altgraph==0.17.4
wrapt==1.16.0
setuptools==75.1.0
setuptools==72.1.0
# Required on 32bit Windows, exclude it based on Python-version
importlib_metadata==8.5.0; python_version < '3.10'
importlib_resources==6.4.5; python_version < '3.10'
zipp==3.20.2; python_version < '3.10'
importlib_metadata==8.2.0; python_version < '3.10'
importlib_resources==6.4.0; python_version < '3.10'
zipp==3.20.0; python_version < '3.10'
# orjson does not support 32bit Windows, also exclude based on Python-version
orjson==3.10.7; python_version > '3.8'
# For the Windows build
pefile==2024.8.26; sys_platform == 'win32'
pywin32-ctypes==0.2.3; sys_platform == 'win32'
pefile==2023.2.7; sys_platform == 'win32'
pywin32-ctypes==0.2.2; sys_platform == 'win32'
# For the macOS build
dmgbuild==1.6.2; sys_platform == 'darwin'

View File

@@ -92,7 +92,7 @@
<span class="icon-bar"></span>
</button>
<a class="navbar-logo navbar-logo-small" href="${root}" title="$T('Home')" data-placement="bottom">
<a class="navbar-logo navbar-logo-small" href="${root}" title="$T('Home')">
#include $webdir + "/staticcfg/images/logo-small.svg"#
</a>
</div>

View File

@@ -28,7 +28,7 @@
</label>
<div class="advanced-buttonSeperator"></div>
<div class="chart-selector-container" title="$T('selectedDates')" data-placement="bottom">
<div class="chart-selector-container" title="$T('selectedDates')">
<span class="glyphicon glyphicon-signal"></span>
<!--#set today = datetime.date.today()#-->
<input type="date" name="chart-start" id="chart-start" value="<!--#echo (today-datetime.timedelta(days=30)).strftime('%Y-%m-%d')#-->"> -
@@ -142,7 +142,7 @@
</div>
</div>
<!--#set $prio_colors = ["#59cc33", "#26a69a", "#3366cc", "#7f33cc", "#cc33a6", "#f39c12", "#cc3333", "#8d6e63"] #-->
<!--#set $prio_colors = ["#59cc33", "#3366cc","#7f33cc", "#cc33a6", "#cc3333"] #-->
<!--#set $cur_prio_color = -1 #-->
<!--#set $last_prio = -1 #-->
<!--#for $cur, $server in enumerate($servers) #-->

View File

@@ -71,7 +71,7 @@
<div class="field-pair">
<label class="config" for="field_sort_string_$cur">$T('sortString')</label>
<input type="text" name="sort_string" id="field_sort_string_$cur" value="$slot.sort_string" required="required" />
<button type="button" class="btn btn-default patternKey" onclick="jQuery('#pattern_explainer_$cur').toggle(); window.scrollBy(0, 500);">
<button type="button" title="$T('sort-legenda')" class="btn btn-default patternKey" onclick="jQuery('#pattern_explainer_$cur').toggle(); window.scrollBy(0, 500);">
<span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span> $T('sort-legenda')
</button>
</div>

View File

@@ -1,4 +1,3 @@
<!DOCTYPE HTML>
<html lang="$active_lang">
<head>
<title>SABnzbd - $T('login')</title>

View File

@@ -208,7 +208,7 @@ ul.tabs a,
#subscriptions,
.RSS form[action="add_rss_feed"] tr:nth-child(even),
.Config .table {
border: 1px solid #555555;
border: 1px solid #555555 !important;
}
.Categories form:first-of-type tr:last-of-type,

View File

@@ -19,7 +19,6 @@ body {
float: left;
overflow: visible;
border: 1px solid #dfdede;
border-bottom: none !important;
background-color: #FFF;
width: 100%
}
@@ -1223,6 +1222,7 @@ input[type="checkbox"] {
}
.value-and-select select {
min-width: 30px;
margin-top: 1px;
}
.dotOne, .dotTwo, .dotThree {

View File

@@ -262,10 +262,9 @@ function do_restart() {
// Show overlay
$('.main-restarting').show()
// Check if we need redirect
// Uses == on purpose, because val() returns string and data() returns int!
// What template
var switchedHTTPS = ($('#enable_https').is(':checked') === ($('#enable_https').data('original') === undefined))
var portsUnchanged = ($('#port').val() == $('#port').data('original')) && ($('#https_port').val() == $('#https_port').data('original'))
var portsUnchanged = ($('#port').val() === $('#port').data('original')) && ($('#https_port').val() === $('#https_port').data('original'))
// Are we on settings page or did nothing change?
if(!$('body').hasClass('General') || (!switchedHTTPS && portsUnchanged)) {
@@ -490,9 +489,6 @@ $(document).ready(function () {
addRowColor()
}
addRowColor()
// Add tooltips
jQuery('[title]').tooltip()
});
/*

View File

@@ -135,7 +135,7 @@
<div class="col-sm-6 col-dot-overflow" data-bind="visible: hasPerformanceInfo">
<span data-bind="text: statusInfo.pystone"></span>
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest') (~10 $T('seconds'))"><span class="glyphicon glyphicon-repeat"></span></a>
<small title="$cpumodel $cpusimd $docker" data-tooltip="true">$cpumodel $cpusimd $docker</small>
<small title="$cpumodel $cpusimd" data-tooltip="true">$cpumodel $cpusimd</small>
</div>
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
</div>

View File

@@ -30,7 +30,7 @@
<url type="faq">https://sabnzbd.org/wiki/faq</url>
<url type="contact">https://sabnzbd.org/live-chat.html</url>
<releases>
<release version="4.3.3" date="2024-08-01" type="stable"/>
<release version="4.3.3" date="2024-08-20" type="stable"/>
<release version="4.3.2" date="2024-05-30" type="stable"/>
<release version="4.3.1" date="2024-05-03" type="stable"/>
<release version="4.3.0" date="2024-05-01" type="stable"/>

View File

Binary file not shown.

View File

@@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: team@sabnzbd.org\n"
"Language-Team: SABnzbd <team@sabnzbd.org>\n"

View File

@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Language-Team: Czech (https://app.transifex.com/sabnzbd/teams/111101/cs/)\n"
"MIME-Version: 1.0\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Danish (https://app.transifex.com/sabnzbd/teams/111101/da/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Spanish (https://app.transifex.com/sabnzbd/teams/111101/es/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Finnish (https://app.transifex.com/sabnzbd/teams/111101/fi/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: French (https://app.transifex.com/sabnzbd/teams/111101/fr/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: ION, 2020\n"
"Language-Team: Hebrew (https://app.transifex.com/sabnzbd/teams/111101/he/)\n"

View File

@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Language-Team: Italian (https://app.transifex.com/sabnzbd/teams/111101/it/)\n"
"MIME-Version: 1.0\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Norwegian Bokmål (https://app.transifex.com/sabnzbd/teams/111101/nb/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Dutch (https://app.transifex.com/sabnzbd/teams/111101/nl/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Polish (https://app.transifex.com/sabnzbd/teams/111101/pl/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Portuguese (Brazil) (https://app.transifex.com/sabnzbd/teams/111101/pt_BR/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Romanian (https://app.transifex.com/sabnzbd/teams/111101/ro/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Russian (https://app.transifex.com/sabnzbd/teams/111101/ru/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Serbian (https://app.transifex.com/sabnzbd/teams/111101/sr/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Swedish (https://app.transifex.com/sabnzbd/teams/111101/sv/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Chinese (China) (https://app.transifex.com/sabnzbd/teams/111101/zh_CN/)\n"

View File

@@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: team@sabnzbd.org\n"
"Language-Team: SABnzbd <team@sabnzbd.org>\n"
@@ -399,10 +399,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr ""

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Czech (https://app.transifex.com/sabnzbd/teams/111101/cs/)\n"
@@ -434,10 +434,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr "Přímé rozbalení"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Danish (https://app.transifex.com/sabnzbd/teams/111101/da/)\n"
@@ -437,10 +437,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr ""

View File

@@ -14,13 +14,12 @@
# HandyDandy04, 2024
# Safihre <safihre@sabnzbd.org>, 2024
# Gjelbrim Haskaj, 2024
# Stefan Rodriguez Galeano, 2024
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Stefan Rodriguez Galeano, 2024\n"
"Last-Translator: Gjelbrim Haskaj, 2024\n"
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -258,7 +257,7 @@ msgstr "Die Verbindung konnte nicht überprüft werden. (%s)"
#: sabnzbd/api.py
msgid "Resolving address"
msgstr "Adresse wird aufgelöst"
msgstr "Adresse wird aufgelöst"
#. No value, used in dropdown menus
#: sabnzbd/api.py, sabnzbd/skintext.py
@@ -478,10 +477,6 @@ msgstr "Entschleiern korrigierte die Erweiterung von %d Datei(en)"
msgid "Deobfuscate renamed %d file(s)"
msgstr "Entschleiern hat %dDatei(en) umbenannt"
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr "Umbenannte Untertiteldatei(en)%d verschleiern"
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr "Direkt entpacken"
@@ -562,7 +557,7 @@ msgstr "Schwerer Fehler im Downloader"
#. Warning message
#: sabnzbd/downloader.py
msgid "%s@%s: Received unknown status code %s for article %s"
msgstr "%s@%s:Unbekannter Statuscode%s für Artikel erhalten %s"
msgstr ""
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
@@ -1236,22 +1231,21 @@ msgstr "Prowl-Nachricht konnte nicht versendet werden"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr "Übertragung der Info-Nachricht fehlgeschlagen - keine URLs definiert"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
msgstr "Eine oder mehrere Informations-URLs konnten nicht geladen werden."
msgstr ""
#: sabnzbd/notifier.py
msgid "Failed to send one or more Apprise Notifications"
msgstr ""
"Eine oder mehrere Info-Benachrichtigungen konnten nicht gesendet werden"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message"
msgstr "Info-Nachricht konnte nicht gesendet werden"
msgstr ""
#. Error message
#: sabnzbd/notifier.py
@@ -2436,7 +2430,7 @@ msgstr "Alle Elemente in der Warteschlange löschen?"
#. Delete confirmation popup
#: sabnzbd/skintext.py
msgid "Are you sure you want to remove these jobs?"
msgstr "Sind Sie sicher, dass Sie diese Aufträge entfernen wollen?"
msgstr ""
#. Queue page button
#: sabnzbd/skintext.py
@@ -2461,7 +2455,7 @@ msgstr "NZBs und Dateien löschen"
#. Checkbox if job should be added to Archive
#: sabnzbd/skintext.py
msgid "Permanently delete (skip archive)"
msgstr "erhaft löschen (Archiv überspringen)"
msgstr ""
#. Caption for missing articles in Queue
#: sabnzbd/skintext.py
@@ -2484,7 +2478,7 @@ msgstr "Kontingent jetzt zurücksetzen"
#: sabnzbd/skintext.py
msgid "Archive"
msgstr "Archiv"
msgstr ""
#. Button/link hiding History job details
#: sabnzbd/skintext.py
@@ -2509,7 +2503,7 @@ msgstr "Alle anzeigen"
#. Button showing all archived jobs
#: sabnzbd/skintext.py
msgid "Show Archive"
msgstr "Zeige Archiv"
msgstr ""
#. History table header - Size of the download quota
#: sabnzbd/skintext.py
@@ -2802,11 +2796,11 @@ msgstr "Port, auf dem SABnzbd auf Anfragen warten soll."
#: sabnzbd/skintext.py
msgid "Web Interface Theme"
msgstr "Benutzeroberfläche"
msgstr ""
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr "Wählen Sie ein Theme."
msgstr ""
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
@@ -2977,36 +2971,28 @@ msgstr "Alle Aufträge behalten"
msgid ""
"Move jobs to the archive if the history exceeds specified number of jobs"
msgstr ""
"Verschieben von Aufträgen in das Archiv, wenn der Verlauf die angegebene "
"Anzahl von Aufträgen überschreitet."
#: sabnzbd/skintext.py
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
"Löschen von Aufträgen, wenn der Verlauf und das Archiv die angegebene Anzahl"
" von Aufträgen überschreiten"
#: sabnzbd/skintext.py
msgid "Move jobs to the archive after specified number of days"
msgstr ""
"Verschieben von Aufträgen in das Archiv nach einer bestimmten Anzahl von "
"Tagen"
#: sabnzbd/skintext.py
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
"Löschen von Aufträgen aus der Historie und dem Archiv nach einer bestimmten "
"Anzahl von Tagen"
#: sabnzbd/skintext.py
msgid "Move all completed jobs to archive"
msgstr "Alle abgeschlossenen Aufträge ins Archiv verschieben"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete all completed jobs"
msgstr "Alle abgeschlossenen Aufträge löschen"
msgstr ""
#: sabnzbd/skintext.py
msgid "Jobs"
@@ -3295,7 +3281,7 @@ msgstr ""
#: sabnzbd/skintext.py
msgid "Purge Logs"
msgstr "Protokolle bereinigen"
msgstr ""
#: sabnzbd/skintext.py
msgid ".nzb Backup Folder"
@@ -3420,7 +3406,7 @@ msgstr "Aufgabe abgebrochen (verschoben in die Historie)"
#: sabnzbd/skintext.py
msgid "Abort post-processing"
msgstr "Nachbearbeitung abbrechen"
msgstr ""
#: sabnzbd/skintext.py
msgid "Action when unwanted extension detected"
@@ -3493,7 +3479,7 @@ msgstr ""
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr "Skript zur Beendigung der Warteschlange"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
@@ -4294,13 +4280,11 @@ msgstr "Geräte, welche die Benachrichtigungen empfangen sollen"
#. Apprise settings
#: sabnzbd/skintext.py
msgid "Enable Apprise notifications"
msgstr "Aktivieren Sie Info-Benachrichtigungen"
msgstr ""
#: sabnzbd/skintext.py
msgid "Send notifications using Apprise to almost any notification service"
msgstr ""
"Senden Sie Benachrichtigungen mit Anfragen an fast jeden "
"Benachrichtigungsdienst"
#. Apprise settings
#: sabnzbd/skintext.py
@@ -4311,15 +4295,11 @@ msgstr ""
#: sabnzbd/skintext.py
msgid "Use a comma and/or space to identify more than one URL."
msgstr ""
"Verwenden Sie ein Komma und/oder ein Leerzeichen, um mehr als eine URL zu "
"kennzeichnen."
#: sabnzbd/skintext.py
msgid ""
"Override the default URLs for specific notification types below, if desired."
msgstr ""
"Falls gewünscht, können Sie die Standard-URLs für bestimmte "
"Benachrichtigungstypen unten überschreiben."
#. Header for Notification Script notification section
#: sabnzbd/skintext.py
@@ -4818,9 +4798,6 @@ msgid ""
"When you Retry a job, 'Duplicate Detection' and 'Abort jobs that cannot be "
"completed' are disabled."
msgstr ""
"Wenn Sie einen Auftrag wiederholen, sind die Funktionen „Erkennung von "
"Duplikaten“ und „Abbruch von Aufträgen, die nicht abgeschlossen werden "
"können“ deaktiviert."
#: sabnzbd/skintext.py
msgid "View Script Log"
@@ -5055,7 +5032,7 @@ msgstr ""
#. Error message
#: sabnzbd/sorting.py
msgid "Failed to rename %s to %s"
msgstr "Fehler beim Umbenennen von %s nach %s"
msgstr "Fehler beim umbennenen von %s nach %s"
#. Error message
#: sabnzbd/sorting.py

View File

@@ -8,7 +8,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Spanish (https://app.transifex.com/sabnzbd/teams/111101/es/)\n"
@@ -455,10 +455,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr "Descomprimir directamente"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Finnish (https://app.transifex.com/sabnzbd/teams/111101/fi/)\n"
@@ -433,10 +433,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr ""

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Fred L <88com88@gmail.com>, 2024\n"
"Language-Team: French (https://app.transifex.com/sabnzbd/teams/111101/fr/)\n"
@@ -469,10 +469,6 @@ msgstr "La désobfuscation a corrigé l'extension de %d fichier(s)"
msgid "Deobfuscate renamed %d file(s)"
msgstr "La désobfuscation a renommé %d fichier(s)"
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr "Désobfusquer le(s) fichier(s) de sous-titres renommé(s) %d"
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr "Décompression Directe"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: ION, 2024\n"
"Language-Team: Hebrew (https://app.transifex.com/sabnzbd/teams/111101/he/)\n"
@@ -437,10 +437,6 @@ msgstr "אי־האפלה תיקנה את הסיומת של %d קבצים"
msgid "Deobfuscate renamed %d file(s)"
msgstr "אי־האפלה שינתה שם של %d קבצים"
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr "פריקה ישירה"

View File

@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Language-Team: Italian (https://app.transifex.com/sabnzbd/teams/111101/it/)\n"
"MIME-Version: 1.0\n"
@@ -420,10 +420,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr ""

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Norwegian Bokmål (https://app.transifex.com/sabnzbd/teams/111101/nb/)\n"
@@ -431,10 +431,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr ""

View File

@@ -8,7 +8,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2024\n"
"Language-Team: Dutch (https://app.transifex.com/sabnzbd/teams/111101/nl/)\n"
@@ -463,10 +463,6 @@ msgstr "Extensie van %d bestand(en) gecorrigeerd"
msgid "Deobfuscate renamed %d file(s)"
msgstr "Bestandsnamen van %d bestand(en) aangepast."
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr "Direct Uitpakken"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Polish (https://app.transifex.com/sabnzbd/teams/111101/pl/)\n"
@@ -430,10 +430,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr ""

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Portuguese (Brazil) (https://app.transifex.com/sabnzbd/teams/111101/pt_BR/)\n"
@@ -444,10 +444,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr ""

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Romanian (https://app.transifex.com/sabnzbd/teams/111101/ro/)\n"
@@ -447,10 +447,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr "Dezarhivare directă"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Russian (https://app.transifex.com/sabnzbd/teams/111101/ru/)\n"
@@ -430,10 +430,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr ""

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Serbian (https://app.transifex.com/sabnzbd/teams/111101/sr/)\n"
@@ -427,10 +427,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr ""

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Swedish (https://app.transifex.com/sabnzbd/teams/111101/sv/)\n"
@@ -428,10 +428,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr ""

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Kangwei Li <lkw20010211@gmail.com>, 2023\n"
"Language-Team: Chinese (China) (https://app.transifex.com/sabnzbd/teams/111101/zh_CN/)\n"
@@ -425,10 +425,6 @@ msgstr ""
msgid "Deobfuscate renamed %d file(s)"
msgstr ""
#: sabnzbd/deobfuscate_filenames.py
msgid "Deobfuscate renamed %d subtitle file(s)"
msgstr ""
#: sabnzbd/directunpacker.py, sabnzbd/skintext.py
msgid "Direct Unpack"
msgstr ""

View File

@@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha2\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: team@sabnzbd.org\n"
"Language-Team: SABnzbd <team@sabnzbd.org>\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Pavel C <quoing_transifex@mess.cz>, 2022\n"
"Language-Team: Czech (https://app.transifex.com/sabnzbd/teams/111101/cs/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Danish (https://app.transifex.com/sabnzbd/teams/111101/da/)\n"

View File

@@ -9,7 +9,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Lorenz B, 2024\n"
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Ester Molla Aragones <moarages@gmail.com>, 2020\n"
"Language-Team: Spanish (https://app.transifex.com/sabnzbd/teams/111101/es/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Finnish (https://app.transifex.com/sabnzbd/teams/111101/fi/)\n"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Fred L <88com88@gmail.com>, 2024\n"
"Language-Team: French (https://app.transifex.com/sabnzbd/teams/111101/fr/)\n"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: ION, 2024\n"
"Language-Team: Hebrew (https://app.transifex.com/sabnzbd/teams/111101/he/)\n"

View File

@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Language-Team: Italian (https://app.transifex.com/sabnzbd/teams/111101/it/)\n"
"MIME-Version: 1.0\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Norwegian Bokmål (https://app.transifex.com/sabnzbd/teams/111101/nb/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2024\n"
"Language-Team: Dutch (https://app.transifex.com/sabnzbd/teams/111101/nl/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Polish (https://app.transifex.com/sabnzbd/teams/111101/pl/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Portuguese (Brazil) (https://app.transifex.com/sabnzbd/teams/111101/pt_BR/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Romanian (https://app.transifex.com/sabnzbd/teams/111101/ro/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Russian (https://app.transifex.com/sabnzbd/teams/111101/ru/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Serbian (https://app.transifex.com/sabnzbd/teams/111101/sr/)\n"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Petter Ramme, 2024\n"
"Language-Team: Swedish (https://app.transifex.com/sabnzbd/teams/111101/sv/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.4.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Chinese (China) (https://app.transifex.com/sabnzbd/teams/111101/zh_CN/)\n"

View File

@@ -1,51 +1,50 @@
# Main requirements
# Note that not all sub-dependencies are listed, but only ones we know could cause trouble
apprise==1.9.0
apprise==1.8.1
sabctools==8.2.5
CT3==3.3.3.post1
cffi==1.17.1
cffi==1.17.0
pycparser==2.22
feedparser==6.0.11
configobj==5.0.9
configobj==5.0.8
cheroot==10.0.1
six==1.16.0
cherrypy==18.10.0
jaraco.functools==4.1.0
jaraco.functools==4.0.2
jaraco.collections==5.0.0
jaraco.text==3.8.1 # Newer version introduces irrelevant extra dependencies
jaraco.classes==3.4.0
jaraco.context==4.3.0
more-itertools==10.5.0
more-itertools==10.4.0
zc.lockfile==3.0.post1
python-dateutil==2.9.0.post0
tempora==5.7.0
pytz==2024.2
pytz==2024.1
sgmllib3k==1.0.0
portend==3.2.0
chardet==5.2.0
pyunormalize==16.0.0
PySocks==1.7.1
puremagic==1.28
puremagic==1.27
guessit==3.8.0
babelfish==0.6.1
rebulk==3.2.0
# Recent cryptography versions require Rust. If you run into issues compiling this
# SABnzbd will also work with older pre-Rust versions such as cryptography==3.3.2
cryptography==43.0.1
cryptography==43.0.0
# We recommend using "orjson" as it is 2x as fast as "ujson". However, it requires
# Rust so SABnzbd works just as well with "ujson" or the Python built in "json" module
ujson==5.10.0
# Windows system integration
pywin32==308; sys_platform == 'win32'
windows-toasts==1.3.0; sys_platform == 'win32' and python_version > '3.8'
winrt-runtime==2.2.0; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.Data.Xml.Dom==2.2.0; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.Foundation==2.2.0; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.Foundation.Collections==2.2.0; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.UI.Notifications==2.2.0; sys_platform == 'win32' and python_version > '3.8'
pywin32==306; sys_platform == 'win32'
windows-toasts==1.2.0; sys_platform == 'win32' and python_version > '3.8'
winrt-runtime==2.1.0; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.Data.Xml.Dom==2.1.0; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.Foundation==2.1.0; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.Foundation.Collections==2.1.0; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.UI.Notifications==2.1.0; sys_platform == 'win32' and python_version > '3.8'
# macOS system calls
pyobjc-core==10.3.1; sys_platform == 'darwin'
@@ -58,14 +57,14 @@ notify2==0.3.1; sys_platform != 'win32' and sys_platform != 'darwin'
requests==2.32.3
requests-oauthlib==2.0.0
PyYAML==6.0.2
markdown==3.7
markdown==3.6
paho-mqtt==1.6.1 # Pinned, newer versions don't work with AppRise yet
# Requests Requirements
charset_normalizer==3.4.0
idna==3.10
urllib3==2.2.3
certifi==2024.8.30
charset_normalizer==3.3.2
idna==3.7
urllib3==2.2.2
certifi==2024.7.4
oauthlib==3.2.2
PyJWT==2.9.0
blinker==1.8.2

View File

@@ -249,7 +249,6 @@ def initialize(pause_downloader=False, clean_up=False, repair=0):
cfg.web_port.callback(cfg.guard_restart)
cfg.web_dir.callback(cfg.guard_restart)
cfg.web_color.callback(cfg.guard_restart)
cfg.url_base.callback(trigger_restart)
cfg.username.callback(cfg.guard_restart)
cfg.password.callback(cfg.guard_restart)
cfg.log_dir.callback(cfg.guard_restart)
@@ -275,8 +274,30 @@ def initialize(pause_downloader=False, clean_up=False, repair=0):
# Set end-of-queue action
sabnzbd.misc.change_queue_complete_action(cfg.queue_complete(), new=False)
# Do any config conversions
cfg.config_conversions()
# Convert auto-sort
if cfg.auto_sort() == "0":
cfg.auto_sort.set("")
elif cfg.auto_sort() == "1":
cfg.auto_sort.set("avg_age asc")
# Convert old series/date/movie sorters
if not cfg.sorters_converted():
misc.convert_sorter_settings()
cfg.sorters_converted.set(True)
# Convert duplicate settings
if cfg.no_series_dupes():
cfg.no_smart_dupes.set(cfg.no_series_dupes())
cfg.no_series_dupes.set(0)
# Convert history retention setting
if cfg.history_retention():
misc.convert_history_retention()
cfg.history_retention.set("")
# Add hostname to the whitelist
if not cfg.host_whitelist():
cfg.host_whitelist.set(socket.gethostname())
# Do repair if requested
if misc.check_repair_request():
@@ -298,6 +319,10 @@ def initialize(pause_downloader=False, clean_up=False, repair=0):
# Run startup tasks
sabnzbd.NzbQueue.read_queue(repair)
sabnzbd.Scheduler.analyse(pause_downloader)
# Set cache limit for new users
if not cfg.cache_limit():
cfg.cache_limit.set(misc.get_cache_limit())
sabnzbd.ArticleCache.new_limit(cfg.cache_limit.get_int())
logging.info("All processes started")

View File

@@ -115,11 +115,9 @@ def validate_single_tag(value: List[str]) -> Tuple[None, List[str]]:
return None, value
def validate_url_base(value: str) -> Tuple[None, str]:
"""Strips the right slash and adds starting slash, if not present"""
if value and isinstance(value, str):
if not value.startswith("/"):
value = "/" + value
def validate_strip_right_slash(value: str) -> Tuple[None, str]:
"""Strips the right slash"""
if value:
return None, value.rstrip("/")
return None, value
@@ -279,9 +277,6 @@ def validate_default_if_empty(root: str, value: str, default: str) -> Tuple[None
# Special settings
##############################################################################
# Increase everytime we do a configuration conversion
config_conversion_version = OptionNumber("misc", "config_conversion_version", default_val=0)
# This should be here so it's initialized first when the config is read
helpful_warnings = OptionBool("misc", "helpful_warnings", True)
@@ -491,7 +486,7 @@ wait_ext_drive = OptionNumber("misc", "wait_ext_drive", 5, minval=1, maxval=60)
max_foldername_length = OptionNumber("misc", "max_foldername_length", DEF_FOLDER_MAX, minval=20, maxval=65000)
marker_file = OptionStr("misc", "nomedia_marker")
ipv6_servers = OptionBool("misc", "ipv6_servers", True)
url_base = OptionStr("misc", "url_base", "", validation=validate_url_base)
url_base = OptionStr("misc", "url_base", "/sabnzbd", validation=validate_strip_right_slash)
host_whitelist = OptionList("misc", "host_whitelist", validation=all_lowercase)
local_ranges = OptionList("misc", "local_ranges", protect=True)
max_url_retries = OptionNumber("misc", "max_url_retries", 10, minval=1)
@@ -696,9 +691,7 @@ def set_root_folders2():
##############################################################################
def new_limit():
"""Callback for article cache changes"""
if sabnzbd.__INITIALIZED__:
# Only update after full startup
sabnzbd.ArticleCache.new_limit(cache_limit.get_int())
sabnzbd.ArticleCache.new_limit(cache_limit.get_int())
def guard_restart():
@@ -739,52 +732,3 @@ def guard_language():
def guard_https_ver():
"""Callback for change of https verification"""
sabnzbd.misc.set_https_verification(enable_https_verification())
##############################################################################
# Conversions
##############################################################################
def config_conversions():
"""Update sections of the config, only once"""
# Basic old conversions
if config_conversion_version() < 1:
logging.info("Config conversion set 1")
# Convert auto-sort
if auto_sort() == "0":
auto_sort.set("")
elif auto_sort() == "1":
auto_sort.set("avg_age asc")
# Convert old series/date/movie sorters
if not sorters_converted():
sabnzbd.misc.convert_sorter_settings()
sorters_converted.set(True)
# Convert duplicate settings
if no_series_dupes():
no_smart_dupes.set(no_series_dupes())
no_series_dupes.set(0)
# Convert history retention setting
if history_retention():
sabnzbd.misc.convert_history_retention()
history_retention.set("")
# Add hostname to the whitelist
if not host_whitelist():
host_whitelist.set(socket.gethostname())
# Set cache limit for new users
if not cache_limit():
cache_limit.set(sabnzbd.misc.get_cache_limit())
# Done
config_conversion_version.set(1)
# url_base conversion
if config_conversion_version() < 2:
logging.info("Config conversion set 2")
# We did not end up applying this conversion, so we skip this conversion_version
pass

View File

@@ -120,8 +120,7 @@ class Option:
"""Set new value, no validation"""
global CFG_MODIFIED
if value is not None:
# Use get() to make sure we use default if nothing was set yet
if isinstance(value, list) or isinstance(value, dict) or value != self.get():
if isinstance(value, list) or isinstance(value, dict) or value != self.__value:
self.__value = value
CFG_MODIFIED = True
if self.__callback:

View File

@@ -101,7 +101,6 @@ SOFT_QUEUE_LIMIT = 0.5
# Percentage of cache to use before adding file to assembler
ASSEMBLER_WRITE_THRESHOLD = 5
NNTP_BUFFER_SIZE = int(800 * KIBI)
NTTP_MAX_BUFFER_SIZE = int(10 * MEBI)
REPAIR_PRIORITY = 3
FORCE_PRIORITY = 2

View File

@@ -35,7 +35,7 @@ from sabnzbd.constants import DB_HISTORY_NAME, STAGES, Status, PP_LOOKUP
from sabnzbd.bpsmeter import this_week, this_month
from sabnzbd.decorators import synchronized
from sabnzbd.encoding import ubtou, utob
from sabnzbd.misc import caller_name, opts_to_pp, to_units, bool_conv, match_str
from sabnzbd.misc import caller_name, opts_to_pp, to_units, bool_conv
from sabnzbd.filesystem import remove_file, clip_path
DB_LOCK = threading.Lock()
@@ -129,7 +129,7 @@ class HistoryDB:
logging.error(T("Cannot write to History database, check access rights!"))
# Report back success, because there's no recovery possible
return True
elif match_str(error, ("not a database", "malformed", "no such table", "duplicate column name")):
elif "not a database" in error or "malformed" in error or "duplicate column name" in error:
logging.error(T("Damaged History database, created empty replacement"))
logging.info("Traceback: ", exc_info=True)
self.close()
@@ -141,7 +141,7 @@ class HistoryDB:
self.connect()
# Return False in case of "duplicate column" error
# because the column addition in connect() must be terminated
return True
return "duplicate column name" not in error
else:
logging.error(T("SQL Command Failed, see log"))
logging.info("SQL: %s", command)
@@ -604,5 +604,6 @@ def unpack_history_info(item: sqlite3.Row) -> Dict[str, Any]:
def scheduled_history_purge():
logging.info("Scheduled history purge")
with HistoryDB() as history_db:
history_db.auto_history_purge()

View File

@@ -92,7 +92,7 @@ def decode(article: Article, data_view: memoryview):
sabnzbd.Downloader.pause()
# This article should be fetched again
article.allow_new_fetcher()
sabnzbd.NzbQueue.reset_try_lists(article)
return
except BadData as error:

View File

@@ -27,13 +27,14 @@ files to the job-name in the queue if the filename looks obfuscated
Based on work by P1nGu1n
"""
import hashlib
import logging
import os
import re
import sabnzbd
from sabnzbd.filesystem import get_unique_filename, renamer, get_ext, get_basename, listdir_normalized
from sabnzbd.filesystem import get_unique_filename, renamer, get_ext, get_basename
from sabnzbd.par2file import is_parfile, parse_par2_file
import sabnzbd.utils.file_extension as file_extension
from sabnzbd.misc import match_str
@@ -59,7 +60,7 @@ def decode_par2(parfile: str) -> List[str]:
# Parse all files in the folder
dirname = os.path.dirname(parfile)
new_files = [] # list of new files generated
for fn in listdir_normalized(dirname):
for fn in os.listdir(dirname):
filepath = os.path.join(dirname, fn)
# Only check files
if os.path.isfile(filepath):
@@ -168,29 +169,21 @@ def is_probably_obfuscated(myinputfilename: str) -> bool:
return True # default is obfuscated
def get_biggest_file(filelist: List[str]) -> str:
"""Returns biggest file if that file is much bigger than the other files
If only one file exists, return that. If no file, return None
Note: the files in filelist must exist, because their sizes on disk are checked"""
# sort from big to small
filelist = sorted(filelist, key=os.path.getsize)[::-1] # reversed, so big to small. Format [start:stop:step]
def first_file_is_much_bigger(filelist):
# returns True if first file is much bigger than second file
# Note: input parameter filelist must ordered on size!
try:
factor = os.path.getsize(filelist[0]) / os.path.getsize(filelist[1])
if factor > 3:
return filelist[0]
return True
else:
return False
except:
if len(filelist) == 1:
# the only file, so biggest
return filelist[0]
else:
# no existing file(s)
return None
# no second file at all
return True
def deobfuscate(nzo, filelist: List[str], usefulname: str) -> List[str]:
def deobfuscate(nzo, filelist: List[str], usefulname: str):
"""
For files in filelist:
1. if a file has no meaningful extension, add it (for example ".txt" or ".png")
@@ -232,60 +225,69 @@ def deobfuscate(nzo, filelist: List[str], usefulname: str) -> List[str]:
nzo: sabnzbd.nzbstuff.NzbObject
# to be sure, only keep really existing files and remove any duplicates:
filtered_filelist = list(set(f for f in filelist if os.path.isfile(f)))
filelist = set(f for f in filelist if os.path.isfile(f))
# Do not deobfuscate/rename anything if there is a typical DVD or Bluray directory:
ignored_movie_folders_with_dir_sep = tuple(os.path.sep + f + os.path.sep for f in IGNORED_MOVIE_FOLDERS)
match_ignored_movie_folders = [f for f in filtered_filelist if match_str(f, ignored_movie_folders_with_dir_sep)]
match_ignored_movie_folders = [f for f in filelist if match_str(f, ignored_movie_folders_with_dir_sep)]
if match_ignored_movie_folders:
logging.info(
"Skipping deobfuscation because of DVD/Bluray directory name(s), like: %s",
str(match_ignored_movie_folders)[:200],
)
nzo.set_unpack_info("Deobfuscate", T("Deobfuscate skipped due to DVD/Bluray directories"))
return filtered_filelist
return
# If needed, add a useful extension (by looking at file contents)
# Example: if 'kjladsflkjadf.adsflkjads' is probably a PNG, rename to 'kjladsflkjadf.adsflkjads.png'
new_filelist = []
newlist = []
nr_ext_renamed = 0
for file in filtered_filelist:
for file in filelist:
if file_extension.has_popular_extension(file):
# common extension, like .doc or .iso, so assume OK and change nothing
logging.debug("Extension of %s looks common", file)
new_filelist.append(file)
newlist.append(file)
else:
# uncommon (so: obfuscated) extension
if new_extension_to_add := file_extension.what_is_most_likely_extension(file):
new_extension_to_add = file_extension.what_is_most_likely_extension(file)
if new_extension_to_add:
new_name = get_unique_filename("%s%s" % (file, new_extension_to_add))
logging.info("Deobfuscate renaming (adding extension) %s to %s", file, new_name)
# Use output of renamer, just in case it's somehow modified by sanitization
new_filelist.append(renamer(file, new_name))
renamer(file, new_name)
newlist.append(new_name)
nr_ext_renamed += 1
else:
# no new extension found
new_filelist.append(file)
newlist.append(file)
if nr_ext_renamed:
nzo.set_unpack_info("Deobfuscate", T("Deobfuscate corrected the extension of %d file(s)") % nr_ext_renamed)
filtered_filelist = new_filelist
nr_files_renamed = 0
filelist = newlist
logging.debug("Trying to see if there are qualifying files to be deobfuscated")
nr_files_renamed = 0
if not (biggest_file := get_biggest_file(filtered_filelist)) or not os.path.isfile(biggest_file):
# We pick the biggest file ... probably the most important file
# so sort filelist on size:
filelist = sorted(filelist, key=os.path.getsize, reverse=True)
if filelist:
biggest_file = filelist[0]
else:
biggest_file = None
if not biggest_file or not os.path.isfile(biggest_file):
# no file found, which is weird
logging.info("No biggest file found, or not found (%s)", biggest_file)
return filtered_filelist
logging.info("No file given, or not found (%s)", biggest_file)
return
logging.debug("Deobfuscate inspecting biggest file%s", biggest_file)
if not first_file_is_much_bigger(filelist):
logging.debug("%s excluded from deobfuscation because it is not much bigger than other file(s)", biggest_file)
return
if get_ext(biggest_file) in EXCLUDED_FILE_EXTS:
logging.debug("%s excluded from deobfuscation because of excluded extension", biggest_file)
return filtered_filelist
return
if not is_probably_obfuscated(biggest_file):
logging.debug("%s excluded from deobfuscation because filename does not look obfuscated", biggest_file)
return filtered_filelist
return
# if we get here, the biggest_file is relatively big, has no excluded extension, and is obfuscated
# Rename the biggest_file and make sure the new filename is unique
@@ -293,89 +295,20 @@ def deobfuscate(nzo, filelist: List[str], usefulname: str) -> List[str]:
# construct new_name: <path><usefulname><extension>
new_name = get_unique_filename("%s%s" % (os.path.join(path, usefulname), get_ext(biggest_file)))
logging.info("Deobfuscate renaming %s to %s", biggest_file, new_name)
filtered_filelist.remove(biggest_file)
filtered_filelist.append(renamer(biggest_file, new_name))
renamer(biggest_file, new_name)
nr_files_renamed += 1
# Now find other files with the same basename in filelist, and rename them in the same way:
basedirfile = get_basename(biggest_file) # something like "/home/this/myiso"
for otherfile in filtered_filelist[:]:
for otherfile in filelist:
if otherfile.startswith(basedirfile) and os.path.isfile(otherfile):
# yes, same basedirfile, only different ending
remaining_ending = otherfile.replace(basedirfile, "") # might be long ext, like ".dut.srt" or "-sample.iso"
new_name = get_unique_filename("%s%s" % (os.path.join(path, usefulname), remaining_ending))
logging.info("Deobfuscate renaming %s to %s", otherfile, new_name)
filtered_filelist.remove(otherfile)
filtered_filelist.append(renamer(otherfile, new_name))
# Rename and make sure the new filename is unique
renamer(otherfile, new_name)
nr_files_renamed += 1
if nr_files_renamed:
nzo.set_unpack_info("Deobfuscate", T("Deobfuscate renamed %d file(s)") % nr_files_renamed)
return filtered_filelist
def without_extension(fullpathfilename: str) -> str:
"""Returns full file path, without extension
So '/some/dir/somefile.bin' results in '/some/dir/somefile'"""
return os.path.splitext(fullpathfilename)[0]
def deobfuscate_subtitles(nzo, filelist: List[str]):
"""
input:
nzo, so we can update result via set_unpack_info()
filelist must be a List of existing filenames
Find .srt subtitle files, and rename to match the biggest file (if there is a clearly biggest file)
Some_Big_File_2024.avi # biggest file
Some_Big_File_2024.srt # no renaming wanted
Some_Big_File_2024.ger.srt # no renaming wanted
14_English.srt # to be renamed
dut.srt # to be renamed
Something.else.txt # no renaming wanted, because no .srt
will result in
Some_Big_File_2024.avi
Some_Big_File_2024.srt
Some_Big_File_2024.ger.srt
Some_Big_File_2024.14_English.srt # renamed by prepending base name
Some_Big_File_2024.dut.srt # renamed by prepending base name
Something.else.txt
"""
# Can't be imported directly due to circular import
nzo: sabnzbd.nzbstuff.NzbObject
# find .srt files
if not (srt_files := [f for f in filelist if f.endswith(".srt")]):
logging.debug("No .srt files found, so nothing to do")
return None
# check there is a clearly biggest file
if not (biggest_file := get_biggest_file(filelist)):
logging.debug("No clearly biggest file found, so no subtitle renaming feasible")
return None
biggest_file_without_ext = without_extension(biggest_file) # get full path base name of biggest file
logging.debug(f"Using as base filename: {biggest_file_without_ext}")
# handle srt files one by one
nr_files_renamed = 0
for srt_file in srt_files:
if without_extension(srt_file).startswith(biggest_file_without_ext):
# already the same start as the biggest file, so skip
continue
# not the same start, so rename the srt file
nr_files_renamed += 1
filename_only = os.path.basename(srt_file) # like "14_English.srt", so without path
# now put that name after the base name of the biggestfile:
new_full_name = f"{biggest_file_without_ext}.{filename_only}" # put (renamed) srt behind that
unique_filename = get_unique_filename(new_full_name) # make sure it's really unique
renamer(srt_file, unique_filename) # ... and rename actual file on disk
if nr_files_renamed > 0:
# and put it into history to be shown in GUI
nzo.set_unpack_info("Deobfuscate", T("Deobfuscate renamed %d subtitle file(s)") % nr_files_renamed)

View File

@@ -165,12 +165,11 @@ class Server:
self.reset_article_queue()
def stop(self):
"""Remove all connections and cached articles from server"""
"""Remove all connections from server"""
for nw in self.idle_threads:
sabnzbd.Downloader.remove_socket(nw)
nw.hard_reset()
self.idle_threads = set()
self.reset_article_queue()
@synchronized(DOWNLOADER_LOCK)
def get_article(self):
@@ -196,13 +195,10 @@ class Server:
self.next_article_search = time.time() + _SERVER_CHECK_DELAY
return None
@synchronized(DOWNLOADER_LOCK)
def reset_article_queue(self):
"""Reset articles queued for the Server. Locked to prevent
articles getting stuck in the Server when enabled/disabled"""
logging.debug("Resetting article queue for %s (%s)", self, self.article_queue)
logging.debug("Resetting article queue for %s", self)
for article in self.article_queue:
article.allow_new_fetcher()
sabnzbd.NzbQueue.reset_try_lists(article)
self.article_queue = []
def request_addrinfo(self):
@@ -215,7 +211,7 @@ class Server:
def request_addrinfo_blocking(self):
"""Blocking attempt to run getaddrinfo() and Happy Eyeballs for specified server"""
logging.debug("Retrieving server address information for %s", self)
logging.debug("Retrieving server address information for %s", self.host)
# Disable IPV6 if desired
family = socket.AF_UNSPEC
@@ -233,7 +229,7 @@ class Server:
sabnzbd.Downloader.wakeup()
def __repr__(self):
return "<Server: id=%s, host=%s:%s>" % (self.id, self.host, self.port)
return "<Server: %s:%s>" % (self.host, self.port)
class Downloader(Thread):
@@ -333,6 +329,7 @@ class Downloader(Thread):
create = False
server.newid = newserver
server.restart = True
server.reset_article_queue()
self.server_restarts += 1
break
@@ -513,8 +510,8 @@ class Downloader(Thread):
# Handle broken articles directly
if not data_view:
if not article.search_new_server():
article.nzf.nzo.increase_bad_articles_counter("missing_articles")
sabnzbd.NzbQueue.register_article(article, success=False)
article.nzf.nzo.increase_bad_articles_counter("missing_articles")
return
# Decode and send to article cache
@@ -707,14 +704,9 @@ class Downloader(Thread):
except ssl.SSLWantReadError:
return
except (ConnectionError, ConnectionAbortedError):
# The ConnectionAbortedError is also thrown by sabctools in case of fatal SSL-layer problems
# The ConnectionAbortedError is thrown by sabctools in case of fatal SSL-layer problems
self.__reset_nw(nw, "Server closed connection", wait=False)
return
except BufferError:
# The BufferError is thrown when exceeding maximum buffer size
# Make sure to discard the article
self.__reset_nw(nw, "Maximum data buffer size exceeded", wait=False, retry_article=False)
return
article = nw.article
server = nw.server
@@ -968,9 +960,14 @@ class Downloader(Thread):
self.decode(nw.article)
nw.article.tries = 0
else:
# Allow all servers again for this article
# Do not use the article_queue, as the server could already have been disabled when we get here!
nw.article.allow_new_fetcher()
# Retry again with the same server
logging.debug(
"Re-adding article %s from %s to server %s",
nw.article.article,
nw.article.nzf.filename,
nw.article.fetcher,
)
nw.article.fetcher.article_queue.append(nw.article)
# Reset connection object
nw.hard_reset(wait)

View File

@@ -20,7 +20,6 @@ sabnzbd.encoding - Unicode/byte translation functions
"""
import locale
import pyunormalize
import chardet
from xml.sax.saxutils import escape
from typing import AnyStr
@@ -28,11 +27,6 @@ from typing import AnyStr
CODEPAGE = locale.getpreferredencoding()
def normalize_utf8(inputstring: str) -> str:
"""Make sure we return an utf8 normalized version"""
return pyunormalize.NFC(inputstring)
def utob(str_in: AnyStr) -> bytes:
"""Shorthand for converting UTF-8 string to bytes"""
if isinstance(str_in, bytes):
@@ -43,19 +37,22 @@ def utob(str_in: AnyStr) -> bytes:
def ubtou(str_in: AnyStr) -> str:
"""Shorthand for converting unicode bytes to UTF-8 string"""
if isinstance(str_in, str):
return normalize_utf8(str_in)
return normalize_utf8(str_in.decode("utf-8"))
return str_in
return str_in.decode("utf-8")
def platform_btou(str_in: AnyStr) -> str:
"""Return Unicode string, if not already Unicode, decode with locale encoding"""
"""Return Unicode string, if not already Unicode, decode with locale encoding.
NOTE: Used for POpen because universal_newlines/text parameter doesn't
always work! We cannot use encoding-parameter because it's Python 3.7+
"""
if isinstance(str_in, bytes):
try:
return ubtou(str_in)
except UnicodeDecodeError:
return normalize_utf8(str_in.decode(CODEPAGE, errors="replace").replace("?", "!"))
return str_in.decode(CODEPAGE, errors="replace").replace("?", "!")
else:
return normalize_utf8(str_in)
return str_in
def correct_unknown_encoding(str_or_bytes_in: AnyStr) -> str:
@@ -74,10 +71,10 @@ def correct_unknown_encoding(str_or_bytes_in: AnyStr) -> str:
except UnicodeDecodeError:
try:
# Try using 8-bit ASCII, if came from Windows
return normalize_utf8(str_or_bytes_in.decode("ISO-8859-1"))
return str_or_bytes_in.decode("ISO-8859-1")
except ValueError:
# Last resort we use the slow chardet package
return normalize_utf8(str_or_bytes_in.decode(chardet.detect(str_or_bytes_in)["encoding"]))
return str_or_bytes_in.decode(chardet.detect(str_or_bytes_in)["encoding"])
def correct_cherrypy_encoding(inputstring: str) -> str:

View File

@@ -46,7 +46,7 @@ except ImportError:
import sabnzbd
from sabnzbd.decorators import synchronized, cache_maintainer
from sabnzbd.constants import FUTURE_Q_FOLDER, JOB_ADMIN, GIGI, DEF_FILE_MAX, IGNORED_FILES_AND_FOLDERS, DEF_LOG_FILE
from sabnzbd.encoding import correct_unknown_encoding, utob, ubtou, normalize_utf8
from sabnzbd.encoding import correct_unknown_encoding, utob, ubtou
from sabnzbd.utils import rarfile
@@ -561,7 +561,7 @@ def globber(path: str, pattern: str = "*") -> List[str]:
"""Return matching base file/folder names in folder `path`"""
# Cannot use glob.glob() because it doesn't support Windows long name notation
if os.path.exists(path):
return [f for f in listdir_normalized(path) if safe_fnmatch(f, pattern)]
return [f for f in os.listdir(path) if safe_fnmatch(f, pattern)]
return []
@@ -569,8 +569,7 @@ def globber_full(path: str, pattern: str = "*") -> List[str]:
"""Return matching full file/folder names in folder `path`"""
# Cannot use glob.glob() because it doesn't support Windows long name notation
if os.path.exists(path):
path = normalize_utf8(path)
return [os.path.join(path, f) for f in listdir_normalized(path) if safe_fnmatch(f, pattern)]
return [os.path.join(path, f) for f in os.listdir(path) if safe_fnmatch(f, pattern)]
return []
@@ -582,7 +581,7 @@ def fix_unix_encoding(folder: str):
if not sabnzbd.WIN32 and not sabnzbd.MACOS:
for root, dirs, files in os.walk(folder):
for name in files:
new_name = normalize_utf8(correct_unknown_encoding(name))
new_name = correct_unknown_encoding(name)
if name != new_name:
try:
renamer(os.path.join(root, name), os.path.join(root, new_name))
@@ -805,12 +804,6 @@ def get_unique_filename(path: str) -> str:
return path
def listdir_normalized(input_dir: str) -> List[str]:
"""On macOS, the OS returns un-normalized results.
Always use the same normalization on all platforms"""
return [normalize_utf8(path) for path in os.listdir(input_dir)]
@synchronized(DIR_LOCK)
def listdir_full(input_dir: str, recursive: bool = True) -> List[str]:
"""List all files in dirs and sub-dirs"""
@@ -819,7 +812,7 @@ def listdir_full(input_dir: str, recursive: bool = True) -> List[str]:
for file in files:
# Ignore special folders and resources files created by macOS
if not sabnzbd.misc.match_str(root, IGNORED_FILES_AND_FOLDERS) and not file.startswith("._"):
filelist.append(normalize_utf8(os.path.join(root, file)))
filelist.append(os.path.join(root, file))
if not recursive:
break
return filelist
@@ -1393,7 +1386,7 @@ def pathbrowser(path: str, show_hidden: bool = False, show_files: bool = False)
# List all files and folders
file_list = []
for filename in listdir_normalized(path):
for filename in os.listdir(path):
fpath = os.path.join(path, filename)
isdir = os.path.isdir(fpath)

View File

@@ -395,8 +395,9 @@ def Raiser(root: str = "", **kwargs):
if kwargs:
root = "%s?%s" % (root, urllib.parse.urlencode(kwargs))
# Add the leading /sabnzbd/ (or what the user set)
root = cfg.url_base() + root
# Optionally add the leading /sabnzbd/ (or what the user set)
if not root.startswith(cfg.url_base()):
root = cherrypy.request.script_name + root
# Log the redirect
if cfg.api_logging():
@@ -433,7 +434,6 @@ class MainPage:
info["cpumodel"] = get_cpu_name()
info["cpusimd"] = sabnzbd.decoder.SABCTOOLS_SIMD
info["docker"] = "Docker" if sabnzbd.DOCKER else ""
# Have logout only with HTML and if inet=5, only when we are external
info["have_logout"] = (
@@ -641,7 +641,7 @@ class LoginPage:
# Check if there's even a username/password set
if check_login():
raise Raiser("/")
raise Raiser(cherrypy.request.script_name + "/")
# Check login info
if kwargs.get("username") == cfg.username() and kwargs.get("password") == cfg.password():
@@ -650,7 +650,7 @@ class LoginPage:
# Log the success
logging.info("Successful login from %s", cherrypy.request.remote_label)
# Redirect
raise Raiser("/")
raise Raiser(cherrypy.request.script_name + "/")
elif kwargs.get("username") or kwargs.get("password"):
info["error"] = T("Authentication failed, check username/password.")
# Warn about the potential security problem

View File

@@ -63,7 +63,6 @@ from sabnzbd.filesystem import (
SEVENMULTI_RE,
is_size,
get_basename,
listdir_normalized,
)
from sabnzbd.nzbstuff import NzbObject
import sabnzbd.cfg as cfg
@@ -1021,7 +1020,7 @@ def par2_repair(nzo: NzbObject, setname: str) -> Tuple[bool, bool]:
return False, True
parfile = os.path.join(nzo.download_path, parfile_nzf.filename)
old_dir_content = listdir_normalized(nzo.download_path)
old_dir_content = os.listdir(nzo.download_path)
used_joinables = ()
joinables = ()
used_for_repair = ()
@@ -1081,7 +1080,7 @@ def par2_repair(nzo: NzbObject, setname: str) -> Tuple[bool, bool]:
try:
if cfg.enable_par_cleanup():
deletables = []
new_dir_content = listdir_normalized(nzo.download_path)
new_dir_content = os.listdir(nzo.download_path)
# If Multipar or par2cmdline repairs a broken part of a joinable, it doesn't list it as such.
# So we need to manually add all joinables of the set to the list of used joinables.

View File

@@ -30,7 +30,7 @@ from typing import Optional, Tuple, Union
import sabnzbd
import sabnzbd.cfg
from sabnzbd.constants import DEF_NETWORKING_TIMEOUT, NNTP_BUFFER_SIZE, NTTP_MAX_BUFFER_SIZE
from sabnzbd.constants import DEF_NETWORKING_TIMEOUT, NNTP_BUFFER_SIZE
from sabnzbd.encoding import utob, ubtou
from sabnzbd.happyeyeballs import AddrInfo
from sabnzbd.decorators import synchronized, DOWNLOADER_LOCK
@@ -230,10 +230,6 @@ class NewsWrapper:
def increase_data_buffer(self):
"""Resize the buffer in the extremely unlikely case that it overflows"""
# Sanity check before we go any further
if len(self.data) > NTTP_MAX_BUFFER_SIZE:
raise BufferError("Maximum data buffer size exceeded")
# Input needs to be integer, floats don't work
new_buffer = sabctools.bytearray_malloc(len(self.data) + NNTP_BUFFER_SIZE // 2)
new_buffer[: len(self.data)] = self.data

View File

@@ -669,6 +669,16 @@ class NzbQueue:
except:
return -1
@staticmethod
def reset_try_lists(article: Article, remove_fetcher_from_trylist: bool = True):
"""Let article get new fetcher and reset trylists"""
if remove_fetcher_from_trylist:
article.remove_from_try_list(article.fetcher)
article.fetcher = None
article.tries = 0
article.nzf.reset_try_list()
article.nzf.nzo.reset_try_list()
def has_forced_jobs(self) -> bool:
"""Check if the queue contains any Forced
Priority jobs to download while paused
@@ -875,7 +885,7 @@ class NzbQueue:
logging.info("Found idle job %s", nzo.final_name)
empty.append(nzo)
# Stall prevention by checking if all servers are in the try list
# Stall prevention by checking if all servers are in the trylist
# This is a CPU-cheaper alternative to prevent stalling
if nzo.all_servers_in_try_list(active_servers):
# Maybe the NZF's need a reset too?
@@ -888,13 +898,13 @@ class NzbQueue:
for article in nzf.articles[:]:
if article.all_servers_in_try_list(active_servers):
logging.debug("Removing article %s with bad trylist in file %s", article, nzf.filename)
nzo.increase_bad_articles_counter("missing_articles")
sabnzbd.NzbQueue.register_article(article, success=False)
nzo.increase_bad_articles_counter("missing_articles")
logging.info("Resetting bad trylist for file %s in job %s", nzf.filename, nzo.final_name)
nzf.reset_try_list()
# Reset main try list, minimal performance impact
# Reset main trylist, minimal performance impact
logging.info("Resetting bad trylist for job %s", nzo.final_name)
nzo.reset_try_list()

View File

@@ -111,7 +111,7 @@ RE_RAR = re.compile(r"(\.rar|\.r\d\d|\.s\d\d|\.t\d\d|\.u\d\d|\.v\d\d)$", re.I)
# Trylist
##############################################################################
TRYLIST_LOCK = threading.RLock()
TRYLIST_LOCK = threading.Lock()
class TryList:
@@ -203,25 +203,12 @@ class Article(TryList):
self.crc32: Optional[int] = None
self.nzf: NzbFile = nzf
@synchronized(TRYLIST_LOCK)
def reset_try_list(self):
"""In addition to resetting the try list, also reset fetcher so all servers
are tried again. Locked so fetcher setting changes are also protected."""
"""In addition to resetting the try list, also reset fetcher so all servers are tried again"""
self.fetcher = None
self.fetcher_priority = 0
super().reset_try_list()
@synchronized(TRYLIST_LOCK)
def allow_new_fetcher(self, remove_fetcher_from_try_list: bool = True):
"""Let article get new fetcher and reset try lists of file and job.
Locked so all resets are performed at once"""
if remove_fetcher_from_try_list:
self.remove_from_try_list(self.fetcher)
self.fetcher = None
self.tries = 0
self.nzf.reset_try_list()
self.nzf.nzo.reset_try_list()
def get_article(self, server: Server, servers: List[Server]):
"""Return article when appropriate for specified server"""
if self.fetcher or self.server_in_try_list(server):
@@ -262,7 +249,7 @@ class Article(TryList):
if server.priority >= self.fetcher.priority:
self.tries = 0
# Allow all servers for this nzo and nzf again (but not this fetcher for this article)
self.allow_new_fetcher(remove_fetcher_from_try_list=False)
sabnzbd.NzbQueue.reset_try_lists(self, remove_fetcher_from_trylist=False)
return True
logging.info("Article %s unavailable on all servers, discarding", self.article)
@@ -289,6 +276,17 @@ class Article(TryList):
self.fetcher_priority = 0
self.tries = 0
def __eq__(self, other):
"""Articles with the same usenet address are the same"""
return self.article == other.article
def __hash__(self):
"""Required because we implement eq. Articles with the same
usenet address can appear in different NZF's. So we make every
article object unique, even though it is bad practice.
"""
return id(self)
def __repr__(self):
return "<Article: article=%s, bytes=%s, art_id=%s>" % (self.article, self.bytes, self.art_id)
@@ -433,11 +431,8 @@ class NzbFile(TryList):
self.add_to_try_list(server)
return articles
@synchronized(TRYLIST_LOCK)
def reset_all_try_lists(self):
"""Reset all try lists. Locked so reset is performed
for all items at the same time without chance of another
thread changing any of the items while we are resetting"""
"""Clear all lists of visited servers"""
for art in self.articles:
art.reset_try_list()
self.reset_try_list()
@@ -486,12 +481,10 @@ class NzbFile(TryList):
"""Assume it's the same file if the number bytes and first article
are the same or if there are no articles left, use the filenames.
Some NZB's are just a mess and report different sizes for the same article.
We used to compare (__eq__) articles based on article-ID, however, this failed
because some NZB's had the same article-ID twice within one NZF.
"""
if other and (self.bytes == other.bytes or len(self.decodetable) == len(other.decodetable)):
if self.decodetable and other.decodetable:
return self.decodetable[0].article == other.decodetable[0].article
return self.decodetable[0] == other.decodetable[0]
# Fallback to filename comparison
return self.filename == other.filename
return False
@@ -1008,11 +1001,7 @@ class NzbObject(TryList):
except:
logging.debug("The lastrar swap did not go well")
@synchronized(TRYLIST_LOCK)
def reset_all_try_lists(self):
"""Reset all try lists. Locked so reset is performed
for all items at the same time without chance of another
thread changing any of the items while we are resetting"""
for nzf in self.files:
nzf.reset_all_try_lists()
self.reset_try_list()
@@ -1453,7 +1442,7 @@ class NzbObject(TryList):
@synchronized(NZO_LOCK)
def add_parfile(self, parfile: NzbFile) -> bool:
"""Add parfile to the files to be downloaded
Resets try list just to be sure
Resets trylist just to be sure
Adjust download-size accordingly
Returns False when the file couldn't be added
"""
@@ -1603,8 +1592,7 @@ class NzbObject(TryList):
@synchronized(NZO_LOCK)
def increase_bad_articles_counter(self, bad_article_type: str):
"""Record information about bad articles. Should be called before
register_article, which triggers the availability check."""
"""Record information about bad articles"""
if bad_article_type not in self.nzo_info:
self.nzo_info[bad_article_type] = 0
self.nzo_info[bad_article_type] += 1

View File

@@ -73,7 +73,6 @@ from sabnzbd.filesystem import (
get_filename,
directory_is_writable,
check_filesystem_capabilities,
listdir_normalized,
)
from sabnzbd.nzbstuff import NzbObject
from sabnzbd.sorting import Sorter
@@ -487,12 +486,12 @@ def process_job(nzo: NzbObject) -> bool:
if all_ok:
# Move any (left-over) files to destination
nzo.status = Status.MOVING
nzo.set_action_line(T("Moving"), "...")
for root, _, files in os.walk(nzo.download_path):
if not root.endswith(JOB_ADMIN):
for file in files:
path = os.path.join(root, file)
new_path = path.replace(nzo.download_path, tmp_workdir_complete)
nzo.set_action_line(T("Moving"), file)
ok, new_path = move_to_path(path, new_path)
if new_path:
newfiles.append(new_path)
@@ -574,9 +573,7 @@ def process_job(nzo: NzbObject) -> bool:
if cfg.deobfuscate_final_filenames():
# Deobfuscate the filenames
logging.info("Running deobfuscate")
newfiles = deobfuscate.deobfuscate(nzo, newfiles, nzo.final_name)
# Deobfuscate the subtitles
deobfuscate.deobfuscate_subtitles(nzo, newfiles)
deobfuscate.deobfuscate(nzo, newfiles, nzo.final_name)
# Run the user script
if script_path := make_script_path(script):
@@ -962,7 +959,7 @@ def rar_renamer(nzo: NzbObject) -> int:
volnrext = {}
# Scan rar files in workdir, but not subdirs
workdir_files = listdir_normalized(nzo.download_path)
workdir_files = os.listdir(nzo.download_path)
for file_to_check in workdir_files:
file_to_check = os.path.join(nzo.download_path, file_to_check)
@@ -1186,7 +1183,7 @@ def one_file_or_folder(folder: str) -> str:
"""If the dir only contains one file or folder, join that file/folder onto the path"""
if os.path.exists(folder) and os.path.isdir(folder):
try:
cont = listdir_normalized(folder)
cont = os.listdir(folder)
if len(cont) == 1:
folder = os.path.join(folder, cont[0])
folder = one_file_or_folder(folder)

View File

@@ -37,7 +37,6 @@ from sabnzbd.filesystem import (
renamer,
sanitize_foldername,
clip_path,
listdir_normalized,
)
import sabnzbd.config as config
import sabnzbd.cfg as cfg
@@ -617,7 +616,7 @@ def move_to_parent_directory(workdir: str) -> Tuple[str, bool]:
logging.debug("Moving all files from %s to %s", workdir, dest)
# Check for DVD folders and bail out if found
for item in listdir_normalized(workdir):
for item in os.listdir(workdir):
if item.lower() in IGNORED_MOVIE_FOLDERS:
return workdir, True

View File

@@ -6,5 +6,5 @@
# You MUST use double quotes (so " and not ')
# Do not forget to update the appdata file for every major release!
__version__ = "4.4.0Alpha2"
__version__ = "4.3.3RC1"
__baseline__ = "unknown"

View File

@@ -134,7 +134,6 @@ def run_sabnews_and_selenium(request):
# Headless during CI testing
if "CI" in os.environ:
driver_options.browser_version = "127"
driver_options.add_argument("--headless")
driver_options.add_argument("--no-sandbox")

View File

@@ -7,7 +7,7 @@ strict:
stages:
- name: get_files format (json)
request:
url: "http://{SAB_HOST}:{SAB_PORT}/api"
url: "http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api"
method: GET
params:
mode: get_files
@@ -39,7 +39,7 @@ strict:
stages:
- name: get_files format (xml)
request:
url: "http://{SAB_HOST}:{SAB_PORT}/api"
url: "http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api"
method: GET
params:
mode: get_files

View File

@@ -7,7 +7,7 @@ strict:
stages:
- name: history format empty
request:
url: http://{SAB_HOST}:{SAB_PORT}/api
url: http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api
method: GET
params:
mode: history
@@ -38,7 +38,7 @@ test_name: Check empty history format (xml output)
stages:
- name: history format empty
request:
url: http://{SAB_HOST}:{SAB_PORT}/api
url: http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api
method: GET
params:
mode: history

View File

@@ -7,7 +7,7 @@ strict:
stages:
- name: history format single entry
request:
url: http://{SAB_HOST}:{SAB_PORT}/api
url: http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api
method: GET
params:
mode: history
@@ -70,7 +70,7 @@ test_name: Check general history format (xml output)
stages:
- name: history format single entry
request:
url: http://{SAB_HOST}:{SAB_PORT}/api
url: http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api
method: GET
params:
mode: history
@@ -145,7 +145,7 @@ strict:
stages:
- name: history slot count
request:
url: "http://{SAB_HOST}:{SAB_PORT}/api"
url: "http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api"
method: GET
params:
mode: history

View File

@@ -7,7 +7,7 @@ strict:
stages:
- name: queue format empty
request:
url: "http://{SAB_HOST}:{SAB_PORT}/api"
url: "http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api"
method: GET
params:
mode: queue
@@ -61,7 +61,7 @@ test_name: Check empty queue format (xml output)
stages:
- name: queue format empty
request:
url: "http://{SAB_HOST}:{SAB_PORT}/api"
url: "http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api"
method: GET
params:
mode: queue

View File

@@ -7,7 +7,7 @@ strict:
stages:
- name: queue format single entry
request:
url: "http://{SAB_HOST}:{SAB_PORT}/api"
url: "http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api"
method: GET
params:
mode: queue
@@ -81,7 +81,7 @@ test_name: Check general queue format (xml output)
stages:
- name: queue format single entry
request:
url: "http://{SAB_HOST}:{SAB_PORT}/api"
url: "http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api"
method: GET
params:
mode: queue

View File

@@ -7,7 +7,7 @@ strict:
stages:
- name: server_stats (json output)
request:
url: "http://{SAB_HOST}:{SAB_PORT}/api"
url: "http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api"
method: GET
params:
mode: server_stats
@@ -31,7 +31,7 @@ stages:
- name: server_stats (xml output)
request:
url: "http://{SAB_HOST}:{SAB_PORT}/api"
url: "http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api"
method: GET
params:
mode: server_stats

View File

@@ -7,7 +7,7 @@ strict:
stages:
- name: version (json output)
request:
url: http://{SAB_HOST}:{SAB_PORT}/api
url: http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api
method: GET
params:
mode: version
@@ -22,7 +22,7 @@ stages:
- name: version (xml output)
request:
url: http://{SAB_HOST}:{SAB_PORT}/api
url: http://{SAB_HOST}:{SAB_PORT}/sabnzbd/api
method: GET
params:
mode: version

View File

@@ -3,7 +3,7 @@ pytest==7.4.4
setuptools
selenium
requests
pyfakefs>=5.6.0
pyfakefs>=5.4.0
werkzeug<2.1.0 # Breaks httpbin in newer versions
pytest-httpbin
pytest-httpserver

View File

@@ -18,7 +18,7 @@
"""
Testing SABnzbd deobfuscate module
"""
import os.path
import random
import shutil
import zipfile
@@ -404,83 +404,3 @@ class TestDeobfuscateFinalResult:
assert not os.path.isfile(os.path.join(work_dir, "twentymb.bin")) # should now be gone
shutil.rmtree(work_dir)
def test_get_biggest_file(self):
# Create directory (with a random directory name)
dirname = os.path.join(SAB_CACHE_DIR, "testdir" + str(random.randint(10000, 99999)))
os.mkdir(dirname)
smallfile1 = os.path.join(dirname, "AAAA.bin")
create_small_file(smallfile1)
assert os.path.isfile(smallfile1)
bigfile = os.path.join(dirname, "KKKK.bin")
create_big_file(bigfile)
assert os.path.isfile(bigfile)
smallfile2 = os.path.join(dirname, "LLLL.bin")
create_small_file(smallfile2)
assert os.path.isfile(smallfile2)
# empty list should return None
assert not get_biggest_file([])
# just 1 file as input is always the biggest file
assert get_biggest_file([smallfile1]) == smallfile1 # just 1 file, so that's the biggest
# files with same small size, so no biggest file
assert not get_biggest_file([smallfile1, smallfile2])
# now including the bigger file
assert get_biggest_file([smallfile1, smallfile2, bigfile]) == bigfile
shutil.rmtree(dirname)
def test_deobfuscate_subtitles(self):
# input: a big file, and srt file(s), and non-related files
# result: srt file renamed according to the big file
"""Wrapper to avoid the need for NZO"""
nzo = mock.Mock()
nzo.set_unpack_info = mock.Mock()
# Create directory (with a random directory name)
dirname = os.path.join(SAB_CACHE_DIR, "testdir" + str(random.randint(10000, 99999)))
os.mkdir(dirname)
bigfile = os.path.join(dirname, "bigfile.avi")
create_big_file(bigfile)
assert os.path.isfile(bigfile)
already_correct_srt = os.path.join(dirname, "bigfile.srt")
create_small_file(already_correct_srt)
assert os.path.isfile(already_correct_srt)
small_srt = os.path.join(dirname, "dut.srt")
create_small_file(small_srt)
assert os.path.isfile(small_srt)
expected_small_srt = os.path.join(dirname, "bigfile.dut.srt")
small_txt = os.path.join(dirname, "readme.txt")
create_small_file(small_txt)
assert os.path.isfile(small_txt)
# go
deobfuscate_subtitles(nzo, [bigfile, already_correct_srt, small_srt, small_txt])
assert os.path.isfile(bigfile) # unchanged
assert os.path.isfile(already_correct_srt) # unchanged
assert not os.path.isfile(small_srt) # should be renamed to:
assert os.path.isfile(expected_small_srt)
assert os.path.isfile(small_txt) # unchanged
# and if we go again ... nothing should happen: all files are already correct
deobfuscate_subtitles(nzo, [bigfile, already_correct_srt, expected_small_srt, small_txt])
assert os.path.isfile(bigfile) # unchanged
assert os.path.isfile(already_correct_srt) # unchanged
assert not os.path.isfile(small_srt) # should be renamed to:
assert os.path.isfile(expected_small_srt)
assert os.path.isfile(small_txt) # unchanged
shutil.rmtree(dirname)

Some files were not shown because too many files have changed in this diff Show More