mirror of
https://github.com/noDRM/DeDRM_tools.git
synced 2025-01-12 03:14:43 +06:00
tools v4.7
This commit is contained in:
parent
ba5927a20d
commit
e95ed1a8ed
@ -16,24 +16,23 @@ import re
|
|||||||
|
|
||||||
class K4DeDRM(FileTypePlugin):
|
class K4DeDRM(FileTypePlugin):
|
||||||
name = 'K4PC, K4Mac, Kindle Mobi and Topaz DeDRM' # Name of the plugin
|
name = 'K4PC, K4Mac, Kindle Mobi and Topaz DeDRM' # Name of the plugin
|
||||||
description = 'Removes DRM from K4PC and Mac, Kindle Mobi and Topaz files. Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
|
description = 'Removes DRM from Mobipocket, Kindle/Mobi, Kindle/Topaz and Kindle/Print Replica files. Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
|
||||||
supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
|
supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
|
||||||
author = 'DiapDealer, SomeUpdates' # The author of this plugin
|
author = 'DiapDealer, SomeUpdates' # The author of this plugin
|
||||||
version = (0, 3, 6) # The version number of this plugin
|
version = (0, 3, 7) # The version number of this plugin
|
||||||
file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
|
file_types = set(['prc','mobi','azw','azw1','azw4','tpz']) # The file types that this plugin will be applied to
|
||||||
on_import = True # Run this plugin during the import
|
on_import = True # Run this plugin during the import
|
||||||
priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm
|
priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm
|
||||||
minimum_calibre_version = (0, 7, 55)
|
minimum_calibre_version = (0, 7, 55)
|
||||||
|
|
||||||
def run(self, path_to_ebook):
|
def run(self, path_to_ebook):
|
||||||
|
plug_ver = '.'.join(str(self.version).strip('()').replace(' ', '').split(','))
|
||||||
k4 = True
|
k4 = True
|
||||||
if sys.platform.startswith('linux'):
|
if sys.platform.startswith('linux'):
|
||||||
k4 = False
|
k4 = False
|
||||||
pids = []
|
pids = []
|
||||||
serials = []
|
serials = []
|
||||||
kInfoFiles = []
|
kInfoFiles = []
|
||||||
|
|
||||||
# Get supplied list of PIDs to try from plugin customization.
|
# Get supplied list of PIDs to try from plugin customization.
|
||||||
customvalues = self.site_customization.split(',')
|
customvalues = self.site_customization.split(',')
|
||||||
for customvalue in customvalues:
|
for customvalue in customvalues:
|
||||||
@ -51,7 +50,7 @@ class K4DeDRM(FileTypePlugin):
|
|||||||
try:
|
try:
|
||||||
# Find Calibre's configuration directory.
|
# Find Calibre's configuration directory.
|
||||||
confpath = os.path.split(os.path.split(self.plugin_path)[0])[0]
|
confpath = os.path.split(os.path.split(self.plugin_path)[0])[0]
|
||||||
print 'K4MobiDeDRM: Calibre configuration directory = %s' % confpath
|
print 'K4MobiDeDRM v%s: Calibre configuration directory = %s' % (plug_ver, confpath)
|
||||||
files = os.listdir(confpath)
|
files = os.listdir(confpath)
|
||||||
filefilter = re.compile("\.info$|\.kinf$", re.IGNORECASE)
|
filefilter = re.compile("\.info$|\.kinf$", re.IGNORECASE)
|
||||||
files = filter(filefilter.search, files)
|
files = filter(filefilter.search, files)
|
||||||
@ -59,9 +58,9 @@ class K4DeDRM(FileTypePlugin):
|
|||||||
for filename in files:
|
for filename in files:
|
||||||
fpath = os.path.join(confpath, filename)
|
fpath = os.path.join(confpath, filename)
|
||||||
kInfoFiles.append(fpath)
|
kInfoFiles.append(fpath)
|
||||||
print 'K4MobiDeDRM: Kindle info/kinf file %s found in config folder.' % filename
|
print 'K4MobiDeDRM v%s: Kindle info/kinf file %s found in config folder.' % (plug_ver, filename)
|
||||||
except IOError:
|
except IOError:
|
||||||
print 'K4MobiDeDRM: Error reading kindle info/kinf files from config directory.'
|
print 'K4MobiDeDRM v%s: Error reading kindle info/kinf files from config directory.' % plug_ver
|
||||||
pass
|
pass
|
||||||
|
|
||||||
mobi = True
|
mobi = True
|
||||||
@ -83,30 +82,34 @@ class K4DeDRM(FileTypePlugin):
|
|||||||
try:
|
try:
|
||||||
mb.processBook(pidlst)
|
mb.processBook(pidlst)
|
||||||
|
|
||||||
except mobidedrm.DrmException:
|
except mobidedrm.DrmException, e:
|
||||||
#if you reached here then no luck raise and exception
|
#if you reached here then no luck raise and exception
|
||||||
if is_ok_to_use_qt():
|
if is_ok_to_use_qt():
|
||||||
from PyQt4.Qt import QMessageBox
|
from PyQt4.Qt import QMessageBox
|
||||||
d = QMessageBox(QMessageBox.Warning, "K4MobiDeDRM Plugin", "Error decoding: %s\n" % path_to_ebook)
|
d = QMessageBox(QMessageBox.Warning, "K4MobiDeDRM v%s Plugin" % plug_ver, "Error: " + str(e) + "... %s\n" % path_to_ebook)
|
||||||
d.show()
|
d.show()
|
||||||
d.raise_()
|
d.raise_()
|
||||||
d.exec_()
|
d.exec_()
|
||||||
raise Exception("K4MobiDeDRM plugin could not decode the file")
|
raise Exception("K4MobiDeDRM plugin v%s Error: %s" % (plug_ver, str(e)))
|
||||||
except topazextract.TpzDRMError:
|
except topazextract.TpzDRMError, e:
|
||||||
#if you reached here then no luck raise and exception
|
#if you reached here then no luck raise and exception
|
||||||
if is_ok_to_use_qt():
|
if is_ok_to_use_qt():
|
||||||
from PyQt4.Qt import QMessageBox
|
from PyQt4.Qt import QMessageBox
|
||||||
d = QMessageBox(QMessageBox.Warning, "K4MobiDeDRM Plugin", "Error decoding: %s\n" % path_to_ebook)
|
d = QMessageBox(QMessageBox.Warning, "K4MobiDeDRM v%s Plugin" % plug_ver, "Error: " + str(e) + "... %s\n" % path_to_ebook)
|
||||||
d.show()
|
d.show()
|
||||||
d.raise_()
|
d.raise_()
|
||||||
d.exec_()
|
d.exec_()
|
||||||
raise Exception("K4MobiDeDRM plugin could not decode the file")
|
raise Exception("K4MobiDeDRM plugin v%s Error: %s" % (plug_ver, str(e)))
|
||||||
|
|
||||||
print "Success!"
|
print "Success!"
|
||||||
if mobi:
|
if mobi:
|
||||||
of = self.temporary_file(bookname+'.mobi')
|
if mb.getPrintReplica():
|
||||||
|
of = self.temporary_file(bookname+'.azw4')
|
||||||
|
print 'K4MobiDeDRM v%s: Print Replica format detected.' % plug_ver
|
||||||
|
else:
|
||||||
|
of = self.temporary_file(bookname+'.mobi')
|
||||||
mb.getMobiFile(of.name)
|
mb.getMobiFile(of.name)
|
||||||
else :
|
else:
|
||||||
of = self.temporary_file(bookname+'.htmlz')
|
of = self.temporary_file(bookname+'.htmlz')
|
||||||
mb.getHTMLZip(of.name)
|
mb.getHTMLZip(of.name)
|
||||||
mb.cleanup()
|
mb.cleanup()
|
||||||
|
@ -17,7 +17,7 @@ from __future__ import with_statement
|
|||||||
# and many many others
|
# and many many others
|
||||||
|
|
||||||
|
|
||||||
__version__ = '3.6'
|
__version__ = '3.7'
|
||||||
|
|
||||||
class Unbuffered:
|
class Unbuffered:
|
||||||
def __init__(self, stream):
|
def __init__(self, stream):
|
||||||
@ -76,7 +76,7 @@ def cleanup_name(name):
|
|||||||
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
|
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
|
||||||
# handle the obvious cases at the beginning
|
# handle the obvious cases at the beginning
|
||||||
if not os.path.isfile(infile):
|
if not os.path.isfile(infile):
|
||||||
print "Error: Input file does not exist"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: Input file does not exist"
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
mobi = True
|
mobi = True
|
||||||
@ -106,17 +106,20 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
|
|||||||
mb.processBook(pidlst)
|
mb.processBook(pidlst)
|
||||||
|
|
||||||
except mobidedrm.DrmException, e:
|
except mobidedrm.DrmException, e:
|
||||||
print "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
||||||
return 1
|
return 1
|
||||||
except topazextract.TpzDRMError, e:
|
except topazextract.TpzDRMError, e:
|
||||||
print "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
||||||
return 1
|
return 1
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if mobi:
|
if mobi:
|
||||||
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.mobi')
|
if mb.getPrintReplica():
|
||||||
|
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.azw4')
|
||||||
|
else:
|
||||||
|
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.mobi')
|
||||||
mb.getMobiFile(outfile)
|
mb.getMobiFile(outfile)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@ -158,7 +161,6 @@ def main(argv=sys.argv):
|
|||||||
print ('K4MobiDeDrm v%(__version__)s '
|
print ('K4MobiDeDrm v%(__version__)s '
|
||||||
'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals())
|
'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals())
|
||||||
|
|
||||||
print ' '
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "k:p:s:")
|
opts, args = getopt.getopt(sys.argv[1:], "k:p:s:")
|
||||||
except getopt.GetoptError, err:
|
except getopt.GetoptError, err:
|
||||||
|
Binary file not shown.
@ -53,8 +53,9 @@
|
|||||||
# files, but they are not for HUFF/CDIC compress files!
|
# files, but they are not for HUFF/CDIC compress files!
|
||||||
# 0.30 - Modified interface slightly to work better with new calibre plugin style
|
# 0.30 - Modified interface slightly to work better with new calibre plugin style
|
||||||
# 0.31 - The multibyte encrytion info is true for version 7 files too.
|
# 0.31 - The multibyte encrytion info is true for version 7 files too.
|
||||||
|
# 0.32 - Added support for "Print Replica" Kindle ebooks
|
||||||
|
|
||||||
__version__ = '0.31'
|
__version__ = '0.32'
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -163,6 +164,9 @@ class MobiBook:
|
|||||||
return self.data_file[off:endoff]
|
return self.data_file[off:endoff]
|
||||||
|
|
||||||
def __init__(self, infile):
|
def __init__(self, infile):
|
||||||
|
print ('MobiDeDrm v%(__version__)s. '
|
||||||
|
'Copyright 2008-2011 The Dark Reverser et al.' % globals())
|
||||||
|
|
||||||
# initial sanity check on file
|
# initial sanity check on file
|
||||||
self.data_file = file(infile, 'rb').read()
|
self.data_file = file(infile, 'rb').read()
|
||||||
self.mobi_data = ''
|
self.mobi_data = ''
|
||||||
@ -193,6 +197,7 @@ class MobiBook:
|
|||||||
self.meta_array = {}
|
self.meta_array = {}
|
||||||
return
|
return
|
||||||
self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18])
|
self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18])
|
||||||
|
self.mobi_codepage, = struct.unpack('>L',self.sect[0x1c:0x20])
|
||||||
self.mobi_version, = struct.unpack('>L',self.sect[0x68:0x6C])
|
self.mobi_version, = struct.unpack('>L',self.sect[0x68:0x6C])
|
||||||
print "MOBI header version = %d, length = %d" %(self.mobi_version, self.mobi_length)
|
print "MOBI header version = %d, length = %d" %(self.mobi_version, self.mobi_length)
|
||||||
self.extra_data_flags = 0
|
self.extra_data_flags = 0
|
||||||
@ -230,8 +235,13 @@ class MobiBook:
|
|||||||
except:
|
except:
|
||||||
self.meta_array = {}
|
self.meta_array = {}
|
||||||
pass
|
pass
|
||||||
|
self.print_replica = False
|
||||||
|
|
||||||
def getBookTitle(self):
|
def getBookTitle(self):
|
||||||
|
codec_map = {
|
||||||
|
1252 : 'windows-1252',
|
||||||
|
65001 : 'utf-8',
|
||||||
|
}
|
||||||
title = ''
|
title = ''
|
||||||
if 503 in self.meta_array:
|
if 503 in self.meta_array:
|
||||||
title = self.meta_array[503]
|
title = self.meta_array[503]
|
||||||
@ -242,7 +252,10 @@ class MobiBook:
|
|||||||
if title == '':
|
if title == '':
|
||||||
title = self.header[:32]
|
title = self.header[:32]
|
||||||
title = title.split("\0")[0]
|
title = title.split("\0")[0]
|
||||||
return title
|
codec = 'windows-1252'
|
||||||
|
if self.mobi_codepage in codec_map.keys():
|
||||||
|
codec = codec_map[self.mobi_codepage]
|
||||||
|
return unicode(title, codec).encode('utf-8')
|
||||||
|
|
||||||
def getPIDMetaInfo(self):
|
def getPIDMetaInfo(self):
|
||||||
rec209 = ''
|
rec209 = ''
|
||||||
@ -307,16 +320,26 @@ class MobiBook:
|
|||||||
def getMobiFile(self, outpath):
|
def getMobiFile(self, outpath):
|
||||||
file(outpath,'wb').write(self.mobi_data)
|
file(outpath,'wb').write(self.mobi_data)
|
||||||
|
|
||||||
|
def getPrintReplica(self):
|
||||||
|
return self.print_replica
|
||||||
|
|
||||||
def processBook(self, pidlist):
|
def processBook(self, pidlist):
|
||||||
crypto_type, = struct.unpack('>H', self.sect[0xC:0xC+2])
|
crypto_type, = struct.unpack('>H', self.sect[0xC:0xC+2])
|
||||||
print 'Crypto Type is: ', crypto_type
|
print 'Crypto Type is: ', crypto_type
|
||||||
self.crypto_type = crypto_type
|
self.crypto_type = crypto_type
|
||||||
if crypto_type == 0:
|
if crypto_type == 0:
|
||||||
print "This book is not encrypted."
|
print "This book is not encrypted."
|
||||||
|
# we must still check for Print Replica
|
||||||
|
self.print_replica = (self.loadSection(1)[0:4] == '%MOP')
|
||||||
self.mobi_data = self.data_file
|
self.mobi_data = self.data_file
|
||||||
return
|
return
|
||||||
if crypto_type != 2 and crypto_type != 1:
|
if crypto_type != 2 and crypto_type != 1:
|
||||||
raise DrmException("Cannot decode unknown Mobipocket encryption type %d" % crypto_type)
|
raise DrmException("Cannot decode unknown Mobipocket encryption type %d" % crypto_type)
|
||||||
|
if 406 in self.meta_array:
|
||||||
|
data406 = self.meta_array[406]
|
||||||
|
val406, = struct.unpack('>Q',data406)
|
||||||
|
if val406 != 0:
|
||||||
|
raise DrmException("Cannot decode library or rented ebooks.")
|
||||||
|
|
||||||
goodpids = []
|
goodpids = []
|
||||||
for pid in pidlist:
|
for pid in pidlist:
|
||||||
@ -367,7 +390,10 @@ class MobiBook:
|
|||||||
if i%100 == 0:
|
if i%100 == 0:
|
||||||
print ".",
|
print ".",
|
||||||
# print "record %d, extra_size %d" %(i,extra_size)
|
# print "record %d, extra_size %d" %(i,extra_size)
|
||||||
self.mobi_data += PC1(found_key, data[0:len(data) - extra_size])
|
decoded_data = PC1(found_key, data[0:len(data) - extra_size])
|
||||||
|
if i==1:
|
||||||
|
self.print_replica = (decoded_data[0:4] == '%MOP')
|
||||||
|
self.mobi_data += decoded_data
|
||||||
if extra_size > 0:
|
if extra_size > 0:
|
||||||
self.mobi_data += data[-extra_size:]
|
self.mobi_data += data[-extra_size:]
|
||||||
if self.num_sections > self.records+1:
|
if self.num_sections > self.records+1:
|
||||||
@ -392,9 +418,9 @@ def getUnencryptedBookWithList(infile,pidlist):
|
|||||||
|
|
||||||
def main(argv=sys.argv):
|
def main(argv=sys.argv):
|
||||||
print ('MobiDeDrm v%(__version__)s. '
|
print ('MobiDeDrm v%(__version__)s. '
|
||||||
'Copyright 2008-2010 The Dark Reverser.' % globals())
|
'Copyright 2008-2011 The Dark Reverser et al.' % globals())
|
||||||
if len(argv)<3 or len(argv)>4:
|
if len(argv)<3 or len(argv)>4:
|
||||||
print "Removes protection from Mobipocket books"
|
print "Removes protection from Kindle/Mobipocket and Kindle/Print Replica ebooks"
|
||||||
print "Usage:"
|
print "Usage:"
|
||||||
print " %s <infile> <outfile> [<Comma separated list of PIDs to try>]" % sys.argv[0]
|
print " %s <infile> <outfile> [<Comma separated list of PIDs to try>]" % sys.argv[0]
|
||||||
return 1
|
return 1
|
||||||
@ -402,9 +428,9 @@ def main(argv=sys.argv):
|
|||||||
infile = argv[1]
|
infile = argv[1]
|
||||||
outfile = argv[2]
|
outfile = argv[2]
|
||||||
if len(argv) is 4:
|
if len(argv) is 4:
|
||||||
pidlist = argv[3].split(',')
|
pidlist = argv[3].split(',')
|
||||||
else:
|
else:
|
||||||
pidlist = {}
|
pidlist = {}
|
||||||
try:
|
try:
|
||||||
stripped_file = getUnencryptedBookWithList(infile, pidlist)
|
stripped_file = getUnencryptedBookWithList(infile, pidlist)
|
||||||
file(outfile, 'wb').write(stripped_file)
|
file(outfile, 'wb').write(stripped_file)
|
||||||
|
Binary file not shown.
@ -24,17 +24,17 @@
|
|||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>droplet</string>
|
<string>droplet</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>DeDRM 2.9, Written 2010–2011 by Apprentice Alf and others.</string>
|
<string>DeDRM 3.0, Written 2010–2011 by Apprentice Alf and others.</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>droplet</string>
|
<string>droplet</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>DeDRM</string>
|
<string>DeDRM 3.0</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2.9</string>
|
<string>3.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>dplt</string>
|
<string>dplt</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
@ -43,18 +43,14 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>WindowState</key>
|
<key>WindowState</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>dividerCollapsed</key>
|
|
||||||
<true/>
|
|
||||||
<key>eventLogLevel</key>
|
|
||||||
<integer>-1</integer>
|
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
<string>ScriptWindowState</string>
|
<string>ScriptWindowState</string>
|
||||||
<key>positionOfDivider</key>
|
<key>positionOfDivider</key>
|
||||||
<real>0</real>
|
<real>274</real>
|
||||||
<key>savedFrame</key>
|
<key>savedFrame</key>
|
||||||
<string>1578 27 862 788 1440 -150 1680 1050 </string>
|
<string>39 376 439 476 0 0 1440 878 </string>
|
||||||
<key>selectedTabView</key>
|
<key>selectedTabView</key>
|
||||||
<string>event log</string>
|
<string>result</string>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -1,4 +1,4 @@
|
|||||||
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350
|
{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540
|
||||||
{\fonttbl}
|
{\fonttbl}
|
||||||
{\colortbl;\red255\green255\blue255;}
|
{\colortbl;\red255\green255\blue255;}
|
||||||
}
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 362 B After Width: | Height: | Size: 362 B |
@ -17,7 +17,7 @@ from __future__ import with_statement
|
|||||||
# and many many others
|
# and many many others
|
||||||
|
|
||||||
|
|
||||||
__version__ = '3.6'
|
__version__ = '3.7'
|
||||||
|
|
||||||
class Unbuffered:
|
class Unbuffered:
|
||||||
def __init__(self, stream):
|
def __init__(self, stream):
|
||||||
@ -76,7 +76,7 @@ def cleanup_name(name):
|
|||||||
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
|
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
|
||||||
# handle the obvious cases at the beginning
|
# handle the obvious cases at the beginning
|
||||||
if not os.path.isfile(infile):
|
if not os.path.isfile(infile):
|
||||||
print "Error: Input file does not exist"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: Input file does not exist"
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
mobi = True
|
mobi = True
|
||||||
@ -106,17 +106,20 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
|
|||||||
mb.processBook(pidlst)
|
mb.processBook(pidlst)
|
||||||
|
|
||||||
except mobidedrm.DrmException, e:
|
except mobidedrm.DrmException, e:
|
||||||
print "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
||||||
return 1
|
return 1
|
||||||
except topazextract.TpzDRMError, e:
|
except topazextract.TpzDRMError, e:
|
||||||
print "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
||||||
return 1
|
return 1
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if mobi:
|
if mobi:
|
||||||
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.mobi')
|
if mb.getPrintReplica():
|
||||||
|
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.azw4')
|
||||||
|
else:
|
||||||
|
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.mobi')
|
||||||
mb.getMobiFile(outfile)
|
mb.getMobiFile(outfile)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@ -158,7 +161,6 @@ def main(argv=sys.argv):
|
|||||||
print ('K4MobiDeDrm v%(__version__)s '
|
print ('K4MobiDeDrm v%(__version__)s '
|
||||||
'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals())
|
'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals())
|
||||||
|
|
||||||
print ' '
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "k:p:s:")
|
opts, args = getopt.getopt(sys.argv[1:], "k:p:s:")
|
||||||
except getopt.GetoptError, err:
|
except getopt.GetoptError, err:
|
||||||
|
@ -53,8 +53,9 @@
|
|||||||
# files, but they are not for HUFF/CDIC compress files!
|
# files, but they are not for HUFF/CDIC compress files!
|
||||||
# 0.30 - Modified interface slightly to work better with new calibre plugin style
|
# 0.30 - Modified interface slightly to work better with new calibre plugin style
|
||||||
# 0.31 - The multibyte encrytion info is true for version 7 files too.
|
# 0.31 - The multibyte encrytion info is true for version 7 files too.
|
||||||
|
# 0.32 - Added support for "Print Replica" Kindle ebooks
|
||||||
|
|
||||||
__version__ = '0.31'
|
__version__ = '0.32'
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -163,6 +164,9 @@ class MobiBook:
|
|||||||
return self.data_file[off:endoff]
|
return self.data_file[off:endoff]
|
||||||
|
|
||||||
def __init__(self, infile):
|
def __init__(self, infile):
|
||||||
|
print ('MobiDeDrm v%(__version__)s. '
|
||||||
|
'Copyright 2008-2011 The Dark Reverser et al.' % globals())
|
||||||
|
|
||||||
# initial sanity check on file
|
# initial sanity check on file
|
||||||
self.data_file = file(infile, 'rb').read()
|
self.data_file = file(infile, 'rb').read()
|
||||||
self.mobi_data = ''
|
self.mobi_data = ''
|
||||||
@ -193,6 +197,7 @@ class MobiBook:
|
|||||||
self.meta_array = {}
|
self.meta_array = {}
|
||||||
return
|
return
|
||||||
self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18])
|
self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18])
|
||||||
|
self.mobi_codepage, = struct.unpack('>L',self.sect[0x1c:0x20])
|
||||||
self.mobi_version, = struct.unpack('>L',self.sect[0x68:0x6C])
|
self.mobi_version, = struct.unpack('>L',self.sect[0x68:0x6C])
|
||||||
print "MOBI header version = %d, length = %d" %(self.mobi_version, self.mobi_length)
|
print "MOBI header version = %d, length = %d" %(self.mobi_version, self.mobi_length)
|
||||||
self.extra_data_flags = 0
|
self.extra_data_flags = 0
|
||||||
@ -230,8 +235,13 @@ class MobiBook:
|
|||||||
except:
|
except:
|
||||||
self.meta_array = {}
|
self.meta_array = {}
|
||||||
pass
|
pass
|
||||||
|
self.print_replica = False
|
||||||
|
|
||||||
def getBookTitle(self):
|
def getBookTitle(self):
|
||||||
|
codec_map = {
|
||||||
|
1252 : 'windows-1252',
|
||||||
|
65001 : 'utf-8',
|
||||||
|
}
|
||||||
title = ''
|
title = ''
|
||||||
if 503 in self.meta_array:
|
if 503 in self.meta_array:
|
||||||
title = self.meta_array[503]
|
title = self.meta_array[503]
|
||||||
@ -242,7 +252,10 @@ class MobiBook:
|
|||||||
if title == '':
|
if title == '':
|
||||||
title = self.header[:32]
|
title = self.header[:32]
|
||||||
title = title.split("\0")[0]
|
title = title.split("\0")[0]
|
||||||
return title
|
codec = 'windows-1252'
|
||||||
|
if self.mobi_codepage in codec_map.keys():
|
||||||
|
codec = codec_map[self.mobi_codepage]
|
||||||
|
return unicode(title, codec).encode('utf-8')
|
||||||
|
|
||||||
def getPIDMetaInfo(self):
|
def getPIDMetaInfo(self):
|
||||||
rec209 = ''
|
rec209 = ''
|
||||||
@ -307,16 +320,26 @@ class MobiBook:
|
|||||||
def getMobiFile(self, outpath):
|
def getMobiFile(self, outpath):
|
||||||
file(outpath,'wb').write(self.mobi_data)
|
file(outpath,'wb').write(self.mobi_data)
|
||||||
|
|
||||||
|
def getPrintReplica(self):
|
||||||
|
return self.print_replica
|
||||||
|
|
||||||
def processBook(self, pidlist):
|
def processBook(self, pidlist):
|
||||||
crypto_type, = struct.unpack('>H', self.sect[0xC:0xC+2])
|
crypto_type, = struct.unpack('>H', self.sect[0xC:0xC+2])
|
||||||
print 'Crypto Type is: ', crypto_type
|
print 'Crypto Type is: ', crypto_type
|
||||||
self.crypto_type = crypto_type
|
self.crypto_type = crypto_type
|
||||||
if crypto_type == 0:
|
if crypto_type == 0:
|
||||||
print "This book is not encrypted."
|
print "This book is not encrypted."
|
||||||
|
# we must still check for Print Replica
|
||||||
|
self.print_replica = (self.loadSection(1)[0:4] == '%MOP')
|
||||||
self.mobi_data = self.data_file
|
self.mobi_data = self.data_file
|
||||||
return
|
return
|
||||||
if crypto_type != 2 and crypto_type != 1:
|
if crypto_type != 2 and crypto_type != 1:
|
||||||
raise DrmException("Cannot decode unknown Mobipocket encryption type %d" % crypto_type)
|
raise DrmException("Cannot decode unknown Mobipocket encryption type %d" % crypto_type)
|
||||||
|
if 406 in self.meta_array:
|
||||||
|
data406 = self.meta_array[406]
|
||||||
|
val406, = struct.unpack('>Q',data406)
|
||||||
|
if val406 != 0:
|
||||||
|
raise DrmException("Cannot decode library or rented ebooks.")
|
||||||
|
|
||||||
goodpids = []
|
goodpids = []
|
||||||
for pid in pidlist:
|
for pid in pidlist:
|
||||||
@ -367,7 +390,10 @@ class MobiBook:
|
|||||||
if i%100 == 0:
|
if i%100 == 0:
|
||||||
print ".",
|
print ".",
|
||||||
# print "record %d, extra_size %d" %(i,extra_size)
|
# print "record %d, extra_size %d" %(i,extra_size)
|
||||||
self.mobi_data += PC1(found_key, data[0:len(data) - extra_size])
|
decoded_data = PC1(found_key, data[0:len(data) - extra_size])
|
||||||
|
if i==1:
|
||||||
|
self.print_replica = (decoded_data[0:4] == '%MOP')
|
||||||
|
self.mobi_data += decoded_data
|
||||||
if extra_size > 0:
|
if extra_size > 0:
|
||||||
self.mobi_data += data[-extra_size:]
|
self.mobi_data += data[-extra_size:]
|
||||||
if self.num_sections > self.records+1:
|
if self.num_sections > self.records+1:
|
||||||
@ -392,9 +418,9 @@ def getUnencryptedBookWithList(infile,pidlist):
|
|||||||
|
|
||||||
def main(argv=sys.argv):
|
def main(argv=sys.argv):
|
||||||
print ('MobiDeDrm v%(__version__)s. '
|
print ('MobiDeDrm v%(__version__)s. '
|
||||||
'Copyright 2008-2010 The Dark Reverser.' % globals())
|
'Copyright 2008-2011 The Dark Reverser et al.' % globals())
|
||||||
if len(argv)<3 or len(argv)>4:
|
if len(argv)<3 or len(argv)>4:
|
||||||
print "Removes protection from Mobipocket books"
|
print "Removes protection from Kindle/Mobipocket and Kindle/Print Replica ebooks"
|
||||||
print "Usage:"
|
print "Usage:"
|
||||||
print " %s <infile> <outfile> [<Comma separated list of PIDs to try>]" % sys.argv[0]
|
print " %s <infile> <outfile> [<Comma separated list of PIDs to try>]" % sys.argv[0]
|
||||||
return 1
|
return 1
|
||||||
@ -402,9 +428,9 @@ def main(argv=sys.argv):
|
|||||||
infile = argv[1]
|
infile = argv[1]
|
||||||
outfile = argv[2]
|
outfile = argv[2]
|
||||||
if len(argv) is 4:
|
if len(argv) is 4:
|
||||||
pidlist = argv[3].split(',')
|
pidlist = argv[3].split(',')
|
||||||
else:
|
else:
|
||||||
pidlist = {}
|
pidlist = {}
|
||||||
try:
|
try:
|
||||||
stripped_file = getUnencryptedBookWithList(infile, pidlist)
|
stripped_file = getUnencryptedBookWithList(infile, pidlist)
|
||||||
file(outfile, 'wb').write(stripped_file)
|
file(outfile, 'wb').write(stripped_file)
|
||||||
|
@ -263,6 +263,7 @@ class PrefsDialog(Toplevel):
|
|||||||
filetypes=[('ePub Files','.epub'),
|
filetypes=[('ePub Files','.epub'),
|
||||||
('Kindle','.azw'),
|
('Kindle','.azw'),
|
||||||
('Kindle','.azw1'),
|
('Kindle','.azw1'),
|
||||||
|
('Kindle','.azw4'),
|
||||||
('Kindle','.tpz'),
|
('Kindle','.tpz'),
|
||||||
('Kindle','.mobi'),
|
('Kindle','.mobi'),
|
||||||
('Kindle','.prc'),
|
('Kindle','.prc'),
|
||||||
@ -465,7 +466,7 @@ class ConvDialog(Toplevel):
|
|||||||
if ext == '.pdb':
|
if ext == '.pdb':
|
||||||
self.p2 = processPDB(apphome, infile, outdir, rscpath)
|
self.p2 = processPDB(apphome, infile, outdir, rscpath)
|
||||||
return 0
|
return 0
|
||||||
if ext in ['.azw', '.azw1', '.prc', '.mobi', '.tpz']:
|
if ext in ['.azw', '.azw1', '.azw4', '.prc', '.mobi', '.tpz']:
|
||||||
self.p2 = processK4MOBI(apphome, infile, outdir, rscpath)
|
self.p2 = processK4MOBI(apphome, infile, outdir, rscpath)
|
||||||
return 0
|
return 0
|
||||||
if ext == '.pdf':
|
if ext == '.pdf':
|
||||||
|
@ -17,7 +17,7 @@ from __future__ import with_statement
|
|||||||
# and many many others
|
# and many many others
|
||||||
|
|
||||||
|
|
||||||
__version__ = '3.6'
|
__version__ = '3.7'
|
||||||
|
|
||||||
class Unbuffered:
|
class Unbuffered:
|
||||||
def __init__(self, stream):
|
def __init__(self, stream):
|
||||||
@ -76,7 +76,7 @@ def cleanup_name(name):
|
|||||||
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
|
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
|
||||||
# handle the obvious cases at the beginning
|
# handle the obvious cases at the beginning
|
||||||
if not os.path.isfile(infile):
|
if not os.path.isfile(infile):
|
||||||
print "Error: Input file does not exist"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: Input file does not exist"
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
mobi = True
|
mobi = True
|
||||||
@ -106,17 +106,20 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
|
|||||||
mb.processBook(pidlst)
|
mb.processBook(pidlst)
|
||||||
|
|
||||||
except mobidedrm.DrmException, e:
|
except mobidedrm.DrmException, e:
|
||||||
print "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
||||||
return 1
|
return 1
|
||||||
except topazextract.TpzDRMError, e:
|
except topazextract.TpzDRMError, e:
|
||||||
print "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
||||||
return 1
|
return 1
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if mobi:
|
if mobi:
|
||||||
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.mobi')
|
if mb.getPrintReplica():
|
||||||
|
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.azw4')
|
||||||
|
else:
|
||||||
|
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.mobi')
|
||||||
mb.getMobiFile(outfile)
|
mb.getMobiFile(outfile)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@ -158,7 +161,6 @@ def main(argv=sys.argv):
|
|||||||
print ('K4MobiDeDrm v%(__version__)s '
|
print ('K4MobiDeDrm v%(__version__)s '
|
||||||
'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals())
|
'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals())
|
||||||
|
|
||||||
print ' '
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "k:p:s:")
|
opts, args = getopt.getopt(sys.argv[1:], "k:p:s:")
|
||||||
except getopt.GetoptError, err:
|
except getopt.GetoptError, err:
|
||||||
|
@ -53,8 +53,9 @@
|
|||||||
# files, but they are not for HUFF/CDIC compress files!
|
# files, but they are not for HUFF/CDIC compress files!
|
||||||
# 0.30 - Modified interface slightly to work better with new calibre plugin style
|
# 0.30 - Modified interface slightly to work better with new calibre plugin style
|
||||||
# 0.31 - The multibyte encrytion info is true for version 7 files too.
|
# 0.31 - The multibyte encrytion info is true for version 7 files too.
|
||||||
|
# 0.32 - Added support for "Print Replica" Kindle ebooks
|
||||||
|
|
||||||
__version__ = '0.31'
|
__version__ = '0.32'
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -163,6 +164,9 @@ class MobiBook:
|
|||||||
return self.data_file[off:endoff]
|
return self.data_file[off:endoff]
|
||||||
|
|
||||||
def __init__(self, infile):
|
def __init__(self, infile):
|
||||||
|
print ('MobiDeDrm v%(__version__)s. '
|
||||||
|
'Copyright 2008-2011 The Dark Reverser et al.' % globals())
|
||||||
|
|
||||||
# initial sanity check on file
|
# initial sanity check on file
|
||||||
self.data_file = file(infile, 'rb').read()
|
self.data_file = file(infile, 'rb').read()
|
||||||
self.mobi_data = ''
|
self.mobi_data = ''
|
||||||
@ -193,6 +197,7 @@ class MobiBook:
|
|||||||
self.meta_array = {}
|
self.meta_array = {}
|
||||||
return
|
return
|
||||||
self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18])
|
self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18])
|
||||||
|
self.mobi_codepage, = struct.unpack('>L',self.sect[0x1c:0x20])
|
||||||
self.mobi_version, = struct.unpack('>L',self.sect[0x68:0x6C])
|
self.mobi_version, = struct.unpack('>L',self.sect[0x68:0x6C])
|
||||||
print "MOBI header version = %d, length = %d" %(self.mobi_version, self.mobi_length)
|
print "MOBI header version = %d, length = %d" %(self.mobi_version, self.mobi_length)
|
||||||
self.extra_data_flags = 0
|
self.extra_data_flags = 0
|
||||||
@ -230,8 +235,13 @@ class MobiBook:
|
|||||||
except:
|
except:
|
||||||
self.meta_array = {}
|
self.meta_array = {}
|
||||||
pass
|
pass
|
||||||
|
self.print_replica = False
|
||||||
|
|
||||||
def getBookTitle(self):
|
def getBookTitle(self):
|
||||||
|
codec_map = {
|
||||||
|
1252 : 'windows-1252',
|
||||||
|
65001 : 'utf-8',
|
||||||
|
}
|
||||||
title = ''
|
title = ''
|
||||||
if 503 in self.meta_array:
|
if 503 in self.meta_array:
|
||||||
title = self.meta_array[503]
|
title = self.meta_array[503]
|
||||||
@ -242,7 +252,10 @@ class MobiBook:
|
|||||||
if title == '':
|
if title == '':
|
||||||
title = self.header[:32]
|
title = self.header[:32]
|
||||||
title = title.split("\0")[0]
|
title = title.split("\0")[0]
|
||||||
return title
|
codec = 'windows-1252'
|
||||||
|
if self.mobi_codepage in codec_map.keys():
|
||||||
|
codec = codec_map[self.mobi_codepage]
|
||||||
|
return unicode(title, codec).encode('utf-8')
|
||||||
|
|
||||||
def getPIDMetaInfo(self):
|
def getPIDMetaInfo(self):
|
||||||
rec209 = ''
|
rec209 = ''
|
||||||
@ -307,16 +320,26 @@ class MobiBook:
|
|||||||
def getMobiFile(self, outpath):
|
def getMobiFile(self, outpath):
|
||||||
file(outpath,'wb').write(self.mobi_data)
|
file(outpath,'wb').write(self.mobi_data)
|
||||||
|
|
||||||
|
def getPrintReplica(self):
|
||||||
|
return self.print_replica
|
||||||
|
|
||||||
def processBook(self, pidlist):
|
def processBook(self, pidlist):
|
||||||
crypto_type, = struct.unpack('>H', self.sect[0xC:0xC+2])
|
crypto_type, = struct.unpack('>H', self.sect[0xC:0xC+2])
|
||||||
print 'Crypto Type is: ', crypto_type
|
print 'Crypto Type is: ', crypto_type
|
||||||
self.crypto_type = crypto_type
|
self.crypto_type = crypto_type
|
||||||
if crypto_type == 0:
|
if crypto_type == 0:
|
||||||
print "This book is not encrypted."
|
print "This book is not encrypted."
|
||||||
|
# we must still check for Print Replica
|
||||||
|
self.print_replica = (self.loadSection(1)[0:4] == '%MOP')
|
||||||
self.mobi_data = self.data_file
|
self.mobi_data = self.data_file
|
||||||
return
|
return
|
||||||
if crypto_type != 2 and crypto_type != 1:
|
if crypto_type != 2 and crypto_type != 1:
|
||||||
raise DrmException("Cannot decode unknown Mobipocket encryption type %d" % crypto_type)
|
raise DrmException("Cannot decode unknown Mobipocket encryption type %d" % crypto_type)
|
||||||
|
if 406 in self.meta_array:
|
||||||
|
data406 = self.meta_array[406]
|
||||||
|
val406, = struct.unpack('>Q',data406)
|
||||||
|
if val406 != 0:
|
||||||
|
raise DrmException("Cannot decode library or rented ebooks.")
|
||||||
|
|
||||||
goodpids = []
|
goodpids = []
|
||||||
for pid in pidlist:
|
for pid in pidlist:
|
||||||
@ -367,7 +390,10 @@ class MobiBook:
|
|||||||
if i%100 == 0:
|
if i%100 == 0:
|
||||||
print ".",
|
print ".",
|
||||||
# print "record %d, extra_size %d" %(i,extra_size)
|
# print "record %d, extra_size %d" %(i,extra_size)
|
||||||
self.mobi_data += PC1(found_key, data[0:len(data) - extra_size])
|
decoded_data = PC1(found_key, data[0:len(data) - extra_size])
|
||||||
|
if i==1:
|
||||||
|
self.print_replica = (decoded_data[0:4] == '%MOP')
|
||||||
|
self.mobi_data += decoded_data
|
||||||
if extra_size > 0:
|
if extra_size > 0:
|
||||||
self.mobi_data += data[-extra_size:]
|
self.mobi_data += data[-extra_size:]
|
||||||
if self.num_sections > self.records+1:
|
if self.num_sections > self.records+1:
|
||||||
@ -392,9 +418,9 @@ def getUnencryptedBookWithList(infile,pidlist):
|
|||||||
|
|
||||||
def main(argv=sys.argv):
|
def main(argv=sys.argv):
|
||||||
print ('MobiDeDrm v%(__version__)s. '
|
print ('MobiDeDrm v%(__version__)s. '
|
||||||
'Copyright 2008-2010 The Dark Reverser.' % globals())
|
'Copyright 2008-2011 The Dark Reverser et al.' % globals())
|
||||||
if len(argv)<3 or len(argv)>4:
|
if len(argv)<3 or len(argv)>4:
|
||||||
print "Removes protection from Mobipocket books"
|
print "Removes protection from Kindle/Mobipocket and Kindle/Print Replica ebooks"
|
||||||
print "Usage:"
|
print "Usage:"
|
||||||
print " %s <infile> <outfile> [<Comma separated list of PIDs to try>]" % sys.argv[0]
|
print " %s <infile> <outfile> [<Comma separated list of PIDs to try>]" % sys.argv[0]
|
||||||
return 1
|
return 1
|
||||||
@ -402,9 +428,9 @@ def main(argv=sys.argv):
|
|||||||
infile = argv[1]
|
infile = argv[1]
|
||||||
outfile = argv[2]
|
outfile = argv[2]
|
||||||
if len(argv) is 4:
|
if len(argv) is 4:
|
||||||
pidlist = argv[3].split(',')
|
pidlist = argv[3].split(',')
|
||||||
else:
|
else:
|
||||||
pidlist = {}
|
pidlist = {}
|
||||||
try:
|
try:
|
||||||
stripped_file = getUnencryptedBookWithList(infile, pidlist)
|
stripped_file = getUnencryptedBookWithList(infile, pidlist)
|
||||||
file(outfile, 'wb').write(stripped_file)
|
file(outfile, 'wb').write(stripped_file)
|
||||||
|
@ -109,7 +109,7 @@ class MainDialog(Tkinter.Frame):
|
|||||||
# post output from subprocess in scrolled text widget
|
# post output from subprocess in scrolled text widget
|
||||||
def showCmdOutput(self, msg):
|
def showCmdOutput(self, msg):
|
||||||
if msg and msg !='':
|
if msg and msg !='':
|
||||||
msg = msg.encode('utf-8')
|
# msg = msg.encode('utf-8')
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
msg = msg.replace('\r\n','\n')
|
msg = msg.replace('\r\n','\n')
|
||||||
self.stext.insert(Tkconstants.END,msg)
|
self.stext.insert(Tkconstants.END,msg)
|
||||||
@ -149,7 +149,7 @@ class MainDialog(Tkinter.Frame):
|
|||||||
mobipath = tkFileDialog.askopenfilename(
|
mobipath = tkFileDialog.askopenfilename(
|
||||||
initialdir = cpath,
|
initialdir = cpath,
|
||||||
parent=None, title='Select Kindle/Mobi/Topaz eBook File',
|
parent=None, title='Select Kindle/Mobi/Topaz eBook File',
|
||||||
defaultextension='.prc', filetypes=[('Mobi eBook File', '.prc'), ('Mobi eBook File', '.azw'),('Mobi eBook File', '.mobi'),('Mobi eBook File', '.tpz'),('Mobi eBook File', '.azw1'),('All Files', '.*')])
|
defaultextension='.prc', filetypes=[('Mobi eBook File', '.prc'), ('Mobi eBook File', '.azw'),('Mobi eBook File', '.mobi'),('Mobi eBook File', '.tpz'),('Mobi eBook File', '.azw1'),('Mobi azw4 eBook File', '.azw4'),('All Files', '.*')])
|
||||||
if mobipath:
|
if mobipath:
|
||||||
mobipath = os.path.normpath(mobipath)
|
mobipath = os.path.normpath(mobipath)
|
||||||
self.mobipath.delete(0, Tkconstants.END)
|
self.mobipath.delete(0, Tkconstants.END)
|
||||||
|
@ -17,7 +17,7 @@ from __future__ import with_statement
|
|||||||
# and many many others
|
# and many many others
|
||||||
|
|
||||||
|
|
||||||
__version__ = '3.6'
|
__version__ = '3.7'
|
||||||
|
|
||||||
class Unbuffered:
|
class Unbuffered:
|
||||||
def __init__(self, stream):
|
def __init__(self, stream):
|
||||||
@ -76,7 +76,7 @@ def cleanup_name(name):
|
|||||||
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
|
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
|
||||||
# handle the obvious cases at the beginning
|
# handle the obvious cases at the beginning
|
||||||
if not os.path.isfile(infile):
|
if not os.path.isfile(infile):
|
||||||
print "Error: Input file does not exist"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: Input file does not exist"
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
mobi = True
|
mobi = True
|
||||||
@ -106,17 +106,20 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
|
|||||||
mb.processBook(pidlst)
|
mb.processBook(pidlst)
|
||||||
|
|
||||||
except mobidedrm.DrmException, e:
|
except mobidedrm.DrmException, e:
|
||||||
print "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
||||||
return 1
|
return 1
|
||||||
except topazextract.TpzDRMError, e:
|
except topazextract.TpzDRMError, e:
|
||||||
print "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
||||||
return 1
|
return 1
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if mobi:
|
if mobi:
|
||||||
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.mobi')
|
if mb.getPrintReplica():
|
||||||
|
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.azw4')
|
||||||
|
else:
|
||||||
|
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.mobi')
|
||||||
mb.getMobiFile(outfile)
|
mb.getMobiFile(outfile)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@ -158,7 +161,6 @@ def main(argv=sys.argv):
|
|||||||
print ('K4MobiDeDrm v%(__version__)s '
|
print ('K4MobiDeDrm v%(__version__)s '
|
||||||
'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals())
|
'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals())
|
||||||
|
|
||||||
print ' '
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "k:p:s:")
|
opts, args = getopt.getopt(sys.argv[1:], "k:p:s:")
|
||||||
except getopt.GetoptError, err:
|
except getopt.GetoptError, err:
|
||||||
|
@ -53,8 +53,9 @@
|
|||||||
# files, but they are not for HUFF/CDIC compress files!
|
# files, but they are not for HUFF/CDIC compress files!
|
||||||
# 0.30 - Modified interface slightly to work better with new calibre plugin style
|
# 0.30 - Modified interface slightly to work better with new calibre plugin style
|
||||||
# 0.31 - The multibyte encrytion info is true for version 7 files too.
|
# 0.31 - The multibyte encrytion info is true for version 7 files too.
|
||||||
|
# 0.32 - Added support for "Print Replica" Kindle ebooks
|
||||||
|
|
||||||
__version__ = '0.31'
|
__version__ = '0.32'
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -163,6 +164,9 @@ class MobiBook:
|
|||||||
return self.data_file[off:endoff]
|
return self.data_file[off:endoff]
|
||||||
|
|
||||||
def __init__(self, infile):
|
def __init__(self, infile):
|
||||||
|
print ('MobiDeDrm v%(__version__)s. '
|
||||||
|
'Copyright 2008-2011 The Dark Reverser et al.' % globals())
|
||||||
|
|
||||||
# initial sanity check on file
|
# initial sanity check on file
|
||||||
self.data_file = file(infile, 'rb').read()
|
self.data_file = file(infile, 'rb').read()
|
||||||
self.mobi_data = ''
|
self.mobi_data = ''
|
||||||
@ -193,6 +197,7 @@ class MobiBook:
|
|||||||
self.meta_array = {}
|
self.meta_array = {}
|
||||||
return
|
return
|
||||||
self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18])
|
self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18])
|
||||||
|
self.mobi_codepage, = struct.unpack('>L',self.sect[0x1c:0x20])
|
||||||
self.mobi_version, = struct.unpack('>L',self.sect[0x68:0x6C])
|
self.mobi_version, = struct.unpack('>L',self.sect[0x68:0x6C])
|
||||||
print "MOBI header version = %d, length = %d" %(self.mobi_version, self.mobi_length)
|
print "MOBI header version = %d, length = %d" %(self.mobi_version, self.mobi_length)
|
||||||
self.extra_data_flags = 0
|
self.extra_data_flags = 0
|
||||||
@ -230,8 +235,13 @@ class MobiBook:
|
|||||||
except:
|
except:
|
||||||
self.meta_array = {}
|
self.meta_array = {}
|
||||||
pass
|
pass
|
||||||
|
self.print_replica = False
|
||||||
|
|
||||||
def getBookTitle(self):
|
def getBookTitle(self):
|
||||||
|
codec_map = {
|
||||||
|
1252 : 'windows-1252',
|
||||||
|
65001 : 'utf-8',
|
||||||
|
}
|
||||||
title = ''
|
title = ''
|
||||||
if 503 in self.meta_array:
|
if 503 in self.meta_array:
|
||||||
title = self.meta_array[503]
|
title = self.meta_array[503]
|
||||||
@ -242,7 +252,10 @@ class MobiBook:
|
|||||||
if title == '':
|
if title == '':
|
||||||
title = self.header[:32]
|
title = self.header[:32]
|
||||||
title = title.split("\0")[0]
|
title = title.split("\0")[0]
|
||||||
return title
|
codec = 'windows-1252'
|
||||||
|
if self.mobi_codepage in codec_map.keys():
|
||||||
|
codec = codec_map[self.mobi_codepage]
|
||||||
|
return unicode(title, codec).encode('utf-8')
|
||||||
|
|
||||||
def getPIDMetaInfo(self):
|
def getPIDMetaInfo(self):
|
||||||
rec209 = ''
|
rec209 = ''
|
||||||
@ -307,16 +320,26 @@ class MobiBook:
|
|||||||
def getMobiFile(self, outpath):
|
def getMobiFile(self, outpath):
|
||||||
file(outpath,'wb').write(self.mobi_data)
|
file(outpath,'wb').write(self.mobi_data)
|
||||||
|
|
||||||
|
def getPrintReplica(self):
|
||||||
|
return self.print_replica
|
||||||
|
|
||||||
def processBook(self, pidlist):
|
def processBook(self, pidlist):
|
||||||
crypto_type, = struct.unpack('>H', self.sect[0xC:0xC+2])
|
crypto_type, = struct.unpack('>H', self.sect[0xC:0xC+2])
|
||||||
print 'Crypto Type is: ', crypto_type
|
print 'Crypto Type is: ', crypto_type
|
||||||
self.crypto_type = crypto_type
|
self.crypto_type = crypto_type
|
||||||
if crypto_type == 0:
|
if crypto_type == 0:
|
||||||
print "This book is not encrypted."
|
print "This book is not encrypted."
|
||||||
|
# we must still check for Print Replica
|
||||||
|
self.print_replica = (self.loadSection(1)[0:4] == '%MOP')
|
||||||
self.mobi_data = self.data_file
|
self.mobi_data = self.data_file
|
||||||
return
|
return
|
||||||
if crypto_type != 2 and crypto_type != 1:
|
if crypto_type != 2 and crypto_type != 1:
|
||||||
raise DrmException("Cannot decode unknown Mobipocket encryption type %d" % crypto_type)
|
raise DrmException("Cannot decode unknown Mobipocket encryption type %d" % crypto_type)
|
||||||
|
if 406 in self.meta_array:
|
||||||
|
data406 = self.meta_array[406]
|
||||||
|
val406, = struct.unpack('>Q',data406)
|
||||||
|
if val406 != 0:
|
||||||
|
raise DrmException("Cannot decode library or rented ebooks.")
|
||||||
|
|
||||||
goodpids = []
|
goodpids = []
|
||||||
for pid in pidlist:
|
for pid in pidlist:
|
||||||
@ -367,7 +390,10 @@ class MobiBook:
|
|||||||
if i%100 == 0:
|
if i%100 == 0:
|
||||||
print ".",
|
print ".",
|
||||||
# print "record %d, extra_size %d" %(i,extra_size)
|
# print "record %d, extra_size %d" %(i,extra_size)
|
||||||
self.mobi_data += PC1(found_key, data[0:len(data) - extra_size])
|
decoded_data = PC1(found_key, data[0:len(data) - extra_size])
|
||||||
|
if i==1:
|
||||||
|
self.print_replica = (decoded_data[0:4] == '%MOP')
|
||||||
|
self.mobi_data += decoded_data
|
||||||
if extra_size > 0:
|
if extra_size > 0:
|
||||||
self.mobi_data += data[-extra_size:]
|
self.mobi_data += data[-extra_size:]
|
||||||
if self.num_sections > self.records+1:
|
if self.num_sections > self.records+1:
|
||||||
@ -392,9 +418,9 @@ def getUnencryptedBookWithList(infile,pidlist):
|
|||||||
|
|
||||||
def main(argv=sys.argv):
|
def main(argv=sys.argv):
|
||||||
print ('MobiDeDrm v%(__version__)s. '
|
print ('MobiDeDrm v%(__version__)s. '
|
||||||
'Copyright 2008-2010 The Dark Reverser.' % globals())
|
'Copyright 2008-2011 The Dark Reverser et al.' % globals())
|
||||||
if len(argv)<3 or len(argv)>4:
|
if len(argv)<3 or len(argv)>4:
|
||||||
print "Removes protection from Mobipocket books"
|
print "Removes protection from Kindle/Mobipocket and Kindle/Print Replica ebooks"
|
||||||
print "Usage:"
|
print "Usage:"
|
||||||
print " %s <infile> <outfile> [<Comma separated list of PIDs to try>]" % sys.argv[0]
|
print " %s <infile> <outfile> [<Comma separated list of PIDs to try>]" % sys.argv[0]
|
||||||
return 1
|
return 1
|
||||||
@ -402,9 +428,9 @@ def main(argv=sys.argv):
|
|||||||
infile = argv[1]
|
infile = argv[1]
|
||||||
outfile = argv[2]
|
outfile = argv[2]
|
||||||
if len(argv) is 4:
|
if len(argv) is 4:
|
||||||
pidlist = argv[3].split(',')
|
pidlist = argv[3].split(',')
|
||||||
else:
|
else:
|
||||||
pidlist = {}
|
pidlist = {}
|
||||||
try:
|
try:
|
||||||
stripped_file = getUnencryptedBookWithList(infile, pidlist)
|
stripped_file = getUnencryptedBookWithList(infile, pidlist)
|
||||||
file(outfile, 'wb').write(stripped_file)
|
file(outfile, 'wb').write(stripped_file)
|
||||||
|
@ -53,8 +53,9 @@
|
|||||||
# files, but they are not for HUFF/CDIC compress files!
|
# files, but they are not for HUFF/CDIC compress files!
|
||||||
# 0.30 - Modified interface slightly to work better with new calibre plugin style
|
# 0.30 - Modified interface slightly to work better with new calibre plugin style
|
||||||
# 0.31 - The multibyte encrytion info is true for version 7 files too.
|
# 0.31 - The multibyte encrytion info is true for version 7 files too.
|
||||||
|
# 0.32 - Added support for "Print Replica" Kindle ebooks
|
||||||
|
|
||||||
__version__ = '0.31'
|
__version__ = '0.32'
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -163,6 +164,9 @@ class MobiBook:
|
|||||||
return self.data_file[off:endoff]
|
return self.data_file[off:endoff]
|
||||||
|
|
||||||
def __init__(self, infile):
|
def __init__(self, infile):
|
||||||
|
print ('MobiDeDrm v%(__version__)s. '
|
||||||
|
'Copyright 2008-2011 The Dark Reverser et al.' % globals())
|
||||||
|
|
||||||
# initial sanity check on file
|
# initial sanity check on file
|
||||||
self.data_file = file(infile, 'rb').read()
|
self.data_file = file(infile, 'rb').read()
|
||||||
self.mobi_data = ''
|
self.mobi_data = ''
|
||||||
@ -193,6 +197,7 @@ class MobiBook:
|
|||||||
self.meta_array = {}
|
self.meta_array = {}
|
||||||
return
|
return
|
||||||
self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18])
|
self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18])
|
||||||
|
self.mobi_codepage, = struct.unpack('>L',self.sect[0x1c:0x20])
|
||||||
self.mobi_version, = struct.unpack('>L',self.sect[0x68:0x6C])
|
self.mobi_version, = struct.unpack('>L',self.sect[0x68:0x6C])
|
||||||
print "MOBI header version = %d, length = %d" %(self.mobi_version, self.mobi_length)
|
print "MOBI header version = %d, length = %d" %(self.mobi_version, self.mobi_length)
|
||||||
self.extra_data_flags = 0
|
self.extra_data_flags = 0
|
||||||
@ -230,8 +235,13 @@ class MobiBook:
|
|||||||
except:
|
except:
|
||||||
self.meta_array = {}
|
self.meta_array = {}
|
||||||
pass
|
pass
|
||||||
|
self.print_replica = False
|
||||||
|
|
||||||
def getBookTitle(self):
|
def getBookTitle(self):
|
||||||
|
codec_map = {
|
||||||
|
1252 : 'windows-1252',
|
||||||
|
65001 : 'utf-8',
|
||||||
|
}
|
||||||
title = ''
|
title = ''
|
||||||
if 503 in self.meta_array:
|
if 503 in self.meta_array:
|
||||||
title = self.meta_array[503]
|
title = self.meta_array[503]
|
||||||
@ -242,7 +252,10 @@ class MobiBook:
|
|||||||
if title == '':
|
if title == '':
|
||||||
title = self.header[:32]
|
title = self.header[:32]
|
||||||
title = title.split("\0")[0]
|
title = title.split("\0")[0]
|
||||||
return title
|
codec = 'windows-1252'
|
||||||
|
if self.mobi_codepage in codec_map.keys():
|
||||||
|
codec = codec_map[self.mobi_codepage]
|
||||||
|
return unicode(title, codec).encode('utf-8')
|
||||||
|
|
||||||
def getPIDMetaInfo(self):
|
def getPIDMetaInfo(self):
|
||||||
rec209 = ''
|
rec209 = ''
|
||||||
@ -307,16 +320,26 @@ class MobiBook:
|
|||||||
def getMobiFile(self, outpath):
|
def getMobiFile(self, outpath):
|
||||||
file(outpath,'wb').write(self.mobi_data)
|
file(outpath,'wb').write(self.mobi_data)
|
||||||
|
|
||||||
|
def getPrintReplica(self):
|
||||||
|
return self.print_replica
|
||||||
|
|
||||||
def processBook(self, pidlist):
|
def processBook(self, pidlist):
|
||||||
crypto_type, = struct.unpack('>H', self.sect[0xC:0xC+2])
|
crypto_type, = struct.unpack('>H', self.sect[0xC:0xC+2])
|
||||||
print 'Crypto Type is: ', crypto_type
|
print 'Crypto Type is: ', crypto_type
|
||||||
self.crypto_type = crypto_type
|
self.crypto_type = crypto_type
|
||||||
if crypto_type == 0:
|
if crypto_type == 0:
|
||||||
print "This book is not encrypted."
|
print "This book is not encrypted."
|
||||||
|
# we must still check for Print Replica
|
||||||
|
self.print_replica = (self.loadSection(1)[0:4] == '%MOP')
|
||||||
self.mobi_data = self.data_file
|
self.mobi_data = self.data_file
|
||||||
return
|
return
|
||||||
if crypto_type != 2 and crypto_type != 1:
|
if crypto_type != 2 and crypto_type != 1:
|
||||||
raise DrmException("Cannot decode unknown Mobipocket encryption type %d" % crypto_type)
|
raise DrmException("Cannot decode unknown Mobipocket encryption type %d" % crypto_type)
|
||||||
|
if 406 in self.meta_array:
|
||||||
|
data406 = self.meta_array[406]
|
||||||
|
val406, = struct.unpack('>Q',data406)
|
||||||
|
if val406 != 0:
|
||||||
|
raise DrmException("Cannot decode library or rented ebooks.")
|
||||||
|
|
||||||
goodpids = []
|
goodpids = []
|
||||||
for pid in pidlist:
|
for pid in pidlist:
|
||||||
@ -367,7 +390,10 @@ class MobiBook:
|
|||||||
if i%100 == 0:
|
if i%100 == 0:
|
||||||
print ".",
|
print ".",
|
||||||
# print "record %d, extra_size %d" %(i,extra_size)
|
# print "record %d, extra_size %d" %(i,extra_size)
|
||||||
self.mobi_data += PC1(found_key, data[0:len(data) - extra_size])
|
decoded_data = PC1(found_key, data[0:len(data) - extra_size])
|
||||||
|
if i==1:
|
||||||
|
self.print_replica = (decoded_data[0:4] == '%MOP')
|
||||||
|
self.mobi_data += decoded_data
|
||||||
if extra_size > 0:
|
if extra_size > 0:
|
||||||
self.mobi_data += data[-extra_size:]
|
self.mobi_data += data[-extra_size:]
|
||||||
if self.num_sections > self.records+1:
|
if self.num_sections > self.records+1:
|
||||||
@ -392,9 +418,9 @@ def getUnencryptedBookWithList(infile,pidlist):
|
|||||||
|
|
||||||
def main(argv=sys.argv):
|
def main(argv=sys.argv):
|
||||||
print ('MobiDeDrm v%(__version__)s. '
|
print ('MobiDeDrm v%(__version__)s. '
|
||||||
'Copyright 2008-2010 The Dark Reverser.' % globals())
|
'Copyright 2008-2011 The Dark Reverser et al.' % globals())
|
||||||
if len(argv)<3 or len(argv)>4:
|
if len(argv)<3 or len(argv)>4:
|
||||||
print "Removes protection from Mobipocket books"
|
print "Removes protection from Kindle/Mobipocket and Kindle/Print Replica ebooks"
|
||||||
print "Usage:"
|
print "Usage:"
|
||||||
print " %s <infile> <outfile> [<Comma separated list of PIDs to try>]" % sys.argv[0]
|
print " %s <infile> <outfile> [<Comma separated list of PIDs to try>]" % sys.argv[0]
|
||||||
return 1
|
return 1
|
||||||
@ -402,9 +428,9 @@ def main(argv=sys.argv):
|
|||||||
infile = argv[1]
|
infile = argv[1]
|
||||||
outfile = argv[2]
|
outfile = argv[2]
|
||||||
if len(argv) is 4:
|
if len(argv) is 4:
|
||||||
pidlist = argv[3].split(',')
|
pidlist = argv[3].split(',')
|
||||||
else:
|
else:
|
||||||
pidlist = {}
|
pidlist = {}
|
||||||
try:
|
try:
|
||||||
stripped_file = getUnencryptedBookWithList(infile, pidlist)
|
stripped_file = getUnencryptedBookWithList(infile, pidlist)
|
||||||
file(outfile, 'wb').write(stripped_file)
|
file(outfile, 'wb').write(stripped_file)
|
||||||
|
Loading…
Reference in New Issue
Block a user