tools v5.6
This commit is contained in:
@@ -1,13 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# DeDRM.pyw, version 5.5.3
|
||||
# DeDRM.pyw, version 5.6
|
||||
# By some_updates and Apprentice Alf
|
||||
|
||||
import sys
|
||||
import os, os.path
|
||||
sys.path.append(os.path.join(sys.path[0],"lib"))
|
||||
os.environ['PYTHONIOENCODING'] = "utf-8"
|
||||
import sys, os
|
||||
import codecs
|
||||
|
||||
from argv_utils import add_cp65001_codec, set_utf8_default_encoding, utf8_argv
|
||||
add_cp65001_codec()
|
||||
set_utf8_default_encoding()
|
||||
|
||||
|
||||
import shutil
|
||||
import Tkinter
|
||||
@@ -16,15 +22,35 @@ import Tkconstants
|
||||
import tkFileDialog
|
||||
from scrolltextwidget import ScrolledText
|
||||
from activitybar import ActivityBar
|
||||
import subprocess
|
||||
from subprocess import Popen, PIPE, STDOUT
|
||||
import subasyncio
|
||||
from subasyncio import Process
|
||||
import re
|
||||
import simpleprefs
|
||||
|
||||
from Queue import Full
|
||||
from Queue import Empty
|
||||
from multiprocessing import Process, Queue
|
||||
|
||||
__version__ = '5.5.3'
|
||||
from scriptinterface import decryptepub, decryptpdb, decryptpdf, decryptk4mobi
|
||||
|
||||
|
||||
# Wrap a stream so that output gets flushed immediately
|
||||
# and appended to shared queue
|
||||
class QueuedStream:
|
||||
def __init__(self, stream, q):
|
||||
self.stream = stream
|
||||
self.encoding = stream.encoding
|
||||
self.q = q
|
||||
if self.encoding == None:
|
||||
self.encoding = "utf-8"
|
||||
def write(self, data):
|
||||
if isinstance(data,unicode):
|
||||
data = data.encode(self.encoding,"replace")
|
||||
self.q.put(data)
|
||||
# self.stream.write(data)
|
||||
# self.stream.flush()
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.stream, attr)
|
||||
|
||||
__version__ = '5.6'
|
||||
|
||||
class DrmException(Exception):
|
||||
pass
|
||||
@@ -35,6 +61,7 @@ class MainApp(Tk):
|
||||
self.withdraw()
|
||||
self.dnd = dnd
|
||||
self.apphome = apphome
|
||||
|
||||
# preference settings
|
||||
# [dictionary key, file in preferences directory where info is stored]
|
||||
description = [ ['pids' , 'pidlist.txt' ],
|
||||
@@ -152,7 +179,7 @@ class PrefsDialog(Toplevel):
|
||||
self.pidnums.set(self.prefs_array['pids'])
|
||||
self.pidinfo.grid(row=3, column=1, sticky=sticky)
|
||||
|
||||
Tkinter.Label(body, text='eInk Kindle Serial Number list\n(16 characters, first character B, comma separated)').grid(row=4, sticky=Tkconstants.E)
|
||||
Tkinter.Label(body, text='eInk Kindle Serial Number list\n(16 characters, comma separated)').grid(row=4, sticky=Tkconstants.E)
|
||||
self.sernums = Tkinter.StringVar()
|
||||
self.serinfo = Tkinter.Entry(body, width=50, textvariable=self.sernums)
|
||||
if 'serials' in self.prefs_array:
|
||||
@@ -327,10 +354,11 @@ class ConvDialog(Toplevel):
|
||||
self.filenames = filenames
|
||||
self.interval = 50
|
||||
self.p2 = None
|
||||
self.q = Queue()
|
||||
self.running = 'inactive'
|
||||
self.numgood = 0
|
||||
self.numbad = 0
|
||||
self.log = u""
|
||||
self.log = ''
|
||||
self.status = Tkinter.Label(self, text='DeDRM processing...')
|
||||
self.status.pack(fill=Tkconstants.X, expand=1)
|
||||
body = Tkinter.Frame(self)
|
||||
@@ -378,16 +406,18 @@ class ConvDialog(Toplevel):
|
||||
if len(self.filenames) > 0:
|
||||
filename = self.filenames.pop(0)
|
||||
if filename == None:
|
||||
msg = u"\nComplete: Successes: {0}, Failures: {1}\n".format(self.numgood,self.numbad)
|
||||
msg = '\nComplete: '
|
||||
msg += 'Successes: %d, ' % self.numgood
|
||||
msg += 'Failures: %d\n' % self.numbad
|
||||
self.showCmdOutput(msg)
|
||||
if self.numbad == 0:
|
||||
self.after(2000,self.conversion_done())
|
||||
logfile = os.path.join(rscpath,'dedrm.log')
|
||||
file(logfile,'w').write(self.log.encode('utf8'))
|
||||
file(logfile,'wb').write(self.log)
|
||||
return
|
||||
infile = filename
|
||||
bname = os.path.basename(infile)
|
||||
msg = u"Processing: {0} ... ".format(bname)
|
||||
msg = 'Processing: ' + bname + ' ... '
|
||||
self.log += msg
|
||||
self.showCmdOutput(msg)
|
||||
outdir = os.path.dirname(filename)
|
||||
@@ -399,9 +429,9 @@ class ConvDialog(Toplevel):
|
||||
if rv == 0:
|
||||
self.bar.start()
|
||||
self.running = 'active'
|
||||
self.processPipe()
|
||||
self.processQueue()
|
||||
else:
|
||||
msg = u"Unknown File: {0}\n".format(bname)
|
||||
msg = 'Unknown File: ' + bname + '\n'
|
||||
self.log += msg
|
||||
self.showCmdOutput(msg)
|
||||
self.numbad += 1
|
||||
@@ -410,7 +440,7 @@ class ConvDialog(Toplevel):
|
||||
# kill any still running subprocess
|
||||
self.running = 'stopped'
|
||||
if self.p2 != None:
|
||||
if (self.p2.wait('nowait') == None):
|
||||
if (self.p2.exitcode == None):
|
||||
self.p2.terminate()
|
||||
self.conversion_done()
|
||||
|
||||
@@ -426,130 +456,127 @@ class ConvDialog(Toplevel):
|
||||
# read from subprocess pipe without blocking
|
||||
# invoked every interval via the widget "after"
|
||||
# option being used, so need to reset it for the next time
|
||||
def processPipe(self):
|
||||
def processQueue(self):
|
||||
if self.p2 == None:
|
||||
# nothing to wait for so just return
|
||||
return
|
||||
poll = self.p2.wait('nowait')
|
||||
poll = self.p2.exitcode
|
||||
if poll != None:
|
||||
self.bar.stop()
|
||||
if poll == 0:
|
||||
msg = u"\nSuccess\n"
|
||||
msg = 'Success\n'
|
||||
self.numgood += 1
|
||||
text = self.p2.read().decode('utf8')
|
||||
text += self.p2.readerr().decode('utf8')
|
||||
done = False
|
||||
text = ''
|
||||
while not done:
|
||||
try:
|
||||
data = self.q.get_nowait()
|
||||
text += data
|
||||
except Empty:
|
||||
done = True
|
||||
pass
|
||||
self.log += text
|
||||
self.log += msg
|
||||
else:
|
||||
msg = u"\nFailed\n"
|
||||
text = self.p2.read().decode('utf8')
|
||||
text += self.p2.readerr().decode('utf8')
|
||||
msg += text
|
||||
self.numbad += 1
|
||||
if poll != 0:
|
||||
msg = 'Failed\n'
|
||||
done = False
|
||||
text = ''
|
||||
while not done:
|
||||
try:
|
||||
data = self.q.get_nowait()
|
||||
text += data
|
||||
except Empty:
|
||||
done = True
|
||||
pass
|
||||
msg += '\n'
|
||||
self.log += text
|
||||
self.log += msg
|
||||
self.numbad += 1
|
||||
self.p2.join()
|
||||
self.showCmdOutput(msg)
|
||||
self.p2 = None
|
||||
self.running = 'inactive'
|
||||
self.after(50,self.processBooks)
|
||||
return
|
||||
try:
|
||||
text = self.q.get_nowait()
|
||||
except Empty:
|
||||
text = ''
|
||||
pass
|
||||
if text != '':
|
||||
self.log += text
|
||||
# make sure we get invoked again by event loop after interval
|
||||
self.stext.after(self.interval,self.processPipe)
|
||||
self.stext.after(self.interval,self.processQueue)
|
||||
return
|
||||
|
||||
def decrypt_ebook(self, infile, outdir, rscpath):
|
||||
apphome = self.apphome
|
||||
q = self.q
|
||||
rv = 1
|
||||
name, ext = os.path.splitext(os.path.basename(infile))
|
||||
ext = ext.lower()
|
||||
if ext == '.epub':
|
||||
self.p2 = processEPUB(apphome, infile, outdir, rscpath)
|
||||
self.p2 = Process(target=processEPUB, args=(q, infile, outdir, rscpath))
|
||||
self.p2.start()
|
||||
return 0
|
||||
if ext == '.pdb':
|
||||
self.p2 = processPDB(apphome, infile, outdir, rscpath)
|
||||
self.p2 = Process(target=processPDB, args=(q, infile, outdir, rscpath))
|
||||
self.p2.start()
|
||||
return 0
|
||||
if ext in ['.azw', '.azw1', '.azw3', '.azw4', '.prc', '.mobi', '.tpz']:
|
||||
self.p2 = processK4MOBI(apphome, infile, outdir, rscpath)
|
||||
self.p2 = Process(target=processK4MOBI,args=(q, infile, outdir, rscpath))
|
||||
self.p2.start()
|
||||
return 0
|
||||
if ext == '.pdf':
|
||||
self.p2 = processPDF(apphome, infile, outdir, rscpath)
|
||||
self.p2 = Process(target=processPDF, args=(q, infile, outdir, rscpath))
|
||||
self.p2.start()
|
||||
return 0
|
||||
return rv
|
||||
|
||||
|
||||
# run as a subprocess via pipes and collect stdout, stderr, and return value
|
||||
def runit(apphome, ncmd, nparms):
|
||||
pengine = sys.executable
|
||||
if pengine is None or pengine == '':
|
||||
pengine = 'python'
|
||||
pengine = os.path.normpath(pengine)
|
||||
cmdline = pengine + ' "' + os.path.join(apphome, ncmd) + '" '
|
||||
# if sys.platform.startswith('win'):
|
||||
# search_path = os.environ['PATH']
|
||||
# search_path = search_path.lower()
|
||||
# if search_path.find('python') < 0:
|
||||
# # if no python hope that win registry finds what is associated with py extension
|
||||
# cmdline = pengine + ' "' + os.path.join(apphome, ncmd) + '" '
|
||||
cmdline += nparms
|
||||
cmdline = cmdline.encode(sys.getfilesystemencoding())
|
||||
p2 = subasyncio.Process(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False, env = os.environ)
|
||||
return p2
|
||||
# child process starts here
|
||||
def processK4MOBI(q, infile, outdir, rscpath):
|
||||
add_cp65001_codec()
|
||||
set_utf8_default_encoding()
|
||||
sys.stdout = QueuedStream(sys.stdout, q)
|
||||
sys.stderr = QueuedStream(sys.stderr, q)
|
||||
rv = decryptk4mobi(infile, outdir, rscpath)
|
||||
sys.exit(rv)
|
||||
|
||||
def processK4MOBI(apphome, infile, outdir, rscpath):
|
||||
cmd = os.path.join('lib','k4mobidedrm.py')
|
||||
parms = ''
|
||||
pidnums = ''
|
||||
pidspath = os.path.join(rscpath,'pidlist.txt')
|
||||
if os.path.exists(pidspath):
|
||||
pidnums = file(pidspath,'r').read()
|
||||
pidnums = pidnums.rstrip(os.linesep)
|
||||
if pidnums != '':
|
||||
parms += '-p "' + pidnums + '" '
|
||||
serialnums = ''
|
||||
serialnumspath = os.path.join(rscpath,'seriallist.txt')
|
||||
if os.path.exists(serialnumspath):
|
||||
serialnums = file(serialnumspath,'r').read()
|
||||
serialnums = serialnums.rstrip(os.linesep)
|
||||
if serialnums != '':
|
||||
parms += '-s "' + serialnums + '" '
|
||||
# child process starts here
|
||||
def processPDF(q, infile, outdir, rscpath):
|
||||
add_cp65001_codec()
|
||||
set_utf8_default_encoding()
|
||||
sys.stdout = QueuedStream(sys.stdout, q)
|
||||
sys.stderr = QueuedStream(sys.stderr, q)
|
||||
rv = decryptpdf(infile, outdir, rscpath)
|
||||
sys.exit(rv)
|
||||
|
||||
files = os.listdir(rscpath)
|
||||
filefilter = re.compile("\.info$|\.kinf$", re.IGNORECASE)
|
||||
files = filter(filefilter.search, files)
|
||||
if files:
|
||||
for filename in files:
|
||||
dpath = os.path.join(rscpath,filename)
|
||||
parms += '-k "' + dpath + '" '
|
||||
parms += '"' + infile +'" "' + outdir + '"'
|
||||
p2 = runit(apphome, cmd, parms)
|
||||
return p2
|
||||
# child process starts here
|
||||
def processEPUB(q, infile, outdir, rscpath):
|
||||
add_cp65001_codec()
|
||||
set_utf8_default_encoding()
|
||||
sys.stdout = QueuedStream(sys.stdout, q)
|
||||
sys.stderr = QueuedStream(sys.stderr, q)
|
||||
rv = decryptepub(infile, outdir, rscpath)
|
||||
sys.exit(rv)
|
||||
|
||||
def processPDF(apphome, infile, outdir, rscpath):
|
||||
cmd = os.path.join('lib','decryptpdf.py')
|
||||
parms = '"' + infile + '" "' + outdir + '" "' + rscpath + '"'
|
||||
p2 = runit(apphome, cmd, parms)
|
||||
return p2
|
||||
|
||||
def processEPUB(apphome, infile, outdir, rscpath):
|
||||
# invoke routine to check both Adept and Barnes and Noble
|
||||
cmd = os.path.join('lib','decryptepub.py')
|
||||
parms = '"' + infile + '" "' + outdir + '" "' + rscpath + '"'
|
||||
p2 = runit(apphome, cmd, parms)
|
||||
return p2
|
||||
|
||||
def processPDB(apphome, infile, outdir, rscpath):
|
||||
cmd = os.path.join('lib','decryptpdb.py')
|
||||
parms = '"' + infile + '" "' + outdir + '" "' + rscpath + '"'
|
||||
p2 = runit(apphome, cmd, parms)
|
||||
return p2
|
||||
# child process starts here
|
||||
def processPDB(q, infile, outdir, rscpath):
|
||||
add_cp65001_codec()
|
||||
set_utf8_default_encoding()
|
||||
sys.stdout = QueuedStream(sys.stdout, q)
|
||||
sys.stderr = QueuedStream(sys.stderr, q)
|
||||
rv = decryptpdb(infile, outdir, rscpath)
|
||||
sys.exit(rv)
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
apphome = os.path.dirname(sys.argv[0])
|
||||
def main(argv=utf8_argv()):
|
||||
apphome = os.path.dirname(argv[0])
|
||||
apphome = os.path.abspath(apphome)
|
||||
|
||||
# windows may pass a spurious quoted null string as argv[1] from bat file
|
||||
# simply work around this until we can figure out a better way to handle things
|
||||
if len(argv) == 2:
|
||||
if sys.platform.startswith('win') and len(argv) == 2:
|
||||
temp = argv[1]
|
||||
temp = temp.strip('"')
|
||||
temp = temp.strip()
|
||||
@@ -563,11 +590,10 @@ def main(argv=sys.argv):
|
||||
else : # processing books via drag and drop
|
||||
dnd = True
|
||||
# build a list of the files to be processed
|
||||
# note all filenames and paths have been utf-8 encoded
|
||||
infilelst = argv[1:]
|
||||
filenames = []
|
||||
for infile in infilelst:
|
||||
infile = infile.decode(sys.getfilesystemencoding())
|
||||
print infile
|
||||
infile = infile.replace('"','')
|
||||
infile = os.path.abspath(infile)
|
||||
if os.path.isdir(infile):
|
||||
|
||||
@@ -34,10 +34,14 @@ def _load_libalfcrypto():
|
||||
else:
|
||||
name_of_lib = 'libalfcrypto64.so'
|
||||
|
||||
# hard code to local location for libalfcrypto
|
||||
libalfcrypto = os.path.join(sys.path[0],name_of_lib)
|
||||
|
||||
if not os.path.isfile(libalfcrypto):
|
||||
raise Exception('libalfcrypto not found')
|
||||
libalfcrypto = os.path.join(sys.path[0], 'lib', name_of_lib)
|
||||
if not os.path.isfile(libalfcrypto):
|
||||
libalfcrypto = os.path.join('.',name_of_lib)
|
||||
if not os.path.isfile(libalfcrypto):
|
||||
raise Exception('libalfcrypto not found at %s' % libalfcrypto)
|
||||
|
||||
libalfcrypto = CDLL(libalfcrypto)
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys, os
|
||||
import locale
|
||||
import codecs
|
||||
|
||||
# get sys.argv arguments and encode them into utf-8
|
||||
def utf8_argv():
|
||||
if sys.platform.startswith('win'):
|
||||
# Versions 2.x of Python don't support Unicode in sys.argv on
|
||||
# Windows, with the underlying Windows API instead replacing multi-byte
|
||||
# characters with '?'. So use shell32.GetCommandLineArgvW to get sys.argv
|
||||
# as a list of Unicode strings and encode them as utf-8
|
||||
|
||||
from ctypes import POINTER, byref, cdll, c_int, windll
|
||||
from ctypes.wintypes import LPCWSTR, LPWSTR
|
||||
|
||||
GetCommandLineW = cdll.kernel32.GetCommandLineW
|
||||
GetCommandLineW.argtypes = []
|
||||
GetCommandLineW.restype = LPCWSTR
|
||||
|
||||
CommandLineToArgvW = windll.shell32.CommandLineToArgvW
|
||||
CommandLineToArgvW.argtypes = [LPCWSTR, POINTER(c_int)]
|
||||
CommandLineToArgvW.restype = POINTER(LPWSTR)
|
||||
|
||||
cmd = GetCommandLineW()
|
||||
argc = c_int(0)
|
||||
argv = CommandLineToArgvW(cmd, byref(argc))
|
||||
if argc.value > 0:
|
||||
# Remove Python executable and commands if present
|
||||
start = argc.value - len(sys.argv)
|
||||
return [argv[i].encode('utf-8') for i in
|
||||
xrange(start, argc.value)]
|
||||
# this should never happen
|
||||
return None
|
||||
else:
|
||||
argv = []
|
||||
argvencoding = sys.stdin.encoding
|
||||
if argvencoding == None:
|
||||
argvencoding = sys.getfilesystemencoding()
|
||||
if argvencoding == None:
|
||||
argvencoding = 'utf-8'
|
||||
for arg in sys.argv:
|
||||
if type(arg) == unicode:
|
||||
argv.append(arg.encode('utf-8'))
|
||||
else:
|
||||
argv.append(arg.decode(argvencoding).encode('utf-8'))
|
||||
return argv
|
||||
|
||||
|
||||
def add_cp65001_codec():
|
||||
try:
|
||||
codecs.lookup('cp65001')
|
||||
except LookupError:
|
||||
codecs.register(
|
||||
lambda name: name == 'cp65001' and codecs.lookup('utf-8') or None)
|
||||
return
|
||||
|
||||
|
||||
def set_utf8_default_encoding():
|
||||
if sys.getdefaultencoding() == 'utf-8':
|
||||
return
|
||||
|
||||
# Regenerate setdefaultencoding.
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf-8')
|
||||
|
||||
for attr in dir(locale):
|
||||
if attr[0:3] != 'LC_':
|
||||
continue
|
||||
aref = getattr(locale, attr)
|
||||
try:
|
||||
locale.setlocale(aref, '')
|
||||
except locale.Error:
|
||||
continue
|
||||
try:
|
||||
lang = locale.getlocale(aref)[0]
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
if lang:
|
||||
try:
|
||||
locale.setlocale(aref, (lang, 'UTF-8'))
|
||||
except locale.Error:
|
||||
os.environ[attr] = lang + '.UTF-8'
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
except locale.Error:
|
||||
pass
|
||||
return
|
||||
|
||||
|
||||
@@ -255,13 +255,15 @@ class PageParser(object):
|
||||
|
||||
'empty_text_region' : (1, 'snippets', 1, 0),
|
||||
|
||||
'img' : (1, 'snippets', 1, 0),
|
||||
'img.x' : (1, 'scalar_number', 0, 0),
|
||||
'img.y' : (1, 'scalar_number', 0, 0),
|
||||
'img.h' : (1, 'scalar_number', 0, 0),
|
||||
'img.w' : (1, 'scalar_number', 0, 0),
|
||||
'img.src' : (1, 'scalar_number', 0, 0),
|
||||
'img.color_src' : (1, 'scalar_number', 0, 0),
|
||||
'img' : (1, 'snippets', 1, 0),
|
||||
'img.x' : (1, 'scalar_number', 0, 0),
|
||||
'img.y' : (1, 'scalar_number', 0, 0),
|
||||
'img.h' : (1, 'scalar_number', 0, 0),
|
||||
'img.w' : (1, 'scalar_number', 0, 0),
|
||||
'img.src' : (1, 'scalar_number', 0, 0),
|
||||
'img.color_src' : (1, 'scalar_number', 0, 0),
|
||||
'img.gridBeginCenter' : (1, 'scalar_number', 0, 0),
|
||||
'img.gridEndCenter' : (1, 'scalar_number', 0, 0),
|
||||
|
||||
'paragraph' : (1, 'snippets', 1, 0),
|
||||
'paragraph.class' : (1, 'scalar_text', 0, 0),
|
||||
@@ -307,6 +309,7 @@ class PageParser(object):
|
||||
'span.gridEndCenter' : (1, 'scalar_number', 0, 0),
|
||||
|
||||
'extratokens' : (1, 'snippets', 1, 0),
|
||||
'extratokens.class' : (1, 'scalar_text', 0, 0),
|
||||
'extratokens.type' : (1, 'scalar_text', 0, 0),
|
||||
'extratokens.firstGlyph' : (1, 'scalar_number', 0, 0),
|
||||
'extratokens.lastGlyph' : (1, 'scalar_number', 0, 0),
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
|
||||
|
||||
class Unbuffered:
|
||||
def __init__(self, stream):
|
||||
self.stream = stream
|
||||
def write(self, data):
|
||||
self.stream.write(data)
|
||||
self.stream.flush()
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.stream, attr)
|
||||
|
||||
import sys
|
||||
sys.stdout=Unbuffered(sys.stdout)
|
||||
import os
|
||||
|
||||
import ineptepub
|
||||
import ignobleepub
|
||||
import zipfix
|
||||
import re
|
||||
|
||||
def main(argv=sys.argv):
|
||||
args = argv[1:]
|
||||
if len(args) != 3:
|
||||
return -1
|
||||
infile = args[0]
|
||||
outdir = args[1]
|
||||
rscpath = args[2]
|
||||
errlog = ''
|
||||
|
||||
# first fix the epub to make sure we do not get errors
|
||||
name, ext = os.path.splitext(os.path.basename(infile))
|
||||
bpath = os.path.dirname(infile)
|
||||
zippath = os.path.join(bpath,name + '_temp.zip')
|
||||
rv = zipfix.repairBook(infile, zippath)
|
||||
if rv != 0:
|
||||
print "Error while trying to fix epub"
|
||||
return rv
|
||||
|
||||
# determine a good name for the output file
|
||||
outfile = os.path.join(outdir, name + '_nodrm.epub')
|
||||
|
||||
rv = 1
|
||||
# first try with the Adobe adept epub
|
||||
# try with any keyfiles (*.der) in the rscpath
|
||||
files = os.listdir(rscpath)
|
||||
filefilter = re.compile("\.der$", re.IGNORECASE)
|
||||
files = filter(filefilter.search, files)
|
||||
if files:
|
||||
for filename in files:
|
||||
keypath = os.path.join(rscpath, filename)
|
||||
try:
|
||||
rv = ineptepub.decryptBook(keypath, zippath, outfile)
|
||||
if rv == 0:
|
||||
break
|
||||
except Exception, e:
|
||||
errlog += str(e)
|
||||
rv = 1
|
||||
pass
|
||||
if rv == 0:
|
||||
os.remove(zippath)
|
||||
return 0
|
||||
|
||||
# still no luck
|
||||
# now try with ignoble epub
|
||||
# try with any keyfiles (*.b64) in the rscpath
|
||||
files = os.listdir(rscpath)
|
||||
filefilter = re.compile("\.b64$", re.IGNORECASE)
|
||||
files = filter(filefilter.search, files)
|
||||
if files:
|
||||
for filename in files:
|
||||
keypath = os.path.join(rscpath, filename)
|
||||
try:
|
||||
rv = ignobleepub.decryptBook(keypath, zippath, outfile)
|
||||
if rv == 0:
|
||||
break
|
||||
except Exception, e:
|
||||
errlog += str(e)
|
||||
rv = 1
|
||||
pass
|
||||
os.remove(zippath)
|
||||
if rv != 0:
|
||||
print errlog
|
||||
return rv
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
|
||||
|
||||
class Unbuffered:
|
||||
def __init__(self, stream):
|
||||
self.stream = stream
|
||||
def write(self, data):
|
||||
self.stream.write(data)
|
||||
self.stream.flush()
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.stream, attr)
|
||||
|
||||
import sys
|
||||
sys.stdout=Unbuffered(sys.stdout)
|
||||
import os
|
||||
|
||||
import erdr2pml
|
||||
|
||||
def main(argv=sys.argv):
|
||||
args = argv[1:]
|
||||
if len(args) != 3:
|
||||
return -1
|
||||
infile = args[0]
|
||||
outdir = args[1]
|
||||
rscpath = args[2]
|
||||
rv = 1
|
||||
socialpath = os.path.join(rscpath,'sdrmlist.txt')
|
||||
if os.path.exists(socialpath):
|
||||
keydata = file(socialpath,'r').read()
|
||||
keydata = keydata.rstrip(os.linesep)
|
||||
ar = keydata.split(',')
|
||||
for i in ar:
|
||||
try:
|
||||
name, cc8 = i.split(':')
|
||||
except ValueError:
|
||||
print ' Error parsing user supplied social drm data.'
|
||||
return 1
|
||||
rv = erdr2pml.decryptBook(infile, outdir, True, erdr2pml.getuser_key(name, cc8) )
|
||||
if rv == 0:
|
||||
break
|
||||
return rv
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
|
||||
|
||||
class Unbuffered:
|
||||
def __init__(self, stream):
|
||||
self.stream = stream
|
||||
def write(self, data):
|
||||
self.stream.write(data)
|
||||
self.stream.flush()
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.stream, attr)
|
||||
|
||||
import sys
|
||||
sys.stdout=Unbuffered(sys.stdout)
|
||||
import os
|
||||
import re
|
||||
import ineptpdf
|
||||
|
||||
def main(argv=sys.argv):
|
||||
args = argv[1:]
|
||||
if len(args) != 3:
|
||||
return -1
|
||||
infile = args[0]
|
||||
outdir = args[1]
|
||||
rscpath = args[2]
|
||||
errlog = ''
|
||||
rv = 1
|
||||
|
||||
# determine a good name for the output file
|
||||
name, ext = os.path.splitext(os.path.basename(infile))
|
||||
outfile = os.path.join(outdir, name + '_nodrm.pdf')
|
||||
|
||||
# try with any keyfiles (*.der) in the rscpath
|
||||
files = os.listdir(rscpath)
|
||||
filefilter = re.compile("\.der$", re.IGNORECASE)
|
||||
files = filter(filefilter.search, files)
|
||||
if files:
|
||||
for filename in files:
|
||||
keypath = os.path.join(rscpath, filename)
|
||||
try:
|
||||
rv = ineptpdf.decryptBook(keypath, infile, outfile)
|
||||
if rv == 0:
|
||||
break
|
||||
except Exception, e:
|
||||
errlog += str(e)
|
||||
rv = 1
|
||||
pass
|
||||
if rv != 0:
|
||||
print errlog
|
||||
return rv
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -387,10 +387,14 @@ class DocParser(object):
|
||||
ws_last = int(argres)
|
||||
|
||||
elif name.endswith('word.class'):
|
||||
(cname, space) = argres.split('-',1)
|
||||
if space == '' : space = '0'
|
||||
if (cname == 'spaceafter') and (int(space) > 0) :
|
||||
word_class = 'sa'
|
||||
# we only handle spaceafter word class
|
||||
try:
|
||||
(cname, space) = argres.split('-',1)
|
||||
if space == '' : space = '0'
|
||||
if (cname == 'spaceafter') and (int(space) > 0) :
|
||||
word_class = 'sa'
|
||||
except:
|
||||
pass
|
||||
|
||||
elif name.endswith('word.img.src'):
|
||||
result.append(('img' + word_class, int(argres)))
|
||||
|
||||
@@ -117,7 +117,7 @@ class Dictionary(object):
|
||||
self.pos = val
|
||||
return self.stable[self.pos]
|
||||
else:
|
||||
print "Error - %d outside of string table limits" % val
|
||||
print "Error: %d outside of string table limits" % val
|
||||
raise TpzDRMError('outside or string table limits')
|
||||
# sys.exit(-1)
|
||||
def getSize(self):
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
# ignobleepub.pyw, version 3.6
|
||||
# ignobleepub.pyw, version 3.7
|
||||
# Copyright © 2009-2010 by i♥cabbages
|
||||
|
||||
# Released under the terms of the GNU General Public Licence, version 3
|
||||
@@ -26,18 +26,19 @@ from __future__ import with_statement
|
||||
# 2 - Added OS X support by using OpenSSL when available
|
||||
# 3 - screen out improper key lengths to prevent segfaults on Linux
|
||||
# 3.1 - Allow Windows versions of libcrypto to be found
|
||||
# 3.2 - add support for encoding to 'utf-8' when building up list of files to cecrypt from encryption.xml
|
||||
# 3.3 - On Windows try PyCrypto first and OpenSSL next
|
||||
# 3.4 - Modify interace to allow use with import
|
||||
# 3.2 - add support for encoding to 'utf-8' when building up list of files to decrypt from encryption.xml
|
||||
# 3.3 - On Windows try PyCrypto first, OpenSSL next
|
||||
# 3.4 - Modify interface to allow use with import
|
||||
# 3.5 - Fix for potential problem with PyCrypto
|
||||
# 3.6 - Revised to allow use in calibre plugins to eliminate need for duplicate code
|
||||
# 3.7 - Tweaked to match ineptepub more closely
|
||||
|
||||
"""
|
||||
Decrypt Barnes & Noble encrypted ePub books.
|
||||
"""
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__version__ = "3.6"
|
||||
__version__ = "3.7"
|
||||
|
||||
import sys
|
||||
import os
|
||||
@@ -254,18 +255,17 @@ def ignobleBook(inpath):
|
||||
return True
|
||||
return False
|
||||
|
||||
# return error code and error message duple
|
||||
def decryptBook(keyb64, inpath, outpath):
|
||||
if AES is None:
|
||||
# 1 means don't try again
|
||||
return (1, u"PyCrypto or OpenSSL must be installed.")
|
||||
raise IGNOBLEError(u"PyCrypto or OpenSSL must be installed.")
|
||||
key = keyb64.decode('base64')[:16]
|
||||
aes = AES(key)
|
||||
with closing(ZipFile(open(inpath, 'rb'))) as inf:
|
||||
namelist = set(inf.namelist())
|
||||
if 'META-INF/rights.xml' not in namelist or \
|
||||
'META-INF/encryption.xml' not in namelist:
|
||||
return (1, u"Not a secure Barnes & Noble ePub.")
|
||||
print u"{0:s} is DRM-free.".format(os.path.basename(inpath))
|
||||
return 1
|
||||
for name in META_NAMES:
|
||||
namelist.remove(name)
|
||||
try:
|
||||
@@ -274,7 +274,8 @@ def decryptBook(keyb64, inpath, outpath):
|
||||
expr = './/%s' % (adept('encryptedKey'),)
|
||||
bookkey = ''.join(rights.findtext(expr))
|
||||
if len(bookkey) != 64:
|
||||
return (1, u"Not a secure Barnes & Noble ePub.")
|
||||
print u"{0:s} is not a secure Barnes & Noble ePub.".format(os.path.basename(inpath))
|
||||
return 1
|
||||
bookkey = aes.decrypt(bookkey.decode('base64'))
|
||||
bookkey = bookkey[:-ord(bookkey[-1])]
|
||||
encryption = inf.read('META-INF/encryption.xml')
|
||||
@@ -286,21 +287,23 @@ def decryptBook(keyb64, inpath, outpath):
|
||||
for path in namelist:
|
||||
data = inf.read(path)
|
||||
outf.writestr(path, decryptor.decrypt(path, data))
|
||||
except Exception, e:
|
||||
return (2, u"{0}.".format(e.args[0]))
|
||||
return (0, u"Success")
|
||||
except:
|
||||
print u"Could not decrypt {0:s} because of an exception:\n{1:s}".format(os.path.basename(inpath), traceback.format_exc())
|
||||
return 2
|
||||
return 0
|
||||
|
||||
|
||||
def cli_main(argv=unicode_argv()):
|
||||
progname = os.path.basename(argv[0])
|
||||
if len(argv) != 4:
|
||||
print u"usage: {0} <keyfile.der> <inbook.epub> <outbook.epub>".format(progname)
|
||||
print u"usage: {0} <keyfile.b64> <inbook.epub> <outbook.epub>".format(progname)
|
||||
return 1
|
||||
keypath, inpath, outpath = argv[1:]
|
||||
userkey = open(keypath,'rb').read()
|
||||
result = decryptBook(userkey, inpath, outpath)
|
||||
print result[1]
|
||||
return result[0]
|
||||
if result == 0:
|
||||
print u"Successfully decrypted {0:s} as {1:s}".format(os.path.basename(inpath),os.path.basename(outpath))
|
||||
return result
|
||||
|
||||
def gui_main():
|
||||
import Tkinter
|
||||
@@ -399,10 +402,10 @@ def gui_main():
|
||||
except Exception, e:
|
||||
self.status['text'] = u"Error: {0}".format(e.args[0])
|
||||
return
|
||||
if decrypt_status[0] == 0:
|
||||
if decrypt_status == 0:
|
||||
self.status['text'] = u"File successfully decrypted"
|
||||
else:
|
||||
self.status['text'] = decrypt_status[1]
|
||||
self.status['text'] = u"The was an error decrypting the file."
|
||||
|
||||
root = Tkinter.Tk()
|
||||
root.title(u"Barnes & Noble ePub Decrypter v.{0}".format(__version__))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#! /usr/bin/python
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import with_statement
|
||||
@@ -542,7 +542,7 @@ def gui_main():
|
||||
try:
|
||||
decrypt_status = decryptBook(userkey, inpath, outpath)
|
||||
except Exception, e:
|
||||
self.status['text'] = u"Error; {0}".format(e)
|
||||
self.status['text'] = u"Error: {0}".format(e.args[0])
|
||||
return
|
||||
if decrypt_status == 0:
|
||||
self.status['text'] = u"File successfully decrypted"
|
||||
|
||||
@@ -50,8 +50,9 @@ from __future__ import with_statement
|
||||
# 4.7 - Added timing reports, and changed search for Mac key files
|
||||
# 4.8 - Much better unicode handling, matching the updated inept and ignoble scripts
|
||||
# - Moved back into plugin, __init__ in plugin now only contains plugin code.
|
||||
# 4.9 - Missed some invalid characters in cleanup_name
|
||||
|
||||
__version__ = '4.8'
|
||||
__version__ = '4.9'
|
||||
|
||||
|
||||
import sys, os, re
|
||||
@@ -144,7 +145,7 @@ def unicode_argv():
|
||||
# and with some (heavily edited) code from Paul Durrant's kindlenamer.py
|
||||
def cleanup_name(name):
|
||||
# substitute filename unfriendly characters
|
||||
name = name.replace(u"<",u"[").replace(u">",u"]").replace(u" : ",u" – ").replace(u": ",u" – ").replace(u":",u"—").replace(u"/",u"_").replace(u"\\",u"_").replace(u"|",u"_").replace(u"\"",u"\'")
|
||||
name = name.replace(u"<",u"[").replace(u">",u"]").replace(u" : ",u" – ").replace(u": ",u" – ").replace(u":",u"—").replace(u"/",u"_").replace(u"\\",u"_").replace(u"|",u"_").replace(u"\"",u"\'").replace(u"*",u"_").replace(u"?",u"")
|
||||
# delete control characters
|
||||
name = u"".join(char for char in name if ord(char)>=32)
|
||||
# white space to single space, delete leading and trailing while space
|
||||
@@ -220,6 +221,7 @@ def decryptBook(infile, outdir, kInfoFiles, serials, pids):
|
||||
book = GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime)
|
||||
except Exception, e:
|
||||
print u"Error decrypting book after {1:.1f} seconds: {0}".format(e.args[0],time.time()-starttime)
|
||||
traceback.print_exc()
|
||||
return 1
|
||||
|
||||
# if we're saving to the same folder as the original, use file name_
|
||||
@@ -246,6 +248,7 @@ def decryptBook(infile, outdir, kInfoFiles, serials, pids):
|
||||
|
||||
# remove internal temporary directory of Topaz pieces
|
||||
book.cleanup()
|
||||
return 0
|
||||
|
||||
|
||||
def usage(progname):
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import ineptepub
|
||||
import ignobleepub
|
||||
import zipfix
|
||||
import ineptpdf
|
||||
import erdr2pml
|
||||
import k4mobidedrm
|
||||
|
||||
def decryptepub(infile, outdir, rscpath):
|
||||
errlog = ''
|
||||
|
||||
# first fix the epub to make sure we do not get errors
|
||||
name, ext = os.path.splitext(os.path.basename(infile))
|
||||
bpath = os.path.dirname(infile)
|
||||
zippath = os.path.join(bpath,name + '_temp.zip')
|
||||
rv = zipfix.repairBook(infile, zippath)
|
||||
if rv != 0:
|
||||
print "Error while trying to fix epub"
|
||||
return rv
|
||||
|
||||
# determine a good name for the output file
|
||||
outfile = os.path.join(outdir, name + '_nodrm.epub')
|
||||
|
||||
rv = 1
|
||||
# first try with the Adobe adept epub
|
||||
# try with any keyfiles (*.der) in the rscpath
|
||||
files = os.listdir(rscpath)
|
||||
filefilter = re.compile("\.der$", re.IGNORECASE)
|
||||
files = filter(filefilter.search, files)
|
||||
if files:
|
||||
for filename in files:
|
||||
keypath = os.path.join(rscpath, filename)
|
||||
userkey = open(keypath,'rb').read()
|
||||
try:
|
||||
rv = ineptepub.decryptBook(userkey, zippath, outfile)
|
||||
if rv == 0:
|
||||
break
|
||||
except Exception, e:
|
||||
errlog += str(e)
|
||||
rv = 1
|
||||
pass
|
||||
if rv == 0:
|
||||
os.remove(zippath)
|
||||
return 0
|
||||
|
||||
# still no luck
|
||||
# now try with ignoble epub
|
||||
# try with any keyfiles (*.b64) in the rscpath
|
||||
files = os.listdir(rscpath)
|
||||
filefilter = re.compile("\.b64$", re.IGNORECASE)
|
||||
files = filter(filefilter.search, files)
|
||||
if files:
|
||||
for filename in files:
|
||||
keypath = os.path.join(rscpath, filename)
|
||||
userkey = open(keypath,'rb').read()
|
||||
try:
|
||||
rv = ignobleepub.decryptBook(userkey, zippath, outfile)
|
||||
if rv == 0:
|
||||
break
|
||||
except Exception, e:
|
||||
errlog += str(e)
|
||||
rv = 1
|
||||
pass
|
||||
os.remove(zippath)
|
||||
if rv != 0:
|
||||
print errlog
|
||||
return rv
|
||||
|
||||
|
||||
def decryptpdf(infile, outdir, rscpath):
|
||||
errlog = ''
|
||||
rv = 1
|
||||
|
||||
# determine a good name for the output file
|
||||
name, ext = os.path.splitext(os.path.basename(infile))
|
||||
outfile = os.path.join(outdir, name + '_nodrm.pdf')
|
||||
|
||||
# try with any keyfiles (*.der) in the rscpath
|
||||
files = os.listdir(rscpath)
|
||||
filefilter = re.compile("\.der$", re.IGNORECASE)
|
||||
files = filter(filefilter.search, files)
|
||||
if files:
|
||||
for filename in files:
|
||||
keypath = os.path.join(rscpath, filename)
|
||||
userkey = open(keypath,'rb').read()
|
||||
try:
|
||||
rv = ineptpdf.decryptBook(userkey, infile, outfile)
|
||||
if rv == 0:
|
||||
break
|
||||
except Exception, e:
|
||||
errlog += str(e)
|
||||
rv = 1
|
||||
pass
|
||||
if rv != 0:
|
||||
print errlog
|
||||
return rv
|
||||
|
||||
|
||||
def decryptpdb(infile, outdir, rscpath):
|
||||
outname = os.path.splitext(os.path.basename(infile))[0] + ".pmlz"
|
||||
outpath = os.path.join(outdir, outname)
|
||||
rv = 1
|
||||
socialpath = os.path.join(rscpath,'sdrmlist.txt')
|
||||
if os.path.exists(socialpath):
|
||||
keydata = file(socialpath,'r').read()
|
||||
keydata = keydata.rstrip(os.linesep)
|
||||
ar = keydata.split(',')
|
||||
for i in ar:
|
||||
try:
|
||||
name, cc8 = i.split(':')
|
||||
except ValueError:
|
||||
print ' Error parsing user supplied social drm data.'
|
||||
return 1
|
||||
rv = erdr2pml.decryptBook(infile, outpath, True, erdr2pml.getuser_key(name, cc8))
|
||||
if rv == 0:
|
||||
break
|
||||
return rv
|
||||
|
||||
|
||||
def decryptk4mobi(infile, outdir, rscpath):
|
||||
rv = 1
|
||||
pidnums = []
|
||||
pidspath = os.path.join(rscpath,'pidlist.txt')
|
||||
if os.path.exists(pidspath):
|
||||
pidstr = file(pidspath,'r').read()
|
||||
pidstr = pidstr.rstrip(os.linesep)
|
||||
pidstr = pidstr.strip()
|
||||
if pidstr != '':
|
||||
pidnums = pidstr.split(',')
|
||||
serialnums = []
|
||||
serialnumspath = os.path.join(rscpath,'seriallist.txt')
|
||||
if os.path.exists(serialnumspath):
|
||||
serialstr = file(serialnumspath,'r').read()
|
||||
serialstr = serialstr.rstrip(os.linesep)
|
||||
serialstr = serialstr.strip()
|
||||
if serialstr != '':
|
||||
serialnums = serialstr.split(',')
|
||||
kInfoFiles = []
|
||||
files = os.listdir(rscpath)
|
||||
filefilter = re.compile("\.info$|\.kinf$", re.IGNORECASE)
|
||||
files = filter(filefilter.search, files)
|
||||
if files:
|
||||
for filename in files:
|
||||
dpath = os.path.join(rscpath,filename)
|
||||
kInfoFiles.append(dpath)
|
||||
rv = k4mobidedrm.decryptBook(infile, outdir, kInfoFiles, serialnums, pidnums)
|
||||
return rv
|
||||
@@ -1,7 +1,7 @@
|
||||
ReadMe_DeDRM_v5.5.3_WinApp
|
||||
ReadMe_DeDRM_v5.6_WinApp
|
||||
========================
|
||||
|
||||
DeDRM_v5.5.3_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto the DeDRM_Drop_Target to have the DRM removed. It repackages all the "tools" python software in one easy to use program that remembers preferences and settings.
|
||||
DeDRM_v5.6_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto the DeDRM_Drop_Target to have the DRM removed. It repackages all the "tools" python software in one easy to use program that remembers preferences and settings.
|
||||
|
||||
It will work without manual configuration for Kindle for PC ebooks and Adobe Adept epub and pdf ebooks.
|
||||
|
||||
@@ -23,9 +23,9 @@ Installation
|
||||
|
||||
0. If you don't already have a correct version of Python and PyCrypto installed, follow the "Installing Python on Windows" and "Installing PyCrypto on Windows" sections below before continuing.
|
||||
|
||||
1. Drag the DeDRM_5.5.3 folder from tools_v5.5.3/DeDRM_Applications/Windows to your "My Documents" folder.
|
||||
1. Drag the DeDRM_5.6 folder from tools_v5.6/DeDRM_Applications/Windows to your "My Documents" folder.
|
||||
|
||||
2. Open the DeDRM_5.5.3 folder you've just dragged, and make a short-cut of the DeDRM_Drop_Target.bat file (right-click/Create Shortcut). Drag the shortcut file onto your Desktop.
|
||||
2. Open the DeDRM_5.6 folder you've just dragged, and make a short-cut of the DeDRM_Drop_Target.bat file (right-click/Create Shortcut). Drag the shortcut file onto your Desktop.
|
||||
|
||||
3. To set the preferences simply double-click on your just created short-cut.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user