Browse Source

Convert to Unicode application.

This breaks compatibility with existing 0.7.x queues.
Polish and Romanian no longer need conversion to latin1.
pull/84/head
shypike 12 years ago
parent
commit
620e10a69f
  1. 44
      NSIS_Installer.nsi
  2. 5
      README.md
  3. 25
      SABnzbd.py
  4. 4
      package.py
  5. 0
      po/email/pl.po
  6. 0
      po/email/ro.po
  7. 0
      po/main/pl.po
  8. 0
      po/main/ro.po
  9. 0
      po/nsis/pl.po
  10. 0
      po/nsis/ro.po
  11. 16
      sabnzbd/__init__.py
  12. 7
      sabnzbd/api.py
  13. 37
      sabnzbd/config.py
  14. 8
      sabnzbd/constants.py
  15. 2
      sabnzbd/database.py
  16. 131
      sabnzbd/encoding.py
  17. 8
      sabnzbd/growler.py
  18. 7
      sabnzbd/interface.py
  19. 186
      sabnzbd/lang.py
  20. 50
      sabnzbd/misc.py
  21. 9
      sabnzbd/newsunpack.py
  22. 2
      sabnzbd/newzbin.py
  23. 14
      sabnzbd/nzbqueue.py
  24. 43
      sabnzbd/nzbstuff.py
  25. 4
      sabnzbd/postproc.py
  26. 14
      sabnzbd/rss.py
  27. 54
      sabnzbd/sabtray.py
  28. 3
      sabnzbd/utils/json.py
  29. 5
      sabnzbd/utils/rarfile.py
  30. 11
      sabnzbd/wizard.py
  31. 4
      tools/extract_pot.py
  32. 116
      tools/make_mo.py
  33. 27
      util/apireg.py

44
NSIS_Installer.nsi

@ -25,6 +25,7 @@
!include "LogicLib.nsh" !include "LogicLib.nsh"
!include "WinVer.nsh" !include "WinVer.nsh"
!include "WinSxSQuery.nsh" !include "WinSxSQuery.nsh"
!include "nsProcess.nsh"
;------------------------------------------------------------------ ;------------------------------------------------------------------
; ;
@ -48,6 +49,7 @@
Delete "${idir}\email\email-pt_BR.tmpl" Delete "${idir}\email\email-pt_BR.tmpl"
Delete "${idir}\email\email-sr.tmpl" Delete "${idir}\email\email-sr.tmpl"
Delete "${idir}\email\email-ru.tmpl" Delete "${idir}\email\email-ru.tmpl"
Delete "${idir}\email\email-zh_CN.tmpl"
Delete "${idir}\email\rss-de.tmpl" Delete "${idir}\email\rss-de.tmpl"
Delete "${idir}\email\rss-en.tmpl" Delete "${idir}\email\rss-en.tmpl"
Delete "${idir}\email\rss-nl.tmpl" Delete "${idir}\email\rss-nl.tmpl"
@ -62,6 +64,7 @@
Delete "${idir}\email\rss-pt_BR.tmpl" Delete "${idir}\email\rss-pt_BR.tmpl"
Delete "${idir}\email\rss-sr.tmpl" Delete "${idir}\email\rss-sr.tmpl"
Delete "${idir}\email\rss-ru.tmpl" Delete "${idir}\email\rss-ru.tmpl"
Delete "${idir}\email\rss-zh_CN.tmpl"
Delete "${idir}\email\badfetch-da.tmpl" Delete "${idir}\email\badfetch-da.tmpl"
Delete "${idir}\email\badfetch-de.tmpl" Delete "${idir}\email\badfetch-de.tmpl"
Delete "${idir}\email\badfetch-en.tmpl" Delete "${idir}\email\badfetch-en.tmpl"
@ -76,6 +79,7 @@
Delete "${idir}\email\badfetch-es.tmpl" Delete "${idir}\email\badfetch-es.tmpl"
Delete "${idir}\email\badfetch-pt_BR.tmpl" Delete "${idir}\email\badfetch-pt_BR.tmpl"
Delete "${idir}\email\badfetch-ru.tmpl" Delete "${idir}\email\badfetch-ru.tmpl"
Delete "${idir}\email\badfetch-zh_CN.tmpl"
RMDir "${idir}\email" RMDir "${idir}\email"
RMDir /r "${idir}\locale" RMDir /r "${idir}\locale"
RMDir /r "${idir}\interfaces\Classic" RMDir /r "${idir}\interfaces\Classic"
@ -222,6 +226,9 @@
!insertmacro MUI_LANGUAGE "Romanian" !insertmacro MUI_LANGUAGE "Romanian"
!insertmacro MUI_LANGUAGE "Spanish" !insertmacro MUI_LANGUAGE "Spanish"
!insertmacro MUI_LANGUAGE "PortugueseBR" !insertmacro MUI_LANGUAGE "PortugueseBR"
!insertmacro MUI_LANGUAGE "Serbian"
!insertmacro MUI_LANGUAGE "Russian"
!insertmacro MUI_LANGUAGE "SimpChinese"
;------------------------------------------------------------------ ;------------------------------------------------------------------
@ -279,13 +286,13 @@ runtime_loop:
;make sure user terminates sabnzbd.exe or else abort ;make sure user terminates sabnzbd.exe or else abort
; ;
loop: loop:
StrCpy $0 "SABnzbd.exe" ${nsProcess::FindProcess} "SABnzbd.exe" $R0
KillProc::FindProcesses StrCmp $R0 0 0 endcheck
StrCmp $0 "0" endcheck MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION $(MsgCloseSab) IDOK loop IDCANCEL exitinstall
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION $(MsgCloseSab) /SD IDCANCEL IDOK loop IDCANCEL exitinstall
exitinstall: exitinstall:
${nsProcess::Unload}
Abort Abort
endcheck: endcheck:
FunctionEnd FunctionEnd
@ -311,6 +318,7 @@ File /r "dist\*"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" "" "$INSTDIR" WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" "" "$INSTDIR"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" "Installer Language" "$(MsgLangCode)"
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayName" "SABnzbd ${SAB_VERSION}" WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayName" "SABnzbd ${SAB_VERSION}"
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "UninstallString" '"$INSTDIR\uninstall.exe"' WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayVersion" '${SAB_VERSION}' WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayVersion" '${SAB_VERSION}'
@ -360,29 +368,8 @@ UninstallText $(MsgUninstall)
Section "un.$(MsgDelProgram)" Uninstall Section "un.$(MsgDelProgram)" Uninstall
;make sure sabnzbd.exe isnt running..if so shut it down ;make sure sabnzbd.exe isnt running..if so shut it down
${nsProcess::KillProcess} "SABnzbd.exe" $R0
StrCpy $0 "sabnzbd.exe" ${nsProcess::Unload}
DetailPrint "Searching for processes called '$0'"
KillProc::FindProcesses
StrCmp $1 "-1" wooops
DetailPrint "-> Found $0 processes"
StrCmp $0 "0" completed
Sleep 1500
StrCpy $0 "sabnzbd.exe"
DetailPrint "Killing all processes called '$0'"
KillProc::KillProcesses
StrCmp $1 "-1" wooops
DetailPrint "-> Killed $0 processes, failed to kill $1 processes"
Goto completed
wooops:
DetailPrint "-> Error: Something went wrong :-("
Abort
completed:
DetailPrint "Process Killed" DetailPrint "Process Killed"
@ -456,6 +443,7 @@ SectionEnd
LangString MsgRemoveOld2 ${LANG_ENGLISH} "Your settings and data will be preserved." LangString MsgRemoveOld2 ${LANG_ENGLISH} "Your settings and data will be preserved."
LangString MsgLangCode ${LANG_ENGLISH} "en"
Function un.onInit Function un.onInit
!insertmacro MUI_UNGETLANGUAGE !insertmacro MUI_UNGETLANGUAGE

5
README.md

@ -1,6 +1,11 @@
SABnzbd - The automated Usenet download tool SABnzbd - The automated Usenet download tool
============================================ ============================================
# WARNING
This Unicode release is not compatible with 0.7.x queues!
----
SABnzbd is an Open Source Binary Newsreader written in Python. SABnzbd is an Open Source Binary Newsreader written in Python.
It's totally free, incredibly easy to use, and works practically everywhere. It's totally free, incredibly easy to use, and works practically everywhere.

25
SABnzbd.py

@ -20,6 +20,16 @@ if sys.version_info < (2, 5):
print "Sorry, requires Python 2.5, 2.6 or 2.7." print "Sorry, requires Python 2.5, 2.6 or 2.7."
sys.exit(1) sys.exit(1)
# Make sure UTF-8 is default 8bit encoding
if not hasattr(sys,"setdefaultencoding"):
reload(sys)
try:
sys.setdefaultencoding('utf-8')
except:
print 'Sorry, you MUST add the SABnzbd folder to the PYTHONPATH environment variable'
print 'or find another way to force Python to use UTF-8 for string encoding.'
sys.exit(1)
import logging import logging
import logging.handlers import logging.handlers
import os import os
@ -63,6 +73,14 @@ except:
else: else:
SQLITE_DLL = False SQLITE_DLL = False
import locale, __builtin__
try:
locale.setlocale(locale.LC_ALL, "")
__builtin__.__dict__['codepage'] = locale.getlocale()[1] or 'cp1252'
except:
# Work-around for Python-ports with bad "locale" support
__builtin__.__dict__['codepage'] = 'cp1252'
import sabnzbd import sabnzbd
import sabnzbd.lang import sabnzbd.lang
import sabnzbd.interface import sabnzbd.interface
@ -78,7 +96,7 @@ import sabnzbd.scheduler as scheduler
import sabnzbd.config as config import sabnzbd.config as config
import sabnzbd.cfg import sabnzbd.cfg
import sabnzbd.downloader import sabnzbd.downloader
from sabnzbd.encoding import unicoder, latin1 from sabnzbd.encoding import unicoder, latin1, deunicode
import sabnzbd.growler as growler import sabnzbd.growler as growler
from threading import Thread from threading import Thread
@ -364,6 +382,7 @@ def CheckColor(color, web_dir):
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
def fix_webname(name): def fix_webname(name):
if name: if name:
name = deunicode(name)
xname = name.title() xname = name.title()
else: else:
xname = '' xname = ''
@ -417,8 +436,8 @@ def GetProfileInfo(vista_plus):
try: try:
# Conversion to 8bit ASCII required for CherryPy # Conversion to 8bit ASCII required for CherryPy
sabnzbd.DIR_APPDATA = sabnzbd.DIR_APPDATA.encode('latin-1') sabnzbd.DIR_APPDATA = sabnzbd.DIR_APPDATA.encode(codepage)
sabnzbd.DIR_HOME = sabnzbd.DIR_HOME.encode('latin-1') sabnzbd.DIR_HOME = sabnzbd.DIR_HOME.encode(codepage)
ok = True ok = True
except: except:
# If unconvertible characters exist, use MSDOS name # If unconvertible characters exist, use MSDOS name

4
package.py

@ -252,12 +252,12 @@ else:
PanDoc = None PanDoc = None
if os.name == 'nt': if os.name == 'nt':
msg = 'Requires the standard version of NSIS' msg = 'Requires the Unicode version of NSIS'
NSIS = CheckPath('makensis') NSIS = CheckPath('makensis')
if NSIS: if NSIS:
log = '%s.log' % NSIS log = '%s.log' % NSIS
os.system('%s >%s' % (NSIS, log)) os.system('%s >%s' % (NSIS, log))
if 'Unicode' not in open(log).read(): if 'Unicode' in open(log).read():
msg = '' msg = ''
delete_files(log) delete_files(log)
if msg: if msg:

0
po/email/pl.px → po/email/pl.po

0
po/email/ro.px → po/email/ro.po

0
po/main/pl.px → po/main/pl.po

0
po/main/ro.px → po/main/ro.po

0
po/nsis/pl.px → po/nsis/pl.po

0
po/nsis/ro.px → po/nsis/ro.po

16
sabnzbd/__init__.py

@ -586,7 +586,7 @@ def add_nzbfile(nzbfile, pp=None, script=None, cat=None, priority=NORMAL_PRIORIT
if script and script.lower()=='default': script = None if script and script.lower()=='default': script = None
if cat and cat.lower()=='default': cat = None if cat and cat.lower()=='default': cat = None
if isinstance(nzbfile, str): if isinstance(nzbfile, str) or isinstance(nzbfile, unicode):
# File coming from queue repair # File coming from queue repair
filename = nzbfile filename = nzbfile
keep = True keep = True
@ -594,7 +594,9 @@ def add_nzbfile(nzbfile, pp=None, script=None, cat=None, priority=NORMAL_PRIORIT
# File coming from API/TAPI # File coming from API/TAPI
# Consider reception of Latin-1 names for non-Windows platforms # Consider reception of Latin-1 names for non-Windows platforms
# When an OSX/Unix server receives a file from Windows platform # When an OSX/Unix server receives a file from Windows platform
filename = encoding.special_fixer(nzbfile.filename) # CherryPy delivers filename as UTF-8 disguised as Unicode!
filename = nzbfile.filename.encode('cp1252').decode('utf-8')
filename = encoding.special_fixer(filename)
keep = False keep = False
if not sabnzbd.WIN32: if not sabnzbd.WIN32:
@ -612,7 +614,15 @@ def add_nzbfile(nzbfile, pp=None, script=None, cat=None, priority=NORMAL_PRIORIT
else: else:
try: try:
f, path = tempfile.mkstemp(suffix=ext, text=False) f, path = tempfile.mkstemp(suffix=ext, text=False)
os.write(f, nzbfile.value) # More CherryPy madness, sometimes content is in 'value', sometimes not.
if nzbfile.value:
os.write(f, nzbfile.value)
elif hasattr(nzbfile, 'file'):
# CherryPy 3.2.2 object
if hasattr(nzbfile.file, 'file'):
os.write(f, nzbfile.file.file.read())
else:
os.write(f, nzbfile.file.read())
os.close(f) os.close(f)
except: except:
logging.error(Ta('Cannot create temp file for %s'), filename) logging.error(Ta('Cannot create temp file for %s'), filename)

7
sabnzbd/api.py

@ -294,6 +294,13 @@ def _api_addfile(name, output, kwargs):
#Side effect of next line is that attribute .value is created #Side effect of next line is that attribute .value is created
#which is needed to make add_nzbfile() work #which is needed to make add_nzbfile() work
size = name.length size = name.length
elif hasattr(name, 'file') and hasattr(name, 'filename') and name.filename:
# CherryPy 3.2.2 object
if hasattr(name.file, 'file'):
name.value = name.file.file.read()
else:
name.value = name.file.read()
size = len(name.value)
elif hasattr(name, 'value'): elif hasattr(name, 'value'):
size = len(name.value) size = len(name.value)
else: else:

37
sabnzbd/config.py

@ -20,6 +20,7 @@ sabnzbd.config - Configuration Support
""" """
import os import os
import re
import logging import logging
import threading import threading
import shutil import shutil
@ -683,19 +684,41 @@ def _read_config(path, try_backup=False):
return False, 'Cannot create INI file %s' % path return False, 'Cannot create INI file %s' % path
try: try:
CFG = configobj.ConfigObj(path) fp = open(path, 'r')
lines = fp.read().split('\n')
fp.close()
try: try:
if int(CFG['__version__']) > int(CONFIG_VERSION): # First try UTF-8 encoding
return False, "Incorrect version number %s in %s" % (CFG['__version__'], path) CFG = configobj.ConfigObj(lines, default_encoding='utf-8', encoding='utf-8')
except (KeyError, ValueError): except UnicodeDecodeError:
CFG['__version__'] = CONFIG_VERSION # Failed, enable retry
except configobj.ConfigObjError, strerror: CFG = {}
if not re.search(r'utf[ -]*8', CFG.get('__encoding__', ''), re.I):
# INI file is still in 8bit ASCII encoding, so try Latin-1 instead
CFG = configobj.ConfigObj(lines, default_encoding='cp1252', encoding='cp1252')
except (IOError, configobj.ConfigObjError, UnicodeEncodeError), strerror:
if try_backup: if try_backup:
if isinstance(strerror, UnicodeEncodeError):
strerror = 'Character encoding of the file is inconsistent'
return False, '"%s" is not a valid configuration file<br>Error message: %s' % (path, strerror) return False, '"%s" is not a valid configuration file<br>Error message: %s' % (path, strerror)
else: else:
# Try backup file
return _read_config(path, True) return _read_config(path, True)
CFG['__version__'] = CONFIG_VERSION try:
version = sabnzbd.misc.int_conv(CFG['__version__'])
if version > int(CONFIG_VERSION):
return False, "Incorrect version number %s in %s" % (version, path)
except (KeyError, ValueError):
pass
CFG.filename = path
CFG.encoding = 'utf-8'
CFG['__encoding__'] = u'utf-8'
CFG['__version__'] = unicode(CONFIG_VERSION)
if 'misc' in CFG: if 'misc' in CFG:
compatibility_fix(CFG['misc']) compatibility_fix(CFG['misc'])

8
sabnzbd/constants.py

@ -15,10 +15,10 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
CONFIG_VERSION = 19 CONFIG_VERSION = 20
QUEUE_VERSION = 9 QUEUE_VERSION = 10
POSTPROC_QUEUE_VERSION = 1 POSTPROC_QUEUE_VERSION = 2
PNFO_REPAIR_FIELD = 0 PNFO_REPAIR_FIELD = 0
PNFO_UNPACK_FIELD = 1 PNFO_UNPACK_FIELD = 1
@ -53,7 +53,7 @@ GIGI = float(2 ** 30)
MEBI = float(2 ** 20) MEBI = float(2 ** 20)
KIBI = float(2 ** 10) KIBI = float(2 ** 10)
BYTES_FILE_NAME = 'totals%s.sab' % QUEUE_VERSION BYTES_FILE_NAME = 'totals9.sab'
QUEUE_FILE_TMPL = 'queue%s.sab' QUEUE_FILE_TMPL = 'queue%s.sab'
QUEUE_FILE_NAME = QUEUE_FILE_TMPL % QUEUE_VERSION QUEUE_FILE_NAME = QUEUE_FILE_TMPL % QUEUE_VERSION
POSTPROC_QUEUE_FILE_NAME = 'postproc%s.sab' % POSTPROC_QUEUE_VERSION POSTPROC_QUEUE_FILE_NAME = 'postproc%s.sab' % POSTPROC_QUEUE_VERSION

2
sabnzbd/database.py

@ -83,7 +83,7 @@ class HistoryDB(object):
else: else:
create_table = False create_table = False
if sabnzbd.WIN32 and isinstance(db_path, str): if sabnzbd.WIN32 and isinstance(db_path, str):
self.con = sqlite3.connect(db_path.decode('latin-1').encode('utf-8')) self.con = sqlite3.connect(db_path.decode('cp1252').encode('utf-8'))
else: else:
self.con = sqlite3.connect(db_path) self.con = sqlite3.connect(db_path)
self.con.row_factory = dict_factory self.con.row_factory = dict_factory

131
sabnzbd/encoding.py

@ -56,34 +56,26 @@ def reliable_unpack_names():
return gUTF return gUTF
def platform_encode(p): def platform_encode(p):
""" Return the correct encoding for the platform: """ Return Unicode name, if not already Unicode, decode with UTF-8 or latin1
Latin-1 for Windows/Posix-non-UTF and UTF-8 for OSX/Posix-UTF
""" """
if isinstance(p, unicode): if p is None or isinstance(p, unicode):
if gUTF:
return p.encode('utf-8')
else:
return p.encode('latin-1', 'replace')
elif isinstance(p, basestring):
if gUTF:
try:
p.decode('utf-8')
return p
except:
return p.decode('latin-1').encode('utf-8')
else:
try:
return p.decode('utf-8').encode('latin-1', 'replace')
except:
return p
else:
return p return p
else:
try:
return p.decode('utf-8')
except:
return p.decode('cp1252')
def name_fixer(p): def name_fixer(p):
""" Return UTF-8 encoded string, if appropriate for the platform """ """ Return Unicode name of 8bit ASCII string, first try UTF-8, then cp1252
"""
if gUTF and p: if isinstance(p, unicode):
return p.decode('Latin-1', 'replace').encode('utf-8', 'replace').replace('?', '_') return p
elif isinstance(p, str):
try:
return p.decode('utf-8')
except:
return p.decode('cp1252')
else: else:
return p return p
@ -104,24 +96,17 @@ def special_fixer(p):
Also takes care of the situation where a non-Windows/UTF-8 system Also takes care of the situation where a non-Windows/UTF-8 system
receives a latin-1 encoded name. receives a latin-1 encoded name.
""" """
if sabnzbd.WIN32: if isinstance(p, unicode):
try: return p
return p.decode('utf-8').encode('latin-1', 'replace').replace('?', '_') try:
except: # First see if it isn't just UTF-8
return p p.decode('utf-8')
else: if sabnzbd.DARWIN and '&#' in p:
if gUTF: p = fixup_ff4(p)
try: return p.decode('utf-8')
# First see if it isn't just UTF-8 except:
p.decode('utf-8') # Now assume it's 8bit ASCII
if sabnzbd.DARWIN and '&#' in p: return p.decode('cp1252')
p = fixup_ff4(p)
return p
except:
# Now assume it's latin-1
return p.decode('Latin-1').encode('utf-8')
else:
return p
def unicoder(p): def unicoder(p):
""" Make sure a Unicode string is returned """ """ Make sure a Unicode string is returned """
@ -132,8 +117,8 @@ def unicoder(p):
try: try:
return p.decode('utf-8') return p.decode('utf-8')
except: except:
return p.decode('latin-1', 'replace') return p.decode('cp1252', 'replace')
return p.decode('latin-1', 'replace') return p.decode('cp1252', 'replace')
else: else:
return unicode(str(p)) return unicode(str(p))
@ -141,11 +126,7 @@ def unicode2local(p):
""" Convert Unicode filename to appropriate local encoding """ Convert Unicode filename to appropriate local encoding
Leave ? characters for uncovertible characters Leave ? characters for uncovertible characters
""" """
if sabnzbd.WIN32: return p
return p.encode('Latin-1', 'replace')
else:
return p.encode('utf-8', 'replace')
def xml_name(p, keep_escape=False, encoding=None): def xml_name(p, keep_escape=False, encoding=None):
""" Prepare name for use in HTML/XML contect """ """ Prepare name for use in HTML/XML contect """
@ -158,7 +139,7 @@ def xml_name(p, keep_escape=False, encoding=None):
elif gUTF: elif gUTF:
p = p.decode('utf-8', 'replace') p = p.decode('utf-8', 'replace')
else: else:
p = p.decode('Latin-1', 'replace') p = p.decode(codepage, 'replace')
else: else:
p = str(p) p = str(p)
@ -170,13 +151,7 @@ def xml_name(p, keep_escape=False, encoding=None):
def latin1(txt): def latin1(txt):
""" When Unicode or UTF-8, convert to Latin-1 """ """ When Unicode or UTF-8, convert to Latin-1 """
if isinstance(txt, unicode): return unicoder(txt)
return txt.encode('latin-1', 'replace').replace('?', '_')
elif txt and gUTF:
#return unicodedata.normalize('NFC', txt.decode('utf-8')).encode('latin-1', 'replace').replace('?', '_')
return txt.decode('utf-8').encode('latin-1', 'replace').replace('?', '_')
else:
return txt
def encode_for_xml(ustr, encoding='ascii'): def encode_for_xml(ustr, encoding='ascii'):
@ -187,7 +162,7 @@ def encode_for_xml(ustr, encoding='ascii'):
if isinstance(ustr, unicode): if isinstance(ustr, unicode):
pass pass
elif isinstance(ustr, str): elif isinstance(ustr, str):
ustr = ustr.decode('Latin-1', 'replace') ustr = ustr.decode(codepage, 'replace')
else: else:
ustr = unicode(str(ustr)) ustr = unicode(str(ustr))
return ustr.encode(encoding, 'xmlcharrefreplace') return ustr.encode(encoding, 'xmlcharrefreplace')
@ -195,7 +170,7 @@ def encode_for_xml(ustr, encoding='ascii'):
def titler(p): def titler(p):
""" title() replacement """ title() replacement
Python's title() fails with Latin-1, so use Unicode detour. Python's title() fails with 8bit ASCII, so use Unicode detour.
""" """
if isinstance(p, unicode): if isinstance(p, unicode):
return p.title() return p.title()
@ -203,9 +178,9 @@ def titler(p):
try: try:
return p.decode('utf-8').title().encode('utf-8') return p.decode('utf-8').title().encode('utf-8')
except: except:
return p.decode('latin-1', 'replace').title().encode('latin-1', 'replace') return p.decode(codepage, 'replace').title().encode(codepage, 'replace')
else: else:
return p.decode('latin-1', 'replace').title().encode('latin-1', 'replace') return p.decode(codepage, 'replace').title().encode(codepage, 'replace')
class LatinFilter(Filter): class LatinFilter(Filter):
@ -216,11 +191,11 @@ class LatinFilter(Filter):
elif isinstance(val, basestring): elif isinstance(val, basestring):
try: try:
if sabnzbd.WIN32: if sabnzbd.WIN32:
return val.decode('latin-1') return val.decode(codepage)
else: else:
return val.decode('utf-8') return val.decode('utf-8')
except: except:
return val.decode('latin-1', 'replace') return val.decode(codepage, 'replace')
elif val is None: elif val is None:
return u'' return u''
else: else:
@ -228,7 +203,7 @@ class LatinFilter(Filter):
class EmailFilter(Filter): class EmailFilter(Filter):
""" Make sure Cheetah gets only Unicode strings """ Make sure Cheetah gets only Unicode strings
First try utf-8, then latin1 First try utf-8, then 8bit ASCII
""" """
def filter(self, val, str=str, **kw): def filter(self, val, str=str, **kw):
if isinstance(val, unicode): if isinstance(val, unicode):
@ -237,7 +212,7 @@ class EmailFilter(Filter):
try: try:
return val.decode('utf-8') return val.decode('utf-8')
except: except:
return val.decode('latin-1', 'replace') return val.decode(codepage, 'replace')
elif val is None: elif val is None:
return u'' return u''
else: else:
@ -339,4 +314,30 @@ def html_escape(txt):
else: else:
return txt return txt
def deunicode(p):
""" Return the correct 8bit ASCII encoding for the platform:
Latin-1 for Windows/Posix-non-UTF and UTF-8 for OSX/Posix-UTF
"""
if isinstance(p, unicode):
if gUTF:
return p.encode('utf-8')
else:
return p.encode('cp1252', 'replace')
elif isinstance(p, basestring):
if gUTF:
try:
p.decode('utf-8')
return p
except:
return p.decode('cp1252').encode('utf-8')
else:
try:
return p.decode('utf-8').encode('cp1252', 'replace')
except:
return p
else:
return p
auto_fsys() auto_fsys()

8
sabnzbd/growler.py

@ -194,9 +194,11 @@ def send_growl(title , msg, gtype):
if _GROWL: if _GROWL:
assert isinstance(_GROWL, GrowlNotifier) assert isinstance(_GROWL, GrowlNotifier)
_GROWL_REG = True _GROWL_REG = True
if not isinstance(msg, str) and not isinstance(msg, unicode): if isinstance(msg, unicode):
msg = msg.decode('utf-8')
elif not isinstance(msg, str):
msg = str(msg) msg = str(msg)
logging.debug('Send to Growl: %s %s %s', gtype, latin1(title), latin1(msg)) logging.debug('Send to Growl: %s %s %s', gtype, title, msg)
try: try:
ret = _GROWL.notify( ret = _GROWL.notify(
noteType = Tx(NOTIFICATION.get(gtype, 'other')), noteType = Tx(NOTIFICATION.get(gtype, 'other')),
@ -264,7 +266,7 @@ if _HAVE_NTFOSD:
icon = os.path.join(sabnzbd.DIR_PROG, 'sabnzbd.ico') icon = os.path.join(sabnzbd.DIR_PROG, 'sabnzbd.ico')
_NTFOSD = _NTFOSD or pynotify.init('icon-summary-body') _NTFOSD = _NTFOSD or pynotify.init('icon-summary-body')
if _NTFOSD: if _NTFOSD:
logging.info('Send to NotifyOSD: %s / %s', latin1(title), latin1(message)) logging.info('Send to NotifyOSD: %s / %s', title, message)
try: try:
note = pynotify.Notification(title, message, icon) note = pynotify.Notification(title, message, icon)
note.show() note.show()

7
sabnzbd/interface.py

@ -356,9 +356,10 @@ class MainPage(object):
if msg: return msg if msg: return msg
nzbfile = kwargs.get('nzbfile') nzbfile = kwargs.get('nzbfile')
if nzbfile is not None and nzbfile.filename and nzbfile.value: if nzbfile is not None and nzbfile.filename:
sabnzbd.add_nzbfile(nzbfile, kwargs.get('pp'), kwargs.get('script'), if nzbfile.value or nzbfile.file:
kwargs.get('cat'), kwargs.get('priority', NORMAL_PRIORITY)) sabnzbd.add_nzbfile(nzbfile, kwargs.get('pp'), kwargs.get('script'),
kwargs.get('cat'), kwargs.get('priority', NORMAL_PRIORITY))
raise dcRaiser(self.__root, kwargs) raise dcRaiser(self.__root, kwargs)
@cherrypy.expose @cherrypy.expose

186
sabnzbd/lang.py

@ -42,6 +42,7 @@ __all__ = ['set_locale_info', 'set_language', 'list_languages']
_DOMAIN = '' # Holds translation domain _DOMAIN = '' # Holds translation domain
_LOCALEDIR = '' # Holds path to the translation base folder _LOCALEDIR = '' # Holds path to the translation base folder
CODEPAGE = '1252'
def set_locale_info(domain, localedir): def set_locale_info(domain, localedir):
@ -55,7 +56,9 @@ def set_locale_info(domain, localedir):
def set_language(language=None): def set_language(language=None):
""" Activate language, empty language will set default texts. """ Activate language, empty language will set default texts.
""" """
global CODEPAGE
if not language: language = '' if not language: language = ''
CODEPAGE = str(LanguageTable.get(language, (0, 0, 0))[2] or 1252)
# 'codeset' will determine the output of lgettext # 'codeset' will determine the output of lgettext
lng = gettext.translation(_DOMAIN, _LOCALEDIR, [language], fallback=True, codeset='latin-1') lng = gettext.translation(_DOMAIN, _LOCALEDIR, [language], fallback=True, codeset='latin-1')
@ -63,9 +66,9 @@ def set_language(language=None):
# The unicode flag will make _() return Unicode # The unicode flag will make _() return Unicode
lng.install(unicode=True, names=['lgettext']) lng.install(unicode=True, names=['lgettext'])
__builtin__.__dict__['T'] = __builtin__.__dict__['_'] # Unicode __builtin__.__dict__['T'] = __builtin__.__dict__['_'] # Unicode
__builtin__.__dict__['Ta'] = __builtin__.__dict__['lgettext'] # Latin-1 __builtin__.__dict__['Ta'] = __builtin__.__dict__['_'] # Unicode (Used to Latin-1, compatibility support)
__builtin__.__dict__['Tx'] = __builtin__.__dict__['_'] # Dynamic translation (unicode) __builtin__.__dict__['Tx'] = __builtin__.__dict__['_'] # Dynamic translation (unicode)
__builtin__.__dict__['TT'] = lambda x:x # Use in text tables __builtin__.__dict__['TT'] = lambda x:unicode(x) # Use in text tables
def list_languages(): def list_languages():
@ -106,94 +109,97 @@ def list_languages():
LanguageTable = { LanguageTable = {
'aa' : ('Afar', 'Afaraf'), 'aa' : ('Afar', 'Afaraf', 0),
'af' : ('Afrikaans', 'Afrikaans'), 'af' : ('Afrikaans', 'Afrikaans', 0),
'ak' : ('Akan', 'Akan'), 'ak' : ('Akan', 'Akan', 0),
'sq' : ('Albanian', 'Shqip'), 'sq' : ('Albanian', 'Shqip', 0),
'an' : ('Aragonese', 'Aragonés'), 'an' : ('Aragonese', 'Aragonés', 0),
'ae' : ('Avestan', 'Avesta'), 'ae' : ('Avestan', 'Avesta', 0),
'ay' : ('Aymara', 'Aymararu'), 'ay' : ('Aymara', 'Aymararu', 0),
'bm' : ('Bambara', 'Bamanankan'), 'bm' : ('Bambara', 'Bamanankan', 0),
'eu' : ('Basque', 'Euskara'), 'eu' : ('Basque', 'Euskara', 0),
'bi' : ('Bislama', 'Bislama'), 'bi' : ('Bislama', 'Bislama', 0),
'bs' : ('Bosnian', 'Bosanskijezik'), 'bs' : ('Bosnian', 'Bosanskijezik', 0),
'br' : ('Breton', 'Brezhoneg'), 'br' : ('Breton', 'Brezhoneg', 0),
'ca' : ('Catalan', 'Català'), 'ca' : ('Catalan', 'Català', 0),
'ch' : ('Chamorro', 'Chamoru'), 'ch' : ('Chamorro', 'Chamoru', 0),
'kw' : ('Cornish', 'Kernewek'), 'kw' : ('Cornish', 'Kernewek', 0),
'co' : ('Corsican', 'Corsu'), 'co' : ('Corsican', 'Corsu', 0),
'hr' : ('Croatian', 'Hrvatski'), 'hr' : ('Croatian', 'Hrvatski', 0),
'cs' : ('Czech', 'Cesky, ceština'), 'cs' : ('Czech', 'Cesky, ceština', 0),
'da' : ('Danish', 'Dansk'), 'da' : ('Danish', 'Dansk', 0),
'nl' : ('Dutch', 'Nederlands'), 'nl' : ('Dutch', 'Nederlands', 0),
'en' : ('English', 'English'), 'en' : ('English', 'English', 0),
'eo' : ('Esperanto', 'Esperanto'), 'eo' : ('Esperanto', 'Esperanto', 0),
'et' : ('Estonian', 'Eesti'), 'et' : ('Estonian', 'Eesti', 0),
'fo' : ('Faroese', 'Føroyskt'), 'fo' : ('Faroese', 'Føroyskt', 0),
'fj' : ('Fijian', 'Vosa Vakaviti'), 'fj' : ('Fijian', 'Vosa Vakaviti', 0),
'fi' : ('Finnish', 'Suomi'), 'fi' : ('Finnish', 'Suomi', 0),
'fr' : ('French', 'Français'), 'fr' : ('French', 'Français', 0),
'gl' : ('Galician', 'Galego'), 'gl' : ('Galician', 'Galego', 0),
'de' : ('German', 'Deutsch'), 'de' : ('German', 'Deutsch', 0),
'hz' : ('Herero', 'Otjiherero'), 'hz' : ('Herero', 'Otjiherero', 0),
'ho' : ('Hiri Motu', 'Hiri Motu'), 'ho' : ('Hiri Motu', 'Hiri Motu', 0),
'hu' : ('Hungarian', 'Magyar'), 'hu' : ('Hungarian', 'Magyar', 0),
'id' : ('Indonesian', 'Bahasa Indonesia'), 'id' : ('Indonesian', 'Bahasa Indonesia', 0),
'ga' : ('Irish', 'Gaeilge'), 'ga' : ('Irish', 'Gaeilge', 0),
'io' : ('Ido', 'Ido'), 'io' : ('Ido', 'Ido', 0),
'is' : ('Icelandic', 'Íslenska'), 'is' : ('Icelandic', 'Íslenska', 0),
'it' : ('Italian', 'Italiano'), 'it' : ('Italian', 'Italiano', 0),
'jv' : ('Javanese', 'BasaJawa'), 'jv' : ('Javanese', 'BasaJawa', 0),
'rw' : ('Kinyarwanda', 'Ikinyarwanda'), 'rw' : ('Kinyarwanda', 'Ikinyarwanda', 0),
'kg' : ('Kongo', 'KiKongo'), 'kg' : ('Kongo', 'KiKongo', 0),
'kj' : ('Kwanyama', 'Kuanyama'), 'kj' : ('Kwanyama', 'Kuanyama', 0),
'la' : ('Latin', 'Lingua latina'), 'la' : ('Latin', 'Lingua latina', 0),
'lb' : ('Luxembourgish', 'Lëtzebuergesch'), 'lb' : ('Luxembourgish', 'Lëtzebuergesch', 0),
'lg' : ('Luganda', 'Luganda'), 'lg' : ('Luganda', 'Luganda', 0),
'li' : ('Limburgish', 'Limburgs'), 'li' : ('Limburgish', 'Limburgs', 0),
'ln' : ('Lingala', 'Lingála'), 'ln' : ('Lingala', 'Lingála', 0),
'lt' : ('Lithuanian', 'Lietuviukalba'), 'lt' : ('Lithuanian', 'Lietuviukalba', 0),
'lv' : ('Latvian', 'Latviešuvaloda'), 'lv' : ('Latvian', 'Latviešuvaloda', 0),
'gv' : ('Manx', 'Gaelg'), 'gv' : ('Manx', 'Gaelg', 0),
'mg' : ('Malagasy', 'Malagasy fiteny'), 'mg' : ('Malagasy', 'Malagasy fiteny', 0),
'mt' : ('Maltese', 'Malti'), 'mt' : ('Maltese', 'Malti', 0),
'nb' : ('Norwegian Bokmål', 'Norsk bokmål'), 'nb' : ('Norwegian Bokmål', 'Norsk bokmål', 0),
'nn' : ('Norwegian Nynorsk', 'Norsk nynorsk'), 'nn' : ('Norwegian Nynorsk', 'Norsk nynorsk', 0),
'no' : ('Norwegian', 'Norsk'), 'no' : ('Norwegian', 'Norsk', 0),
'oc' : ('Occitan', 'Occitan'), 'oc' : ('Occitan', 'Occitan', 0),
'om' : ('Oromo', 'Afaan Oromoo'), 'om' : ('Oromo', 'Afaan Oromoo', 0),
'pl' : ('Polish', 'Polski'), 'pl' : ('Polish', 'Polski', 0),
'pt' : ('Portuguese', 'Português'), 'pt' : ('Portuguese', 'Português', 0),
'pt_BR' : ('Portuguese Brazillian', 'Português Brasileiro'), 'pt_BR' : ('Portuguese Brazillian', 'Português Brasileiro', 0),
'rm' : ('Romansh', 'Rumantsch grischun'), 'rm' : ('Romansh', 'Rumantsch grischun', 0),
'rn' : ('Kirundi', 'kiRundi'), 'rn' : ('Kirundi', 'kiRundi', 0),
'ro' : ('Romanian', 'Româna'), 'ro' : ('Romanian', 'Româna', 1250),
'sc' : ('Sardinian', 'Sardu'), 'sc' : ('Sardinian', 'Sardu', 0),
'se' : ('Northern Sami', 'Davvisámegiella'), 'se' : ('Northern Sami', 'Davvisámegiella', 0),
'sm' : ('Samoan', 'Gagana fa\'a Samoa'), 'sm' : ('Samoan', 'Gagana fa\'a Samoa', 0),
'gd' : ('Gaelic', 'Gàidhlig'), 'gd' : ('Gaelic', 'Gàidhlig', 0),
'sn' : ('Shona', 'Chi Shona'), 'ru' : ('Russian', 'русский язык', 1251),
'sk' : ('Slovak', 'Slovencina'), 'sr' : ('Serbian', 'српски', 1251),
'sl' : ('Slovene', 'Slovenšcina'), 'sn' : ('Shona', 'Chi Shona', 0),
'st' : ('Southern Sotho', 'Sesotho'), 'sk' : ('Slovak', 'Slovencina', 0),
'es' : ('Spanish Castilian', 'Español, castellano'), 'sl' : ('Slovene', 'Slovenšcina', 0),
'su' : ('Sundanese', 'Basa Sunda'), 'st' : ('Southern Sotho', 'Sesotho', 0),
'sw' : ('Swahili', 'Kiswahili'), 'es' : ('Spanish Castilian', 'Español, castellano', 0),
'ss' : ('Swati', 'SiSwati'), 'su' : ('Sundanese', 'Basa Sunda', 0),
'sv' : ('Swedish', 'Svenska'), 'sw' : ('Swahili', 'Kiswahili', 0),
'tn' : ('Tswana', 'Setswana'), 'ss' : ('Swati', 'SiSwati', 0),
'to' : ('Tonga (Tonga Islands)', 'faka Tonga'), 'sv' : ('Swedish', 'Svenska', 0),
'tr' : ('Turkish', 'Türkçe'), 'tn' : ('Tswana', 'Setswana', 0),
'ts' : ('Tsonga', 'Xitsonga'), 'to' : ('Tonga (Tonga Islands)', 'faka Tonga', 0),
'tw' : ('Twi', 'Twi'), 'tr' : ('Turkish', 'Türkçe', 0),
'ty' : ('Tahitian', 'Reo Tahiti'), 'ts' : ('Tsonga', 'Xitsonga', 0),
'wa' : ('Walloon', 'Walon'), 'tw' : ('Twi', 'Twi', 0),
'cy' : ('Welsh', 'Cymraeg'), 'ty' : ('Tahitian', 'Reo Tahiti', 0),
'wo' : ('Wolof', 'Wollof'), 'wa' : ('Walloon', 'Walon', 0),
'fy' : ('Western Frisian', 'Frysk'), 'cy' : ('Welsh', 'Cymraeg', 0),
'xh' : ('Xhosa', 'isi Xhosa'), 'wo' : ('Wolof', 'Wollof', 0),
'yo' : ('Yoruba', 'Yorùbá'), 'fy' : ('Western Frisian', 'Frysk', 0),
'zu' : ('Zulu', 'isi Zulu'), 'xh' : ('Xhosa', 'isi Xhosa', 0),
'yo' : ('Yoruba', 'Yorùbá', 0),
'zu' : ('Zulu', 'isi Zulu', 0),
'zh_CN' : ('SimpChinese', '简体中文', 936),
} }
# Setup a safe null-translation # Setup a safe null-translation

50
sabnzbd/misc.py

@ -222,8 +222,8 @@ def sanitize_filename(name):
FL_ILLEGAL = CH_ILLEGAL + ':\x92"' FL_ILLEGAL = CH_ILLEGAL + ':\x92"'
FL_LEGAL = CH_LEGAL + "-''" FL_LEGAL = CH_LEGAL + "-''"
uFL_ILLEGAL = FL_ILLEGAL.decode('latin-1') uFL_ILLEGAL = FL_ILLEGAL.decode('cp1252')
uFL_LEGAL = FL_LEGAL.decode('latin-1') uFL_LEGAL = FL_LEGAL.decode('cp1252')
def sanitize_foldername(name): def sanitize_foldername(name):
""" Return foldername with dodgy chars converted to safe ones """ Return foldername with dodgy chars converted to safe ones
@ -405,20 +405,7 @@ def get_user_shellfolders():
try: try:
for i in range(0, _winreg.QueryInfoKey(key)[1]): for i in range(0, _winreg.QueryInfoKey(key)[1]):
name, value, val_type = _winreg.EnumValue(key, i) name, value, val_type = _winreg.EnumValue(key, i)
try: values[name] = value
values[name] = value.encode('latin-1')
except UnicodeEncodeError:
try:
# If the path name cannot be converted to latin-1 (contains high ASCII value strings)
# then try and use the short name
import win32api
# Need to make sure the path actually exists, otherwise ignore
if os.path.exists(value):
values[name] = win32api.GetShortPathName(value)
except:
# probably a pywintypes.error error such as folder does not exist
logging.error("Traceback: ", exc_info = True)
values[name] = 'c:\\'
i += 1 i += 1
_winreg.CloseKey(key) _winreg.CloseKey(key)
_winreg.CloseKey(hive) _winreg.CloseKey(hive)
@ -1039,35 +1026,30 @@ def loadavg():
def format_time_string(seconds, days=0): def format_time_string(seconds, days=0):
""" Return a formatted and translated time string """ """ Return a formatted and translated time string """
def unit(single, n):
if n == 1:
return sabnzbd.api.Ttemplate(single)
else:
return sabnzbd.api.Ttemplate(single + 's')
seconds = int_conv(seconds) seconds = int_conv(seconds)
completestr = [] completestr = []
if days: if days:
completestr.append('%s %s' % (days, s_returner('day', days))) completestr.append('%s %s' % (days, unit('day', days)))
if (seconds/3600) >= 1: if (seconds/3600) >= 1:
completestr.append('%s %s' % (seconds/3600, s_returner('hour', (seconds/3600)))) completestr.append('%s %s' % (seconds/3600, unit('hour', (seconds/3600))))
seconds -= (seconds/3600)*3600 seconds -= (seconds/3600)*3600
if (seconds/60) >= 1: if (seconds/60) >= 1:
completestr.append('%s %s' % (seconds/60, s_returner('minute',(seconds/60)))) completestr.append('%s %s' % (seconds/60, unit('minute',(seconds/60))))
seconds -= (seconds/60)*60 seconds -= (seconds/60)*60
if seconds > 0: if seconds > 0:
completestr.append('%s %s' % (seconds, s_returner('second', seconds))) completestr.append('%s %s' % (seconds, unit('second', seconds)))
elif not completestr: elif not completestr:
completestr.append('0 %s' % s_returner('second', 0)) completestr.append('0 %s' % unit('second', 0))
p = ' '.join(completestr)
if isinstance(p, unicode):
return p.encode('latin-1')
else:
return p
return ' '.join(completestr)
def s_returner(item, value):
""" Return a plural form of 'item', based on 'value' (english only)
"""
if value == 1:
return Tx(item)
else:
return Tx(item + 's')
def int_conv(value): def int_conv(value):
""" Safe conversion to int (can handle None) """ Safe conversion to int (can handle None)

9
sabnzbd/newsunpack.py

@ -29,7 +29,7 @@ import binascii
import sabnzbd import sabnzbd
from sabnzbd.encoding import TRANS, UNTRANS, unicode2local, name_fixer, \ from sabnzbd.encoding import TRANS, UNTRANS, unicode2local, name_fixer, \
reliable_unpack_names, unicoder, latin1, platform_encode reliable_unpack_names, unicoder, latin1, platform_encode, deunicode
from sabnzbd.utils.rarfile import RarFile, is_rarfile from sabnzbd.utils.rarfile import RarFile, is_rarfile
from sabnzbd.misc import format_time_string, find_on_path, make_script_path, int_conv, \ from sabnzbd.misc import format_time_string, find_on_path, make_script_path, int_conv, \
flag_file, real_path, globber flag_file, real_path, globber
@ -1341,8 +1341,9 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False):
elif line.startswith('File:') and line.find('data blocks from') > 0: elif line.startswith('File:') and line.find('data blocks from') > 0:
# Find out if a joinable file has been used for joining # Find out if a joinable file has been used for joining
uline = unicoder(line)
for jn in joinables: for jn in joinables:
if line.find(os.path.split(jn)[1]) > 0: if uline.find(os.path.split(jn)[1]) > 0:
used_joinables.append(jn) used_joinables.append(jn)
break break
# Special case of joined RAR files, the "of" and "from" must both be RAR files # Special case of joined RAR files, the "of" and "from" must both be RAR files
@ -1454,6 +1455,10 @@ def fix_env():
def build_command(command): def build_command(command):
""" Prepare list from running an external program """ Prepare list from running an external program
""" """
for n in xrange(len(command)):
if isinstance(command[n], unicode):
command[n] = deunicode(command[n])
if not sabnzbd.WIN32: if not sabnzbd.WIN32:
if IONICE_COMMAND and cfg.ionice().strip(): if IONICE_COMMAND and cfg.ionice().strip():
lst = cfg.ionice().split() lst = cfg.ionice().split()

2
sabnzbd/newzbin.py

@ -106,8 +106,6 @@ class MSGIDGrabber(Thread):
filename, data, newzbin_cat, nzo_info = _grabnzb(msgid) filename, data, newzbin_cat, nzo_info = _grabnzb(msgid)
if filename and data: if filename and data:
filename = name_fixer(filename)
pp = nzo.pp pp = nzo.pp
script = nzo.script script = nzo.script
cat = nzo.cat cat = nzo.cat

14
sabnzbd/nzbqueue.py

@ -35,7 +35,7 @@ from sabnzbd.decorators import NZBQUEUE_LOCK, synchronized, synchronized_CV
from sabnzbd.constants import QUEUE_FILE_NAME, QUEUE_VERSION, FUTURE_Q_FOLDER, JOB_ADMIN, \ from sabnzbd.constants import QUEUE_FILE_NAME, QUEUE_VERSION, FUTURE_Q_FOLDER, JOB_ADMIN, \
LOW_PRIORITY, NORMAL_PRIORITY, HIGH_PRIORITY, TOP_PRIORITY, \ LOW_PRIORITY, NORMAL_PRIORITY, HIGH_PRIORITY, TOP_PRIORITY, \
REPAIR_PRIORITY, STOP_PRIORITY, VERIFIED_FILE, \ REPAIR_PRIORITY, STOP_PRIORITY, VERIFIED_FILE, \
PNFO_BYTES_FIELD, PNFO_BYTES_LEFT_FIELD, Status PNFO_BYTES_FIELD, PNFO_BYTES_LEFT_FIELD, Status, QUEUE_FILE_TMPL
import sabnzbd.cfg as cfg import sabnzbd.cfg as cfg
from sabnzbd.articlecache import ArticleCache from sabnzbd.articlecache import ArticleCache
import sabnzbd.downloader import sabnzbd.downloader
@ -71,7 +71,15 @@ class NzbQueue(TryList):
if repair < 2: if repair < 2:
# Read the queue from the saved files # Read the queue from the saved files
data = sabnzbd.load_admin(QUEUE_FILE_NAME) data = sabnzbd.load_admin(QUEUE_FILE_NAME)
if data: if not data:
try:
# Try previous queue file
queue_vers, nzo_ids, dummy = sabnzbd.load_admin(QUEUE_FILE_TMPL % '9')
except:
nzo_ids = []
if nzo_ids:
logging.warning(T('Old queue detected, use Status->Repair to convert the queue'))
else:
try: try:
queue_vers, nzo_ids, dummy = data queue_vers, nzo_ids, dummy = data
if not queue_vers == QUEUE_VERSION: if not queue_vers == QUEUE_VERSION:
@ -115,7 +123,7 @@ class NzbQueue(TryList):
def scan_jobs(self, all=False, action=True): def scan_jobs(self, all=False, action=True):
""" Scan "incomplete" for mssing folders, """ Scan "incomplete" for missing folders,
'all' is True: Include active folders 'all' is True: Include active folders
'action' is True, do the recovery action 'action' is True, do the recovery action
returns list of orphaned folders returns list of orphaned folders

43
sabnzbd/nzbstuff.py

@ -41,7 +41,7 @@ from sabnzbd.constants import sample_match, GIGI, ATTRIB_FILE, JOB_ADMIN, \
from sabnzbd.misc import to_units, cat_to_opts, cat_convert, sanitize_foldername, \ from sabnzbd.misc import to_units, cat_to_opts, cat_convert, sanitize_foldername, \
get_unique_path, get_admin_path, remove_all, format_source_url, \ get_unique_path, get_admin_path, remove_all, format_source_url, \
sanitize_filename, globber, sanitize_foldername, int_conv, \ sanitize_filename, globber, sanitize_foldername, int_conv, \
set_permissions set_permissions, format_time_string
import sabnzbd.cfg as cfg import sabnzbd.cfg as cfg
from sabnzbd.trylist import TryList from sabnzbd.trylist import TryList
from sabnzbd.encoding import unicoder, platform_encode, latin1, name_fixer from sabnzbd.encoding import unicoder, platform_encode, latin1, name_fixer
@ -361,8 +361,6 @@ class NzbParser(xml.sax.handler.ContentHandler):
logging.info('Skipping sample file %s', subject) logging.info('Skipping sample file %s', subject)
else: else:
self.in_file = True self.in_file = True
if isinstance(subject, unicode):
subject = subject.encode('latin-1', 'replace')
self.fileSubject = subject self.fileSubject = subject
try: try:
self.file_date = int(attrs.get('date')) self.file_date = int(attrs.get('date'))
@ -757,6 +755,9 @@ class NzbObject(TryList):
# Pickup backed-up attributes when re-using # Pickup backed-up attributes when re-using
if reuse: if reuse:
cat, pp, script, priority, name, self.url = get_attrib_file(self.workpath, 6) cat, pp, script, priority, name, self.url = get_attrib_file(self.workpath, 6)
cat = unicoder(cat)
script = unicoder(script)
name = unicoder(name)
self.set_final_name_pw(name) self.set_final_name_pw(name)
# Determine category and find pp/script values # Determine category and find pp/script values
@ -1039,9 +1040,9 @@ class NzbObject(TryList):
if dif > 0: if dif > 0:
prefix += Ta('WAIT %s sec') % dif + ' / ' #: Queue indicator for waiting URL fetch prefix += Ta('WAIT %s sec') % dif + ' / ' #: Queue indicator for waiting URL fetch
if self.password: if self.password:
return '%s%s / %s' % (name_fixer(prefix), self.final_name, self.password) return '%s%s / %s' % (prefix, self.final_name, self.password)
else: else:
return '%s%s' % (name_fixer(prefix), self.final_name) return '%s%s' % (prefix, self.final_name)
@property @property
def final_name_pw_clean(self): def final_name_pw_clean(self):
@ -1051,7 +1052,7 @@ class NzbObject(TryList):
return self.final_name return self.final_name
def set_final_name_pw(self, name): def set_final_name_pw(self, name):
if isinstance(name, str): if isinstance(name, str) or isinstance(name, unicode):
name, self.password = scan_password(platform_encode(name)) name, self.password = scan_password(platform_encode(name))
self.final_name = sanitize_foldername(name) self.final_name = sanitize_foldername(name)
self.save_attribs() self.save_attribs()
@ -1574,36 +1575,6 @@ def split_filename(name):
return name.strip(), "" return name.strip(), ""
def format_time_string(seconds, days=0):
""" Given seconds and days, return formatted day/hour/min/sec string
"""
def unit(n, single):
if n == 1:
return n, Tx(single)
else:
return n, Tx(single + 's')
try:
seconds = int(seconds)
except ValueError:
seconds = 0
completestr = ''
if days:
completestr += '%s %s ' % unit(days, 'day')
if (seconds/3600) >= 1:
completestr += '%s %s ' % unit(seconds/3600, 'hour')
seconds -= (seconds/3600)*3600
if (seconds/60) >= 1:
completestr += '%s %s ' % unit(seconds/60, 'minute')
seconds -= (seconds/60)*60
if seconds > 0:
completestr += '%s %s ' % unit(seconds, 'second')
else:
completestr += '%s %s' % unit(0, 'second')
return completestr.strip()
RE_PASSWORD1 = re.compile(r'([^/\\]+)[/\\](.+)') RE_PASSWORD1 = re.compile(r'([^/\\]+)[/\\](.+)')
RE_PASSWORD2 = re.compile(r'(.+){{([^{}]+)}}$') RE_PASSWORD2 = re.compile(r'(.+){{([^{}]+)}}$')
RE_PASSWORD3 = re.compile(r'(.+)\s+password\s*=\s*(.+)$', re.I) RE_PASSWORD3 = re.compile(r'(.+)\s+password\s*=\s*(.+)$', re.I)

4
sabnzbd/postproc.py

@ -94,8 +94,8 @@ class PostProcessor(Thread):
try: try:
version, history_queue = data version, history_queue = data
if POSTPROC_QUEUE_VERSION != version: if POSTPROC_QUEUE_VERSION != version:
logging.warning(Ta('Failed to load postprocessing queue: Wrong version (need:%s, found:%s)'), POSTPROC_QUEUE_VERSION, version) logging.warning(T('Old queue detected, use Status->Repair to convert the queue'))
if isinstance(history_queue, list): elif isinstance(history_queue, list):
self.history_queue = [nzo for nzo in history_queue if os.path.exists(nzo.downpath)] self.history_queue = [nzo for nzo in history_queue if os.path.exists(nzo.downpath)]
except: except:
logging.info('Corrupt %s file, discarding', POSTPROC_QUEUE_FILE_NAME) logging.info('Corrupt %s file, discarding', POSTPROC_QUEUE_FILE_NAME)

14
sabnzbd/rss.py

@ -374,21 +374,17 @@ class RSSQueue(object):
link, category = _get_link(uri, entry) link, category = _get_link(uri, entry)
except (AttributeError, IndexError): except (AttributeError, IndexError):
link = None link = None
category = '' category = u''
logging.info(Ta('Incompatible feed') + ' ' + uri) logging.info(Ta('Incompatible feed') + ' ' + uri)
logging.info("Traceback: ", exc_info = True) logging.info("Traceback: ", exc_info = True)
return T('Incompatible feed') return T('Incompatible feed')
category = latin1(category) title = entry.title
# Make sure only latin-1 encodable characters occur
atitle = latin1(entry.title)
title = unicoder(atitle)
else: else:
link = entry link = entry
category = jobs[link].get('orgcat', '') category = jobs[link].get('orgcat', '')
if category in ('', '*'): if category in ('', '*'):
category = None category = None
atitle = latin1(jobs[link].get('title', '')) title = jobs[link].get('title', '')
title = unicoder(atitle)
if link: if link:
# Make sure spaces are quoted in the URL # Make sure spaces are quoted in the URL
@ -406,7 +402,7 @@ class RSSQueue(object):
jobstat = 'N' jobstat = 'N'
if jobstat in 'NGB' or (jobstat == 'X' and readout): if jobstat in 'NGB' or (jobstat == 'X' and readout):
# Match this title against all filters # Match this title against all filters
logging.debug('Trying title %s', atitle) logging.debug('Trying title %s', title)
result = False result = False
myCat = defCat myCat = defCat
myPP = defPP myPP = defPP
@ -465,7 +461,7 @@ class RSSQueue(object):
if cfg.no_dupes() and dup_title(title): if cfg.no_dupes() and dup_title(title):
if cfg.no_dupes() == 1: if cfg.no_dupes() == 1:
logging.info("Ignoring duplicate job %s", atitle) logging.info("Ignoring duplicate job %s", title)
continue continue
else: else:
myPrio = DUP_PRIORITY myPrio = DUP_PRIORITY

54
sabnzbd/sabtray.py

@ -55,18 +55,38 @@ class SABTrayThread(SysTrayIconThread):
self.counter = 0 self.counter = 0
text = "SABnzbd" text = "SABnzbd"
self.set_texts()
menu_options = ( menu_options = (
(T('Show interface'), None, self.browse), (self.txt_show_int, None, self.browse),
(T('Open complete folder'), None, self.opencomplete), (self.txt_open_comp, None, self.opencomplete),
(T('Troubleshoot'), None, ((T('Restart'), None, self.restart), (self.txt_trouble, None, ((self.txt_restart, None, self.restart),
(T('Restart without login'), None, self.nologin), (self.txt_restart_nl, None, self.nologin),
(T('Restart') + ' - 127.0.0.1:8080', None, self.defhost))), (self.txt_restart + ' - 127.0.0.1:8080', None, self.defhost))),
(T('Pause') + '/' + T('Resume'), None, self.pauseresume), (self.txt_pause + '/' + self.txt_resume, None, self.pauseresume),
(T('Shutdown'), None, self.shutdown), (self.txt_shutdown, None, self.shutdown),
) )
SysTrayIconThread.__init__(self, self.sabicons['default'], text, menu_options, None, 0, "SabTrayIcon") SysTrayIconThread.__init__(self, self.sabicons['default'], text, menu_options, None, 0, "SabTrayIcon")
def set_texts(self):
def fix(txt):
if trans:
return Tx(txt)
else:
return txt
trans = str(get_codepage()) == str(sabnzbd.lang.CODEPAGE)
self.txt_show_int = fix(TT('Show interface'))
self.txt_open_comp = fix(TT('Open complete folder'))
self.txt_trouble = fix(TT('Troubleshoot'))
self.txt_pause = fix(TT('Pause'))
self.txt_shutdown = fix(TT('Shutdown'))
self.txt_resume = fix(TT('Resume'))
self.txt_restart = fix(TT('Restart'))
self.txt_restart_nl = fix(TT('Restart without login'))
self.txt_idle = fix(TT('Idle'))
self.txt_paused = fix(TT('Paused'))
self.txt_remaining = fix(TT('Remaining'))
# called every few ms by SysTrayIconThread # called every few ms by SysTrayIconThread
def doUpdates(self): def doUpdates(self):
@ -78,13 +98,13 @@ class SABTrayThread(SysTrayIconThread):
speed = to_units(bpsnow, dec_limit=1) speed = to_units(bpsnow, dec_limit=1)
if self.sabpaused: if self.sabpaused:
self.hover_text = T('Paused') self.hover_text = self.txt_paused
self.icon = self.sabicons['pause'] self.icon = self.sabicons['pause']
elif bytes_left > 0: elif bytes_left > 0:
self.hover_text = "%sB/s %s: %sB (%s)" % (speed, T('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'] self.icon = self.sabicons['green']
else: else:
self.hover_text = T('Idle') self.hover_text = self.txt_idle
self.icon = self.sabicons['default'] self.icon = self.sabicons['default']
self.refresh_icon() self.refresh_icon()
@ -112,7 +132,7 @@ class SABTrayThread(SysTrayIconThread):
# menu handler # menu handler
def restart(self, icon): def restart(self, icon):
self.hover_text = T('Restart') self.hover_text = self.txt_restart
sabnzbd.halt() sabnzbd.halt()
cherrypy.engine.restart() cherrypy.engine.restart()
@ -121,7 +141,7 @@ class SABTrayThread(SysTrayIconThread):
sabnzbd.cfg.username.set('') sabnzbd.cfg.username.set('')
sabnzbd.cfg.password.set('') sabnzbd.cfg.password.set('')
sabnzbd.config.save_config() sabnzbd.config.save_config()
self.hover_text = T('Restart') self.hover_text = self.txt_restart
sabnzbd.halt() sabnzbd.halt()
cherrypy.engine.restart() cherrypy.engine.restart()
@ -130,13 +150,13 @@ class SABTrayThread(SysTrayIconThread):
sabnzbd.cfg.cherryhost.set('127.0.0.1') sabnzbd.cfg.cherryhost.set('127.0.0.1')
sabnzbd.cfg.enable_https.set(False) sabnzbd.cfg.enable_https.set(False)
sabnzbd.config.save_config() sabnzbd.config.save_config()
self.hover_text = T('Restart') self.hover_text = self.txt_restart
sabnzbd.halt() sabnzbd.halt()
cherrypy.engine.restart() cherrypy.engine.restart()
# menu handler - adapted from interface.py # menu handler - adapted from interface.py
def shutdown(self, icon): def shutdown(self, icon):
self.hover_text = T('Shutdown') self.hover_text = self.txt_shutdown
sabnzbd.halt() sabnzbd.halt()
cherrypy.engine.exit() cherrypy.engine.exit()
sabnzbd.SABSTOP = True sabnzbd.SABSTOP = True
@ -151,3 +171,9 @@ class SABTrayThread(SysTrayIconThread):
scheduler.plan_resume(0) scheduler.plan_resume(0)
sabnzbd.unpause_all() sabnzbd.unpause_all()
def get_codepage():
import locale
lang, code = locale.getlocale()
logging.debug('SysTray uses codepage %s', code)
return code

3
sabnzbd/utils/json.py

@ -68,7 +68,8 @@ class JsonWriter(object):
try: try:
obj.decode('utf-8') obj.decode('utf-8')
except: except:
obj = obj.decode('latin-1').encode('utf-8', 'replace') # Should never be needed
obj = obj.decode('cp1252').encode('utf-8', 'replace')
obj = obj.replace('\\', r'\\') obj = obj.replace('\\', r'\\')
if self._escaped_forward_slash: if self._escaped_forward_slash:
obj = obj.replace('/', r'\/') obj = obj.replace('/', r'\/')

5
sabnzbd/utils/rarfile.py

@ -7,8 +7,6 @@
# - Improve compatibility with Python's ZipFile support: # - Improve compatibility with Python's ZipFile support:
# - Always use Unix separators '/' in pathnames (ascii & unicode) # - Always use Unix separators '/' in pathnames (ascii & unicode)
# - Foldernames must always end with a '/' (ascii & unicode) # - Foldernames must always end with a '/' (ascii & unicode)
# - Use CP850 as default codepage
# - Convert ASCII filenames to Python's default 'latin-1' encoding
# #
# Optimized to fit in SABnzbd: # Optimized to fit in SABnzbd:
# - No extract hack (not needed for just rarred NZB files). # - No extract hack (not needed for just rarred NZB files).
@ -357,8 +355,7 @@ class RarFile:
h.filename = name[:nul] h.filename = name[:nul]
u = _UnicodeFilename(h.filename, name[nul + 1 : ]) u = _UnicodeFilename(h.filename, name[nul + 1 : ])
h.unicode_filename = u.decode() h.unicode_filename = u.decode()
# Remap ASCII name from CP850 to Python's default Latin-1 h.filename = h.filename.decode(self.charset, 'replace')
h.filename = h.filename.decode(self.charset, 'replace').encode('latin-1', 'replace')
else: else:
h.filename = name h.filename = name
h.unicode_filename = name.decode(self.charset, 'replace') h.unicode_filename = name.decode(self.charset, 'replace')

11
sabnzbd/wizard.py

@ -20,6 +20,7 @@ sabnzbd.wizard - Wizard Webinterface
""" """
import os import os
import logging
import cherrypy import cherrypy
from Cheetah.Template import Template from Cheetah.Template import Template
@ -50,10 +51,18 @@ class Wizard(object):
info = self.info.copy() info = self.info.copy()
info['num'] = '' info['num'] = ''
info['number'] = 0 info['number'] = 0
info['lang'] = cfg.language() lng = None
if sabnzbd.WIN32:
import util.apireg
lng = util.apireg.get_install_lng()
logging.debug('Installer language code "%s"', lng)
info['lang'] = lng or cfg.language()
info['languages'] = list_languages() info['languages'] = list_languages()
info['T'] = Ttemplate info['T'] = Ttemplate
set_language(info['lang'])
sabnzbd.api.clear_trans_cache()
if not os.path.exists(self.__web_dir): if not os.path.exists(self.__web_dir):
# If the wizard folder does not exist, simply load the normal page # If the wizard folder does not exist, simply load the normal page
raise cherrypy.HTTPRedirect('') raise cherrypy.HTTPRedirect('')

4
tools/extract_pot.py

@ -184,10 +184,8 @@ dst.write('\n')
count = 0 count = 0
for line in src: for line in src:
count += 1 count += 1
if 'Please, first check' in line:
pass
m = RE_NSIS.search(line) m = RE_NSIS.search(line)
if m: if m and 'MsgLangCode' not in line:
dst.write('#: %s:%s\n' % (NSIS, count)) dst.write('#: %s:%s\n' % (NSIS, count))
text = m.group(1).replace('$\\"', '\\"').replace('$\\', '\\\\') text = m.group(1).replace('$\\"', '\\"').replace('$\\', '\\\\')
dst.write('msgid %s\n' % text) dst.write('msgid %s\n' % text)

116
tools/make_mo.py

@ -105,6 +105,8 @@ LanguageTable = {
'se' : ('Northern Sami', 'Davvisámegiella'), 'se' : ('Northern Sami', 'Davvisámegiella'),
'sm' : ('Samoan', 'Gagana fa\'a Samoa'), 'sm' : ('Samoan', 'Gagana fa\'a Samoa'),
'gd' : ('Gaelic', 'Gàidhlig'), 'gd' : ('Gaelic', 'Gàidhlig'),
'ru' : ('Russian', 'русский язык'),
'sr' : ('Serbian', 'српски'),
'sn' : ('Shona', 'Chi Shona'), 'sn' : ('Shona', 'Chi Shona'),
'sk' : ('Slovak', 'Slovencina'), 'sk' : ('Slovak', 'Slovencina'),
'sl' : ('Slovene', 'Slovenšcina'), 'sl' : ('Slovene', 'Slovenšcina'),
@ -127,6 +129,7 @@ LanguageTable = {
'xh' : ('Xhosa', 'isi Xhosa'), 'xh' : ('Xhosa', 'isi Xhosa'),
'yo' : ('Yoruba', 'Yorùbá'), 'yo' : ('Yoruba', 'Yorùbá'),
'zu' : ('Zulu', 'isi Zulu'), 'zu' : ('Zulu', 'isi Zulu'),
'zh_CN' : ('SimpChinese', '简体中文'),
} }
# Filter for retrieving readable language from PO file # Filter for retrieving readable language from PO file
@ -194,95 +197,11 @@ def make_templates():
os.remove(mo_path) os.remove(mo_path)
# Convert Romanian PX files to Latin1 PO files
ro_table = {
u"\u015f" : u"s", # ș
u"\u015e" : u"S", # Ș
u"\u0163" : u"t", # ț
u"\u0162" : u"T", # Ț
u"\u0103" : u"ã", # ă
u"\u0102" : u"Ã", # Ă
u'\u021b' : u"t", # ț
u'\u0218' : u"S", # Ș
u'\u0219' : u"s" # ș
}
# Convert Polish PX files to Latin1 PO files
pl_table = {
u"\u0104" : u"A", # Ą
u"\u0106" : u"C", # Ć
u"\u0118" : u"E", # Ę
u"\u0141" : u"L", # Ł
u"\u013B" : u"L", # Ł
u"\u0143" : u"N", # Ń
#u"\u00D3" : u"O", # Ó
u"\u015A" : u"S", # Ś
u"\u0179" : u"Z", # Ź
u"\u017B" : u"Z", # Ż
u"\u0105" : u"a", # ą
u"\u0107" : u"c", # ć
u"\u0119" : u"e", # ę
u"\u0142" : u"l", # ł
u"\u0144" : u"n", # ń
#u"\u00F3" : u"o", # ó
u"\u015B" : u"s", # ś
u"\u017A" : u"z", # ź
u"\u017C" : u"z" # ż
}
def fix_ro():
""" Convert ro.px files to ro.po files with only Latin1
"""
for section in ('main', 'email', 'nsis'):
f = open('po/%s/ro.px' % section, 'rb')
data = f.read().decode('utf-8')
f.close()
for ch in ro_table:
data = data.replace(ch, ro_table[ch])
f = open('po/%s/ro.po' % section, 'wb')
f.write(data.encode('utf-8'))
f.close()
try:
lnum = 0
for line in data.split('\n'):
lnum += 1
line.encode('latin-1')
except:
print line.encode('utf-8')
print 'WARNING: line %d in file po/%s/ro.po is not Latin-1' % (lnum, section)
exit(1)
def fix_pl():
""" Convert pl.px files to pl.po files with only Latin1
"""
for section in ('main', 'email', 'nsis'):
f = open('po/%s/pl.px' % section, 'rb')
data = f.read().decode('utf-8')
f.close()
for ch in pl_table:
data = data.replace(ch, pl_table[ch])
f = open('po/%s/pl.po' % section, 'wb')
f.write(data.encode('utf-8'))
f.close()
try:
lnum = 0
for line in data.split('\n'):
lnum += 1
line.encode('latin-1')
except:
print line.encode('utf-8')
print 'WARNING: line %d in file po/%s/pl.po is not Latin-1' % (lnum, section)
exit(1)
def patch_nsis(): def patch_nsis():
""" Patch translation into the NSIS script """ Patch translation into the NSIS script
""" """
RE_NSIS = re.compile(r'^(\s*LangString\s+\w+\s+\$\{LANG_)(\w+)\}\s+(".*)', re.I) RE_NSIS = re.compile(r'^(\s*LangString\s+\w+\s+\$\{LANG_)(\w+)\}\s+(".*)', re.I)
RE_NSIS = re.compile(r'^(\s*LangString\s+)(\w+)(\s+\$\{LANG_)(\w+)\}\s+(".*)', re.I)
languages = [os.path.split(path)[1] for path in glob.glob(os.path.join(MO_DIR, '*'))] languages = [os.path.split(path)[1] for path in glob.glob(os.path.join(MO_DIR, '*'))]
src = open(NSIS, 'r') src = open(NSIS, 'r')
@ -291,8 +210,10 @@ def patch_nsis():
m = RE_NSIS.search(line) m = RE_NSIS.search(line)
if m: if m:
leader = m.group(1) leader = m.group(1)
langname = m.group(2).upper() item = m.group(2)
text = m.group(3).strip('"\n') rest = m.group(3)
langname = m.group(4).upper()
text = m.group(5).strip('"\n')
if langname == 'ENGLISH': if langname == 'ENGLISH':
# Write back old content # Write back old content
new.append(line) new.append(line)
@ -302,13 +223,16 @@ def patch_nsis():
lng = LanguageTable.get(lcode) lng = LanguageTable.get(lcode)
if lng and lcode != 'en': if lng and lcode != 'en':
lng = lng[0].decode('utf-8').encode('latin-1').upper() lng = lng[0].decode('utf-8').encode('latin-1').upper()
trans = gettext.translation(DOMAIN_N, MO_DIR, [lcode], fallback=False, codeset='latin-1') if item == 'MsgLangCode':
# The unicode flag will make _() return Unicode trans = lcode
trans.install(unicode=True, names=['lgettext']) else:
trans = lgettext(text) trans = gettext.translation(DOMAIN_N, MO_DIR, [lcode], fallback=False, codeset='latin-1')
trans = trans.replace('\r', '').replace('\n', '\\r\\n') # The unicode flag will make _() return Unicode
trans = trans.replace('\\', '$\\').replace('"', '$\\"') trans.install(unicode=True, names=['lgettext'])
line = '%s%s} "%s"\n' % (leader, lng, trans) trans = _(text).encode('utf-8')
trans = trans.replace('\r', '').replace('\n', '\\r\\n')
trans = trans.replace('\\', '$\\').replace('"', '$\\"')
line = '%s%s%s%s} "%s"\n' % (leader, item, rest, lng, trans)
new.append(line) new.append(line)
elif lng is None: elif lng is None:
print 'Warning: unsupported language %s (%s), add to table in this script' % (langname, lcode) print 'Warning: unsupported language %s (%s), add to table in this script' % (langname, lcode)
@ -331,10 +255,6 @@ if os.path.exists(tl):
else: else:
TOOL = '"%s"' % tl TOOL = '"%s"' % tl
# Fix up Romanian and Polish texts
fix_ro()
fix_pl()
if len(sys.argv) > 1 and sys.argv[1] == 'all': if len(sys.argv) > 1 and sys.argv[1] == 'all':
print 'NSIS MO file' print 'NSIS MO file'
process_po_folder(DOMAIN_N, PON_DIR) process_po_folder(DOMAIN_N, PON_DIR)

27
util/apireg.py

@ -46,7 +46,6 @@ def get_connection_info(user=True):
key = _winreg.OpenKey(hive, keypath + r'\api') key = _winreg.OpenKey(hive, keypath + r'\api')
for i in range(0, _winreg.QueryInfoKey(key)[1]): for i in range(0, _winreg.QueryInfoKey(key)[1]):
name, value, val_type = _winreg.EnumValue(key, i) name, value, val_type = _winreg.EnumValue(key, i)
value = value.encode('latin-1', 'replace')
if name == 'url': if name == 'url':
url = value url = value
@ -101,6 +100,26 @@ def del_connection_info(user=True):
_winreg.CloseKey(hive) _winreg.CloseKey(hive)
#print get_connection_info() def get_install_lng():
#del_connection_info() """ Return language-code used by the installer """
#set_connection_info('localhost', '8080', 'blabla', user=False) lng = 0
try:
hive = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
key = _winreg.OpenKey(hive, r"Software\SABnzbd")
for i in range(0, _winreg.QueryInfoKey(key)[1]):
name, value, val_type = _winreg.EnumValue(key, i)
if name == 'Installer Language':
lng = value
_winreg.CloseKey(key)
except WindowsError:
pass
finally:
_winreg.CloseKey(hive)
return lng
if __name__ == '__main__':
print 'URL = %s' %get_connection_info()
print 'Language = %s' % get_install_lng()
#del_connection_info()
#set_connection_info('localhost', '8080', 'blabla', user=False)

Loading…
Cancel
Save