Browse Source

Sync with 0.6.x

tags/0.6.0
ShyPike 15 years ago
parent
commit
b10e3a19be
  1. 20
      CHANGELOG.txt
  2. 11
      ISSUES.txt
  3. 28
      SABHelper.py
  4. 90
      SABnzbd.py
  5. 1
      language/nl-du.txt
  6. 1
      language/us-en.txt
  7. 2
      sabnzbd/cfg.py
  8. 35
      sabnzbd/dirscanner.py
  9. 4
      sabnzbd/encoding.py
  10. 5
      sabnzbd/interface.py
  11. 2
      sabnzbd/misc.py
  12. 6
      sabnzbd/newsunpack.py
  13. 26
      sabnzbd/newzbin.py
  14. 20
      sabnzbd/nzbqueue.py
  15. 12
      sabnzbd/nzbstuff.py
  16. 3
      sabnzbd/postproc.py
  17. 2
      sabnzbd/rss.py
  18. 3
      sabnzbd/scheduler.py

20
CHANGELOG.txt

@ -1,5 +1,23 @@
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
0.5.2 RC2 by The SABnzbd-Team 0.5.2 RC1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fixed: Large queue caused very slow UI and high memory usage
- Fixed: Some very large rar sets failed to unpack
- Fixed: garbled emails were sent
- Python user scripts now run properly on OSX
- Fixed: SeasonSort could produce trailing spaces, which fail on Windows
- Fixed: unpacking errors not properly reported to user script
- Keep trying when receiving garbage from nzbmatrix.com
- Add total-size fields to API-call History.
- Auto-search for free port when specified port is occupied
- Improve reporting of newzbin errors
-------------------------------------------------------------------------------
0.5.1 Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix accented character problems in emails
- Warn when user doesn't have permission to use a web port (Linux/OSX)
-------------------------------------------------------------------------------
0.5.1 RC2 by The SABnzbd-Team
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
- Accept comma-separated email address in "email_to" option. - Accept comma-separated email address in "email_to" option.
- Allow manual retry of URL-based NZB fetches when a bad NZB is received - Allow manual retry of URL-based NZB fetches when a bad NZB is received

11
ISSUES.txt

@ -14,6 +14,12 @@
in Config->Switches. in Config->Switches.
This will force the use of the old and tried, but slower par2-classic program. This will force the use of the old and tried, but slower par2-classic program.
- A bug in Windows 7 may cause severe memory leaks when you use SABnzbd in
combination with some virus scanners and firewals.
Install this hotfix:
Description: http://support.microsoft.com/kb/979223/en-us
Download location: http://support.microsoft.com/hotfix/KBHotfix.aspx?kbnum=979223&kbln=en-us
- Windows cannot handle pathnames longer than 254 characters. - Windows cannot handle pathnames longer than 254 characters.
Currently, SABnzbd doesn't handle this problem gracefully. Currently, SABnzbd doesn't handle this problem gracefully.
We have added the INI-only option "folder_length_max" in which you can set We have added the INI-only option "folder_length_max" in which you can set
@ -62,8 +68,3 @@
make sure that the drives are mounted. make sure that the drives are mounted.
The operating system wil simply redirect your files to alternative locations. The operating system wil simply redirect your files to alternative locations.
You may have trouble finding the files when mounting the drive later. You may have trouble finding the files when mounting the drive later.
- Sometimes logging stops. This is a notorious bug in Python logging. SABnzbd will
function as normal. If you run from sources or use the --console option with the
Win32-binary, you will see that logging continues in the console window, but
nothing will be written to the log-files.

28
SABHelper.py

@ -43,25 +43,43 @@ def HandleCommandLine(allow_service=True):
""" Handle command line for a Windows Service """ Handle command line for a Windows Service
Prescribed name that will be called by Py2Exe. Prescribed name that will be called by Py2Exe.
You MUST set 'cmdline_style':'custom' in the package.py! You MUST set 'cmdline_style':'custom' in the package.py!
Returns True when any service commands were detected.
""" """
win32serviceutil.HandleCommandLine(SABHelper) win32serviceutil.HandleCommandLine(SABHelper)
def start_sab():
return subprocess.Popen('net start SABnzbd', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).stdout.read()
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
def main(): def main():
mail = MailSlot() mail = MailSlot()
if not mail.create(200): if not mail.create(10):
return '- Cannot create Mailslot' return '- Cannot create Mailslot'
active = False # SABnzbd should be running
counter = 0 # Time allowed for SABnzbd to be silent
while True: while True:
msg = mail.receive() msg = mail.receive()
if msg == 'restart': if msg == 'restart':
time.sleep(1.0) time.sleep(1.0)
res = subprocess.Popen('net start SABnzbd', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).stdout.read() counter = 0
start_sab()
elif msg == 'stop':
active = False
elif msg == 'active':
active = True
counter = 0
if active:
counter += 1
if counter > 120: # 120 seconds
counter = 0
start_sab()
rc = win32event.WaitForMultipleObjects((WIN_SERVICE.hWaitStop, rc = win32event.WaitForMultipleObjects((WIN_SERVICE.hWaitStop,
WIN_SERVICE.overlapped.hEvent), 0, 500) WIN_SERVICE.overlapped.hEvent), 0, 1000)
if rc == win32event.WAIT_OBJECT_0: if rc == win32event.WAIT_OBJECT_0:
mail.disconnect() mail.disconnect()
return '' return ''
@ -79,7 +97,7 @@ class SABHelper(win32serviceutil.ServiceFramework):
_svc_display_name_ = 'SABnzbd Helper' _svc_display_name_ = 'SABnzbd Helper'
_svc_deps_ = ["EventLog", "Tcpip"] _svc_deps_ = ["EventLog", "Tcpip"]
_svc_description_ = 'Automated downloading from Usenet. ' \ _svc_description_ = 'Automated downloading from Usenet. ' \
'This service helps SABnzbdcd.. to restart itself.' 'This service helps SABnzbd to restart itself.'
def __init__(self, args): def __init__(self, args):
global WIN_SERVICE global WIN_SERVICE

90
SABnzbd.py

@ -113,6 +113,44 @@ def guard_loglevel():
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# Improved RotatingFileHandler
# See: http://www.mail-archive.com/python-bugs-list@python.org/msg53913.html
# http://bugs.python.org/file14420/NTSafeLogging.py
# Thanks Erik Antelman
#
if sabnzbd.WIN32:
import msvcrt
import _subprocess
import codecs
def duplicate(handle, inheritable=False):
target_process = _subprocess.GetCurrentProcess()
return _subprocess.DuplicateHandle(
_subprocess.GetCurrentProcess(), handle, target_process,
0, inheritable, _subprocess.DUPLICATE_SAME_ACCESS).Detach()
class MyRotatingFileHandler(logging.handlers.RotatingFileHandler):
def _open(self):
"""
Open the current base file with the (original) mode and encoding.
Return the resulting stream.
"""
if self.encoding is None:
stream = open(self.baseFilename, self.mode)
newosf = duplicate(msvcrt.get_osfhandle(stream.fileno()), inheritable=False)
newFD = msvcrt.open_osfhandle(newosf,os.O_APPEND)
newstream = os.fdopen(newFD,self.mode)
stream.close()
return newstream
else:
stream = codecs.open(self.baseFilename, self.mode, self.encoding)
return stream
else:
MyRotatingFileHandler = logging.handlers.RotatingFileHandler
#------------------------------------------------------------------------------
class FilterCP3: class FilterCP3:
### Filter out all CherryPy3-Access logging that we receive, ### Filter out all CherryPy3-Access logging that we receive,
### because we have the root logger ### because we have the root logger
@ -370,17 +408,21 @@ def GetProfileInfo(vista_plus):
pass pass
elif sabnzbd.DARWIN: elif sabnzbd.DARWIN:
sabnzbd.DIR_APPDATA = '%s/Library/Application Support/SABnzbd' % (os.environ['HOME']) home = os.environ.get('HOME')
sabnzbd.DIR_LCLDATA = sabnzbd.DIR_APPDATA if home:
sabnzbd.DIR_HOME = os.environ['HOME'] sabnzbd.DIR_APPDATA = '%s/Library/Application Support/SABnzbd' % home
ok = True sabnzbd.DIR_LCLDATA = sabnzbd.DIR_APPDATA
sabnzbd.DIR_HOME = home
ok = True
else: else:
# Unix/Linux # Unix/Linux
sabnzbd.DIR_APPDATA = '%s/.%s' % (os.environ['HOME'], DEF_WORKDIR) home = os.environ.get('HOME')
sabnzbd.DIR_LCLDATA = sabnzbd.DIR_APPDATA if home:
sabnzbd.DIR_HOME = os.environ['HOME'] sabnzbd.DIR_APPDATA = '%s/.%s' % (home, DEF_WORKDIR)
ok = True sabnzbd.DIR_LCLDATA = sabnzbd.DIR_APPDATA
sabnzbd.DIR_HOME = home
ok = True
if not ok: if not ok:
panic("Cannot access the user profile.", panic("Cannot access the user profile.",
@ -651,7 +693,7 @@ def cherrypy_logging(log_path):
# Make a new RotatingFileHandler for the error log. # Make a new RotatingFileHandler for the error log.
fname = getattr(log, "rot_error_file", log_path) fname = getattr(log, "rot_error_file", log_path)
h = logging.handlers.RotatingFileHandler(fname, 'a', maxBytes, backupCount) h = MyRotatingFileHandler(fname, 'a', maxBytes, backupCount)
h.setLevel(logging.DEBUG) h.setLevel(logging.DEBUG)
h.setFormatter(cherrypy._cplogging.logfmt) h.setFormatter(cherrypy._cplogging.logfmt)
log.error_log.addHandler(h) log.error_log.addHandler(h)
@ -970,7 +1012,7 @@ def main():
try: try:
sabnzbd.LOGFILE = os.path.join(logdir, DEF_LOG_FILE) sabnzbd.LOGFILE = os.path.join(logdir, DEF_LOG_FILE)
logsize = sabnzbd.cfg.log_size.get_int() logsize = sabnzbd.cfg.log_size.get_int()
rollover_log = logging.handlers.RotatingFileHandler(\ rollover_log = MyRotatingFileHandler(\
sabnzbd.LOGFILE, 'a+', sabnzbd.LOGFILE, 'a+',
logsize, logsize,
sabnzbd.cfg.log_backups()) sabnzbd.cfg.log_backups())
@ -1224,6 +1266,17 @@ def main():
check_latest_version() check_latest_version()
autorestarted = False autorestarted = False
mail = None
if sabnzbd.WIN_SERVICE:
mail = MailSlot()
if mail.connect():
logging.info('Connected to the SABHelper service')
mail.send('active')
else:
logging.error('Cannot reach the SABHelper service')
mail = None
# Have to keep this running, otherwise logging will terminate # Have to keep this running, otherwise logging will terminate
timer = 0 timer = 0
while not sabnzbd.SABSTOP: while not sabnzbd.SABSTOP:
@ -1259,6 +1312,9 @@ def main():
if not sabnzbd.check_all_tasks(): if not sabnzbd.check_all_tasks():
autorestarted = True autorestarted = True
cherrypy.engine.execv = True cherrypy.engine.execv = True
# Notify guardian
if sabnzbd.WIN_SERVICE and mail:
mail.send('active')
else: else:
timer += 1 timer += 1
@ -1289,20 +1345,18 @@ def main():
pid = os.fork() pid = os.fork()
if pid == 0: if pid == 0:
os.execv(sys.executable, args) os.execv(sys.executable, args)
elif sabnzbd.WIN_SERVICE: elif sabnzbd.WIN_SERVICE and mail:
logging.info('Asking the SABnzbdHelper service for a restart') logging.info('Asking the SABHelper service for a restart')
mail = MailSlot() mail.send('restart')
if mail.connect(): mail.disconnect()
mail.send('restart')
mail.disconnect()
else:
logging.error('Cannot reach the SABnzbdHelper service')
return return
else: else:
cherrypy.engine._do_execv() cherrypy.engine._do_execv()
config.save_config() config.save_config()
if sabnzbd.WIN_SERVICE and mail:
mail.send('stop')
notify("SAB_Shutdown", None) notify("SAB_Shutdown", None)
osx.sendGrowlMsg('SABnzbd',T('grwl-shutdown-end-msg'),osx.NOTIFICATION['startup']) osx.sendGrowlMsg('SABnzbd',T('grwl-shutdown-end-msg'),osx.NOTIFICATION['startup'])
logging.info('Leaving SABnzbd') logging.info('Leaving SABnzbd')

1
language/nl-du.txt

@ -368,6 +368,7 @@ sch-speedlimit Maximum snelheid
sch-pause_all Alles pauzeren sch-pause_all Alles pauzeren
sch-pause_post Pauzeer nabewerken sch-pause_post Pauzeer nabewerken
sch-resume_post Hervat nabewerken sch-resume_post Hervat nabewerken
sch-scan_folder Bewaakte map uitlezen
# Config->RSS # Config->RSS

1
language/us-en.txt

@ -392,6 +392,7 @@ sch-speedlimit Speedlimit
sch-pause_all Pause All sch-pause_all Pause All
sch-pause_post Pause post-processing sch-pause_post Pause post-processing
sch-resume_post Resume post-processing sch-resume_post Resume post-processing
sch-scan_folder Scan watched folder
# Config->RSS # Config->RSS
configRSS RSS Configuration configRSS RSS Configuration

2
sabnzbd/cfg.py

@ -149,7 +149,7 @@ cache_dir = OptionDir('misc', 'cache_dir', 'cache', validation=validate_safedir)
admin_dir = OptionDir('misc', 'admin_dir', 'admin', validation=validate_safedir) admin_dir = OptionDir('misc', 'admin_dir', 'admin', validation=validate_safedir)
#log_dir = OptionDir('misc', 'log_dir', 'logs') #log_dir = OptionDir('misc', 'log_dir', 'logs')
dirscan_dir = OptionDir('misc', 'dirscan_dir', create=False) dirscan_dir = OptionDir('misc', 'dirscan_dir', create=False)
dirscan_speed = OptionNumber('misc', 'dirscan_speed', DEF_SCANRATE, 1, 3600) dirscan_speed = OptionNumber('misc', 'dirscan_speed', DEF_SCANRATE, 0, 3600)
SIZE_LIMIT = OptionStr('misc', 'size_limit') SIZE_LIMIT = OptionStr('misc', 'size_limit')
cherryhost = OptionStr('misc','host', DEF_HOST) cherryhost = OptionStr('misc','host', DEF_HOST)

35
sabnzbd/dirscanner.py

@ -228,6 +228,7 @@ class DirScanner(threading.Thread):
self.error_reported = False # Prevents mulitple reporting of missing watched folder self.error_reported = False # Prevents mulitple reporting of missing watched folder
self.dirscan_dir = cfg.dirscan_dir.get_path() self.dirscan_dir = cfg.dirscan_dir.get_path()
self.dirscan_speed = cfg.dirscan_speed() self.dirscan_speed = cfg.dirscan_speed()
self.busy = False
cfg.dirscan_dir.callback(self.newdir) cfg.dirscan_dir.callback(self.newdir)
DirScanner.do = self DirScanner.do = self
@ -247,6 +248,20 @@ class DirScanner(threading.Thread):
sabnzbd.save_admin((self.dirscan_dir, self.ignored, self.suspected), sabnzbd.SCAN_FILE_NAME) sabnzbd.save_admin((self.dirscan_dir, self.ignored, self.suspected), sabnzbd.SCAN_FILE_NAME)
def run(self): def run(self):
logging.info('Dirscanner starting up')
self.shutdown = False
while not self.shutdown:
# Use variable scan delay
x = max(self.dirscan_speed, 1)
while (x > 0) and not self.shutdown:
time.sleep(1.0)
x = x - 1
if self.dirscan_speed and not self.shutdown:
self.scan()
def scan(self):
def run_dir(folder, catdir): def run_dir(folder, catdir):
try: try:
files = os.listdir(folder) files = os.listdir(folder)
@ -326,18 +341,10 @@ class DirScanner(threading.Thread):
CleanList(self.ignored, folder, files) CleanList(self.ignored, folder, files)
CleanList(self.suspected, folder, files) CleanList(self.suspected, folder, files)
logging.info('Dirscanner starting up') if not self.busy:
self.shutdown = False self.busy = True
while not self.shutdown:
# Use variable scan delay
dirscan_dir = self.dirscan_dir dirscan_dir = self.dirscan_dir
x = self.dirscan_speed if dirscan_dir and not sabnzbd.PAUSED_ALL:
while (x > 0) and not self.shutdown:
time.sleep(1.0)
x = x - 1
if dirscan_dir and not self.shutdown and not sabnzbd.PAUSED_ALL:
run_dir(dirscan_dir, None) run_dir(dirscan_dir, None)
try: try:
@ -353,4 +360,10 @@ class DirScanner(threading.Thread):
dpath = os.path.join(dirscan_dir, dd) dpath = os.path.join(dirscan_dir, dd)
if os.path.isdir(dpath) and dd.lower() in cats: if os.path.isdir(dpath) and dd.lower() in cats:
run_dir(dpath, dd.lower()) run_dir(dpath, dd.lower())
self.busy = False
def dirscan():
""" Wrapper required for scheduler """
logging.info('Scheduled folder scan')
DirScanner.do.scan()

4
sabnzbd/encoding.py

@ -49,7 +49,7 @@ def platform_encode(p):
if gUTF: if gUTF:
return p.encode('utf-8') return p.encode('utf-8')
else: else:
return p.encode('latin-1', 'replace').replace('?', '_') return p.encode('latin-1', 'replace')
elif isinstance(p, basestring): elif isinstance(p, basestring):
if gUTF: if gUTF:
try: try:
@ -59,7 +59,7 @@ def platform_encode(p):
return p.decode('latin-1').encode('utf-8') return p.decode('latin-1').encode('utf-8')
else: else:
try: try:
return p.decode('utf-8').encode('latin-1', 'replace').replace('?', '_') return p.decode('utf-8').encode('latin-1', 'replace')
except: except:
return p return p
else: else:

5
sabnzbd/interface.py

@ -2132,7 +2132,8 @@ class ConfigRss:
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
_SCHED_ACTIONS = ('resume', 'pause', 'pause_all', 'shutdown', 'restart', 'speedlimit', 'pause_post', 'resume_post') _SCHED_ACTIONS = ('resume', 'pause', 'pause_all', 'shutdown', 'restart', 'speedlimit',
'pause_post', 'resume_post', 'scan_folder')
class ConfigScheduling: class ConfigScheduling:
def __init__(self, web_dir, root, prim): def __init__(self, web_dir, root, prim):
@ -2182,7 +2183,7 @@ class ConfigScheduling:
act = '' act = ''
if act in ('enable_server', 'disable_server'): if act in ('enable_server', 'disable_server'):
action = T("sch-" + act) + ' ' + server action = T("sch-" + act) + ' ' + server
item = (snum, h, '%02d' % int(m), days[day], action) item = (snum, h, '%02d' % int(m), days.get(day, '**'), action)
conf['taskinfo'].append(item) conf['taskinfo'].append(item)
snum += 1 snum += 1

2
sabnzbd/misc.py

@ -978,7 +978,7 @@ def bad_fetch(nzo, url, msg='', retry=False, content=False):
msg = T('his-badArchive') msg = T('his-badArchive')
else: else:
# Failed fetch # Failed fetch
msg = T('his-failedURL') msg = ' (' + msg + ')'
if retry: if retry:
nzbname = nzo.get_dirname_rename() nzbname = nzo.get_dirname_rename()

6
sabnzbd/newsunpack.py

@ -354,7 +354,6 @@ def file_join(nzo, workdir, workdir_complete, delete, joinables):
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
def rar_unpack(nzo, workdir, workdir_complete, delete, rars): def rar_unpack(nzo, workdir, workdir_complete, delete, rars):
errors = False
extracted_files = [] extracted_files = []
rar_sets = {} rar_sets = {}
@ -385,10 +384,9 @@ def rar_unpack(nzo, workdir, workdir_complete, delete, rars):
try: try:
newfiles, rars = RAR_Extract(rarpath, len(rar_sets[rar_set]), newfiles, rars = RAR_Extract(rarpath, len(rar_sets[rar_set]),
nzo, rar_set, extraction_path) nzo, rar_set, extraction_path)
success = True success = newfiles and rars
except: except:
success = False success = False
errors = True
msg = sys.exc_info()[1] msg = sys.exc_info()[1]
nzo.set_fail_msg(T('error-unpackFail@1') % msg) nzo.set_fail_msg(T('error-unpackFail@1') % msg)
setname = nzo.get_dirname() setname = nzo.get_dirname()
@ -419,7 +417,7 @@ def rar_unpack(nzo, workdir, workdir_complete, delete, rars):
except OSError: except OSError:
logging.warning(Ta('warn-delFailed@1'), brokenrar) logging.warning(Ta('warn-delFailed@1'), brokenrar)
return errors, extracted_files return not success, extracted_files
def RAR_Extract(rarfile, numrars, nzo, setname, extraction_path): def RAR_Extract(rarfile, numrars, nzo, setname, extraction_path):

26
sabnzbd/newzbin.py

@ -132,7 +132,7 @@ class MSGIDGrabber(Thread):
sleeper(int(filename)) sleeper(int(filename))
else: else:
# Fatal error, give up on this one # Fatal error, give up on this one
bad_fetch(nzo, msgid, retry=False) bad_fetch(nzo, msgid, msg=nzo_info, retry=True)
msgid = None msgid = None
osx.sendGrowlMsg(T('grwl-nzbadd-title'),filename,osx.NOTIFICATION['download']) osx.sendGrowlMsg(T('grwl-nzbadd-title'),filename,osx.NOTIFICATION['download'])
@ -146,7 +146,7 @@ class MSGIDGrabber(Thread):
def _grabnzb(msgid): def _grabnzb(msgid):
""" Grab one msgid from newzbin """ """ Grab one msgid from newzbin """
nothing = (None, None, None, None) msg = ''
retry = (60, None, None, None) retry = (60, None, None, None)
nzo_info = {'msgid': msgid} nzo_info = {'msgid': msgid}
@ -188,7 +188,7 @@ def _grabnzb(msgid):
pass pass
if not (rcode or rtext): if not (rcode or rtext):
logging.error(T('error-nbProtocol')) logging.error(T('error-nbProtocol'))
return nothing return None, None, None, None
# Official return codes: # Official return codes:
# 200 = OK, NZB content follows # 200 = OK, NZB content follows
@ -221,27 +221,27 @@ def _grabnzb(msgid):
return int(wait+1), None, None, None return int(wait+1), None, None, None
if rcode in ('402'): if rcode in ('402'):
logging.warning(Ta('warn-nbCredit')) msg = Ta('warn-nbCredit')
return nothing return None, None, None, msg
if rcode in ('401'): if rcode in ('401'):
logging.warning(Ta('warn-nbNoAuth')) msg = Ta('warn-nbNoAuth')
return nothing return None, None, None, msg
if rcode in ('400', '404'): if rcode in ('400', '404'):
logging.error(Ta('error-nbReport@1'), msgid) msg = Ta('error-nbReport@1') % msgid
return nothing return None, None, None, msg
if rcode != '200': if rcode != '200':
logging.error(Ta('error-nbUnkownError@2'), rcode, rtext) msg = Ta('error-nbUnkownError@2') % (rcode, rtext)
return nothing return None, None, None, msg
# Process data # Process data
report_name = response.getheader('X-DNZB-Name') report_name = response.getheader('X-DNZB-Name')
report_cat = response.getheader('X-DNZB-Category') report_cat = response.getheader('X-DNZB-Category')
if not (report_name and report_cat): if not (report_name and report_cat):
logging.error(Ta('error-nbInfo@1'), msgid) msg = Ta('error-nbInfo@1') % msgid
return nothing return None, None, None, msg
# sanitize report_name # sanitize report_name
newname = sanitize_foldername(report_name) newname = sanitize_foldername(report_name)

20
sabnzbd/nzbqueue.py

@ -99,8 +99,8 @@ class NzbQueue(TryList):
self.add(nzo, save = False) self.add(nzo, save = False)
@synchronized(NZBQUEUE_LOCK) @synchronized(NZBQUEUE_LOCK)
def save(self): def save(self, save_nzo=None):
""" Save queue """ """ Save queue, all nzo's or just the specified one """
logging.info("Saving queue") logging.info("Saving queue")
nzo_ids = [] nzo_ids = []
@ -110,7 +110,8 @@ class NzbQueue(TryList):
nzo_ids.append(os.path.join(nzo.get_workdir(), nzo.nzo_id)) nzo_ids.append(os.path.join(nzo.get_workdir(), nzo.nzo_id))
else: else:
nzo_ids.append(nzo.nzo_id) nzo_ids.append(nzo.nzo_id)
sabnzbd.save_data(nzo, nzo.nzo_id, nzo.get_workpath()) if save_nzo is None or nzo is save_nzo:
sabnzbd.save_data(nzo, nzo.nzo_id, nzo.get_workpath())
sabnzbd.save_admin((QUEUE_VERSION, nzo_ids, []), QUEUE_FILE_NAME) sabnzbd.save_admin((QUEUE_VERSION, nzo_ids, []), QUEUE_FILE_NAME)
@ -151,7 +152,7 @@ class NzbQueue(TryList):
try: try:
future.__init__(filename, msgid, pp, scr, nzb=data, futuretype=False, cat=categ, priority=priority, nzbname=nzbname, nzo_info=nzo_info) future.__init__(filename, msgid, pp, scr, nzb=data, futuretype=False, cat=categ, priority=priority, nzbname=nzbname, nzo_info=nzo_info)
future.nzo_id = nzo_id future.nzo_id = nzo_id
self.save() self.save(future)
except ValueError: except ValueError:
self.remove(nzo_id, False) self.remove(nzo_id, False)
except TypeError: except TypeError:
@ -245,7 +246,7 @@ class NzbQueue(TryList):
#if the queue is empty then simple append the item to the bottom #if the queue is empty then simple append the item to the bottom
self.__nzo_list.append(nzo) self.__nzo_list.append(nzo)
if save: if save:
self.save() self.save(nzo)
if nzo.get_status() not in ('Fetching',): if nzo.get_status() not in ('Fetching',):
osx.sendGrowlMsg(T('grwl-nzbadd-title'),nzo.get_filename(),osx.NOTIFICATION['download']) osx.sendGrowlMsg(T('grwl-nzbadd-title'),nzo.get_filename(),osx.NOTIFICATION['download'])
@ -274,14 +275,15 @@ class NzbQueue(TryList):
self.cleanup_nzo(nzo) self.cleanup_nzo(nzo)
if save: if save:
self.save() self.save(nzo)
@synchronized(NZBQUEUE_LOCK) @synchronized(NZBQUEUE_LOCK)
def remove_multiple(self, nzo_ids): def remove_multiple(self, nzo_ids):
for nzo_id in nzo_ids: for nzo_id in nzo_ids:
self.remove(nzo_id, add_to_history = False, save = False) self.remove(nzo_id, add_to_history = False, save = False)
self.save() # Save with invalid nzo_id, to that only queue file is saved
self.save('x')
@synchronized(NZBQUEUE_LOCK) @synchronized(NZBQUEUE_LOCK)
def remove_all(self): def remove_all(self):
@ -891,9 +893,9 @@ def reset_all_try_lists():
global __NZBQ global __NZBQ
if __NZBQ: __NZBQ.reset_all_try_lists() if __NZBQ: __NZBQ.reset_all_try_lists()
def save(): def save(nzo=None):
global __NZBQ global __NZBQ
if __NZBQ: __NZBQ.save() if __NZBQ: __NZBQ.save(nzo)
def generate_future(msg, pp, script, cat, url, priority, nzbname): def generate_future(msg, pp, script, cat, url, priority, nzbname):
global __NZBQ global __NZBQ

12
sabnzbd/nzbstuff.py

@ -822,13 +822,17 @@ class NzbObject(TryList):
for nzf in self.__files: for nzf in self.__files:
# Don't try to get an article if server is in try_list of nzf # Don't try to get an article if server is in try_list of nzf
if not nzf.server_in_try_list(server): if not nzf.server_in_try_list(server):
if not nzf.import_finished: # Only load NZF when it's a primary server
# or when it's a backup server without active primaries
if server.fillserver ^ sabnzbd.active_primaries():
nzf.finish_import() nzf.finish_import()
# Still not finished? Something went wrong... # Still not finished? Something went wrong...
if not nzf.import_finished: if not nzf.import_finished:
logging.error(Ta('error-qImport@1'), nzf) logging.error(Ta('error-qImport@1'), nzf)
nzf_remove_list.append(nzf) nzf_remove_list.append(nzf)
continue continue
else:
continue
article = nzf.get_article(server) article = nzf.get_article(server)
if article: if article:
@ -837,12 +841,10 @@ class NzbObject(TryList):
for nzf in nzf_remove_list: for nzf in nzf_remove_list:
self.__files.remove(nzf) self.__files.remove(nzf)
if article: if not article:
return article
else:
# No articles for this server, block for next time # No articles for this server, block for next time
self.add_to_try_list(server) self.add_to_try_list(server)
return return article
def move_top_bulk(self, nzf_ids): def move_top_bulk(self, nzf_ids):
self.__cleanup_nzf_ids(nzf_ids) self.__cleanup_nzf_ids(nzf_ids)

3
sabnzbd/postproc.py

@ -526,9 +526,8 @@ def addPrefixes(path,nzo):
def HandleEmptyQueue(): def HandleEmptyQueue():
""" Check if empty queue calls for action """ """ Check if empty queue calls for action """
sabnzbd.save_state()
if sabnzbd.QUEUECOMPLETEACTION_GO: if sabnzbd.QUEUECOMPLETEACTION_GO:
sabnzbd.save_state()
logging.info("Queue has finished, launching: %s (%s)", \ logging.info("Queue has finished, launching: %s (%s)", \
sabnzbd.QUEUECOMPLETEACTION, sabnzbd.QUEUECOMPLETEARG) sabnzbd.QUEUECOMPLETEACTION, sabnzbd.QUEUECOMPLETEARG)
if sabnzbd.QUEUECOMPLETEARG: if sabnzbd.QUEUECOMPLETEARG:

2
sabnzbd/rss.py

@ -250,7 +250,7 @@ class RSSQueue:
return T('warn-failRSS@2') % (uri, str(d['bozo_exception'])) return T('warn-failRSS@2') % (uri, str(d['bozo_exception']))
if not entries: if not entries:
logging.info('RSS Feed was empty: %s', uri) logging.info('RSS Feed was empty: %s', uri)
return 'RSS Feed was empty' return ''
order = 0 order = 0
# Filter out valid new links # Filter out valid new links

3
sabnzbd/scheduler.py

@ -29,6 +29,7 @@ import sabnzbd.utils.kronos as kronos
import sabnzbd.rss as rss import sabnzbd.rss as rss
from sabnzbd.newzbin import Bookmarks from sabnzbd.newzbin import Bookmarks
import sabnzbd.downloader import sabnzbd.downloader
import sabnzbd.dirscanner
import sabnzbd.misc import sabnzbd.misc
import sabnzbd.config as config import sabnzbd.config as config
import sabnzbd.cfg as cfg import sabnzbd.cfg as cfg
@ -110,6 +111,8 @@ def init():
action = sabnzbd.enable_server action = sabnzbd.enable_server
elif action_name == 'disable_server' and arguments != []: elif action_name == 'disable_server' and arguments != []:
action = sabnzbd.disable_server action = sabnzbd.disable_server
elif action_name == 'scan_folder':
action = sabnzbd.dirscanner.dirscan
else: else:
logging.warning(Ta('warn-badSchedAction@1'), action_name) logging.warning(Ta('warn-badSchedAction@1'), action_name)
continue continue

Loading…
Cancel
Save