Compare commits

...

27 Commits

Author SHA1 Message Date
Safihre
54e03fb40a Update text files for 2.3.5RC1 2018-08-08 20:35:01 +02:00
Safihre
904bb9f85a Remove unused imports 2018-08-07 17:10:13 +02:00
Rik Smith
b011e1a518 Direct Unpack would abort if single-file unpack was too slow (#1165) 2018-08-06 08:40:59 +02:00
Rik Smith
f83f71a950 Fix Deobfuscate.py script (#1166)
* Fix deobfuscate script

* Rename for code check

* Rename for code check
2018-08-06 08:35:01 +02:00
Safihre
4dbf5266ef Par2 files with same number of "+x" blocks were not counted seperatly
Strange why I did that before. It does create the possibility that if we have a huge NZB with many sets with similar filenames that we take forever to repair, but for normal NZB's with lot's of "volXX+40" we would ignore all those extra blocks.
2018-08-04 10:38:02 +02:00
Safihre
05aac4e01e Remove redundant integer conversion 2018-08-04 10:36:03 +02:00
Safihre
267c48f9a7 Update gitignore for PyCharm 2018-08-04 10:00:46 +02:00
Safihre
5168915a65 Manualy par2 parsing in Deobfuscate.py for major performance increase
By @P1nGu1n, thanks!
2018-08-03 15:13:20 +02:00
Safihre
71017d0d55 Diskspeed test did not remove test file 2018-08-03 15:06:19 +02:00
Safihre
a5db51a2c5 Windows-tray also show queue size left info when paused 2018-08-01 21:25:17 +02:00
Safihre
0bf2968e6a Windows installer language wasn't parsed for the wizard
It needs a translation table and it was fetched from the wrong register location
2018-08-01 11:42:23 +02:00
Safihre
2ec5918f5e Extend disk-speed time to 1 second for more stable results 2018-08-01 07:57:24 +02:00
Safihre
04f5a63cd7 Backported new-style speed-test from Py3 branch
Old-style would create bad file on Windows. This is more robust. Thanks @albino1 for report!
2018-07-31 22:25:14 +02:00
Safihre
43d8283f5b Wizard final page not linking to Folders config page
Closes #1163
2018-07-31 22:07:01 +02:00
SABnzbd Automation
f8111121c4 Automatic translation update 2018-07-14 20:49:01 +00:00
Safihre
b53b73c135 Only abort active DirectUnpackers
Only when we have assigned a setname we are doing something, otherwise we might just as well leave the files and not delete too much. For example see: https://forums.sabnzbd.org/viewtopic.php?f=2&t=23440
2018-07-14 22:24:06 +02:00
Safihre
bd7b8a975b Wrap is_rarfile so it can't crash when files are gone
Seen in users log-files. Possible when deleting job during assembly-steps.
2018-07-14 21:20:11 +02:00
Safihre
7ca765f276 Lock start and stop of DirectUnpack so they can't overlap
In high-speed situations this could happen.
2018-07-14 21:18:57 +02:00
Safihre
b918a53af5 Add env-variables to pre-queue call 2018-07-14 17:28:37 +02:00
Safihre
525809afc9 Always add basic env-variables to external calls 2018-07-14 17:28:14 +02:00
Safihre
a7048cdc8e Use server hostname in logs and warnings
Closes #1159
2018-07-14 12:14:48 +02:00
Safihre
02888568bd Log par2 creator
Closes #1153
2018-07-02 10:29:07 +02:00
Safihre
203409f02f Update MultiPar to 1.3.0.1 2018-06-29 10:06:15 +02:00
Safihre
ecc8e6ac0e Update UnRar to 5.60 for Windows and macOS
Closes #1156
2018-06-29 10:01:40 +02:00
Safihre
852636acda Add VPN problems to known-issues 2018-06-12 11:14:07 +02:00
Safihre
bc18369552 Spelling fix in Deobfuscate.py
Closes #1152
2018-06-08 10:45:17 +02:00
Safihre
8f248a2219 Could not set single Indexer Tag for a category
"TV > HD" would become ['TV', '>', 'HD'].
See https://forums.sabnzbd.org/viewtopic.php?f=3&t=23409
2018-05-30 07:53:51 +02:00
37 changed files with 368 additions and 260 deletions

3
.gitignore vendored
View File

@@ -16,8 +16,9 @@ SABnzbd*.exe
SABnzbd*.gz
SABnzbd*.dmg
# WingIDE project files
# WingIDE/PyCharm project files
*.wp[ru]
.idea
# Testing folders
.cache

View File

@@ -66,3 +66,7 @@
Config->Special->wait_for_dfolder to 1.
SABnzbd will appear to hang until the drive is mounted.
- If you experience speed-drops to KB/s when using a VPN, try setting the number of connections
to your servers to a total of 7. There is a CPU-usage reduction feature in SABnzbd that
gets confused by the way some VPN's handle the state of a connection. Below 8 connections
this feature is not active.

View File

@@ -1,7 +1,7 @@
Metadata-Version: 1.0
Name: SABnzbd
Version: 2.3.4
Summary: SABnzbd-2.3.4
Version: 2.3.5RC1
Summary: SABnzbd-2.3.5RC1
Home-page: https://sabnzbd.org
Author: The SABnzbd Team
Author-email: team@sabnzbd.org

View File

@@ -1,18 +1,22 @@
Release Notes - SABnzbd 2.3.4
Release Notes - SABnzbd 2.3.5 RC 1
=========================================================
## Changes since 2.3.3
- Device hostname in hostname-verification always lowercased
- Hostnames ending in ".local" are always accepted
- URLGrabber would not always detect correct filename
- URLGrabber would ignore some successful downloads
- Always send NNTP QUIT after server-test
- Added option "--disable-file-log" to disable file-based logging
- Added CORS-header to API
- Windows: Service compatibility with Windows 10 April update
- Windows: Update Python to 2.7.15
- Windows: Update 7zip to 18.05
- macOS: Restore compatibility with El Capitan (10.11)
## Bug fixes since 2.3.4
- Reworked Deobfuscate.py script for much faster renaming
- All scripts can now receive input through environment variables
- Unable to set only one Indexer Category per category
- Could falsely report not enough blocks are available for repair
- Direct Unpack could abort unnecessarily
- Rare crash during file assembly
- Server hostname is now used in warnings and logs
- Improved disk performance measurement
- Windows: Tray icon also shows remaining size when paused
- Windows: Wizard would not default to installer language
- Windows: Update MultiPar to 1.3.0.1
- Windows and macOS: Update UnRar to 5.60
Looking for help with SABnzbd development:
https://www.reddit.com/r/usenet/918nxv/
## Upgrading from 2.2.x and older
- Finish queue

View File

@@ -20,7 +20,6 @@ if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
print "Sorry, requires Python 2.6 or 2.7."
sys.exit(1)
import os
import time
import subprocess

View File

@@ -22,13 +22,13 @@
<p><strong>$T('opt-complete_dir')</strong></p>
<div class="quoteBlock">
$complete_dir
<a href="${access_url}config/folders" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
<a href="${access_url}/config/folders#complete_dir" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
</div>
<p><strong>$T('opt-download_dir')</strong></p>
<div class="quoteBlock">
$download_dir
<a href="${access_url}config/folders" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
<a href="${access_url}/config/folders#complete_dir" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
</div>
<hr/>

View File

Binary file not shown.

View File

@@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2018-03-15 13:08+0000\n"
"PO-Revision-Date: 2018-04-15 21:22+0000\n"
"Last-Translator: ciho <Unknown>\n"
"PO-Revision-Date: 2018-05-31 06:22+0000\n"
"Last-Translator: scope <Unknown>\n"
"Language-Team: German <de@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2018-04-16 05:40+0000\n"
"X-Generator: Launchpad (build 18610)\n"
"X-Launchpad-Export-Date: 2018-06-01 05:38+0000\n"
"X-Generator: Launchpad (build 18667)\n"
#: SABnzbd.py [Error message]
msgid "MultiPar binary... NOT found!"
@@ -63,7 +63,7 @@ msgstr ""
#: SABnzbd.py [Error message]
msgid "Downloads will not unpacked."
msgstr "Downloads werden nicht enpackt."
msgstr "Downloads werden nicht entpackt."
#: SABnzbd.py [Error message]
msgid "unrar binary... NOT found"

View File

@@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2018-03-15 13:08+0000\n"
"PO-Revision-Date: 2018-03-15 21:38+0000\n"
"PO-Revision-Date: 2018-06-17 21:21+0000\n"
"Last-Translator: ION IL <Unknown>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
"X-Generator: Launchpad (build 18571)\n"
"X-Launchpad-Export-Date: 2018-06-18 05:54+0000\n"
"X-Generator: Launchpad (build 18688)\n"
#: SABnzbd.py [Error message]
msgid "Failed to start web-interface"
@@ -198,7 +198,7 @@ msgstr "%s לא ניתן ליצור קובץ זמני עבור"
#: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message]
msgid "Trying to set status of non-existing server %s"
msgstr "%s מנסה לקבוע מצב של שרת בלתי-קיים"
msgstr "%s מנסה לקבוע מעמד של שרת בלתי קיים"
#: sabnzbd/__init__.py [Error message]
msgid "Failure in tempfile.mkstemp"
@@ -224,7 +224,7 @@ msgstr "&nbsp;פותר כתובת"
#: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files]
msgid "None"
msgstr "ללא"
msgstr "אין"
#: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus]
msgid "Default"
@@ -646,21 +646,21 @@ msgid ""
"API Key missing, please enter the api key from Config->General into your 3rd "
"party program:"
msgstr ""
"מתצורה->כללי לתוך תכנית הצד השלישי שלך api-חסר, אנא הכנס את מפתח ה API מפתח:"
"מתצורה->כללי לתוך תוכנית הצד השלישי שלך api-חסר, אנא הכנס את מפתח ה API מפתח:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"מתצורה->כללי בתכנית הצד השלישי שלך api-אינו נכון, השתמש במפתח ה API מפתח:"
"מתצורה->כללי בתוכנית הצד השלישי שלך api-אינו נכון, השתמש במפתח ה API מפתח:"
#: sabnzbd/interface.py
msgid ""
"Authentication missing, please enter username/password from Config->General "
"into your 3rd party program:"
msgstr ""
":אימות חסר, אנא הכנס שם משתמש/סיסמה מתוך תצורה->כללי לתוך תכנית הצד השלישי "
":אימות חסר, אנא הכנס שם משתמש/סיסמה מתוך תצורה->כללי לתוך תוכנית הצד השלישי "
"שלך"
#: sabnzbd/interface.py [Warning message]
@@ -998,7 +998,7 @@ msgstr "%s על ערכת par2_repair בזמן הרצת \"%s\" שגיאה"
#: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py
msgid ""
"[%s] PAR2 received incorrect options, check your Config->Switches settings"
msgstr "קיבל אפשרויות שגויות, בדוק את קביעות תצורה->מתגים שלך PAR2 [%s]"
msgstr "קיבל אפשרויות שגויות, בדוק את הגדרות תצורה->מתגים שלך PAR2 [%s]"
#: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py
msgid "[%s] Verified in %s, all files correct"
@@ -1090,7 +1090,7 @@ msgstr "וויקי"
#: sabnzbd/notifier.py [Notification]
msgid "Startup/Shutdown"
msgstr "אתחול / כיבוי"
msgstr "הזנק/כיבוי"
#: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue]
msgid "Added NZB"
@@ -1154,7 +1154,7 @@ msgstr "Windows נכשל בשליחת התראת"
#: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message]
msgid "Old queue detected, use Status->Repair to convert the queue"
msgstr "תור ישן התגלה, השתמש במצב->תיקון כדי להמיר את התור"
msgstr "תור ישן התגלה, השתמש במעמד->תיקון כדי להמיר את התור"
#: sabnzbd/nzbqueue.py [Error message]
msgid "Incompatible queuefile found, cannot proceed"
@@ -1442,9 +1442,9 @@ msgid ""
msgstr ""
"\n"
" אחרת SABnzbd גילה נתונים שמורים מגרסת SABnzbd<br>\n"
" .אבל אינו יכול להשתמש מחדש בנתונים של התכנית האחרת<br><br>\n"
" .אתה אולי תרצה לסיים את התור שלך תחילה עם התכנית האחרת<br><br>\n"
" .\"--clean\" לאחר מכן, התחל תכנית זו עם האפשרות<br>\n"
" .אבל אינו יכול להשתמש מחדש בנתונים של התוכנית האחרת<br><br>\n"
" .אתה אולי תרצה לסיים את התור שלך תחילה עם התוכנית האחרת<br><br>\n"
" .\"--clean\" לאחר מכן, התחל תוכנית זו עם האפשרות<br>\n"
" !זה ימחק את התור וההיסטוריה הנוכחיים<br>\n"
" .\"%s\" קרא את הקובץ SABnzbd"
@@ -1457,7 +1457,7 @@ msgid ""
msgstr ""
"\n"
" .%s-אינו יכול למצוא את קבצי ממשק הרשת שלו ב SABnzbd<br>\n"
" .אנא התקן את התכנית שוב<br>\n"
" .אנא התקן את התוכנית שוב<br>\n"
" <br>\n"
#: sabnzbd/panic.py
@@ -1490,7 +1490,7 @@ msgstr "פתח חלון מסוף והקלד את הקו (דוגמה):"
#: sabnzbd/panic.py
msgid "Program did not start!"
msgstr "!התכנית לא התחילה"
msgstr "!התוכנית לא התחילה"
#: sabnzbd/panic.py
msgid ""
@@ -2147,7 +2147,7 @@ msgstr "הגדר"
#: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header]
msgid "Status"
msgstr "מצב"
msgstr "מעמד"
#: sabnzbd/skintext.py [Main menu item]
msgid "Help"
@@ -2235,7 +2235,7 @@ msgstr "שחרור חדש %s זמין ב"
#: sabnzbd/skintext.py
msgid "Are you sure you want to shutdown SABnzbd?"
msgstr "?SABnzbd האם אתה בטוח שברצונך לכבות את"
msgstr "?SABnzbd האם אתה בטוח שאתה רוצה לכבות את"
#: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)]
msgid "Add"
@@ -2611,7 +2611,7 @@ msgid ""
"stability problem.<br />Downloading will be paused before the restart and "
"resume afterwards."
msgstr ""
".SABnzbd זה יפעיל מחדש את<br />השתמש בזה כשאתה חושב שלתכנית יש בעית "
".SABnzbd זה יפעיל מחדש את<br />השתמש בזה כשאתה חושב שלתוכנית יש בעית "
"יציבות.<br />הורדה תושהה לפני ההפעלה מחדש ותומשך לאחר מכן."
#: sabnzbd/skintext.py
@@ -2920,7 +2920,7 @@ msgstr ""
#: sabnzbd/skintext.py
msgid "This key will give 3rd party programs full access to SABnzbd."
msgstr ".SABnzbd מפתח זה יתן לתכניות צד שלישי גישה מלאה אל"
msgstr ".SABnzbd מפתח זה יתן לתוכניות צד שלישי גישה מלאה אל"
#: sabnzbd/skintext.py
msgid "NZB Key"
@@ -2928,7 +2928,7 @@ msgstr "NZB מפתח"
#: sabnzbd/skintext.py
msgid "This key will allow 3rd party programs to add NZBs to SABnzbd."
msgstr ".SABnzbd אל NZB מפתח זה יתיר לתכניות צד שלישי להוסיף קבצי"
msgstr ".SABnzbd אל NZB מפתח זה יתיר לתוכניות צד שלישי להוסיף קבצי"
#: sabnzbd/skintext.py
msgid "Generate New Key"
@@ -3353,7 +3353,7 @@ msgid ""
"Posts will be paused untill they are at least this age. Setting job priority "
"to Force will skip the delay."
msgstr ""
".רשומות יושהו עד שהן לפחות בגיל זה. קביעת עדיפות עבודה אל אילוץ תדלג על "
".רשומות יושהו עד שהן לפחות בגיל זה. הגדרת עדיפות עבודה אל אילוץ תדלג על "
"העיכוב"
#: sabnzbd/skintext.py
@@ -3394,7 +3394,7 @@ msgstr ".Windows עבור שרתים: וודא שהשמות תואמים עם"
#: sabnzbd/skintext.py
msgid "Launch Browser on Startup"
msgstr "הפעל דפדפן באתחול"
msgstr "הפעל דפדפן בהזנק"
#: sabnzbd/skintext.py
msgid "Launch the default web browser when starting SABnzbd."
@@ -4391,7 +4391,7 @@ msgstr "SABnzbd הפעל מחדש את"
#: sabnzbd/skintext.py
msgid "Status and interface options"
msgstr "אפשרויות מצב וממשק"
msgstr "אפשרויות של מעמד וממשק"
#: sabnzbd/skintext.py
msgid "Or drag and drop files in the window!"
@@ -4419,7 +4419,7 @@ msgstr "קצב רענון"
#: sabnzbd/skintext.py
msgid "Use global interface settings"
msgstr "השתמש בקביעות ממשק עולמיות"
msgstr "השתמש בהגדרות ממשק עולמיות"
#: sabnzbd/skintext.py
msgid "Queue item limit"
@@ -4534,7 +4534,7 @@ msgid ""
"LocalStorage (cookies) are disabled in your browser, interface settings will "
"be lost after you close the browser!"
msgstr ""
"!אחסון מקומי (עוגיות) מושבת בדפדפן שלך, קביעות ממשק יאבדו לאחר שתסגור את "
"!אחסון מקומי (עוגיות) מושבת בדפדפן שלך, הגדרות ממשק יאבדו לאחר שתסגור את "
"הדפדפן"
#: sabnzbd/skintext.py
@@ -4833,7 +4833,7 @@ msgstr "תצוגה כפולה 2"
#: sabnzbd/skintext.py
msgid "Are you sure you want to restart SABnzbd?"
msgstr "?SABnzbd האם אתה בטוח שברצונך להפעיל מחדש את"
msgstr "?SABnzbd האם אתה בטוח שאתה רוצה להפעיל מחדש את"
#: sabnzbd/skintext.py
msgid "Hide Edit Options"

View File

@@ -28,9 +28,9 @@ from time import sleep
import hashlib
import sabnzbd
from sabnzbd.misc import get_filepath, sanitize_filename, get_unique_filename, renamer, \
set_permissions, long_path, clip_path, has_win_device, get_all_passwords, diskspace, \
get_filename, get_ext
from sabnzbd.misc import get_filepath, sanitize_filename, set_permissions, \
long_path, clip_path, has_win_device, get_all_passwords, diskspace, \
get_filename, get_ext, is_rarfile
from sabnzbd.constants import Status, GIGI
import sabnzbd.cfg as cfg
from sabnzbd.articlecache import ArticleCache
@@ -117,7 +117,7 @@ class Assembler(Thread):
nzf.remove_admin()
# Do rar-related processing
if rarfile.is_rarfile(filepath):
if is_rarfile(filepath):
# Encryption and unwanted extension detection
rar_encrypted, unwanted_file = check_encrypted_and_unwanted_files(nzo, filepath)
if rar_encrypted:
@@ -246,7 +246,7 @@ def check_encrypted_and_unwanted_files(nzo, filepath):
return encrypted, unwanted
# Is it even a rarfile?
if rarfile.is_rarfile(filepath):
if is_rarfile(filepath):
# Open the rar
rarfile.UNRAR_TOOL = sabnzbd.newsunpack.RAR_COMMAND
zf = rarfile.RarFile(filepath, all_names=True)

View File

@@ -463,7 +463,7 @@ class ConfigCat(object):
self.pp = OptionStr(name, 'pp', '', add=False)
self.script = OptionStr(name, 'script', 'Default', add=False)
self.dir = OptionDir(name, 'dir', add=False, create=False)
self.newzbin = OptionList(name, 'newzbin', add=False)
self.newzbin = OptionList(name, 'newzbin', add=False, validation=validate_single_tag)
self.priority = OptionNumber(name, 'priority', DEFAULT_PRIORITY, add=False)
self.set_dict(values)
@@ -1102,6 +1102,16 @@ def validate_notempty(root, value, default):
return None, default
def validate_single_tag(value):
""" Don't split single indexer tags like "TV > HD"
into ['TV', '>', 'HD']
"""
if len(value) == 3:
if value[1] == '>':
return None, ' '.join(value)
return None, value
def create_api_key():
""" Return a new randomized API_KEY """
# Create some values to seed md5

View File

@@ -40,7 +40,7 @@ from sabnzbd.constants import DB_HISTORY_NAME, STAGES
from sabnzbd.encoding import unicoder
from sabnzbd.bpsmeter import this_week, this_month
from sabnzbd.decorators import synchronized
from sabnzbd.misc import get_all_passwords, int_conv, remove_file, caller_name
from sabnzbd.misc import int_conv, remove_file, caller_name
DB_LOCK = threading.RLock()

View File

@@ -28,9 +28,10 @@ import logging
import sabnzbd
import sabnzbd.cfg as cfg
from sabnzbd.misc import int_conv, clip_path, long_path, remove_all, globber, \
format_time_string, has_win_device, real_path, remove_file
from sabnzbd.misc import int_conv, clip_path, long_path, remove_all, \
format_time_string, real_path, remove_file
from sabnzbd.encoding import TRANS, unicoder
from sabnzbd.decorators import synchronized
from sabnzbd.newsunpack import build_command, EXTRACTFROM_RE, EXTRACTED_RE, rar_volumelist
from sabnzbd.postproc import prepare_extraction_path
from sabnzbd.utils.rarfile import RarFile
@@ -46,6 +47,10 @@ if sabnzbd.WIN32:
# Load the regular POpen (which is now patched on Windows)
from subprocess import Popen
# Need a lock to make sure start and stop is handled correctlty
# Otherwise we could stop while the thread was still starting
START_STOP_LOCK = threading.RLock()
MAX_ACTIVE_UNPACKERS = 10
ACTIVE_UNPACKERS = []
@@ -110,6 +115,7 @@ class DirectUnpacker(threading.Thread):
if none_counter > found_counter:
self.total_volumes = {}
@synchronized(START_STOP_LOCK)
def add(self, nzf):
""" Add jobs and start instance of DirectUnpack """
if not cfg.direct_unpack_tested():
@@ -309,6 +315,7 @@ class DirectUnpacker(threading.Thread):
with self.next_file_lock:
self.next_file_lock.wait()
@synchronized(START_STOP_LOCK)
def create_unrar_instance(self):
""" Start the unrar instance using the user's options """
# Generate extraction path and save for post-proc
@@ -366,9 +373,10 @@ class DirectUnpacker(threading.Thread):
# Doing the first
logging.info('DirectUnpacked volume %s for %s', self.cur_volume, self.cur_setname)
@synchronized(START_STOP_LOCK)
def abort(self):
""" Abort running instance and delete generated files """
if not self.killed:
if not self.killed and self.cur_setname:
logging.info('Aborting DirectUnpack for %s', self.cur_setname)
self.killed = True

View File

@@ -76,7 +76,7 @@ def is_archive(path):
except:
logging.info(T('Cannot read %s'), path, exc_info=True)
return -1, None, ''
elif rarfile.is_rarfile(path):
elif misc.is_rarfile(path):
try:
# Set path to tool to open it
rarfile.UNRAR_TOOL = sabnzbd.newsunpack.RAR_COMMAND

View File

@@ -369,24 +369,24 @@ class Downloader(Thread):
# Was it resolving problem?
if server.info is False:
# Warn about resolving issues
errormsg = T('Cannot connect to server %s [%s]') % (server.id, T('Server name does not resolve'))
errormsg = T('Cannot connect to server %s [%s]') % (server.host, T('Server name does not resolve'))
if server.errormsg != errormsg:
server.errormsg = errormsg
logging.warning(errormsg)
logging.warning(T('Server %s will be ignored for %s minutes'), server.id, _PENALTY_TIMEOUT)
logging.warning(T('Server %s will be ignored for %s minutes'), server.host, _PENALTY_TIMEOUT)
# Not fully the same as the code below for optional servers
server.bad_cons = 0
server.active = False
self.plan_server(server.id, _PENALTY_TIMEOUT)
self.plan_server(server, _PENALTY_TIMEOUT)
# Optional and active server had too many problems.
# Disable it now and send a re-enable plan to the scheduler
if server.optional and server.active and (server.bad_cons / server.threads) > 3:
server.bad_cons = 0
server.active = False
logging.warning(T('Server %s will be ignored for %s minutes'), server.id, _PENALTY_TIMEOUT)
self.plan_server(server.id, _PENALTY_TIMEOUT)
logging.warning(T('Server %s will be ignored for %s minutes'), server.host, _PENALTY_TIMEOUT)
self.plan_server(server, _PENALTY_TIMEOUT)
# Remove all connections to server
for nw in server.idle_threads + server.busy_threads:
@@ -472,7 +472,7 @@ class Downloader(Thread):
if server.retention and article.nzf.nzo.avg_stamp < time.time() - server.retention:
# Let's get rid of all the articles for this server at once
logging.info('Job %s too old for %s, moving on', article.nzf.nzo.work_name, server.id)
logging.info('Job %s too old for %s, moving on', article.nzf.nzo.work_name, server.host)
while article:
self.decode(article, None, None)
article = article.nzf.nzo.get_article(server, self.servers)
@@ -487,10 +487,10 @@ class Downloader(Thread):
self.__request_article(nw)
else:
try:
logging.info("%s@%s: Initiating connection", nw.thrdnum, server.id)
logging.info("%s@%s: Initiating connection", nw.thrdnum, server.host)
nw.init_connect(self.write_fds)
except:
logging.error(T('Failed to initialize %s@%s with reason: %s'), nw.thrdnum, server.id, sys.exc_info()[1])
logging.error(T('Failed to initialize %s@%s with reason: %s'), nw.thrdnum, server.host, sys.exc_info()[1])
self.__reset_nw(nw, "failed to initialize")
# Exit-point
@@ -619,7 +619,7 @@ class Downloader(Thread):
try:
nw.finish_connect(nw.status_code)
if sabnzbd.LOG_ALL:
logging.debug("%s@%s last message -> %s", nw.thrdnum, nw.server.id, nntp_to_msg(nw.data))
logging.debug("%s@%s last message -> %s", nw.thrdnum, nw.server.host, nntp_to_msg(nw.data))
nw.clear_data()
except NNTPPermanentError, error:
# Handle login problems
@@ -636,9 +636,9 @@ class Downloader(Thread):
errormsg = T('Too many connections to server %s') % display_msg
if server.errormsg != errormsg:
server.errormsg = errormsg
logging.warning(T('Too many connections to server %s'), server.id)
logging.warning(T('Too many connections to server %s'), server.host)
self.__reset_nw(nw, None, warn=False, destroy=True, quit=True)
self.plan_server(server.id, _PENALTY_TOOMANY)
self.plan_server(server, _PENALTY_TOOMANY)
server.threads -= 1
elif ecode in ('502', '481', '482') and clues_too_many_ip(msg):
# Account sharing?
@@ -646,7 +646,7 @@ class Downloader(Thread):
errormsg = T('Probable account sharing') + display_msg
if server.errormsg != errormsg:
server.errormsg = errormsg
name = ' (%s)' % server.id
name = ' (%s)' % server.host
logging.warning(T('Probable account sharing') + name)
penalty = _PENALTY_SHARE
block = True
@@ -656,7 +656,7 @@ class Downloader(Thread):
errormsg = T('Failed login for server %s') % display_msg
if server.errormsg != errormsg:
server.errormsg = errormsg
logging.error(T('Failed login for server %s'), server.id)
logging.error(T('Failed login for server %s'), server.host)
penalty = _PENALTY_PERM
block = True
elif ecode in ('502', '482'):
@@ -665,7 +665,7 @@ class Downloader(Thread):
errormsg = T('Cannot connect to server %s [%s]') % ('', display_msg)
if server.errormsg != errormsg:
server.errormsg = errormsg
logging.warning(T('Cannot connect to server %s [%s]'), server.id, msg)
logging.warning(T('Cannot connect to server %s [%s]'), server.host, msg)
if clues_pay(msg):
penalty = _PENALTY_PERM
else:
@@ -674,7 +674,7 @@ class Downloader(Thread):
elif ecode == '400':
# Temp connection problem?
if server.active:
logging.debug('Unspecified error 400 from server %s', server.id)
logging.debug('Unspecified error 400 from server %s', server.host)
penalty = _PENALTY_VERYSHORT
block = True
else:
@@ -683,25 +683,25 @@ class Downloader(Thread):
errormsg = T('Cannot connect to server %s [%s]') % ('', display_msg)
if server.errormsg != errormsg:
server.errormsg = errormsg
logging.warning(T('Cannot connect to server %s [%s]'), server.id, msg)
logging.warning(T('Cannot connect to server %s [%s]'), server.host, msg)
penalty = _PENALTY_UNKNOWN
block = True
if block or (penalty and server.optional):
if server.active:
server.active = False
if penalty and (block or server.optional):
self.plan_server(server.id, penalty)
self.plan_server(server, penalty)
sabnzbd.nzbqueue.NzbQueue.do.reset_all_try_lists()
self.__reset_nw(nw, None, warn=False, quit=True)
continue
except:
logging.error(T('Connecting %s@%s failed, message=%s'),
nw.thrdnum, nw.server.id, nntp_to_msg(nw.data))
nw.thrdnum, nw.server.host, nntp_to_msg(nw.data))
# No reset-warning needed, above logging is sufficient
self.__reset_nw(nw, None, warn=False)
if nw.connected:
logging.info("Connecting %s@%s finished", nw.thrdnum, nw.server.id)
logging.info("Connecting %s@%s finished", nw.thrdnum, nw.server.host)
self.__request_article(nw)
elif nw.status_code == '223':
@@ -718,27 +718,27 @@ class Downloader(Thread):
elif nw.status_code in ('411', '423', '430'):
done = True
logging.debug('Thread %s@%s: Article %s missing (error=%s)',
nw.thrdnum, nw.server.id, article.article, nw.status_code)
nw.thrdnum, nw.server.host, article.article, nw.status_code)
nw.clear_data()
elif nw.status_code == '480':
if server.active:
server.active = False
server.errormsg = T('Server %s requires user/password') % ''
self.plan_server(server.id, 0)
self.plan_server(server, 0)
sabnzbd.nzbqueue.NzbQueue.do.reset_all_try_lists()
msg = T('Server %s requires user/password') % nw.server.id
msg = T('Server %s requires user/password') % nw.server.host
self.__reset_nw(nw, msg, quit=True)
elif nw.status_code == '500':
if nzo.precheck:
# Assume "STAT" command is not supported
server.have_stat = False
logging.debug('Server %s does not support STAT', server.id)
logging.debug('Server %s does not support STAT', server.host)
else:
# Assume "BODY" command is not supported
server.have_body = False
logging.debug('Server %s does not support BODY', server.id)
logging.debug('Server %s does not support BODY', server.host)
nw.clear_data()
self.__request_article(nw)
@@ -746,7 +746,7 @@ class Downloader(Thread):
server.bad_cons = 0 # Succesful data, clear "bad" counter
server.errormsg = server.warning = ''
if sabnzbd.LOG_ALL:
logging.debug('Thread %s@%s: %s done', nw.thrdnum, server.id, article.article)
logging.debug('Thread %s@%s: %s done', nw.thrdnum, server.host, article.article)
self.decode(article, nw.lines, nw.data)
nw.soft_reset()
@@ -778,9 +778,9 @@ class Downloader(Thread):
if warn and errormsg:
server.warning = errormsg
logging.info('Thread %s@%s: ' + errormsg, nw.thrdnum, server.id)
logging.info('Thread %s@%s: ' + errormsg, nw.thrdnum, server.host)
elif errormsg:
logging.info('Thread %s@%s: ' + errormsg, nw.thrdnum, server.id)
logging.info('Thread %s@%s: ' + errormsg, nw.thrdnum, server.host)
if nw in server.busy_threads:
server.busy_threads.remove(nw)
@@ -814,11 +814,11 @@ class Downloader(Thread):
if nw.server.send_group and nzo.group != nw.group:
group = nzo.group
if sabnzbd.LOG_ALL:
logging.debug('Thread %s@%s: GROUP <%s>', nw.thrdnum, nw.server.id, group)
logging.debug('Thread %s@%s: GROUP <%s>', nw.thrdnum, nw.server.host, group)
nw.send_group(group)
else:
if sabnzbd.LOG_ALL:
logging.debug('Thread %s@%s: BODY %s', nw.thrdnum, nw.server.id, nw.article.article)
logging.debug('Thread %s@%s: BODY %s', nw.thrdnum, nw.server.host, nw.article.article)
nw.body(nzo.precheck)
fileno = nw.nntp.sock.fileno()
@@ -840,24 +840,24 @@ class Downloader(Thread):
# Each server has a dictionary entry, consisting of a list of timestamps.
@synchronized(TIMER_LOCK)
def plan_server(self, server_id, interval):
def plan_server(self, server, interval):
""" Plan the restart of a server in 'interval' minutes """
if cfg.no_penalties() and interval > _PENALTY_SHORT:
# Overwrite in case of no_penalties
interval = _PENALTY_SHORT
logging.debug('Set planned server resume %s in %s mins', server_id, interval)
if server_id not in self._timers:
self._timers[server_id] = []
logging.debug('Set planned server resume %s in %s mins', server.host, interval)
if server.id not in self._timers:
self._timers[server.id] = []
stamp = time.time() + 60.0 * interval
self._timers[server_id].append(stamp)
self._timers[server.id].append(stamp)
if interval:
sabnzbd.scheduler.plan_server(self.trigger_server, [server_id, stamp], interval)
sabnzbd.scheduler.plan_server(self.trigger_server, [server.id, stamp], interval)
@synchronized(TIMER_LOCK)
def trigger_server(self, server_id, timestamp):
""" Called by scheduler, start server if timer still valid """
logging.debug('Trigger planned server resume %s', server_id)
logging.debug('Trigger planned server resume for server-id %s', server_id)
if server_id in self._timers:
if timestamp in self._timers[server_id]:
del self._timers[server_id]
@@ -874,7 +874,7 @@ class Downloader(Thread):
# Activate server if it was inactive
for server in self.servers:
if server.id == server_id and not server.active:
logging.debug('Unblock server %s', server_id)
logging.debug('Unblock server %s', server.host)
self.init_server(server_id, server_id)
break
@@ -891,7 +891,7 @@ class Downloader(Thread):
kicked = []
for server_id in self._timers.keys():
if not [stamp for stamp in self._timers[server_id] if stamp >= now]:
logging.debug('Forcing re-evaluation of server %s', server_id)
logging.debug('Forcing re-evaluation of server-id %s', server_id)
del self._timers[server_id]
self.init_server(server_id, server_id)
kicked.append(server_id)
@@ -899,7 +899,7 @@ class Downloader(Thread):
for server in self.servers:
if server.id not in self._timers:
if server.id not in kicked and not server.active:
logging.debug('Forcing activation of server %s', server.id)
logging.debug('Forcing activation of server %s', server.host)
self.init_server(server.id, server.id)
def update_server(self, oldserver, newserver):

View File

@@ -44,7 +44,6 @@ from sabnzbd.misc import real_path, to_units, from_units, time_format, \
long_path, calc_age, same_file, probablyipv4, probablyipv6, \
int_conv, globber, globber_full, remove_all, get_base_url
from sabnzbd.newswrapper import GetServerParms
from sabnzbd.rating import Rating
from sabnzbd.bpsmeter import BPSMeter
from sabnzbd.encoding import TRANS, xml_name, LatinFilter, unicoder, special_fixer, \
platform_encode
@@ -59,13 +58,13 @@ from sabnzbd.decoder import HAVE_YENC, SABYENC_ENABLED
from sabnzbd.utils.diskspeed import diskspeedmeasure
from sabnzbd.utils.getperformance import getpystone
from sabnzbd.constants import NORMAL_PRIORITY, MEBI, DEF_SKIN_COLORS, DEF_STDINTF, \
from sabnzbd.constants import NORMAL_PRIORITY, MEBI, DEF_SKIN_COLORS, \
DEF_STDCONFIG, DEF_MAIN_TMPL, DEFAULT_PRIORITY
from sabnzbd.lang import list_languages
from sabnzbd.api import list_scripts, list_cats, del_from_section, \
api_handler, build_queue, remove_callable, rss_qstatus, build_status, \
api_handler, build_queue, remove_callable, build_status, \
retry_job, retry_all_jobs, build_header, build_history, del_job_files, \
format_bytes, std_time, report, del_hist_job, Ttemplate, build_queue_header, \
_api_test_email, _api_test_notif

View File

@@ -44,6 +44,7 @@ from sabnzbd.constants import DEFAULT_PRIORITY, FUTURE_Q_FOLDER, JOB_ADMIN, \
import sabnzbd.config as config
import sabnzbd.cfg as cfg
from sabnzbd.encoding import unicoder, special_fixer, gUTF
import sabnzbd.utils.rarfile as rarfile
TAB_UNITS = ('', 'K', 'M', 'G', 'T', 'P')
RE_UNITS = re.compile(r'(\d+\.*\d*)\s*([KMGTP]{0,1})', re.I)
@@ -1241,6 +1242,14 @@ def get_admin_path(name, future):
return os.path.join(os.path.join(cfg.download_dir.get_path(), name), JOB_ADMIN)
def is_rarfile(rarfile_path):
""" Wrapper in case it crashes due to missing file or long-path problems """
try:
return rarfile.is_rarfile(rarfile_path)
except:
return False
def on_cleanup_list(filename, skip_nzb=False):
""" Return True if a filename matches the clean-up list """
lst = cfg.cleanup_list()

View File

@@ -32,8 +32,8 @@ import sabnzbd
from sabnzbd.encoding import TRANS, unicoder, platform_encode, deunicode
import sabnzbd.utils.rarfile as rarfile
from sabnzbd.misc import format_time_string, find_on_path, make_script_path, int_conv, \
real_path, globber, globber_full, get_all_passwords, renamer, clip_path, \
has_win_device, calc_age, long_path, remove_file, recursive_listdir
real_path, globber, globber_full, get_all_passwords, renamer, clip_path, calc_age, \
has_win_device, long_path, remove_file, recursive_listdir, is_rarfile
from sabnzbd.sorting import SeriesSorter
import sabnzbd.cfg as cfg
from sabnzbd.constants import Status
@@ -159,14 +159,7 @@ def external_processing(extern_proc, nzo, complete_dir, nicename, status):
'download_time': nzo.nzo_info.get('download_time', ''),
'avg_bps': int(nzo.avg_bps_total / nzo.avg_bps_freq) if nzo.avg_bps_freq else 0,
'age': calc_age(nzo.avg_date),
'orig_nzb_gz': clip_path(nzb_paths[0]) if nzb_paths else '',
'program_dir': sabnzbd.DIR_PROG,
'par2_command': sabnzbd.newsunpack.PAR2_COMMAND,
'multipar_command': sabnzbd.newsunpack.MULTIPAR_COMMAND,
'rar_command': sabnzbd.newsunpack.RAR_COMMAND,
'zip_command': sabnzbd.newsunpack.ZIP_COMMAND,
'7zip_command': sabnzbd.newsunpack.SEVEN_COMMAND,
'version': sabnzbd.__version__}
'orig_nzb_gz': clip_path(nzb_paths[0]) if nzb_paths else ''}
try:
stup, need_shell, command, creationflags = build_command(command)
@@ -510,6 +503,8 @@ def rar_unpack(nzo, workdir, workdir_complete, delete, one_folder, rars):
if wait_count > 60:
# We abort after 2 minutes of no changes
nzo.direct_unpacker.abort()
else:
wait_count = 0
last_stats = nzo.direct_unpacker.get_formatted_stats()
# Did we already direct-unpack it? Not when recursive-unpacking
@@ -656,7 +651,7 @@ def rar_extract_core(rarfile_path, numrars, one_folder, nzo, setname, extraction
stup, need_shell, command, creationflags = build_command(command, flatten_command=True)
# Get list of all the volumes part of this set
logging.debug("Analyzing rar file ... %s found", rarfile.is_rarfile(rarfile_path))
logging.debug("Analyzing rar file ... %s found", is_rarfile(rarfile_path))
logging.debug("Running unrar %s", command)
p = Popen(command, shell=need_shell, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
@@ -1337,7 +1332,7 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, single=False):
block_table = {}
for nzf in nzo.extrapars[setname]:
if not nzf.completed:
block_table[int_conv(nzf.blocks)] = nzf
block_table[nzf.blocks] = nzf
if block_table:
nzf = block_table[min(block_table.keys())]
@@ -1650,7 +1645,7 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, single=False)
block_table = {}
for nzf in nzo.extrapars[setname]:
if not nzf.completed:
block_table[int_conv(nzf.blocks)] = nzf
block_table[nzf.blocks] = nzf
if block_table:
nzf = block_table[min(block_table.keys())]
@@ -1921,7 +1916,7 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, single=False)
return finished, readd, datafiles, used_joinables, used_for_repair
def create_env(nzo=None, extra_env_fields=None):
def create_env(nzo=None, extra_env_fields={}):
""" Modify the environment for pp-scripts with extra information
OSX: Return copy of environment without PYTHONPATH and PYTHONHOME
other: return None
@@ -1945,16 +1940,25 @@ def create_env(nzo=None, extra_env_fields=None):
# Catch key/unicode errors
pass
# Add extra fields
for field in extra_env_fields:
try:
if extra_env_fields[field] is not None:
env['SAB_' + field.upper()] = extra_env_fields[field]
else:
env['SAB_' + field.upper()] = ''
except:
# Catch key/unicode errors
pass
# Always supply basic info
extra_env_fields.update({'program_dir': sabnzbd.DIR_PROG,
'par2_command': sabnzbd.newsunpack.PAR2_COMMAND,
'multipar_command': sabnzbd.newsunpack.MULTIPAR_COMMAND,
'rar_command': sabnzbd.newsunpack.RAR_COMMAND,
'zip_command': sabnzbd.newsunpack.ZIP_COMMAND,
'7zip_command': sabnzbd.newsunpack.SEVEN_COMMAND,
'version': sabnzbd.__version__})
# Add extra fields
for field in extra_env_fields:
try:
if extra_env_fields[field] is not None:
env['SAB_' + field.upper()] = extra_env_fields[field]
else:
env['SAB_' + field.upper()] = ''
except:
# Catch key/unicode errors
pass
if sabnzbd.DARWIN:
if 'PYTHONPATH' in env:
@@ -2099,11 +2103,7 @@ def build_filelists(workdir, workdir_complete=None, check_both=False, check_rar=
# Extra check for rar (takes CPU/disk)
file_is_rar = False
if check_rar:
try:
# Can fail on Windows due to long-path after recursive-unpack
file_is_rar = rarfile.is_rarfile(file)
except:
pass
file_is_rar = is_rarfile(file)
# Run through all the checks
if SEVENZIP_RE.search(file) or SEVENMULTI_RE.search(file):
@@ -2295,23 +2295,33 @@ def analyse_show(name):
info.get('ep_name', '')
def pre_queue(name, pp, cat, script, priority, size, groups):
""" Run pre-queue script (if any) and process results """
def pre_queue(nzo, pp, cat):
""" Run pre-queue script (if any) and process results.
pp and cat are supplied seperate since they can change.
"""
def fix(p):
if not p or str(p).lower() == 'none':
return ''
return unicoder(p)
values = [1, name, pp, cat, script, priority, None]
values = [1, nzo.final_name_pw_clean, pp, cat, nzo.script, nzo.priority, None]
script_path = make_script_path(cfg.pre_script())
if script_path:
command = [script_path, name, pp, cat, script, priority, str(size), ' '.join(groups)]
command.extend(analyse_show(name))
# Basic command-line parameters
command = [script_path, nzo.final_name_pw_clean, pp, cat, nzo.script, nzo.priority, str(nzo.bytes), ' '.join(nzo.groups)]
command.extend(analyse_show(nzo.final_name_pw_clean))
command = [fix(arg) for arg in command]
# Fields not in the NZO directly
extra_env_fields = {'groups': ' '.join(nzo.groups),
'show_name': command[8],
'show_season': command[9],
'show_episode': command[10],
'show_episode_name': command[11]}
try:
stup, need_shell, command, creationflags = build_command(command)
env = create_env()
env = create_env(nzo, extra_env_fields)
logging.info('Running pre-queue script %s', command)
p = Popen(command, shell=need_shell, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
@@ -2332,11 +2342,11 @@ def pre_queue(name, pp, cat, script, priority, size, groups):
n += 1
accept = int_conv(values[0])
if accept < 1:
logging.info('Pre-Q refuses %s', name)
logging.info('Pre-Q refuses %s', nzo.final_name_pw_clean)
elif accept == 2:
logging.info('Pre-Q accepts&fails %s', name)
logging.info('Pre-Q accepts&fails %s', nzo.final_name_pw_clean)
else:
logging.info('Pre-Q accepts %s', name)
logging.info('Pre-Q accepts %s', nzo.final_name_pw_clean)
return values

View File

@@ -25,7 +25,6 @@ from threading import Thread
from nntplib import NNTPPermanentError
import time
import logging
import re
import ssl
import sabnzbd

View File

@@ -23,7 +23,6 @@ sabnzbd.notifier - Send notifications to any notification services
from __future__ import with_statement
import os.path
import logging
import socket
import urllib2
import httplib
import urllib

View File

@@ -324,7 +324,7 @@ class NzbFile(TryList):
self.is_par2 = True
self.setname = setname
self.vol = vol
self.blocks = int(blocks)
self.blocks = int_conv(blocks)
def get_article(self, server, servers):
""" Get next article to be downloaded """
@@ -827,9 +827,9 @@ class NzbObject(TryList):
# Run user pre-queue script if needed
if not reuse and cfg.pre_script():
accept, name, pp, cat_pp, script_pp, priority, group = \
sabnzbd.newsunpack.pre_queue(self.final_name_pw_clean, pp, cat, script,
priority, self.bytes, self.groups)
# Call the script
accept, name, pp, cat_pp, script_pp, priority, group = sabnzbd.newsunpack.pre_queue(self, pp, cat)
# Accept or reject
accept = int_conv(accept)
if accept < 1:
@@ -1098,38 +1098,37 @@ class NzbObject(TryList):
def get_extra_blocks(self, setname, needed_blocks):
""" We want par2-files of all sets that are similar to this one
So that we also can handle multi-sets with duplicate filenames
Block-table has as keys the nr-blocks
Returns number of added blocks in case they are available
In case of duplicate files for the same set, we might add too
little par2 on the first add-run, but that's a risk we need to take.
"""
logging.info('Need %s more blocks, checking blocks', needed_blocks)
avail_blocks = 0
block_table = {}
block_list = []
for setname_search in self.extrapars:
# Do it for our set, or highlight matching one
# We might catch to many par2's, but that's okay
# We might catch too many par2's, but that's okay
if setname_search == setname or difflib.SequenceMatcher(None, setname, setname_search).ratio() > 0.85:
for nzf in self.extrapars[setname_search]:
# Don't count extrapars that are completed already
if nzf.completed:
continue
blocks = int_conv(nzf.blocks)
if blocks not in block_table:
block_table[blocks] = []
# We assume same block-vol-naming for each set
avail_blocks += blocks
block_table[blocks].append(nzf)
block_list.append(nzf)
avail_blocks += nzf.blocks
# Sort by smallest blocks first
block_list.sort(key=lambda x: x.blocks)
logging.info('%s blocks available', avail_blocks)
# Enough?
if avail_blocks >= needed_blocks:
added_blocks = 0
while added_blocks < needed_blocks:
block_size = min(block_table.keys())
for new_nzf in block_table[block_size]:
self.add_parfile(new_nzf)
added_blocks += block_size
block_table.pop(block_size)
new_nzf = block_list.pop()
self.add_parfile(new_nzf)
added_blocks += new_nzf.blocks
logging.info('Added %s blocks to %s', added_blocks, self.final_name)
return added_blocks
else:
@@ -1407,7 +1406,7 @@ class NzbObject(TryList):
if (parset in nzf.filename or parset in original_filename) and self.extrapars[parset]:
for new_nzf in self.extrapars[parset]:
self.add_parfile(new_nzf)
blocks_new += int_conv(new_nzf.blocks)
blocks_new += new_nzf.blocks
# Enough now?
if blocks_new >= self.bad_articles:
logging.info('Prospectively added %s repair blocks to %s', blocks_new, self.final_name)
@@ -1502,11 +1501,11 @@ class NzbObject(TryList):
self.set_unpack_info('Servers', ', '.join(msgs), unique=True)
@synchronized(NZO_LOCK)
def increase_bad_articles_counter(self, type):
def increase_bad_articles_counter(self, article_type):
""" Record information about bad articles """
if type not in self.nzo_info:
self.nzo_info[type] = 0
self.nzo_info[type] += 1
if article_type not in self.nzo_info:
self.nzo_info[article_type] = 0
self.nzo_info[article_type] += 1
self.bad_articles += 1
def get_article(self, server, servers):

View File

@@ -26,7 +26,9 @@ import struct
PROBABLY_PAR2_RE = re.compile(r'(.*)\.vol(\d*)[\+\-](\d*)\.par2', re.I)
PAR_ID = "PAR2\x00PKT"
PAR_PKT_ID = "PAR2\x00PKT"
PAR_FILE_ID = "PAR 2.0\x00FileDesc"
PAR_CREATOR_ID = "PAR 2.0\x00Creator"
PAR_RECOVERY_ID = "RecvSlic"
@@ -35,7 +37,7 @@ def is_parfile(filename):
try:
with open(filename, "rb") as f:
buf = f.read(8)
return buf.startswith(PAR_ID)
return buf.startswith(PAR_PKT_ID)
except:
pass
return False
@@ -129,7 +131,8 @@ def parse_par2_file_packet(f, header):
nothing = None, None, None
if header != PAR_ID:
if header != PAR_PKT_ID:
print header
return nothing
# Length must be multiple of 4 and at least 20
@@ -157,10 +160,14 @@ def parse_par2_file_packet(f, header):
# See if it's the right packet and get name + hash
for offset in range(0, len, 8):
if data[offset:offset + 16] == "PAR 2.0\0FileDesc":
if data[offset:offset + 16] == PAR_FILE_ID:
hash = data[offset + 32:offset + 48]
hash16k = data[offset + 48:offset + 64]
filename = data[offset + 72:].strip('\0')
return filename, hash, hash16k
elif data[offset:offset + 15] == PAR_CREATOR_ID:
# Here untill the end is the creator-text
# Usefull in case of bugs in the par2-creating software
logging.debug('Par2-creator of %s is: %s', os.path.basename(f.name), data[offset+16:])
return nothing

View File

@@ -25,7 +25,6 @@ import urlparse
import time
import logging
import copy
import socket
import Queue
import collections
from threading import RLock, Thread

View File

@@ -19,6 +19,7 @@
sabtray.py - Systray icon for SABnzbd on Windows, contributed by Jan Schejbal
"""
import os
import logging
from time import sleep
@@ -29,8 +30,6 @@ import sabnzbd.scheduler as scheduler
from sabnzbd.downloader import Downloader
import sabnzbd.cfg as cfg
from sabnzbd.misc import to_units
import os
import cherrypy
# contains the tray icon, which demands its own thread
from sabnzbd.utils.systrayiconthread import SysTrayIconThread
@@ -98,10 +97,13 @@ class SABTrayThread(SysTrayIconThread):
speed = to_units(bpsnow)
if self.sabpaused:
self.hover_text = self.txt_paused
if bytes_left > 0:
self.hover_text = "%s - %s: %sB" % (self.txt_paused, self.txt_remaining, mb_left)
else:
self.hover_text = self.txt_paused
self.icon = self.sabicons['pause']
elif bytes_left > 0:
self.hover_text = "%sB/s %s: %sB (%s)" % (speed, self.txt_remaining, mb_left, time_left)
self.hover_text = "%sB/s - %s: %sB (%s)" % (speed, self.txt_remaining, mb_left, time_left)
self.icon = self.sabicons['green']
else:
self.hover_text = self.txt_idle

View File

@@ -21,7 +21,6 @@ sabnzbd.sabtraylinux - System tray icon for Linux, inspired from the Windows one
import gtk
import gobject
import cherrypy
from time import sleep
import subprocess
from threading import Thread

View File

@@ -6,7 +6,6 @@ Functions to check if the path filesystem uses FAT
import sys
import os
import subprocess
debug = False

View File

@@ -3,61 +3,41 @@
import time
import os
import sys
import logging
_DUMP_DATA = '*' * 10000
def writetofile(filename, mysizeMB):
# writes string to specified file repeat delay, until mysizeMB is reached.
writeloops = int(1024 * 1024 * mysizeMB / len(_DUMP_DATA))
try:
f = open(filename, 'w')
except:
logging.debug('Cannot create file %s', filename)
logging.debug("Traceback: ", exc_info=True)
return False
try:
for x in xrange(writeloops):
f.write(_DUMP_DATA)
except:
logging.debug('Cannot write to file %s', filename)
logging.debug("Traceback: ", exc_info=True)
return False
f.close()
return True
_DUMP_DATA_SIZE = 10 * 1024 * 1024
_DUMP_DATA = os.urandom(_DUMP_DATA_SIZE)
def diskspeedmeasure(dirname):
# returns writing speed to dirname in MB/s
# method: keep writing a file, until 0.5 seconds is passed. Then divide bytes written by time passed
filesize = 10 # MB
maxtime = 0.5 # sec
""" Returns writing speed to dirname in MB/s
method: keep writing a file, until 1 second is passed.
Then divide bytes written by time passed
"""
maxtime = 1.0 # sec
total_written = 0
filename = os.path.join(dirname, 'outputTESTING.txt')
if os.name == 'nt':
# On Windows, this crazy action is needed to
# avoid a "permission denied" error
try:
os.popen('echo Hi >%s' % filename)
except:
pass
# Use low-level I/O
fp = os.open(filename, os.O_CREAT | os.O_WRONLY, 0o777)
start = time.time()
loopcounter = 0
while True:
if not writetofile(filename, filesize):
return 0
loopcounter += 1
diff = time.time() - start
if diff > maxtime:
break
# Start looping
total_time = 0.0
while total_time < maxtime:
start = time.time()
os.write(fp, _DUMP_DATA)
os.fsync(fp)
total_time += time.time() - start
total_written += _DUMP_DATA_SIZE
# Remove the file
try:
# Have to use low-level close
os.close(fp)
os.remove(filename)
except:
pass
return (loopcounter * filesize) / diff
return total_written / total_time / 1024 / 1024
if __name__ == "__main__":

View File

@@ -1,4 +1,5 @@
import platform, subprocess
import platform
import subprocess
def getcpu():

View File

@@ -78,7 +78,6 @@ import os
import sys
import sched
import time
import traceback
import weakref
import logging

View File

@@ -25,7 +25,6 @@ import os
from sabnzbd.encoding import unicoder
import sabnzbd.cfg as cfg
from sabnzbd.misc import get_ext, get_filename, get_from_url
import sabnzbd.newsunpack
from sabnzbd.constants import VALID_ARCHIVES, VALID_NZB_FILES
from sabnzbd.dirscanner import ProcessArchiveFile, ProcessSingleFile

View File

@@ -21,7 +21,6 @@ sabnzbd.zconfig - bonjour/zeroconfig support
import os
import logging
import cherrypy
_HOST_PORT = (None, None)

View File

@@ -28,7 +28,7 @@ NOTES:
1) To use this script you need Python installed on your system and
select "Add to path" during its installation. Select this folder in
Config > Folders > Scripts Folder and select this script for each job
you want it sued for, or link it to a category in Config > Categories.
you want it used for, or link it to a category in Config > Categories.
2) Beware that files on the 'Cleanup List' are removed before
scripts are called and if any of them happen to be required by
the found par2 file, it will fail.
@@ -39,37 +39,116 @@ NOTES:
5) Feedback or bugs in this script can be reported in on our forum:
https://forums.sabnzbd.org/viewforum.php?f=9
Improved by P1nGu1n
"""
import os
import sys
import time
import fnmatch
import subprocess
import struct
import hashlib
from os import path
# Files to exclude and minimal file size for renaming
EXCLUDED_FILE_EXTS = ('.vob', '.bin')
MIN_FILE_SIZE = 40*1024*1024
# Are we being called from SABnzbd?
if not os.environ.get('SAB_VERSION'):
print "This script needs to be called from SABnzbd as post-processing script."
sys.exit(1)
# Files to exclude and minimal file size for renaming
EXCLUDED_FILE_EXTS = ('.vob', '.bin')
MIN_FILE_SIZE = 40*1024*1024
# see: http://parchive.sourceforge.net/docs/specifications/parity-volume-spec/article-spec.html
STRUCT_PACKET_HEADER = struct.Struct("<"
"8s" # Magic sequence
"Q" # Length of the entire packet (including header), must be multiple of 4
"16s" # MD5 Hash of packet
"16s" # Recovery Set ID
"16s" # Packet type
)
PACKET_TYPE_FILE_DESC = 'PAR 2.0\x00FileDesc'
STRUCT_FILE_DESC_PACKET = struct.Struct("<"
"16s" # File ID
"16s" # MD5 hash of the entire file
"16s" # MD5 hash of the first 16KiB of the file
"Q" # Length of the file
)
# Supporting functions
def print_splitter():
""" Simple helper function """
print '\n------------------------\n'
# Windows or others?
par2_command = os.environ['SAB_PAR2_COMMAND']
if os.environ['SAB_MULTIPAR_COMMAND']:
par2_command = os.environ['SAB_MULTIPAR_COMMAND']
# Diagnostic info
def decodePar(parfile):
result = False
dir = os.path.dirname(parfile)
with open(parfile, 'rb') as parfileToDecode:
while (True):
header = parfileToDecode.read(STRUCT_PACKET_HEADER.size)
if not header: break # file fully read
(_, packetLength, _, _, packetType) = STRUCT_PACKET_HEADER.unpack(header)
bodyLength = packetLength - STRUCT_PACKET_HEADER.size
# only process File Description packets
if (packetType != PACKET_TYPE_FILE_DESC):
# skip this packet
parfileToDecode.seek(bodyLength, os.SEEK_CUR)
continue
chunck = parfileToDecode.read(STRUCT_FILE_DESC_PACKET.size)
(_, _, hash16k, filelength) = STRUCT_FILE_DESC_PACKET.unpack(chunck)
# filename makes up for the rest of the packet, padded with null characters
targetName = parfileToDecode.read(bodyLength - STRUCT_FILE_DESC_PACKET.size).rstrip('\0')
targetPath = path.join(dir, targetName)
# file already exists, skip it
if (path.exists(targetPath)):
print "File already exists: " + targetName
continue
# find and rename file
srcPath = findFile(dir, filelength, hash16k)
if (srcPath is not None):
os.rename(srcPath, targetPath)
print "Renamed file from " + path.basename(srcPath) + " to " + targetName
result = True
else:
print "No match found for: " + targetName
return result
def findFile(dir, filelength, hash16k):
for filename in os.listdir(dir):
filepath = path.join(dir, filename)
# check if the size matches as an indication
if (path.getsize(filepath) != filelength): continue
with open(filepath, 'rb') as fileToMatch:
data = fileToMatch.read(16 * 1024)
m = hashlib.md5()
m.update(data)
# compare hash to confirm the match
if (m.digest() == hash16k):
return filepath
return None
# Run main program
print_splitter()
print 'SABnzbd version: ', os.environ['SAB_VERSION']
print 'Job location: ', os.environ['SAB_COMPLETE_DIR']
print 'Par2-command: ', par2_command
print_splitter()
# Search for par2 files
@@ -86,34 +165,14 @@ if not matches:
# Run par2 from SABnzbd on them
for par2_file in matches:
# Build command, make it check the whole directory
wildcard = os.path.join(os.environ['SAB_COMPLETE_DIR'], '*')
command = [str(par2_command), 'r', par2_file, wildcard]
# Start command
# Analyse data and analyse result
print_splitter()
print 'Starting command: ', repr(command)
try:
result = subprocess.check_output(command)
except subprocess.CalledProcessError as e:
# Multipar also gives non-zero in case of succes
result = e.output
# Show output
print_splitter()
print result
print_splitter()
# Last status-line for the History
# Check if the magic words are there
if 'Repaired successfully' in result or 'All files are correct' in result or \
'Repair complete' in result or 'All Files Complete' in result or 'PAR File(s) Incomplete' in result:
if decodePar(par2_file):
print 'Recursive repair/verify finished.'
run_renamer = False
else:
print 'Recursive repair/verify did not complete!'
# No matches? Then we try to rename the largest file to the job-name
if run_renamer:
print_splitter()

View File

@@ -105,7 +105,7 @@ def get_install_lng():
""" Return language-code used by the installer """
lng = 0
try:
hive = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
hive = _winreg.ConnectRegistry(None, _winreg.HKEY_CURRENT_USER)
key = _winreg.OpenKey(hive, r"Software\SABnzbd")
for i in range(0, _winreg.QueryInfoKey(key)[1]):
name, value, val_type = _winreg.EnumValue(key, i)
@@ -116,7 +116,31 @@ def get_install_lng():
pass
finally:
_winreg.CloseKey(hive)
return lng
if lng in LanguageMap:
return LanguageMap[lng]
return 'en'
# Map from NSIS-codepage to our language-strings
LanguageMap = {
'1033': 'en',
'1036': 'fr',
'1031': 'de',
'1043': 'nl',
'1035': 'fi',
'1045': 'pl',
'1053': 'sv',
'1030': 'da',
'2068': 'nb',
'1048': 'ro',
'1034': 'es',
'1046': 'pr_BR',
'3098': 'sr',
'1037': 'he',
'1049': 'ru',
'2052': 'zh_CN'
}
if __name__ == '__main__':

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.