mirror of
https://github.com/sabnzbd/sabnzbd.git
synced 2025-12-31 03:30:03 -05:00
Compare commits
1 Commits
4.2.0Beta1
...
feature/pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bd39e4c12 |
12
README.mkd
12
README.mkd
@@ -1,17 +1,10 @@
|
||||
Release Notes - SABnzbd 4.2.0 Beta 1
|
||||
Release Notes - SABnzbd 4.2.0 Alpha 2
|
||||
=========================================================
|
||||
|
||||
## Changes since 4.1.0
|
||||
- Duplicate detection workflow was overhauled:
|
||||
`Series Duplicate Detection` was replaced by
|
||||
`Smart Duplicate Detection` that can also detect `Movie`
|
||||
and `Daily Show` duplicates. Additionally, duplicates will
|
||||
also be detected if they are still in the queue.
|
||||
See: https://sabnzbd.org/wiki/duplicate-detection
|
||||
- Numerous smaller performance improvements were made.
|
||||
- Reduced recursive unpacking to 2 levels, instead of 5.
|
||||
- Server IP-address selection was optimized.
|
||||
- The `On queue finish script` is now set in Switches.
|
||||
- IPv6 addresses are preferred during server address selection.
|
||||
- Stricter check if `Complete Folder` is inside `Download Folder`.
|
||||
- Windows: Reduced size of installer.
|
||||
- Windows/macOS: Updated to Python 3.12.
|
||||
@@ -19,7 +12,6 @@ Release Notes - SABnzbd 4.2.0 Beta 1
|
||||
## Bugfixes since 4.1.0
|
||||
- Multi-select in the queue was broken for some users.
|
||||
- Prevent crash during saving of configuration.
|
||||
- If `weblogging` was enabled, output was also written to regular log.
|
||||
- Removing a failed download from the history could break active downloads.
|
||||
|
||||
## Upgrade notices
|
||||
|
||||
@@ -5,7 +5,7 @@ packaging==23.2
|
||||
pyinstaller-hooks-contrib==2023.10
|
||||
altgraph==0.17.4
|
||||
wrapt==1.16.0
|
||||
setuptools==69.0.2
|
||||
setuptools==68.2.2
|
||||
certifi
|
||||
|
||||
# Required on 32bit Windows, exclude it based on Python-version
|
||||
|
||||
@@ -202,7 +202,7 @@
|
||||
<div class="field-pair">
|
||||
<label class="config" for="nscript_parameters">$T('opt-nscript_parameters')</label>
|
||||
<input type="text" name="nscript_parameters" id="nscript_parameters" value="$nscript_parameters" />
|
||||
<span class="desc">$T('Optional') - $T('readwiki')</span>
|
||||
<span class="desc">$T('Optional') - $T('explain-nscript_parameters')</span>
|
||||
</div>
|
||||
$show_notify_checkboxes('nscript')
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
|
||||
@@ -96,29 +96,23 @@
|
||||
<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>
|
||||
</select>
|
||||
<span class="desc">
|
||||
$T('explain-no_dupes')<br>
|
||||
<a href="https://sabnzbd.org/wiki/duplicate-detection" target="_blank">https://sabnzbd.org/wiki/duplicate-detection</a>
|
||||
</span>
|
||||
<span class="desc">$T('explain-no_dupes')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="no_smart_dupes">$T('opt-no_smart_dupes')</label>
|
||||
<select name="no_smart_dupes" id="no_smart_dupes">
|
||||
<option value="0" <!--#if int($no_smart_dupes) == 0 then 'selected="selected"' else ""#--> >$T('nodupes-off')</option>
|
||||
<option value="4" <!--#if int($no_smart_dupes) == 4 then 'selected="selected"' else ""#--> >$T('nodupes-tag')</option>
|
||||
<option value="2" <!--#if int($no_smart_dupes) == 2 then 'selected="selected"' else ""#--> >$T('nodupes-pause')</option>
|
||||
<option value="3" <!--#if int($no_smart_dupes) == 3 then 'selected="selected"' else ""#--> >$T('nodupes-fail')</option>
|
||||
<option value="1" <!--#if int($no_smart_dupes) == 1 then 'selected="selected"' else ""#--> >$T('nodupes-ignore')</option>
|
||||
<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>
|
||||
</select>
|
||||
<span class="desc">
|
||||
$T('explain-no_smart_dupes')<br>
|
||||
<a href="https://sabnzbd.org/wiki/duplicate-detection" target="_blank">https://sabnzbd.org/wiki/duplicate-detection</a>
|
||||
</span>
|
||||
<span class="desc">$T('explain-no_series_dupes')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="dupes_propercheck">$T('opt-dupes_propercheck')</label>
|
||||
<input type="checkbox" name="dupes_propercheck" id="dupes_propercheck" value="1" <!--#if int($dupes_propercheck) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-dupes_propercheck')</span>
|
||||
<label class="config" for="series_propercheck">$T('opt-series_propercheck')</label>
|
||||
<input type="checkbox" name="series_propercheck" id="series_propercheck" value="1" <!--#if int($series_propercheck) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-series_propercheck')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="pause_on_pwrar">$T('opt-pause_on_pwrar')</label>
|
||||
@@ -193,12 +187,12 @@
|
||||
<div class="field-pair advanced-settings <!--#if not $have_nice then "disabled" else "" #-->">
|
||||
<label class="config" for="nice">$T('opt-nice')</label>
|
||||
<input type="text" name="nice" id="nice" value="$nice" <!--#if not $have_nice then 'readonly="readonly" disabled="disabled"' else "" #--> />
|
||||
<span class="desc">$T('readwiki')</span>
|
||||
<span class="desc">$T('explain-nice')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings <!--#if not $have_ionice then "disabled" else "" #-->">
|
||||
<label class="config" for="ionice">$T('opt-ionice')</label>
|
||||
<input type="text" name="ionice" id="ionice" value="$ionice" <!--#if not $have_ionice then 'readonly="readonly" disabled="disabled"' else "" #--> />
|
||||
<span class="desc">$T('readwiki')</span>
|
||||
<span class="desc">$T('explain-ionice')</span>
|
||||
</div>
|
||||
<!--#else#-->
|
||||
<div class="field-pair advanced-settings">
|
||||
@@ -210,13 +204,13 @@
|
||||
<option value="2" <!--#if int($win_process_prio) == 2 then 'selected="selected"' else ""#-->>$T('win_process_prio-low')</option>
|
||||
<option value="1" <!--#if int($win_process_prio) == 1 then 'selected="selected"' else ""#-->>$T('win_process_prio-idle')</option>
|
||||
</select>
|
||||
<span class="desc">$T('readwiki')</span>
|
||||
<span class="desc">$T('explain-win_process_prio')</span>
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="par_option">$T('opt-par_option')</label>
|
||||
<input type="text" name="par_option" id="par_option" value="$par_option" />
|
||||
<span class="desc">$T('readwiki')</span>
|
||||
<span class="desc">$T('explain-par_option')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="sfv_check">$T('opt-sfv_check')</label>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: team@sabnzbd.org\n"
|
||||
"Language-Team: SABnzbd <team@sabnzbd.org>\n"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: team@sabnzbd.org\n"
|
||||
"Language-Team: SABnzbd <team@sabnzbd.org>\n"
|
||||
@@ -2427,6 +2427,7 @@ msgstr ""
|
||||
msgid "Backup"
|
||||
msgstr ""
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr ""
|
||||
@@ -2903,19 +2904,19 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgid "Detect identical NZB files (based on items in your History or files in .nzb Backup Folder)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid "Detect identical episodes in series (based on \"name/season/episode\" of items in your History)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -2923,7 +2924,7 @@ msgid "Allow proper releases"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in the download name."
|
||||
msgid "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in the download name"
|
||||
msgstr ""
|
||||
|
||||
#. Four way switch for duplicates
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\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"
|
||||
@@ -2522,6 +2522,7 @@ msgstr ""
|
||||
msgid "Backup"
|
||||
msgstr "Záloha"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr ""
|
||||
@@ -3046,19 +3047,23 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Detekovat duplicitní stahování"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3067,8 +3072,8 @@ msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
|
||||
#. Four way switch for duplicates
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\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"
|
||||
@@ -2563,6 +2563,7 @@ msgstr "Oppetid"
|
||||
msgid "Backup"
|
||||
msgstr "Sikkerhedskopi"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "Læs mere om dette på Wiki Help!"
|
||||
@@ -3114,20 +3115,28 @@ msgstr ""
|
||||
"I tilfælde af \"Pause\", skal du angive en adgangskode og genoptage jobbet."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgstr ""
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Find identiske downloads"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
"Fundet identiske NZB filer (baseret på elementer i din historik eller filer "
|
||||
"i. nzb Backup mappe)"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "Opdage identiske episoder i serier"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
"Fundet identiske episoder i serie (baseret på \"navn /sæson /episode\" af "
|
||||
"elementer i din historik)"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Allow proper releases"
|
||||
@@ -3135,8 +3144,8 @@ msgstr "Tillad reelle udgivelser"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
|
||||
#. Four way switch for duplicates
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
|
||||
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"
|
||||
@@ -2641,6 +2641,7 @@ msgstr "Zeit seit Start"
|
||||
msgid "Backup"
|
||||
msgstr "Sicherheitskopie"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "Lesen Sie dazu die Hilfe im Wiki!"
|
||||
@@ -3233,20 +3234,28 @@ msgstr ""
|
||||
"fortsetzen."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgstr ""
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Doppelte Downloads erkennen"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
"Doppelte NZB Datei entdeckt (basierend auf den Eintragungen in der Historie "
|
||||
"oder den .nzb Dateien im NZB-Backup-Ordner)"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "Doppelte Episoden in Serien erkennen"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
"Identische Episoden in den Serien entdeckt (basierend auf "
|
||||
"\"name/season/episode\") der Einträge in der Historie"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Allow proper releases"
|
||||
@@ -3254,9 +3263,11 @@ msgstr "Erlaube \"Proper\" Releases"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
"Umgehe Serien Duplikat-Erkennung, wenn PROPER, REAL oder REPACK im Download-"
|
||||
"Namen erkannt wird"
|
||||
|
||||
#. Four way switch for duplicates
|
||||
#: sabnzbd/skintext.py
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\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"
|
||||
@@ -2629,6 +2629,7 @@ msgstr "Tiempo en Activo"
|
||||
msgid "Backup"
|
||||
msgstr "Copia de seguridad"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "Lee la ayuda en la Wiki (inglés) acerca de esto!"
|
||||
@@ -3196,20 +3197,28 @@ msgstr ""
|
||||
"trabajo."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgstr ""
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Detectar descargas duplicadas"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
"Detecta archivos NZB idénticos (basándose en los elementos de su historial o"
|
||||
" los archivos en el directorio de copia de seguridad .nzb)"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "Detectar episodios duplicadas en serie"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
"Detecta episodios idénticos en series (basándose en "
|
||||
"\"nombre/temporada/episodio\" de los elementos de su historial)"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Allow proper releases"
|
||||
@@ -3217,9 +3226,11 @@ msgstr "Permitir comunicados adecuados"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
"Evitar detección de duplicado de series si se detecta PROPER, REAL o REPACK "
|
||||
"en el nombre de la descarga"
|
||||
|
||||
#. Four way switch for duplicates
|
||||
#: sabnzbd/skintext.py
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\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"
|
||||
@@ -2559,6 +2559,7 @@ msgstr "Käynnissäoloaika"
|
||||
msgid "Backup"
|
||||
msgstr "Varmuuskopioi"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "Lue Wikin ohjeet tähän!"
|
||||
@@ -3121,19 +3122,23 @@ msgstr ""
|
||||
" lataamista."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Tunnista päällekkäiset lataukset"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "Tunnista identtiset jaksot sarjassa"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3142,8 +3147,8 @@ msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
|
||||
#. Four way switch for duplicates
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
|
||||
"Last-Translator: Fred L <88com88@gmail.com>, 2023\n"
|
||||
"Language-Team: French (https://app.transifex.com/sabnzbd/teams/111101/fr/)\n"
|
||||
@@ -1249,7 +1249,7 @@ msgstr "DOUBLON"
|
||||
|
||||
#: sabnzbd/nzbstuff.py
|
||||
msgid "ALTERNATIVE"
|
||||
msgstr "ALTERNATIVE"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/nzbstuff.py
|
||||
msgid "ENCRYPTED"
|
||||
@@ -2641,6 +2641,7 @@ msgstr "Temps de fonctionnement"
|
||||
msgid "Backup"
|
||||
msgstr "Secours"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "Consultez le Wiki pour plus d'info à ce sujet (en anglais) !"
|
||||
@@ -3234,20 +3235,28 @@ msgstr ""
|
||||
"tâche."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgstr ""
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Détecter les doublons de téléchargement"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
"Détecter les fichiers NZB identiques (en fonction des éléments de votre "
|
||||
"historique ou des fichiers .nzb du dossier de backup)"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "Détecter les doublons d'épisodes de séries"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
"Détecter les épisodes de série identiques (en fonction du modèle "
|
||||
"\"nom/saison/épisode\" des éléments de votre historique)"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Allow proper releases"
|
||||
@@ -3255,9 +3264,11 @@ msgstr "Autoriser les versions corrigées (proper)"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
"Contourner la détection des doublons si PROPER, REAL ou REPACK est détecté "
|
||||
"dans l'intitulé du téléchargement"
|
||||
|
||||
#. Four way switch for duplicates
|
||||
#: sabnzbd/skintext.py
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
|
||||
"Language-Team: Hebrew (https://app.transifex.com/sabnzbd/teams/111101/he/)\n"
|
||||
@@ -2568,6 +2568,7 @@ msgstr "זמן פעולה"
|
||||
msgid "Backup"
|
||||
msgstr "גיבוי"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "קרא את עזרת וויקי על זה!"
|
||||
@@ -3125,20 +3126,25 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
|
||||
msgstr "במקרה של \"השהיה\", תצטרך לקבוע סיסמה ולהמשיך את העבודה."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgstr ""
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "גלה הורדות כפולות"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
"גלה קבצי NZB זהים (על סמך פריטים בהיסטוריה שלך או קבצים בתיקיית גיבוי .nzb)"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "גלה פרקים כפולים בסדרות"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgstr ""
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr "גלה פרקים זהים בסדרות (על סמך \"שם/עונה/פרק\" של פריטים בהיסטוריה שלך)"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Allow proper releases"
|
||||
@@ -3146,9 +3152,9 @@ msgstr "התר שחרורים תקינים"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
msgstr ""
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr "עקוף גילוי כפילויות סדרה אם PROPER, REAL או REPACK מתגלים בשם ההורדה"
|
||||
|
||||
#. Four way switch for duplicates
|
||||
#: sabnzbd/skintext.py
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\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"
|
||||
@@ -2553,6 +2553,7 @@ msgstr "Oppetid"
|
||||
msgid "Backup"
|
||||
msgstr "Sikkerhetskopi"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "Les Wiki Help fer dette!"
|
||||
@@ -3102,19 +3103,23 @@ msgstr ""
|
||||
"I tilfelle \"Pause\", så trenger du å sette et passord og gjenoppta jobben."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Oppdag duplikatnedlastinger"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "Oppdag duplikat episoder i serie"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3123,8 +3128,8 @@ msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
|
||||
#. Four way switch for duplicates
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
|
||||
"Language-Team: Dutch (https://app.transifex.com/sabnzbd/teams/111101/nl/)\n"
|
||||
@@ -2614,6 +2614,7 @@ msgstr "Tijd in de lucht"
|
||||
msgid "Backup"
|
||||
msgstr "Reserve"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "Lees de Wiki pagina over dit onderwerp"
|
||||
@@ -3191,20 +3192,28 @@ msgstr ""
|
||||
"download vrij te geven"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgstr ""
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Detecteer dubbele downloads"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
"Detecteer identieke downloads (op basis van downloads in je Geschiedenis of "
|
||||
"bestanden in je .nzb backup map)."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "Detecteer dubbele afleveringen in series"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
"Detecteer identieke afleveringen in series (gebaseerd op "
|
||||
"\"naam/seizoen/aflevering\" van downloads in je Geschiedenis)."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Allow proper releases"
|
||||
@@ -3212,9 +3221,11 @@ msgstr "Sta verbeterde downloads toe"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
"Sla dubbele download detectie over als er in de naam van de download PROPER,"
|
||||
" REAL of REPACK bevat"
|
||||
|
||||
#. Four way switch for duplicates
|
||||
#: sabnzbd/skintext.py
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\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"
|
||||
@@ -2558,6 +2558,7 @@ msgstr "Czas działania"
|
||||
msgid "Backup"
|
||||
msgstr "Zapasowy"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "Przeczytaj o tym w Wiki!"
|
||||
@@ -3110,19 +3111,23 @@ msgstr ""
|
||||
"Jeśli wybrano \"Wstrzymaj\", będzie trzeba ustawić hasło i wznowić zadanie"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Działanie dla duplikatów"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "Wykryj zduplikowane odcinki seriali"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3131,8 +3136,8 @@ msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
|
||||
#. Four way switch for duplicates
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
# Copyright 2007-2023 The SABnzbd-Team
|
||||
#
|
||||
# Translators:
|
||||
# Henrique Moreno, 2023
|
||||
# Safihre <safihre@sabnzbd.org>, 2023
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\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"
|
||||
@@ -68,7 +67,7 @@ msgstr "aplicativo 7za... NÃO encontrado!"
|
||||
#. Error message
|
||||
#: SABnzbd.py
|
||||
msgid "Essential modules are missing, downloading cannot start."
|
||||
msgstr "Módulos essenciais estão faltando, não é possível baixar."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: SABnzbd.py
|
||||
@@ -90,8 +89,6 @@ msgid ""
|
||||
"SABnzbd was started with encoding %s, this should be UTF-8. Expect problems "
|
||||
"with Unicoded file and directory names in downloads."
|
||||
msgstr ""
|
||||
"SABnzbd iniciou com codificado %s, deveria ser UFT-8. Esperado problemas com"
|
||||
" arquivos e nomes de diretórios Unicode nos downloades."
|
||||
|
||||
#. Warning message
|
||||
#: SABnzbd.py
|
||||
@@ -99,13 +96,11 @@ msgid ""
|
||||
"Current umask (%o) might deny SABnzbd access to the files and folders it "
|
||||
"creates."
|
||||
msgstr ""
|
||||
"Mascara atual (%o) pode negar ao SABnzbd acesso aos arquivos e diretórios "
|
||||
"criados."
|
||||
|
||||
#. Warning message
|
||||
#: SABnzbd.py
|
||||
msgid "Could not load additional certificates from certifi package"
|
||||
msgstr "Não foi possível carregar certificado do pacote certifi."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: SABnzbd.py
|
||||
@@ -115,7 +110,7 @@ msgstr "HTTPS desabilitado pela falta de arquivos CERT e KEY"
|
||||
#. Warning message
|
||||
#: SABnzbd.py
|
||||
msgid "Disabled HTTPS because of invalid CERT and KEY files"
|
||||
msgstr "HTTPs desabilitado por caus de arquivo CERT e KEY invalidos"
|
||||
msgstr ""
|
||||
|
||||
#. Error message
|
||||
#: SABnzbd.py
|
||||
@@ -143,22 +138,22 @@ msgstr "Erro fatal ao salvar estado"
|
||||
#. Warning message
|
||||
#: sabnzbd/__init__.py
|
||||
msgid "Restarting because of crashed postprocessor"
|
||||
msgstr "Reiniciado por falha de pós processamento."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/__init__.py
|
||||
msgid "Restarting because of crashed downloader"
|
||||
msgstr "Reiniciado por falha de download"
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/__init__.py
|
||||
msgid "Restarting because of crashed assembler"
|
||||
msgstr "Reiniciado por falha de assembler"
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/__init__.py
|
||||
msgid "Cannot access PID file %s"
|
||||
msgstr "Não é possível acessar arquivo PID %s"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/api.py, sabnzbd/emailer.py
|
||||
msgid "Email succeeded"
|
||||
@@ -213,8 +208,6 @@ msgid ""
|
||||
"Paused job \"%s\" because of encrypted RAR file (if supplied, all passwords "
|
||||
"were tried)"
|
||||
msgstr ""
|
||||
"Tarefa \"%s\" pausado por causa de arquivo RAR encripitado (se fornecido, "
|
||||
"todos as senhas foram tentadas)"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/assembler.py
|
||||
@@ -222,8 +215,6 @@ msgid ""
|
||||
"Aborted job \"%s\" because of encrypted RAR file (if supplied, all passwords"
|
||||
" were tried)"
|
||||
msgstr ""
|
||||
"Tarefa \"%s\" abortado por causa de arquivo RAR encripitado (se fornecido, "
|
||||
"todos as senhas foram tentadas)"
|
||||
|
||||
#: sabnzbd/assembler.py
|
||||
msgid "Aborted, encryption detected"
|
||||
@@ -233,8 +224,6 @@ msgstr "Cancelado, criptografia detectada"
|
||||
#: sabnzbd/assembler.py
|
||||
msgid "In \"%s\" unwanted extension in RAR file. Unwanted file is %s "
|
||||
msgstr ""
|
||||
"Em \"%s\" extensão não necessária em arquivo RAR. Arquivo não necessário é "
|
||||
"%s "
|
||||
|
||||
#: sabnzbd/assembler.py
|
||||
msgid "Unwanted extension is in rar file %s"
|
||||
@@ -2572,6 +2561,7 @@ msgstr "Tempo ativo"
|
||||
msgid "Backup"
|
||||
msgstr "Backup"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "Leia a sessão ajuda no Wiki sobre isso!"
|
||||
@@ -3123,19 +3113,23 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
|
||||
msgstr "Em caso de \"Pausa\", você precisa definir uma senha e retomar a tarefa."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Detectar Downloads Duplicados"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "Detecta episódios duplicados em séries"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3144,8 +3138,8 @@ msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
|
||||
#. Four way switch for duplicates
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\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"
|
||||
@@ -2591,6 +2591,7 @@ msgstr "Durata Funcţionării"
|
||||
msgid "Backup"
|
||||
msgstr "Server Secundar"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "Citeşte Ajutorul Wiki despre asta !"
|
||||
@@ -3139,19 +3140,23 @@ msgstr ""
|
||||
"reluați sarcina."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Detectează Descărcări Duplicate"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "Detectează episoade duplicate în seriale"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3160,8 +3165,8 @@ msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
|
||||
#. Four way switch for duplicates
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\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"
|
||||
@@ -2555,6 +2555,7 @@ msgstr "Время работы"
|
||||
msgid "Backup"
|
||||
msgstr "Резервный"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "Описание см. на вики-странице."
|
||||
@@ -3106,19 +3107,23 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Обнаруживать повторяющиеся загрузки"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3127,8 +3132,8 @@ msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
|
||||
#. Four way switch for duplicates
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\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"
|
||||
@@ -2547,6 +2547,7 @@ msgstr "; Ради"
|
||||
msgid "Backup"
|
||||
msgstr "Резервно"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "За више информација, читајте Вики!"
|
||||
@@ -3093,19 +3094,23 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
|
||||
msgstr "Ако је \"Пауза\", требате да поставите лозинку и да наставите рад."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Откриј дупликатна преузимања"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "Откриј дупле епизоде у серије"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3114,8 +3119,8 @@ msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
|
||||
#. Four way switch for duplicates
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\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"
|
||||
@@ -2555,6 +2555,7 @@ msgstr "Upptid"
|
||||
msgid "Backup"
|
||||
msgstr "Säkerhetskopiera"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "Läs Wiki Help för detta!"
|
||||
@@ -3103,19 +3104,23 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
|
||||
msgstr "Om \"Pausad\", så behöver du ange ett lösenord för att återuppta jobbet."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "Upptäck dubbletter av nedladdningar"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "Hitta dublettavsnitt i serier"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3124,8 +3129,8 @@ msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
|
||||
#. Four way switch for duplicates
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
|
||||
"Language-Team: Chinese (China) (https://app.transifex.com/sabnzbd/teams/111101/zh_CN/)\n"
|
||||
@@ -2534,6 +2534,7 @@ msgstr "启动时间"
|
||||
msgid "Backup"
|
||||
msgstr "备份"
|
||||
|
||||
#. Notification Script settings
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Read the Wiki Help on this!"
|
||||
msgstr "关于该项请参阅 Wiki 帮助!"
|
||||
@@ -3056,20 +3057,24 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
|
||||
msgstr "若选择“暂停”,您将需要设置密码并手动续传对应任务。"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Identical download detection"
|
||||
msgstr ""
|
||||
msgid "Detect Duplicate Downloads"
|
||||
msgstr "侦测重复下载"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect identical downloads based on name or NZB contents."
|
||||
msgstr ""
|
||||
msgid ""
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb "
|
||||
"Backup Folder)"
|
||||
msgstr "检测相同的 NZB 文件 (基于您的历史项目或 .nzb 备份文件夹中的文件)"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Smart duplicate detection"
|
||||
msgstr ""
|
||||
msgid "Detect duplicate episodes in series"
|
||||
msgstr "侦测同季的重复剧集"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Detect duplicates based on analysis of the filename."
|
||||
msgstr ""
|
||||
msgid ""
|
||||
"Detect identical episodes in series (based on \"name/season/episode\" of "
|
||||
"items in your History)"
|
||||
msgstr "在剧目中检测相同的剧集 (基于您的历史项目,参照 \"name/season/episode\" 的规则)"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Allow proper releases"
|
||||
@@ -3077,8 +3082,8 @@ msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name."
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
|
||||
"the download name"
|
||||
msgstr ""
|
||||
|
||||
#. Four way switch for duplicates
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha3\n"
|
||||
"Project-Id-Version: SABnzbd-4.2.0Alpha2\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: team@sabnzbd.org\n"
|
||||
"Language-Team: SABnzbd <team@sabnzbd.org>\n"
|
||||
|
||||
@@ -285,11 +285,6 @@ def initialize(pause_downloader=False, clean_up=False, repair=0):
|
||||
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)
|
||||
|
||||
# Add hostname to the whitelist
|
||||
if not cfg.host_whitelist():
|
||||
cfg.host_whitelist.set(socket.gethostname())
|
||||
|
||||
@@ -1742,7 +1742,6 @@ def add_active_history(postproc_queue: List[NzbObject], items: List[Dict[str, An
|
||||
"size": to_units(nzo.bytes_downloaded, "B"),
|
||||
"meta": None,
|
||||
"series": "",
|
||||
"duplicate_key": nzo.duplicate_key,
|
||||
"md5sum": "",
|
||||
"password": nzo.correct_password,
|
||||
"action_line": nzo.action_line,
|
||||
|
||||
@@ -378,9 +378,8 @@ autodisconnect = OptionBool("misc", "auto_disconnect", True)
|
||||
pre_script = OptionStr("misc", "pre_script", "None", validation=validate_script)
|
||||
end_queue_script = OptionStr("misc", "end_queue_script", "None", validation=validate_script)
|
||||
no_dupes = OptionNumber("misc", "no_dupes", 0)
|
||||
no_series_dupes = OptionNumber("misc", "no_series_dupes", 0) # Kept for converting to no_smart_dupes
|
||||
no_smart_dupes = OptionNumber("misc", "no_smart_dupes", 0)
|
||||
dupes_propercheck = OptionBool("misc", "dupes_propercheck", True)
|
||||
no_series_dupes = OptionNumber("misc", "no_series_dupes", 0)
|
||||
series_propercheck = OptionBool("misc", "series_propercheck", True)
|
||||
pause_on_pwrar = OptionNumber("misc", "pause_on_pwrar", 1)
|
||||
ignore_samples = OptionBool("misc", "ignore_samples", False)
|
||||
deobfuscate_final_filenames = OptionBool("misc", "deobfuscate_final_filenames", True)
|
||||
|
||||
@@ -168,8 +168,8 @@ class Status:
|
||||
class DuplicateStatus:
|
||||
DUPLICATE = "Duplicate" # Simple duplicate
|
||||
DUPLICATE_ALTERNATIVE = "Duplicate Alternative" # Alternative duplicate for a queued job
|
||||
SMART_DUPLICATE = "Smart Duplicate" # Simple Series duplicate
|
||||
SMART_DUPLICATE_ALTERNATIVE = "Smart Duplicate Alternative" # Alternative duplicate for a queued job
|
||||
SERIES_DUPLICATE = "Series Duplicate" # Simple Series duplicate
|
||||
SERIES_DUPLICATE_ALTERNATIVE = "Series Duplicate Alternative" # Alternative duplicate for a queued job
|
||||
|
||||
|
||||
class AddNzbFileResult:
|
||||
|
||||
@@ -82,25 +82,19 @@ class HistoryDB:
|
||||
version = self.cursor.fetchone()["user_version"]
|
||||
except IndexError:
|
||||
version = 0
|
||||
|
||||
# Add any new columns added since last DB version
|
||||
# Use "and" to stop when database has been reset due to corruption
|
||||
if version < 1:
|
||||
# Add any missing columns added since first DB version
|
||||
# Use "and" to stop when database has been reset due to corruption
|
||||
_ = (
|
||||
self.execute("PRAGMA user_version = 1;")
|
||||
and self.execute("ALTER TABLE history ADD COLUMN series TEXT;")
|
||||
and self.execute("ALTER TABLE history ADD COLUMN md5sum TEXT;")
|
||||
and self.execute('ALTER TABLE "history" ADD COLUMN series TEXT;')
|
||||
and self.execute('ALTER TABLE "history" ADD COLUMN md5sum TEXT;')
|
||||
)
|
||||
if version < 2:
|
||||
# Add any missing columns added since second DB version
|
||||
# Use "and" to stop when database has been reset due to corruption
|
||||
_ = self.execute("PRAGMA user_version = 2;") and self.execute(
|
||||
"ALTER TABLE history ADD COLUMN password TEXT;"
|
||||
)
|
||||
if version < 3:
|
||||
# Transfer data to new column (requires WHERE-hack), original column should be removed later
|
||||
_ = (
|
||||
self.execute("PRAGMA user_version = 3;")
|
||||
and self.execute("ALTER TABLE history ADD COLUMN duplicate_key TEXT;")
|
||||
and self.execute("UPDATE history SET duplicate_key = series WHERE 1 = 1;")
|
||||
'ALTER TABLE "history" ADD COLUMN password TEXT;'
|
||||
)
|
||||
|
||||
def execute(self, command: str, args: Sequence = (), save: bool = False) -> bool:
|
||||
@@ -148,7 +142,7 @@ class HistoryDB:
|
||||
"""Create a new (empty) database file"""
|
||||
self.execute(
|
||||
"""
|
||||
CREATE TABLE history (
|
||||
CREATE TABLE "history" (
|
||||
"id" INTEGER PRIMARY KEY,
|
||||
"completed" INTEGER NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
@@ -175,12 +169,11 @@ class HistoryDB:
|
||||
"meta" TEXT,
|
||||
"series" TEXT,
|
||||
"md5sum" TEXT,
|
||||
"password" TEXT,
|
||||
"duplicate_key" TEXT
|
||||
"password" TEXT
|
||||
)
|
||||
"""
|
||||
)
|
||||
self.execute("PRAGMA user_version = 3;")
|
||||
self.execute("PRAGMA user_version = 2;")
|
||||
|
||||
def close(self):
|
||||
"""Close database connection"""
|
||||
@@ -270,7 +263,7 @@ class HistoryDB:
|
||||
self.execute(
|
||||
"""INSERT INTO history (completed, name, nzb_name, category, pp, script, report,
|
||||
url, status, nzo_id, storage, path, script_log, script_line, download_time, postproc_time, stage_log,
|
||||
downloaded, fail_message, url_info, bytes, duplicate_key, md5sum, password)
|
||||
downloaded, fail_message, url_info, bytes, series, md5sum, password)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
t,
|
||||
save=True,
|
||||
@@ -328,17 +321,11 @@ class HistoryDB:
|
||||
|
||||
return items, total_items
|
||||
|
||||
def have_duplicate_key(self, duplicate_key: str) -> bool:
|
||||
"""Check whether History contains this duplicate key"""
|
||||
def have_episode(self, series_key: str) -> bool:
|
||||
"""Check whether History contains this series episode"""
|
||||
total = 0
|
||||
if self.execute(
|
||||
"""
|
||||
SELECT COUNT(*)
|
||||
FROM History
|
||||
WHERE
|
||||
duplicate_key = ? AND
|
||||
STATUS != ?""",
|
||||
(duplicate_key, Status.FAILED),
|
||||
"""SELECT COUNT(*) FROM History WHERE series = ? AND STATUS != ?""", (series_key, Status.FAILED)
|
||||
):
|
||||
total = self.cursor.fetchone()["COUNT(*)"]
|
||||
return total > 0
|
||||
@@ -347,12 +334,7 @@ class HistoryDB:
|
||||
"""Check whether this name or md5sum is already in History"""
|
||||
total = 0
|
||||
if self.execute(
|
||||
"""
|
||||
SELECT COUNT(*)
|
||||
FROM History
|
||||
WHERE
|
||||
( LOWER(name) = LOWER(?) OR md5sum = ? ) AND
|
||||
STATUS != ?""",
|
||||
"""SELECT COUNT(*) FROM History WHERE ( LOWER(name) = LOWER(?) OR md5sum = ? ) AND STATUS != ?""",
|
||||
(name, md5sum, Status.FAILED),
|
||||
):
|
||||
total = self.cursor.fetchone()["COUNT(*)"]
|
||||
@@ -484,7 +466,7 @@ def build_history_info(nzo, workdir_complete: str, postproc_time: int, script_ou
|
||||
report = "future" if nzo.futuretype else ""
|
||||
|
||||
# Make sure we have the duplicate key
|
||||
nzo.set_duplicate_key()
|
||||
nzo.set_duplicate_series_key()
|
||||
|
||||
return (
|
||||
completed,
|
||||
@@ -508,7 +490,7 @@ def build_history_info(nzo, workdir_complete: str, postproc_time: int, script_ou
|
||||
nzo.fail_msg,
|
||||
url_info,
|
||||
nzo.bytes_downloaded,
|
||||
nzo.duplicate_key,
|
||||
nzo.duplicate_series_key,
|
||||
nzo.md5sum,
|
||||
nzo.correct_password,
|
||||
)
|
||||
|
||||
@@ -781,8 +781,8 @@ SWITCH_LIST = (
|
||||
"fail_hopeless_jobs",
|
||||
"enable_all_par",
|
||||
"enable_recursive",
|
||||
"no_smart_dupes",
|
||||
"dupes_propercheck",
|
||||
"no_series_dupes",
|
||||
"series_propercheck",
|
||||
"script_can_fail",
|
||||
"unwanted_extensions",
|
||||
"action_on_unwanted_extensions",
|
||||
|
||||
@@ -36,7 +36,6 @@ import sabnzbd.utils.rarfile as rarfile
|
||||
from sabnzbd.misc import (
|
||||
format_time_string,
|
||||
find_on_path,
|
||||
int_conv,
|
||||
get_all_passwords,
|
||||
calc_age,
|
||||
cmp,
|
||||
@@ -45,7 +44,6 @@ from sabnzbd.misc import (
|
||||
format_time_left,
|
||||
)
|
||||
from sabnzbd.filesystem import (
|
||||
make_script_path,
|
||||
real_path,
|
||||
globber,
|
||||
globber_full,
|
||||
@@ -2134,89 +2132,6 @@ def add_time_left(perc: float, start_time: Optional[float] = None, time_used: Op
|
||||
return " - %s %s" % (format_time_left(int((100 - perc) / (perc / time_used)), short_format=True), T("left"))
|
||||
return ""
|
||||
|
||||
|
||||
def pre_queue(nzo: NzbObject, pp, cat):
|
||||
"""Run pre-queue script (if any) and process results.
|
||||
pp and cat are supplied separate since they can change.
|
||||
"""
|
||||
|
||||
def fix(p):
|
||||
# If added via API, some items can still be "None" (as a string)
|
||||
if not p or str(p).lower() == "none":
|
||||
return ""
|
||||
return str(p)
|
||||
|
||||
values = [1, nzo.final_name_with_password, pp, cat, nzo.script, nzo.priority, None]
|
||||
script_path = make_script_path(cfg.pre_script())
|
||||
if script_path:
|
||||
# Basic command-line parameters
|
||||
command = [
|
||||
script_path,
|
||||
nzo.final_name_with_password,
|
||||
pp,
|
||||
cat,
|
||||
nzo.script,
|
||||
nzo.priority,
|
||||
str(nzo.bytes),
|
||||
" ".join(nzo.groups),
|
||||
]
|
||||
command = [fix(arg) for arg in command]
|
||||
|
||||
# Fields not in the NZO directly
|
||||
show_analysis = sabnzbd.sorting.BasicAnalyzer(nzo.final_name)
|
||||
extra_env_fields = {
|
||||
"groups": " ".join(nzo.groups),
|
||||
"title": show_analysis.info.get("title", ""),
|
||||
"season": show_analysis.info.get("season_num", ""),
|
||||
"episode": show_analysis.info.get("episode_num", ""),
|
||||
"episode_name": show_analysis.info.get("ep_name", ""),
|
||||
"is_proper": show_analysis.is_proper(),
|
||||
"resolution": show_analysis.info.get("resolution", ""),
|
||||
"decade": show_analysis.info.get("decade", ""),
|
||||
"year": show_analysis.info.get("year", ""),
|
||||
"month": show_analysis.info.get("month", ""),
|
||||
"day": show_analysis.info.get("day", ""),
|
||||
"job_type": show_analysis.type,
|
||||
}
|
||||
|
||||
try:
|
||||
p = build_and_run_command(command, env=create_env(nzo, extra_env_fields))
|
||||
except:
|
||||
logging.debug("Failed script %s, Traceback: ", script_path, exc_info=True)
|
||||
return values
|
||||
|
||||
output = p.stdout.read()
|
||||
ret = p.wait()
|
||||
logging.info("Pre-queue script returned %s and output=\n%s", ret, output)
|
||||
if ret == 0:
|
||||
split_output = output.splitlines()
|
||||
try:
|
||||
# Extract category line from pre-queue output
|
||||
pre_queue_category = split_output[3].strip(" '\"")
|
||||
except IndexError:
|
||||
pre_queue_category = None
|
||||
|
||||
for index, line in enumerate(split_output):
|
||||
line = line.strip(" '\"")
|
||||
if index < len(values):
|
||||
if line:
|
||||
values[index] = line
|
||||
elif pre_queue_category and index in (2, 4, 5):
|
||||
# Preserve empty pp, script, and priority lines to prevent
|
||||
# pre-existing values from overriding category-based settings
|
||||
values[index] = ""
|
||||
|
||||
accept = int_conv(values[0])
|
||||
if accept < 1:
|
||||
logging.info("Pre-Q refuses %s", nzo.final_name)
|
||||
elif accept == 2:
|
||||
logging.info("Pre-Q accepts&fails %s", nzo.final_name)
|
||||
else:
|
||||
logging.info("Pre-Q accepts %s", nzo.final_name)
|
||||
|
||||
return values
|
||||
|
||||
|
||||
def is_sevenfile(path: str) -> bool:
|
||||
"""Return True if path has 7Zip-signature and 7Zip is detected"""
|
||||
with open(path, "rb") as sevenzip:
|
||||
|
||||
@@ -953,28 +953,28 @@ class NzbQueue:
|
||||
lname = name.lower()
|
||||
for nzo in self.__nzo_list + sabnzbd.PostProcessor.get_queue():
|
||||
# Skip any jobs already marked as duplicate, to prevent double-triggers
|
||||
# URL's do not have an MD5!
|
||||
if not nzo.duplicate and (
|
||||
nzo.final_name.lower() == lname or (nzo.md5sum and md5sum and nzo.md5sum == md5sum)
|
||||
):
|
||||
return True
|
||||
if not nzo.duplicate:
|
||||
# URL's do not have an MD5!
|
||||
if nzo.final_name.lower() == lname or (nzo.md5sum and md5sum and nzo.md5sum == md5sum):
|
||||
return True
|
||||
return False
|
||||
|
||||
@NzbQueueLocker
|
||||
def have_duplicate_key(self, duplicate_key: str) -> bool:
|
||||
"""Check whether this duplicate key is already
|
||||
def have_episode(self, series_key: str) -> bool:
|
||||
"""Check whether this episode of the series is already
|
||||
in the queue or the post-processing queue"""
|
||||
for nzo in self.__nzo_list + sabnzbd.PostProcessor.get_queue():
|
||||
for nzo in self.__nzo_list:
|
||||
# Skip any jobs already marked as duplicate, to prevent double-triggers
|
||||
if not nzo.duplicate and nzo.duplicate_key == duplicate_key:
|
||||
return True
|
||||
if not nzo.duplicate:
|
||||
if nzo.duplicate_series_key == series_key:
|
||||
return True
|
||||
return False
|
||||
|
||||
@NzbQueueLocker
|
||||
def handle_duplicate_alternatives(self, finished_nzo: NzbObject, success: bool):
|
||||
"""Remove matching duplicates if the first job succeeded,
|
||||
or start the next alternative if the job failed"""
|
||||
if not cfg.no_dupes() and not cfg.no_smart_dupes():
|
||||
if not cfg.no_dupes() and not cfg.no_series_dupes():
|
||||
return
|
||||
|
||||
# Unfortunately we need a copy, since we might remove items from the list
|
||||
@@ -986,16 +986,16 @@ class NzbQueue:
|
||||
if (
|
||||
nzo.final_name.lower() == finished_nzo.final_name.lower()
|
||||
or (nzo.md5sum and finished_nzo.md5sum and nzo.md5sum == finished_nzo.md5sum)
|
||||
) or (nzo.duplicate_key and finished_nzo.duplicate_key and nzo.duplicate_key == finished_nzo.duplicate_key):
|
||||
) or (
|
||||
nzo.duplicate_series_key
|
||||
and finished_nzo.duplicate_series_key
|
||||
and nzo.duplicate_series_key == finished_nzo.duplicate_series_key
|
||||
):
|
||||
# Start the next alternative
|
||||
if not success:
|
||||
# Don't just resume if only set to tag
|
||||
if (nzo.duplicate == DuplicateStatus.DUPLICATE_ALTERNATIVE and cfg.no_dupes() != 4) or (
|
||||
nzo.duplicate == DuplicateStatus.SMART_DUPLICATE_ALTERNATIVE and cfg.no_smart_dupes() != 4
|
||||
):
|
||||
logging.info("Resuming duplicate alternative %s for ", nzo.final_name, finished_nzo.final_name)
|
||||
nzo.resume()
|
||||
logging.info("Resuming duplicate alternative %s for ", nzo.final_name, finished_nzo.final_name)
|
||||
nzo.duplicate = None
|
||||
nzo.resume()
|
||||
return
|
||||
|
||||
# Take action on the alternatives to the duplicate
|
||||
@@ -1003,11 +1003,13 @@ class NzbQueue:
|
||||
# 2 = Pause
|
||||
# 3 = Fail (move to History)
|
||||
# 4 = Tag
|
||||
smart_duplicate = nzo.duplicate == DuplicateStatus.SMART_DUPLICATE_ALTERNATIVE
|
||||
if (not smart_duplicate and cfg.no_dupes() == 1) or (smart_duplicate and cfg.no_smart_dupes() == 1):
|
||||
series_duplicate = nzo.duplicate == DuplicateStatus.SERIES_DUPLICATE_ALTERNATIVE
|
||||
if (not series_duplicate and cfg.no_dupes() == 1) or (series_duplicate and cfg.no_series_dupes() == 1):
|
||||
duplicate_warning(T('Ignoring duplicate NZB "%s"'), nzo.final_name)
|
||||
self.remove(nzo.nzo_id)
|
||||
elif (not smart_duplicate and cfg.no_dupes() == 3) or (smart_duplicate and cfg.no_smart_dupes() == 3):
|
||||
elif (not series_duplicate and cfg.no_dupes() == 3) or (
|
||||
series_duplicate and cfg.no_series_dupes() == 3
|
||||
):
|
||||
duplicate_warning(T('Failing duplicate NZB "%s"'), nzo.final_name)
|
||||
nzo.fail_msg = T("Duplicate NZB")
|
||||
self.fail_to_history(nzo)
|
||||
@@ -1017,7 +1019,7 @@ class NzbQueue:
|
||||
if nzo.duplicate == DuplicateStatus.DUPLICATE_ALTERNATIVE:
|
||||
nzo.duplicate = DuplicateStatus.DUPLICATE
|
||||
else:
|
||||
nzo.duplicate = DuplicateStatus.SMART_DUPLICATE
|
||||
nzo.duplicate = DuplicateStatus.SERIES_DUPLICATE
|
||||
return
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
@@ -563,7 +563,7 @@ NzbObjectSaver = (
|
||||
"encrypted",
|
||||
"bad_articles",
|
||||
"duplicate",
|
||||
"duplicate_key",
|
||||
"duplicate_series_key",
|
||||
"oversized",
|
||||
"precheck",
|
||||
"incomplete",
|
||||
@@ -691,7 +691,7 @@ class NzbObject(TryList):
|
||||
self.nzo_id: Optional[str] = None
|
||||
|
||||
self.duplicate: Optional[str] = None
|
||||
self.duplicate_key: Optional[str] = None
|
||||
self.duplicate_series_key: Optional[str] = None
|
||||
|
||||
self.futuretype = futuretype
|
||||
self.removed_from_queue = False
|
||||
@@ -826,59 +826,15 @@ class NzbObject(TryList):
|
||||
# Determine category and find pp/script values
|
||||
self.cat, pp_tmp, self.script, priority = cat_to_opts(cat, pp, script, self.priority)
|
||||
self.set_priority(priority)
|
||||
self.repair, self.unpack, self.delete = pp_to_opts(pp_tmp)
|
||||
self.set_pp(pp_tmp)
|
||||
|
||||
# Show first meta-password (if any), when there's no explicit password
|
||||
if not self.password and self.meta.get("password"):
|
||||
self.password = self.meta.get("password", [None])[0]
|
||||
|
||||
# Run user pre-queue script if set and valid
|
||||
if not reuse and make_script_path(cfg.pre_script()):
|
||||
# Call the script
|
||||
accept, name, pq_pp, pq_cat, pq_script, pq_priority, pq_group = sabnzbd.newsunpack.pre_queue(self, pp, cat)
|
||||
|
||||
if pq_cat:
|
||||
# An explicit pp/script/priority set upon adding the job takes precedence
|
||||
# over an implicit setting based on the category set by pre-queue
|
||||
if input_priority and not pq_priority:
|
||||
pq_priority = input_priority
|
||||
if input_pp and not pq_pp:
|
||||
pq_pp = input_pp
|
||||
if input_script and not pq_script:
|
||||
pq_script = input_script
|
||||
|
||||
# Accept or reject
|
||||
accept = int_conv(accept)
|
||||
if accept < 1:
|
||||
self.purge_data()
|
||||
raise NzbRejected
|
||||
if accept == 2:
|
||||
raise NzbRejectToHistory(self, T("Pre-queue script marked job as failed"))
|
||||
|
||||
# Process all options, only over-write if set by script
|
||||
# Beware that cannot do "if priority/pp", because those can
|
||||
# also have a valid value of 0, which shouldn't be ignored
|
||||
if name:
|
||||
self.set_final_name_and_scan_password(name)
|
||||
try:
|
||||
pp = int(pq_pp)
|
||||
except:
|
||||
pp = None
|
||||
if pq_cat:
|
||||
cat = pq_cat
|
||||
try:
|
||||
priority = int(pq_priority)
|
||||
except:
|
||||
priority = DEFAULT_PRIORITY
|
||||
if pq_script and is_valid_script(pq_script):
|
||||
script = pq_script
|
||||
if pq_group:
|
||||
self.groups = [str(pq_group)]
|
||||
|
||||
# Re-evaluate results from pre-queue script
|
||||
self.cat, pp, self.script, priority = cat_to_opts(cat, pp, script, priority)
|
||||
self.set_priority(priority)
|
||||
self.repair, self.unpack, self.delete = pp_to_opts(pp)
|
||||
# Run user pre-queue script
|
||||
if not reuse:
|
||||
self.run_pre_queue(input_priority, input_pp, input_script)
|
||||
|
||||
# Pause if requested by the NZB-adding or the pre-queue script
|
||||
if self.priority == PAUSED_PRIORITY:
|
||||
@@ -1344,12 +1300,9 @@ class NzbObject(TryList):
|
||||
def labels(self):
|
||||
"""Return (translated) labels of job"""
|
||||
labels = []
|
||||
if self.duplicate in (DuplicateStatus.DUPLICATE, DuplicateStatus.SMART_DUPLICATE):
|
||||
if self.duplicate in (DuplicateStatus.DUPLICATE, DuplicateStatus.SERIES_DUPLICATE):
|
||||
labels.append(T("DUPLICATE"))
|
||||
if self.duplicate in (
|
||||
DuplicateStatus.DUPLICATE_ALTERNATIVE,
|
||||
DuplicateStatus.SMART_DUPLICATE_ALTERNATIVE,
|
||||
):
|
||||
if self.duplicate in (DuplicateStatus.DUPLICATE_ALTERNATIVE, DuplicateStatus.SERIES_DUPLICATE_ALTERNATIVE):
|
||||
labels.append(T("ALTERNATIVE"))
|
||||
if self.encrypted > 0:
|
||||
labels.append(T("ENCRYPTED"))
|
||||
@@ -1888,40 +1841,28 @@ class NzbObject(TryList):
|
||||
else:
|
||||
nzf_ids.remove(nzf_id)
|
||||
|
||||
def set_duplicate_key(self):
|
||||
def set_duplicate_series_key(self):
|
||||
"""Shorthand to set the key once"""
|
||||
if not self.duplicate_key:
|
||||
show_analysis = sabnzbd.sorting.BasicAnalyzer(self.final_name)
|
||||
if not self.duplicate_series_key:
|
||||
show_analysis = sabnzbd.sorting.analyse_show(self.final_name)
|
||||
if show_analysis["job_type"] == "tv":
|
||||
series, season, episode, is_proper = (
|
||||
show_analysis[key] for key in ("title", "season", "episode", "is_proper")
|
||||
)
|
||||
# Ignore proper results if not desired
|
||||
if not cfg.series_propercheck():
|
||||
is_proper = False
|
||||
|
||||
# We can only set a duplicate key for these types
|
||||
if show_analysis.type not in ("tv", "movie", "date"):
|
||||
return
|
||||
|
||||
# The key always includes the title, for movies we don't add anything else
|
||||
duplicate_key_items = [show_analysis.info.get("title", "")]
|
||||
if show_analysis.type == "tv":
|
||||
# For TV-shows we add the season and episode
|
||||
duplicate_key_items.append(str(show_analysis.info.get("season", "")))
|
||||
duplicate_key_items.append(str(show_analysis.info.get("episode", "")))
|
||||
elif show_analysis.type == "date":
|
||||
# Add date
|
||||
duplicate_key_items.append(str(show_analysis.info.get("year", "")))
|
||||
duplicate_key_items.append(str(show_analysis.info.get("month", "")))
|
||||
duplicate_key_items.append(str(show_analysis.info.get("day", "")))
|
||||
|
||||
# We allow 1 proper result to bypass the detection, if desired
|
||||
if show_analysis.is_proper() and cfg.dupes_propercheck():
|
||||
duplicate_key_items.append("proper")
|
||||
|
||||
self.duplicate_key = "/".join(duplicate_key_items).lower()
|
||||
# We allow 1 proper result to bypass duplicate detection
|
||||
self.duplicate_series_key = f"{series.lower()}/{season}/{episode}{f'/{is_proper}' if is_proper else ''}"
|
||||
|
||||
def duplicate_check(self):
|
||||
"""Set the correct duplicate status"""
|
||||
if not cfg.no_dupes() and not cfg.no_smart_dupes():
|
||||
if not cfg.no_dupes() and not cfg.no_series_dupes():
|
||||
return
|
||||
|
||||
duplicate_in_history = smart_duplicate_in_history = False
|
||||
duplicate_in_queue = smart_duplicate_in_queue = False
|
||||
duplicate_in_history = series_duplicate_in_history = False
|
||||
duplicate_in_queue = series_duplicate_in_queue = False
|
||||
|
||||
with HistoryDB() as history_db:
|
||||
# Dupe check off just name or nzb contents
|
||||
@@ -1939,25 +1880,25 @@ class NzbObject(TryList):
|
||||
logging.debug("Duplicate in queue: %s", duplicate_in_queue)
|
||||
|
||||
# Dupe check off nzb filename
|
||||
if not duplicate_in_history and not duplicate_in_queue and cfg.no_smart_dupes():
|
||||
self.set_duplicate_key()
|
||||
logging.debug("Smart duplicate checking (%s): %s", self.final_name, self.duplicate_key)
|
||||
if self.duplicate_key:
|
||||
smart_duplicate_in_history = history_db.have_duplicate_key(self.duplicate_key)
|
||||
logging.debug("Duplicate in history: %s", smart_duplicate_in_history)
|
||||
if not duplicate_in_history and not duplicate_in_queue and cfg.no_series_dupes():
|
||||
logging.debug("Duplicate episode checking (%s): %s", self.final_name, self.duplicate_series_key)
|
||||
self.set_duplicate_series_key()
|
||||
if self.duplicate_series_key:
|
||||
series_duplicate_in_history = history_db.have_episode(self.duplicate_series_key)
|
||||
logging.debug("Duplicate episode in history: %s", series_duplicate_in_history)
|
||||
|
||||
smart_duplicate_in_queue = sabnzbd.NzbQueue.have_duplicate_key(self.duplicate_key)
|
||||
logging.debug("Duplicate in queue: %s", smart_duplicate_in_queue)
|
||||
series_duplicate_in_queue = sabnzbd.NzbQueue.have_episode(self.duplicate_series_key)
|
||||
logging.debug("Duplicate episode in queue: %s", series_duplicate_in_queue)
|
||||
else:
|
||||
logging.debug("Unknown type, skipping smart duplicate check")
|
||||
logging.debug("Not an episode, skipping duplicate episode check")
|
||||
|
||||
# Set the correct status
|
||||
if smart_duplicate_in_queue:
|
||||
self.duplicate = DuplicateStatus.SMART_DUPLICATE_ALTERNATIVE
|
||||
if series_duplicate_in_queue:
|
||||
self.duplicate = DuplicateStatus.SERIES_DUPLICATE_ALTERNATIVE
|
||||
elif duplicate_in_queue:
|
||||
self.duplicate = DuplicateStatus.DUPLICATE_ALTERNATIVE
|
||||
elif smart_duplicate_in_history:
|
||||
self.duplicate = DuplicateStatus.SMART_DUPLICATE
|
||||
elif series_duplicate_in_history:
|
||||
self.duplicate = DuplicateStatus.SERIES_DUPLICATE
|
||||
elif duplicate_in_history:
|
||||
self.duplicate = DuplicateStatus.DUPLICATE
|
||||
|
||||
@@ -1972,18 +1913,18 @@ class NzbObject(TryList):
|
||||
# 2 = Pause
|
||||
# 3 = Fail (move to History)
|
||||
# 4 = Tag
|
||||
if self.duplicate in (DuplicateStatus.DUPLICATE, DuplicateStatus.SMART_DUPLICATE):
|
||||
smart_duplicate = self.duplicate == DuplicateStatus.SMART_DUPLICATE
|
||||
if (not smart_duplicate and cfg.no_dupes() == 1) or (smart_duplicate and cfg.no_smart_dupes() == 1):
|
||||
if self.duplicate in (DuplicateStatus.DUPLICATE, DuplicateStatus.SERIES_DUPLICATE):
|
||||
series_duplicate = self.duplicate == DuplicateStatus.SERIES_DUPLICATE
|
||||
if (not series_duplicate and cfg.no_dupes() == 1) or (series_duplicate and cfg.no_series_dupes() == 1):
|
||||
# Discard
|
||||
duplicate_warning(T('Ignoring duplicate NZB "%s"'), self.final_name)
|
||||
self.purge_data()
|
||||
raise NzbRejected
|
||||
elif (not smart_duplicate and cfg.no_dupes() == 3) or (smart_duplicate and cfg.no_smart_dupes() == 3):
|
||||
elif (not series_duplicate and cfg.no_dupes() == 3) or (series_duplicate and cfg.no_series_dupes() == 3):
|
||||
# Fail (move to History)
|
||||
duplicate_warning(T('Failing duplicate NZB "%s"'), self.final_name)
|
||||
raise NzbRejectToHistory(self, T("Duplicate NZB"))
|
||||
elif (not smart_duplicate and cfg.no_dupes() == 2) or (smart_duplicate and cfg.no_smart_dupes() == 2):
|
||||
elif (not series_duplicate and cfg.no_dupes() == 2) or (series_duplicate and cfg.no_series_dupes() == 2):
|
||||
# Pause
|
||||
duplicate_warning(T('Pausing duplicate NZB "%s"'), self.final_name)
|
||||
self.pause()
|
||||
@@ -1991,13 +1932,101 @@ class NzbObject(TryList):
|
||||
# Tag job
|
||||
duplicate_warning('%s: "%s"', T("Duplicate NZB"), self.final_name)
|
||||
|
||||
# In case of alternative, just pause (unless only tagging is desired)
|
||||
if (self.duplicate == DuplicateStatus.DUPLICATE_ALTERNATIVE and cfg.no_dupes() != 4) or (
|
||||
self.duplicate == DuplicateStatus.SMART_DUPLICATE_ALTERNATIVE and cfg.no_smart_dupes() != 4
|
||||
):
|
||||
# In case of alternative, just pause
|
||||
if self.duplicate in (DuplicateStatus.DUPLICATE_ALTERNATIVE, DuplicateStatus.SERIES_DUPLICATE_ALTERNATIVE):
|
||||
logging.info("Pausing duplicate alternative %s", self.final_name)
|
||||
self.pause()
|
||||
|
||||
def run_pre_queue(
|
||||
self,
|
||||
input_priority: Optional[Union[int, str]],
|
||||
input_pp: Optional[int],
|
||||
input_script: Optional[str],
|
||||
):
|
||||
"""Run pre-queue script (if any) and process results."""
|
||||
if script_path := make_script_path(cfg.pre_script()):
|
||||
|
||||
def fix_parameter(parameter: Any) -> str:
|
||||
# If added via API, some items can still be "None" (as a string)
|
||||
if not parameter or str(parameter).lower() == "none":
|
||||
return ""
|
||||
return str(parameter)
|
||||
|
||||
# Basic parameters
|
||||
command = [script_path, self.final_name_with_password, self.cat, self.priority, self.pp, self.script]
|
||||
command = [fix_parameter(arg) for arg in command]
|
||||
|
||||
# Fields not in the NZO directly
|
||||
extra_env_fields = sabnzbd.newsunpack.analyse_show(self.final_name_with_password)
|
||||
extra_env_fields["groups"] = " ".join(self.groups)
|
||||
|
||||
try:
|
||||
p = sabnzbd.newsunpack.build_and_run_command(
|
||||
command, env=sabnzbd.newsunpack.create_env(self, extra_env_fields)
|
||||
)
|
||||
except:
|
||||
logging.debug("Failed script %s, Traceback: ", script_path, exc_info=True)
|
||||
return
|
||||
|
||||
output = p.stdout.read()
|
||||
ret = p.wait()
|
||||
logging.info("Pre-queue script returned %s and output=\n%s", ret, output)
|
||||
if ret == 0:
|
||||
# Base values
|
||||
pq_cat = pq_pp = pq_script = pq_priority = None
|
||||
for index, line in enumerate(output.splitlines(), start=1):
|
||||
# Make sure to keep this in line with the documentation!
|
||||
# 1: Accept
|
||||
# 2: Name
|
||||
# 3: Category
|
||||
# 4: Priority
|
||||
# 5: Post-processing
|
||||
# 6: Script
|
||||
# 7: Duplicate
|
||||
# 8: Duplicate key
|
||||
if line := line.strip(" '\""):
|
||||
if index == 1:
|
||||
# Accept or reject
|
||||
accept = int_conv(line)
|
||||
if accept < 1:
|
||||
logging.info("Pre-queue script refuses %s", self.final_name)
|
||||
self.purge_data()
|
||||
raise NzbRejected
|
||||
if accept == 2:
|
||||
logging.info("Pre-queue marking as failed %s", self.final_name)
|
||||
raise NzbRejectToHistory(self, T("Pre-queue script marked job as failed"))
|
||||
logging.info("Pre-queue accepts %s", self.final_name)
|
||||
elif index == 2:
|
||||
self.set_final_name_and_scan_password(line)
|
||||
elif index == 3:
|
||||
pq_cat = line
|
||||
elif index == 4:
|
||||
pq_priority = int_conv(line, default=DEFAULT_PRIORITY)
|
||||
elif index == 5:
|
||||
pq_pp = int_conv(line, default=None)
|
||||
elif index == 6:
|
||||
if is_valid_script(line):
|
||||
pq_script = line
|
||||
elif index == 7:
|
||||
self.duplicate = line
|
||||
elif index == 8:
|
||||
self.duplicate_series_key = line
|
||||
|
||||
if pq_cat:
|
||||
# An explicit pp/script/priority set upon adding the job takes precedence
|
||||
# over an implicit setting based on the category set by pre-queue
|
||||
if input_priority and pq_priority is None:
|
||||
pq_priority = input_priority
|
||||
if input_pp and pq_pp is None:
|
||||
pq_pp = input_pp
|
||||
if input_script and not pq_script:
|
||||
pq_script = input_script
|
||||
|
||||
# Re-evaluate results from pre-queue script
|
||||
self.cat, pp, self.script, priority = cat_to_opts(pq_cat, pq_pp, pq_script, pq_priority)
|
||||
self.set_priority(priority)
|
||||
self.set_pp(pp)
|
||||
|
||||
def __getstate__(self):
|
||||
"""Save to pickle file, selecting attributes"""
|
||||
dict_ = {}
|
||||
|
||||
@@ -308,9 +308,8 @@ class RSSReader:
|
||||
myPrio = defPrio
|
||||
n = 0
|
||||
if ("F" in reTypes or "S" in reTypes) and (not season or not episode):
|
||||
show_analysis = sabnzbd.sorting.BasicAnalyzer(title)
|
||||
season = show_analysis.info.get("season")
|
||||
episode = show_analysis.info.get("episode")
|
||||
show_analysis = sabnzbd.sorting.analyse_show(title)
|
||||
season, episode = show_analysis["season"], show_analysis["episode"]
|
||||
|
||||
# Match against all filters until an positive or negative match
|
||||
logging.debug("Size %s", size)
|
||||
@@ -337,7 +336,12 @@ class RSSReader:
|
||||
logging.debug("Filter requirement match on rule %d", n)
|
||||
result = False
|
||||
break
|
||||
elif reTypes[n] == "S" and ep_match(season, episode, regexes[n], title):
|
||||
elif (
|
||||
reTypes[n] == "S"
|
||||
and season
|
||||
and episode
|
||||
and ep_match(season, episode, regexes[n], title)
|
||||
):
|
||||
logging.debug("Filter matched on rule %d", n)
|
||||
result = True
|
||||
break
|
||||
|
||||
@@ -414,13 +414,17 @@ SKIN_TEXT = {
|
||||
),
|
||||
"opt-pause_on_pwrar": TT("Action when encrypted RAR is downloaded"),
|
||||
"explain-pause_on_pwrar": TT('In case of "Pause", you\'ll need to set a password and resume the job.'),
|
||||
"opt-no_dupes": TT("Identical download detection"),
|
||||
"explain-no_dupes": TT("Detect identical downloads based on name or NZB contents."),
|
||||
"opt-no_smart_dupes": TT("Smart duplicate detection"),
|
||||
"explain-no_smart_dupes": TT("Detect duplicates based on analysis of the filename."),
|
||||
"opt-dupes_propercheck": TT("Allow proper releases"),
|
||||
"explain-dupes_propercheck": TT(
|
||||
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in the download name."
|
||||
"opt-no_dupes": TT("Detect Duplicate Downloads"),
|
||||
"explain-no_dupes": TT(
|
||||
"Detect identical NZB files (based on items in your History or files in .nzb Backup Folder)"
|
||||
),
|
||||
"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)'
|
||||
),
|
||||
"opt-series_propercheck": TT("Allow proper releases"),
|
||||
"explain-series_propercheck": TT(
|
||||
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in the download name"
|
||||
),
|
||||
"nodupes-off": TT("Off"), #: Three way switch for duplicates
|
||||
"nodupes-ignore": TT("Discard"), #: Four way switch for duplicates
|
||||
@@ -451,9 +455,13 @@ SKIN_TEXT = {
|
||||
"opt-end_queue_script": TT("On queue finish script"),
|
||||
"explain-end_queue_script": TT("Executed after the queue finishes downloading."),
|
||||
"opt-par_option": TT("Extra PAR2 Parameters"),
|
||||
"explain-par_option": TT("Read the Wiki Help on this!"),
|
||||
"opt-nice": TT("Nice Parameters"),
|
||||
"explain-nice": TT("Read the Wiki Help on this!"),
|
||||
"opt-ionice": TT("IONice Parameters"),
|
||||
"explain-ionice": TT("Read the Wiki Help on this!"),
|
||||
"opt-win_process_prio": TT("External process priority"),
|
||||
"explain-win_process_prio": TT("Read the Wiki Help on this!"),
|
||||
"win_process_prio-high": TT("High"),
|
||||
"win_process_prio-normal": TT("Normal"),
|
||||
"win_process_prio-low": TT("Low"),
|
||||
@@ -682,6 +690,7 @@ SKIN_TEXT = {
|
||||
"opt-nscript_parameters": TT("Parameters"), #: Notification Script settings
|
||||
"explain-nscript_enable": TT("Executes a custom script"), #: Notification Scriptsettings
|
||||
"explain-nscript_script": TT("Which script should we execute for notification?"), #: Notification Scriptsettings
|
||||
"explain-nscript_parameters": TT("Read the Wiki Help on this!"), #: Notification Script settings
|
||||
# Config->Cat
|
||||
"explain-catTags": TT(
|
||||
'Indexers can supply a category inside the NZB which SABnzbd will try to match to the categories defined below. Additionally, you can add terms to "Indexer Categories / Groups" to match more categories. Use commas to separate terms. Wildcards in the terms are supported. <br>More information can be found on the Wiki.'
|
||||
|
||||
@@ -585,12 +585,10 @@ class Sorter:
|
||||
return move_to_parent_directory(base_path)
|
||||
|
||||
|
||||
class BasicAnalyzer(Sorter):
|
||||
class SeriesAnalyzer(Sorter):
|
||||
def __init__(self, job_name: str):
|
||||
"""Very basic sorter that doesn't require a config"""
|
||||
super().__init__(nzo=None, job_name=job_name)
|
||||
# Directly trigger setting all values
|
||||
self.get_values()
|
||||
|
||||
def match_sorters(self):
|
||||
"""Much more basic matching"""
|
||||
@@ -602,6 +600,25 @@ class BasicAnalyzer(Sorter):
|
||||
self.type = "date" if self.guess.get("date") else "tv"
|
||||
|
||||
|
||||
def analyse_show(job_name: str) -> Dict[str, str]:
|
||||
"""Use the Sorter to collect some basic info on series"""
|
||||
job = SeriesAnalyzer(job_name)
|
||||
job.get_values()
|
||||
return {
|
||||
"title": job.info.get("title", ""),
|
||||
"season": job.info.get("season_num", ""),
|
||||
"episode": job.info.get("episode_num", ""),
|
||||
"episode_name": job.info.get("ep_name", ""),
|
||||
"is_proper": job.is_proper(),
|
||||
"resolution": job.info.get("resolution", ""),
|
||||
"decade": job.info.get("decade", ""),
|
||||
"year": job.info.get("year", ""),
|
||||
"month": job.info.get("month", ""),
|
||||
"day": job.info.get("day", ""),
|
||||
"job_type": job.type,
|
||||
}
|
||||
|
||||
|
||||
def ends_in_file(path: str) -> bool:
|
||||
"""Return True when path ends with '.%ext' or '%fn' while allowing for a lowercase marker"""
|
||||
return bool(RE_ENDEXT.search(path) or RE_ENDFN.search(path))
|
||||
@@ -632,8 +649,9 @@ def move_to_parent_directory(workdir: str) -> Tuple[str, bool]:
|
||||
return dest, True
|
||||
|
||||
|
||||
def guess_what(name: str) -> MatchesDict:
|
||||
"""Guess metadata for movies or episodes from their name."""
|
||||
def guess_what(name: str, sort_type: Optional[str] = None) -> MatchesDict:
|
||||
"""Guess metadata for movies or episodes from their name. The sort_type ('movie' or 'episode')
|
||||
is passed as a hint to guessit, if given."""
|
||||
|
||||
if not name:
|
||||
raise ValueError("Need a name for guessing")
|
||||
@@ -652,6 +670,9 @@ def guess_what(name: str) -> MatchesDict:
|
||||
"excludes": EXCLUDED_GUESSIT_PROPERTIES,
|
||||
"date_year_first": True, # Make sure also short-dates are detected as YY-MM-DD
|
||||
}
|
||||
if sort_type:
|
||||
# Hint the type if known
|
||||
guessit_options["type"] = sort_type
|
||||
|
||||
guess = guessit.api.guessit(digit_fix + name, options=guessit_options)
|
||||
logging.debug("Initial guess for %s is %s", digit_fix + name, guess)
|
||||
@@ -666,7 +687,7 @@ def guess_what(name: str) -> MatchesDict:
|
||||
|
||||
# Try to avoid setting the type to movie on arbitrary jobs (e.g. 'Setup.exe') just because guessit defaults to that
|
||||
table = str.maketrans({char: "" for char in whitespace + "_.-()[]{}"})
|
||||
if guess.get("type") == "movie":
|
||||
if guess.get("type") == "movie" and not sort_type == "movie": # No movie hint
|
||||
if (
|
||||
guess.get("title", "").translate(table) == name.translate(table) # Check for full name used as title
|
||||
or any(
|
||||
@@ -676,9 +697,7 @@ def guess_what(name: str) -> MatchesDict:
|
||||
[key in guess for key in ("year", "screen_size", "video_codec")]
|
||||
) # No typical movie properties set
|
||||
or (
|
||||
name.lower().startswith(("http://", "https://"))
|
||||
and name.lower().endswith(".nzb")
|
||||
and guess.get("container" == "nzb")
|
||||
name.lower().startswith("http://") and name.lower().endswith(".nzb") and guess.get("container" == "nzb")
|
||||
) # URL to an nzb file, can happen when pre-queue script rejects a job
|
||||
):
|
||||
guess["type"] = "unknown"
|
||||
|
||||
@@ -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.2.0Beta1"
|
||||
__version__ = "4.2.0Alpha2"
|
||||
__baseline__ = "unknown"
|
||||
|
||||
@@ -52,7 +52,6 @@ stages:
|
||||
bytes: !anyint
|
||||
meta: null
|
||||
series: !anything
|
||||
duplicate_key: !anything
|
||||
md5sum: !re_match "[0-9a-fA-F]+"
|
||||
password: !anystr
|
||||
action_line: !anything
|
||||
@@ -93,7 +92,7 @@ stages:
|
||||
# so parameters match regardless of their order of appearance. Note
|
||||
# that the content of 'slots' is checked in a separate expression.
|
||||
expression: "^{{(?=.*'version': '{SAB_VERSION}')(?=.*'noofslots': [0-9]+)(?=.*'ppslots': [0-9]+)(?=.*'last_history_update': '?[0-9]+'?)(?=.*'total_size': '[0-9][0-9.]*.?(\ [A-Z])?')(?=.*'month_size': '[0-9][0-9.]*.?(\ [A-Z])?')(?=.*'week_size': '[0-9][0-9.]*.?(\ [A-Z])?')(?=.*'day_size': '[0-9][0-9.]*.?(\ [A-Z])?')(?=.*'slots': .+).*}}$"
|
||||
expression: ".*'slots': \\[{{(?=.*'completed': [0-9]+)(?=.*'name': '.+')(?=.*'nzb_name': '.+')(?=.*'category': '.+')(?=.*'pp': '.?')(?=.*'script': '.+')(?=.*'report': '.+')(?=.*'url': '.+')(?=.*'status': '.+')(?=.*'nzo_id': 'SAB.+')(?=.*'storage': '.+')(?=.*'path': '.+')(?=.*'script_line': '.*')(?=.*'download_time': [0-9]+)(?=.*'postproc_time': [0-9]*)(?=.*'stage_log': \\[.*\\])(?=.*'downloaded': [0-9]+)(?=.*'completeness': None)(?=.*'fail_message': '.*')(?=.*'url_info': '.*')(?=.*'bytes': [0-9]+)(?=.*'meta': None)(?=.*'series': '?.*'?)(?=.*'duplicate_key': '?.*'?)(?=.*'md5sum': '[0-9a-fA-F]+')(?=.*'password': '.*')(?=.*'action_line': '.*')(?=.*'size': '[0-9].*')(?=.*'loaded': (True|False))(?=.*'retry': [0-9]+).*}}\\].*"
|
||||
expression: ".*'slots': \\[{{(?=.*'completed': [0-9]+)(?=.*'name': '.+')(?=.*'nzb_name': '.+')(?=.*'category': '.+')(?=.*'pp': '.?')(?=.*'script': '.+')(?=.*'report': '.+')(?=.*'url': '.+')(?=.*'status': '.+')(?=.*'nzo_id': 'SAB.+')(?=.*'storage': '.+')(?=.*'path': '.+')(?=.*'script_line': '.*')(?=.*'download_time': [0-9]+)(?=.*'postproc_time': [0-9]*)(?=.*'stage_log': \\[.*\\])(?=.*'downloaded': [0-9]+)(?=.*'completeness': None)(?=.*'fail_message': '.*')(?=.*'url_info': '.*')(?=.*'bytes': [0-9]+)(?=.*'meta': None)(?=.*'series': '?.*'?)(?=.*'md5sum': '[0-9a-fA-F]+')(?=.*'password': '.*')(?=.*'action_line': '.*')(?=.*'size': '[0-9].*')(?=.*'loaded': (True|False))(?=.*'retry': [0-9]+).*}}\\].*"
|
||||
|
||||
|
||||
---
|
||||
@@ -151,7 +150,6 @@ stages:
|
||||
<bytes>!anyint</bytes>
|
||||
<meta>!anystr</meta>
|
||||
<series>!anystr</series>
|
||||
<duplicate_key>!anystr</duplicate_key>
|
||||
<md5sum>!anystr</md5sum>
|
||||
<password>!anystr</password>
|
||||
<action_line>!anystr</action_line>
|
||||
|
||||
@@ -174,9 +174,17 @@ class TestAddingNZBs:
|
||||
try:
|
||||
script_path = os.path.join(VAR.SCRIPT_DIR, script_name)
|
||||
with open(script_path, "w") as f:
|
||||
# line 1 = accept; 4 = category; 6 = priority
|
||||
# Lines:
|
||||
# 1: Accept
|
||||
# 2: Name
|
||||
# 3: Category
|
||||
# 4: Priority
|
||||
# 5: Post-processing
|
||||
# 6: Script
|
||||
# 7: Duplicate
|
||||
# 8: Duplicate key
|
||||
f.write(
|
||||
"#!%s\n\nprint('1\\n\\n\\n%s\\n\\n%s\\n')"
|
||||
"#!%s\n\nprint('1\\n\\n%s\\n%s\\n')"
|
||||
% (
|
||||
sys.executable,
|
||||
(category if category else ""),
|
||||
@@ -406,8 +414,8 @@ class TestAddingNZBs:
|
||||
@pytest.mark.parametrize("prio_def_cat", sample(VALID_DEFAULT_PRIORITIES, 2))
|
||||
@pytest.mark.parametrize("prio_add", sample(PRIO_OPTS_ADD, 3))
|
||||
@pytest.mark.parametrize("prio_add_cat", sample(PRIO_OPTS_ADD_CAT, 2))
|
||||
@pytest.mark.parametrize("prio_preq", sample(PRIO_OPTS_PREQ, 2))
|
||||
@pytest.mark.parametrize("prio_preq_cat", sample(PRIO_OPTS_PREQ_CAT, 2))
|
||||
@pytest.mark.parametrize("prio_preq", PRIO_OPTS_PREQ)
|
||||
@pytest.mark.parametrize("prio_preq_cat", PRIO_OPTS_PREQ_CAT)
|
||||
def test_adding_nzbs_priority_sample(
|
||||
self, prio_def_cat, prio_add, prio_add_cat, prio_preq, prio_preq_cat, prio_meta_cat
|
||||
):
|
||||
|
||||
@@ -219,7 +219,7 @@ class FakeHistoryDB(db.HistoryDB):
|
||||
nzo.repair, nzo.unpack, nzo.delete = pp_to_opts(choice(list(PP_LOOKUP.keys()))) # for "pp"
|
||||
nzo.nzo_info = {"download_time": randint(1, 10**4)}
|
||||
nzo.unpack_info = {"unpack_info": "placeholder unpack_info line\r\n" * 3}
|
||||
nzo.duplicate_key = "show/season/episode"
|
||||
nzo.duplicate_series_key = "show/season/episode"
|
||||
nzo.futuretype = False # for "report", only True when fetching an URL
|
||||
nzo.download_path = os.path.join(os.path.dirname(db.HistoryDB.db_path), "placeholder_downpath")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user