Browse Source

Merge in changes from branch sabnzbd-0.5.x Rev 3182-3192.

tags/0.6.0
shypike 16 years ago
parent
commit
0c58243bd7
  1. 9
      main/CHANGELOG.txt
  2. 5
      main/ISSUES.txt
  3. 4
      main/PKG-INFO
  4. 4
      main/README.txt
  5. BIN
      main/cherrypy.zip
  6. 4
      main/interfaces/Classic/templates/queue.tmpl
  7. 1
      main/language/de-de.txt
  8. 1
      main/language/fr-fr.txt
  9. 1
      main/language/nl-du.txt
  10. 1
      main/language/sv-se.txt
  11. 1
      main/language/us-en.txt
  12. 8
      main/sabnzbd/database.py
  13. 61
      main/sabnzbd/downloader.py
  14. 6
      main/sabnzbd/interface.py
  15. 17
      main/sabnzbd/newsunpack.py
  16. 53
      main/sabnzbd/newswrapper.py
  17. 2
      main/sabnzbd/utils/servertests.py

9
main/CHANGELOG.txt

@ -1,4 +1,13 @@
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
0.5.0Beta6 by The SABnzbd-Team
-------------------------------------------------------------------------------
Fixes:
- Solve problems with unwilling servers and "random" server time-outs.
- Do not generate warnings for intermittent server problems.
- Joinable rar-sets were not always properly joined.
- Fixed timing problems when SABnzbd is running behind an Apache server
- Don't report failed default permissions setting when the user has set none
-------------------------------------------------------------------------------
0.5.0Beta5 by The SABnzbd-Team 0.5.0Beta5 by The SABnzbd-Team
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Fixes: Fixes:

5
main/ISSUES.txt

@ -8,11 +8,6 @@ So far we have too little information to reproduce these problems.
Please report such problems on the forum with as much information Please report such problems on the forum with as much information
as possibe (OS, amount of usenet servers etc.) as possibe (OS, amount of usenet servers etc.)
*** (hopefully) Solved issue ***
We are investigating reports of downloads hanging in the
last bit of the actual download.
0.5.0 Beta5 attempts to fix this. Let us hear your experience.
*** Known problems *** *** Known problems ***

4
main/PKG-INFO

@ -1,7 +1,7 @@
Metadata-Version: 1.0 Metadata-Version: 1.0
Name: SABnzbd Name: SABnzbd
Version: 0.5.0Beta5 Version: 0.6.0Alpha0
Summary: SABnzbd-0.5.0Beta5 Summary: SABnzbd-0.6.0ALpha0
Home-page: http://sourceforge.net/projects/sabnzbdplus Home-page: http://sourceforge.net/projects/sabnzbdplus
Author: The SABnzbd Team Author: The SABnzbd Team
Author-email: team@sabnzbd.org Author-email: team@sabnzbd.org

4
main/README.txt

@ -1,5 +1,5 @@
******************************************* *******************************************
*** This is SABnzbd 0.5.0 Beta5 *** *** This is SABnzbd 0.6.0 Alpha0 ***
******************************************* *******************************************
SABnzbd is an open-source cross-platform binary newsreader. SABnzbd is an open-source cross-platform binary newsreader.
It simplifies the process of downloading from Usenet dramatically, It simplifies the process of downloading from Usenet dramatically,
@ -16,7 +16,7 @@ http://wiki.sabnzbd.org/
******************************************* *******************************************
*** Beta Software *** *** Beta Software ***
******************************************* *******************************************
This is Beta software, it´s almost mature. This is Beta software, its almost mature.
We are quite confident, but not enough people We are quite confident, but not enough people
have used it yet. have used it yet.

BIN
main/cherrypy.zip

Binary file not shown.

4
main/interfaces/Classic/templates/queue.tmpl

@ -40,9 +40,9 @@ $T('onQueueFinish'):
<!--#end if#--> <!--#end if#-->
</select> </select>
| $T('speedLimit'): | $T('speedLimit'):
<input id="speedbox" type="text" value="$speedlimit" onChange="location = './set_speedlimit?session=$session&value='+this.value">$T('KBs') <input id="speedbox" type="text" value="$speedlimit" onChange="location = './set_speedlimit?session=$session&value='+this.value">&nbsp;$T('KBs')
| $T('pauseFor'): | $T('pauseFor'):
<input id="speedbox" type="text" size=5 value="" onChange="location = './set_pause?session=$session&value='+this.value">$T('minute') <input id="speedbox" type="text" size=5 value="" onChange="location = './set_pause?session=$session&value='+this.value">&nbsp;$T('minute')
| |
<a href="./purge?session=$session" onclick="return confirm('$T('purgeQueueConf').replace("'","`") ');">$T('purgeQueue')</a> <a href="./purge?session=$session" onclick="return confirm('$T('purgeQueueConf').replace("'","`") ');">$T('purgeQueue')</a>
</span> </span>

1
main/language/de-de.txt

@ -164,6 +164,7 @@ clearWarnings Leeren
server-blocked Freigeben server-blocked Freigeben
warning WARNUNG: warning WARNUNG:
error FEHLER: error FEHLER:
server-resolving &nbsp;Adresse auflösen
# Configuration # Configuration
configuration Einstellungen configuration Einstellungen

1
main/language/fr-fr.txt

@ -164,6 +164,7 @@ clearWarnings effacer
server-blocked Débloquer server-blocked Débloquer
warning AVERTISSEMENT: warning AVERTISSEMENT:
error ERREUR: error ERREUR:
server-resolving &nbsp;Résoudre l'adresse
# Configuration # Configuration

1
main/language/nl-du.txt

@ -160,6 +160,7 @@ clearWarnings Wissen
server-blocked Deblokkeren server-blocked Deblokkeren
warning WAARSCHUWING: warning WAARSCHUWING:
error FOUT: error FOUT:
server-resolving &nbsp;Adres opzoeken
# Configuration # Configuration
configuration Instellingen configuration Instellingen

1
main/language/sv-se.txt

@ -163,6 +163,7 @@ clearWarnings rensa
server-blocked Ta bort blockering server-blocked Ta bort blockering
warning VARNING: warning VARNING:
error FEL: error FEL:
server-resolving &nbsp;Lösa adress
# Configuration # Configuration
configuration Konfiguration configuration Konfiguration

1
main/language/us-en.txt

@ -162,6 +162,7 @@ clearWarnings clear
server-blocked Unblock server-blocked Unblock
warning WARNING: warning WARNING:
error ERROR: error ERROR:
server-resolving &nbsp;Resolving address
# Configuration # Configuration
configuration Configuration configuration Configuration

8
main/sabnzbd/database.py

@ -378,14 +378,10 @@ def unpack_history_info(item):
def decode_factory(text): def decode_factory(text):
''' '''
Recursivly looks through the supplied argument Recursivly looks through the supplied argument
and converts and text to utf-8 and converts and text to Unicode
''' '''
if isinstance(text, str): if isinstance(text, str):
if sabnzbd.WIN32: return unicoder(text)
return text.decode('Latin-1', 'replace').encode('utf-8', 'replace')
else:
return text.decode('utf-8', 'replace')
elif isinstance(text, list): elif isinstance(text, list):
new_text = [] new_text = []

61
main/sabnzbd/downloader.py

@ -29,7 +29,7 @@ from nntplib import NNTPPermanentError
import sabnzbd import sabnzbd
from sabnzbd.decorators import synchronized_CV, CV from sabnzbd.decorators import synchronized_CV, CV
from sabnzbd.decoder import Decoder from sabnzbd.decoder import Decoder
from sabnzbd.newswrapper import NewsWrapper from sabnzbd.newswrapper import NewsWrapper, request_server_info
from sabnzbd.utils import osx from sabnzbd.utils import osx
from sabnzbd.constants import * from sabnzbd.constants import *
import sabnzbd.config as config import sabnzbd.config as config
@ -205,6 +205,9 @@ class Server:
self.active = True self.active = True
self.bad_cons = 0 self.bad_cons = 0
self.errormsg = '' self.errormsg = ''
self.warning = ''
self.info = None # Will hold getaddrinfo() list
self.request = False # True if a getaddrinfo() request is pending
for i in range(threads): for i in range(threads):
self.idle_threads.append(NewsWrapper(self, i+1)) self.idle_threads.append(NewsWrapper(self, i+1))
@ -219,7 +222,7 @@ class Server:
readers.pop(fno) readers.pop(fno)
if fno and fno in writers: if fno and fno in writers:
writers.pop(fno) writers.pop(fno)
nw.terminate() nw.terminate(quit=True)
self.idle_threads = [] self.idle_threads = []
def __repr__(self): def __repr__(self):
@ -367,6 +370,18 @@ class Downloader(Thread):
return True return True
return False return False
def maybe_block_server(self, server):
if server.optional and server.active and (server.bad_cons/server.threads) > 3:
# Optional and active server had too many problems,
# disable it now and send a re-enable plan to the scheduler
server.bad_cons = 0
server.active = False
server.errormsg = T('warn-ignoreServer@2') % ('', _PENALTY_TIMEOUT)
logging.warning(Ta('warn-ignoreServer@2'), server.id, _PENALTY_TIMEOUT)
self.plan_server(server.id, _PENALTY_TIMEOUT)
sabnzbd.nzbqueue.reset_all_try_lists()
def run(self): def run(self):
self.decoder.start() self.decoder.start()
@ -379,15 +394,7 @@ class Downloader(Thread):
else: else:
self.__reset_nw(nw, "timed out") self.__reset_nw(nw, "timed out")
server.bad_cons += 1 server.bad_cons += 1
if server.optional and server.active and (server.bad_cons/server.threads) > 3: self.maybe_block_server(server)
# Optional and active server had too many problems,
# disable it now and send a re-enable plan to the scheduler
server.bad_cons = 0
server.active = False
server.errormsg = T('warn-ignoreServer@2') % ('', _PENALTY_TIMEOUT)
logging.warning(Ta('warn-ignoreServer@2'), server.id, _PENALTY_TIMEOUT)
self.plan_server(server.id, _PENALTY_TIMEOUT)
sabnzbd.nzbqueue.reset_all_try_lists()
if server.restart: if server.restart:
if not server.busy_threads: if not server.busy_threads:
newid = server.newid newid = server.newid
@ -419,6 +426,11 @@ class Downloader(Thread):
if not server.active: if not server.active:
break break
if server.info is None:
self.maybe_block_server(server)
request_server_info(server)
break
article = sabnzbd.nzbqueue.get_article(server) article = sabnzbd.nzbqueue.get_article(server)
if not article: if not article:
@ -465,10 +477,11 @@ class Downloader(Thread):
if self.force_disconnect: if self.force_disconnect:
for server in self.servers: for server in self.servers:
for nw in server.idle_threads[:]: for nw in server.idle_threads + server.busy_threads:
self.__reset_nw(nw, "forcing disconnect", warn=False, wait=False) quit = nw.connected and server.active
for nw in server.busy_threads[:]: self.__reset_nw(nw, "forcing disconnect", warn=False, wait=False, quit=quit)
self.__reset_nw(nw, "forcing disconnect", warn=False, wait=False) # Make sure server address resolution is refreshed
server.info = None
self.force_disconnect = False self.force_disconnect = False
@ -571,7 +584,7 @@ class Downloader(Thread):
if server.active: if server.active:
server.errormsg = Ta('error-serverTooMany@2') % ('', '') server.errormsg = Ta('error-serverTooMany@2') % ('', '')
logging.error(Ta('error-serverTooMany@2'), server.host, server.port) logging.error(Ta('error-serverTooMany@2'), server.host, server.port)
self.__reset_nw(nw, None, warn=False, destroy=True) self.__reset_nw(nw, None, warn=False, destroy=True, quit=True)
self.plan_server(server.id, _PENALTY_TOOMANY) self.plan_server(server.id, _PENALTY_TOOMANY)
server.threads -= 1 server.threads -= 1
elif ecode in ('502', '481') and clues_too_many_ip(msg): elif ecode in ('502', '481') and clues_too_many_ip(msg):
@ -606,7 +619,7 @@ class Downloader(Thread):
logging.info('Server %s ignored for %s minutes', server.id, penalty) logging.info('Server %s ignored for %s minutes', server.id, penalty)
self.plan_server(server.id, penalty) self.plan_server(server.id, penalty)
sabnzbd.nzbqueue.reset_all_try_lists() sabnzbd.nzbqueue.reset_all_try_lists()
self.__reset_nw(nw, None, warn=False) self.__reset_nw(nw, None, warn=False, quit=True)
continue continue
except: except:
logging.error(Ta('error-serverFailed@4'), logging.error(Ta('error-serverFailed@4'),
@ -647,7 +660,7 @@ class Downloader(Thread):
self.plan_server(server.id, 0) self.plan_server(server.id, 0)
sabnzbd.nzbqueue.reset_all_try_lists() sabnzbd.nzbqueue.reset_all_try_lists()
msg = T('error-serverCred@1') % ('%s:%s' % (nw.server.host, nw.server.port)) msg = T('error-serverCred@1') % ('%s:%s' % (nw.server.host, nw.server.port))
self.__reset_nw(nw, msg) self.__reset_nw(nw, msg, quit=True)
if done: if done:
logging.info('Thread %s@%s:%s: %s done', logging.info('Thread %s@%s:%s: %s done',
@ -659,8 +672,7 @@ class Downloader(Thread):
server.busy_threads.remove(nw) server.busy_threads.remove(nw)
server.idle_threads.append(nw) server.idle_threads.append(nw)
def __reset_nw(self, nw, errormsg, warn=True, wait=True, destroy=False, quit=False):
def __reset_nw(self, nw, errormsg, warn=True, wait=True, destroy=False):
server = nw.server server = nw.server
article = nw.article article = nw.article
fileno = None fileno = None
@ -670,7 +682,8 @@ class Downloader(Thread):
nw.nntp.error_msg = None nw.nntp.error_msg = None
if warn and errormsg: if warn and errormsg:
logging.warning('Thread %s@%s:%s: ' + errormsg, server.warning = errormsg
logging.info('Thread %s@%s:%s: ' + errormsg,
nw.thrdnum, server.host, server.port) nw.thrdnum, server.host, server.port)
elif errormsg: elif errormsg:
logging.info('Thread %s@%s:%s: ' + errormsg, logging.info('Thread %s@%s:%s: ' + errormsg,
@ -697,9 +710,9 @@ class Downloader(Thread):
sabnzbd.nzbqueue.reset_try_lists(nzf, nzo) sabnzbd.nzbqueue.reset_try_lists(nzf, nzo)
if destroy: if destroy:
nw.terminate() nw.terminate(quit=quit)
else: else:
nw.hard_reset(wait) nw.hard_reset(wait, quit=quit)
def __request_article(self, nw): def __request_article(self, nw):
try: try:
@ -720,7 +733,7 @@ class Downloader(Thread):
self.read_fds[fileno] = nw self.read_fds[fileno] = nw
except: except:
logging.error(Ta('error-except')) logging.error(Ta('error-except'))
self.__reset_nw(nw, "server broke off connection") self.__reset_nw(nw, "server broke off connection", quit=True)
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# Timed restart of servers admin. # Timed restart of servers admin.

6
main/sabnzbd/interface.py

@ -2479,7 +2479,13 @@ class ConnectionInfo:
if nw.connected: if nw.connected:
connected += 1 connected += 1
if server.warning and not (connected or server.errormsg):
connected = unicoder(server.warning)
if server.request and not server.info:
connected = T('server-resolving')
busy.sort() busy.sort()
header['servers'].append((server.host, server.port, connected, busy, server.ssl, header['servers'].append((server.host, server.port, connected, busy, server.ssl,
server.active, server.errormsg, server.fillserver, server.optional)) server.active, server.errormsg, server.fillserver, server.optional))

17
main/sabnzbd/newsunpack.py

@ -661,7 +661,7 @@ def par2_repair(parfile_nzf, nzo, workdir, setname):
nzo.set_action_line(T('msg-repair'), T('msg-startRepair')) nzo.set_action_line(T('msg-repair'), T('msg-startRepair'))
logging.info('Scanning "%s"', parfile) logging.info('Scanning "%s"', parfile)
joinables, zips, rars, ts = build_filelists(workdir, None) joinables, zips, rars, ts = build_filelists(workdir, None, check_rar=False)
finished, readd, pars, datafiles, used_joinables = PAR_Verify(parfile, parfile_nzf, nzo, finished, readd, pars, datafiles, used_joinables = PAR_Verify(parfile, parfile_nzf, nzo,
setname, joinables) setname, joinables)
@ -1046,7 +1046,7 @@ def par_sort(a, b):
elif bext == 'par2': elif bext == 'par2':
return 1 return 1
def build_filelists(workdir, workdir_complete): def build_filelists(workdir, workdir_complete, check_rar=True):
joinables, zips, rars = ([], [], []) joinables, zips, rars = ([], [], [])
filelist = [] filelist = []
@ -1060,11 +1060,14 @@ def build_filelists(workdir, workdir_complete):
for _file in files: for _file in files:
filelist.append(os.path.join(root, _file)) filelist.append(os.path.join(root, _file))
joinables = [f for f in filelist if SPLITFILE_RE.search(f) and notrar(f)] if check_rar:
joinables = [f for f in filelist if SPLITFILE_RE.search(f) and not israr(f)]
else:
joinables = [f for f in filelist if SPLITFILE_RE.search(f)]
zips = [f for f in filelist if ZIP_RE.search(f)] zips = [f for f in filelist if ZIP_RE.search(f)]
rars = [f for f in filelist if RAR_RE.search(f) and f not in joinables] rars = [f for f in filelist if RAR_RE.search(f) and israr(f)]
ts = [f for f in filelist if TS_RE.search(f) and f not in joinables] ts = [f for f in filelist if TS_RE.search(f) and f not in joinables]
@ -1075,7 +1078,7 @@ def build_filelists(workdir, workdir_complete):
return (joinables, zips, rars, ts) return (joinables, zips, rars, ts)
def notrar(f): def israr(f):
logging.debug("notrar(): testing %s", f) logging.debug("notrar(): testing %s", f)
try: try:
_f = open(f, 'rb') _f = open(f, 'rb')
@ -1087,9 +1090,9 @@ def notrar(f):
if header != 'Rar!': if header != 'Rar!':
logging.debug("notrar(): joinable file %s", f) logging.debug("notrar(): joinable file %s", f)
return True return False
return False return True
def QuickCheck(set, nzo): def QuickCheck(set, nzo):

53
main/sabnzbd/newswrapper.py

@ -49,6 +49,33 @@ import select
socket.setdefaulttimeout(DEF_TIMEOUT) socket.setdefaulttimeout(DEF_TIMEOUT)
#------------------------------------------------------------------------------
# getaddrinfo() can be very slow. In some situations this can lead
# to delayed starts and timeouts on connections.
# Because of this, the results will be cached in the server object.
def _retrieve_info(server):
""" Async attempt to run getaddrinfo() for specified server
"""
info = GetServerParms(server.host, server.port)
if info is None:
server.bad_cons += server.threads
else:
server.bad_cons = 0
(server.info, server.request) = (info, False)
sabnzbd.downloader.wakeup()
def request_server_info(server):
""" Launch async request to resolve server address
"""
if not server.request:
server.request = True
Thread(target=_retrieve_info, args=(server,)).start()
def GetServerParms(host, port): def GetServerParms(host, port):
# Make sure port is numeric (unicode input not supported) # Make sure port is numeric (unicode input not supported)
try: try:
@ -99,17 +126,16 @@ def con(sock, host, port, sslenabled, nntp):
nntp.error(e) nntp.error(e)
class NNTP: class NNTP:
def __init__(self, host, port, sslenabled, nntp, user=None, password=None, block=False): def __init__(self, host, port, info, sslenabled, nntp, user=None, password=None, block=False):
self.host = host self.host = host
self.port = port self.port = port
self.nntp = nntp self.nntp = nntp
self.blocking = block self.blocking = block
self.error_msg = None self.error_msg = None
res= GetServerParms(self.host, self.port) if not info:
if not res:
raise socket.error(errno.EADDRNOTAVAIL, "Address not available - Check for internet or DNS problems") raise socket.error(errno.EADDRNOTAVAIL, "Address not available - Check for internet or DNS problems")
af, socktype, proto, canonname, sa = res[0] af, socktype, proto, canonname, sa = info[0]
if sslenabled and _ssl: if sslenabled and _ssl:
# Some users benefit from SSLv2 not being capped. # Some users benefit from SSLv2 not being capped.
@ -175,7 +201,8 @@ class NNTP:
if self.blocking: if self.blocking:
raise socket.error(errno.ECONNREFUSED, msg) raise socket.error(errno.ECONNREFUSED, msg)
else: else:
logging.error(msg) logging.info(msg)
self.nntp.server.warning = msg
class NewsWrapper: class NewsWrapper:
def __init__(self, server, thrdnum, block=False): def __init__(self, server, thrdnum, block=False):
@ -202,7 +229,7 @@ class NewsWrapper:
self.pass_ok = False self.pass_ok = False
def init_connect(self): def init_connect(self):
self.nntp = NNTP(self.server.host, self.server.port, self.server.ssl, self, self.nntp = NNTP(self.server.host, self.server.port, self.server.info, self.server.ssl, self,
self.server.username, self.server.password, self.blocking) self.server.username, self.server.password, self.blocking)
self.recv = self.nntp.sock.recv self.recv = self.nntp.sock.recv
@ -283,11 +310,12 @@ class NewsWrapper:
self.data = '' self.data = ''
self.lines = [] self.lines = []
def hard_reset(self, wait=True): def hard_reset(self, wait=True, quit=True):
if self.nntp: if self.nntp:
try: try:
self.nntp.sock.sendall('QUIT\r\n') if quit:
time.sleep(0.1) self.nntp.sock.sendall('QUIT\r\n')
time.sleep(0.1)
self.nntp.sock.close() self.nntp.sock.close()
except: except:
pass pass
@ -302,12 +330,13 @@ class NewsWrapper:
# Reset for internal reasons, just wait 5 sec # Reset for internal reasons, just wait 5 sec
self.timeout = time.time() + 5 self.timeout = time.time() + 5
def terminate(self): def terminate(self, quit=False):
""" Close connection and remove nntp object """ """ Close connection and remove nntp object """
if self.nntp: if self.nntp:
try: try:
self.nntp.sock.sendall('QUIT\r\n') if quit:
time.sleep(0.1) self.nntp.sock.sendall('QUIT\r\n')
time.sleep(0.1)
self.nntp.sock.close() self.nntp.sock.close()
except: except:
pass pass

2
main/sabnzbd/utils/servertests.py

@ -118,4 +118,4 @@ def test_nntp_server(host, port, username=None, password=None, ssl=None):
return False, T('srv-generalFail@1') % xml_name(nw.lines[0]) return False, T('srv-generalFail@1') % xml_name(nw.lines[0])
# Close the connection # Close the connection
nw.terminate() nw.terminate(quit=True)

Loading…
Cancel
Save