Compare commits

..

1 Commits

Author SHA1 Message Date
Safihre
8bd39e4c12 Refactor pre-queue script
[skip ci]
2023-11-22 16:17:19 +01:00
39 changed files with 557 additions and 513 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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">

View File

@@ -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>

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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())

View File

@@ -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,

View File

@@ -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)

View File

@@ -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:

View File

@@ -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,
)

View File

@@ -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",

View File

@@ -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:

View File

@@ -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):

View File

@@ -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_ = {}

View File

@@ -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

View File

@@ -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.'

View File

@@ -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"

View File

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

View File

@@ -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>

View File

@@ -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
):

View File

@@ -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")