From b71ed3887ee547c714c8223d1d74bc4e5cdfe809 Mon Sep 17 00:00:00 2001 From: Apprentice Harper Date: Sat, 18 May 2019 18:42:56 +0100 Subject: [PATCH 01/32] Update README.md added three very FAQs --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 6abeb67..1861f20 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ For the latest Amazon KFX format, users of the calibre plugin should also instal I welcome contributions from others to improve these tools, from expanding the range of books handled, improving key retrieval, to just general bug fixes, speed improvements and UI enhancements. +I urge people to read the FAQs. But to cover the most common: Use ADE 2.0.1 to be sure not to get the new DRM scheme that these tools can't handle. Use Kindle for Mac/PC 1.24 or earlier, the tools don't currently work with 1.25 or later. Do remember to unzip the downloaded archive to get the plugin. You can't load the whole archive into calibre. + My special thanks to all those developers who have done the hard work of reverse engineering to provide the initial tools. Apprentice Harper. From 4bd89fa4aaf1a1e58b7f9d7ab20c8dbc8a59f4ec Mon Sep 17 00:00:00 2001 From: Adam Plaice Date: Wed, 12 Jun 2019 21:13:25 +0200 Subject: [PATCH 02/32] Fix automatic import of decryption keys on Linux with wine By default, the wineprefix passed to WineGetKeys is "". Unfortunately, os.path.abspath(os.path.expanduser(os.path.expandvars(""))) returns the path to the working directory, which depends on the directory from which calibre was invoked. Hence under current behaviour the wineprefix becomes that path, no longer being the empty string. This means that the `cmdline` that's run is always `WINEPREFIX=/some/path/ wine python.exe [...]`, rather than `wine python.exe [...]` even under default conditions, when the wineprefix hasn't been changed. Unless the user is improbably lucky and invokes calibre from ~/.wine/ (the default wineprefix), this causes automatic retrieval of the keys to always fail. The bug was introduced in f2190a67558a. Checking for "" allows for correct behaviour in the default case, while keeping the nice behaviour of expanding `~`. --- dedrm_src/wineutils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dedrm_src/wineutils.py b/dedrm_src/wineutils.py index 0485e5e..c455721 100644 --- a/dedrm_src/wineutils.py +++ b/dedrm_src/wineutils.py @@ -26,7 +26,9 @@ def WineGetKeys(scriptpath, extension, wineprefix=""): if not os.path.exists(outdirpath): os.makedirs(outdirpath) - wineprefix = os.path.abspath(os.path.expanduser(os.path.expandvars(wineprefix))) + if wineprefix != "": + wineprefix = os.path.abspath(os.path.expanduser(os.path.expandvars(wineprefix))) + if wineprefix != "" and os.path.exists(wineprefix): cmdline = u"WINEPREFIX=\"{2}\" wine python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath,wineprefix) else: From 8bd53cd99853e670528e8b060e9fbc41aabd9dfe Mon Sep 17 00:00:00 2001 From: Adam Plaice Date: Wed, 12 Jun 2019 22:36:14 +0200 Subject: [PATCH 03/32] Improve documentation for using Kindle for PC with Linux in Wine I've tested this on Ubuntu 18.04, with wine installed from the default package repos (no PPAs) with Kindle for PC version 1.17. --- .../DeDRM_plugin_ReadMe.txt | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/contrib/DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt b/contrib/DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt index 7dde68d..7848c1e 100644 --- a/contrib/DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt +++ b/contrib/DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt @@ -83,7 +83,9 @@ Linux Systems Only Instructions for installing Wine, Kindle for PC, Adobe Digital Editions, Python and PyCrypto -------------------------------------------------------------------------------------------- -These instructions have been tested with Wine 1.4 on Ubuntu but are now very out of date. +These instructions have been tested with Wine 1.4 on Ubuntu but some of them are now very out of date. Parts of the instructions (those relevant to Kindle for PC and Python, but not Adobe Digital Editions and PyCrypto) have been tested with Wine 3.0 on Ubuntu. + +If you only use Kindle for PC, version 1.17, then you won't need PyCrypto nor Adobe Digital Editions, so you can skip the pertinent steps. 1. First download the software you're going to to have to install. a. Adobe Digital Editions 1.7.x from http://helpx.adobe.com/digital-editions/kb/cant-install-digital-editions.html @@ -93,19 +95,23 @@ These instructions have been tested with Wine 1.4 on Ubuntu but are now very out (PyCrypto downloads as a zip file. You will need to unzip it.) 2. Install Wine for 32-bit x86. (e.g. on Ubuntu, Open the Ubuntu Software Center, search for Wine, and install "Wine Windows Program Loader".) 2a. [update] Kindle for PC now requires Windows 7, so in the following setups, choose any option for Windows 7, not Windows XP. - 3. Run "Configure Wine", which will set up the default 'wineprefix' - 4. Navigate to "Install an application" and install Kindle. Alternatively, run `winetricks kindle` + 3. Run "Configure Wine", which will set up the default 'wineprefix'. + 4. Navigate to "Install an application" and install Kindle. Alternatively, run `winetricks kindle`. Note that using `winetricks kindle` will give you version 1.20, which might not be what you want. 5. Install Adobe Digital Editions. Accept all defaults and register with your Adobe ID. - 6. Install Python 2.7.x using `msiexec /i python-2.7.8.msi`. Accept all defaults. + 6. Install Python 2.7.x using `msiexec /i python-2.7.8.msi ALLUSERS=1`. Accept all defaults. Alternatively, run `winetricks python26`. However, if you do that, the automatic retrieval of keys (described in the next section) will be impossible, as dedrm_src/wineutils.py currently hardcodes the path for Python27. For manual extraction, you will also need to change Python27 to Python26 in step 2, below. 7. Install PyCrypto 2.1. Accept all defaults. - 8. Unzip DeDRM_plugin.zip and move kindlekey.py to somewhere in drive_c, such as ~/.wine/drive_c/DeDRM/libraryfiles/kindlekey.py. - 9. Run `wine 'C:\Python27/python.exe' 'C:\DeDRM/libraryfiles/kindlekey.py'`, or wherever you copied kindlekey.py to. - 10. Import the resulting key file to the Calibre plugin through the Kindle for Mac/PC ebooks option. - Instructions for getting Kindle for PC and Adobe Digital Editions default decryption keys ----------------------------------------------------------------------------------------- -If everything has been installed in wine as above, the keys will be retrieved automatically. +If everything has been installed in wine as above, the keys should be retrieved automatically. + +If you have a more complex wine installation, or something goes wrong, you may enter the appropriate WINEPREFIX (by default ~/.wine) in the configuration dialogs for Kindle for PC and Adobe Digital Editions (Preferences > Advanced > Plugins > File type plugins > DeDRM > Customize plugin). You can also test that you have entered the WINEPREFIX correctly by trying to add the default keys to the preferences by clicking on the green plus button in the configuration dialogs. + +Alternatively, if that also doesn't work for some reason, you can extract the keys manually. + + 1. Unzip DeDRM_plugin.zip and move kindlekey.py to somewhere in drive_c, such as ~/.wine/drive_c/DeDRM/libraryfiles/kindlekey.py. + 2. Run `wine 'C:\Python27/python.exe' 'C:\DeDRM/libraryfiles/kindlekey.py'`, or wherever you copied kindlekey.py to. + 3. Import the resulting key file to the Calibre plugin through the Kindle for Mac/PC ebooks option. + -If you have a more complex wine installation, you may enter the appropriate WINEPREFIX in the configuration dialogs for Kindle for PC and Adobe Digital Editions. You can also test that you have entered the WINEPREFIX correctly by trying to add the default keys to the preferences by clicking on the green plus button in the configuration dialogs. From 3f591ce66fa1887d2818b133eb19db403f138335 Mon Sep 17 00:00:00 2001 From: Dan Walters Date: Fri, 14 Jun 2019 14:20:56 -0500 Subject: [PATCH 04/32] Allow decryption with DSN only. --- dedrm_src/kfxdedrm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dedrm_src/kfxdedrm.py b/dedrm_src/kfxdedrm.py index 98ae9f2..4648893 100644 --- a/dedrm_src/kfxdedrm.py +++ b/dedrm_src/kfxdedrm.py @@ -68,7 +68,7 @@ class KFXZipBook: print u'Decrypting KFX DRM voucher: {0}'.format(info.filename) for pid in [''] + totalpids: - for dsn_len,secret_len in [(0,0), (16,0), (16,40), (32,40), (40,40)]: + for dsn_len,secret_len in [(0,0), (16,0), (16,40), (32,40), (40,0), (40,40)]: if len(pid) == dsn_len + secret_len: break # split pid into DSN and account secret else: From 5bb6b58bc1434cfa531a3ee9fead178a333e2c59 Mon Sep 17 00:00:00 2001 From: cclauss Date: Mon, 24 Jun 2019 18:49:38 +0200 Subject: [PATCH 05/32] Use print() function in both Python 2 and Python 3 Legacy __print__ statements are syntax errors in Python 3 but __print()__ function works as expected in both Python 2 and Python 3. --- contrib/Other_Tools/Kobo/obok.py | 45 +++++------ dedrm_src/__init__.py | 123 ++++++++++++++++--------------- dedrm_src/adobekey.py | 27 +++---- dedrm_src/alfcrypto.py | 5 +- dedrm_src/androidkindlekey.py | 31 ++++---- dedrm_src/config.py | 3 +- dedrm_src/convert2xml.py | 59 +++++++-------- dedrm_src/encodebase64.py | 9 ++- dedrm_src/epubtest.py | 3 +- dedrm_src/flatxml2html.py | 7 +- dedrm_src/genbook.py | 71 +++++++++--------- dedrm_src/ignobleepub.py | 11 +-- dedrm_src/ignoblekey.py | 25 ++++--- dedrm_src/ignoblekeyfetch.py | 5 +- dedrm_src/ignoblekeygen.py | 7 +- dedrm_src/kfxdedrm.py | 7 +- dedrm_src/kgenpids.py | 13 ++-- dedrm_src/kindlepid.py | 19 ++--- dedrm_src/mobidedrm.py | 37 +++++----- dedrm_src/scriptinterface.py | 17 +++-- dedrm_src/stylexml2css.py | 27 +++---- dedrm_src/topazextract.py | 61 +++++++-------- dedrm_src/wineutils.py | 15 ++-- dedrm_src/zipfix.py | 9 ++- obok_src/obok/obok.py | 45 +++++------ 25 files changed, 353 insertions(+), 328 deletions(-) diff --git a/contrib/Other_Tools/Kobo/obok.py b/contrib/Other_Tools/Kobo/obok.py index 2a35795..fa71c58 100644 --- a/contrib/Other_Tools/Kobo/obok.py +++ b/contrib/Other_Tools/Kobo/obok.py @@ -150,6 +150,7 @@ # after all. # """Manage all Kobo books, either encrypted or DRM-free.""" +from __future__ import print_function __version__ = '3.2.4' __about__ = u"Obok v{0}\nCopyright © 2012-2016 Physisticated et al.".format(__version__) @@ -291,7 +292,7 @@ class KoboLibrary(object): of books, their titles, and the user's encryption key(s).""" def __init__ (self, serials = [], device_path = None): - print __about__ + print(__about__) self.kobodir = u"" kobodb = u"" @@ -374,7 +375,7 @@ class KoboLibrary(object): # make a copy of the database in a temporary file # so we can ensure it's not using WAL logging which sqlite3 can't do. self.newdb = tempfile.NamedTemporaryFile(mode='wb', delete=False) - print self.newdb.name + print(self.newdb.name) olddb = open(kobodb, 'rb') self.newdb.write(olddb.read(18)) self.newdb.write('\x01\x01') @@ -595,32 +596,32 @@ class KoboFile(object): # assume utf-8 with no BOM textoffset = 0 stride = 1 - print u"Checking text:{0}:".format(contents[:10]) + print(u"Checking text:{0}:".format(contents[:10])) # check for byte order mark if contents[:3]=="\xef\xbb\xbf": # seems to be utf-8 with BOM - print u"Could be utf-8 with BOM" + print(u"Could be utf-8 with BOM") textoffset = 3 elif contents[:2]=="\xfe\xff": # seems to be utf-16BE - print u"Could be utf-16BE" + print(u"Could be utf-16BE") textoffset = 3 stride = 2 elif contents[:2]=="\xff\xfe": # seems to be utf-16LE - print u"Could be utf-16LE" + print(u"Could be utf-16LE") textoffset = 2 stride = 2 else: - print u"Perhaps utf-8 without BOM" + print(u"Perhaps utf-8 without BOM") # now check that the first few characters are in the ASCII range for i in xrange(textoffset,textoffset+5*stride,stride): if ord(contents[i])<32 or ord(contents[i])>127: # Non-ascii, so decryption probably failed - print u"Bad character at {0}, value {1}".format(i,ord(contents[i])) + print(u"Bad character at {0}, value {1}".format(i,ord(contents[i]))) raise ValueError - print u"Seems to be good text" + print(u"Seems to be good text") return True if contents[:5]==" 0: try: for i,userkey in enumerate(newkeys): - print u"{0} v{1}: Trying a new default key".format(PLUGIN_NAME, PLUGIN_VERSION) + print(u"{0} v{1}: Trying a new default key".format(PLUGIN_NAME, PLUGIN_VERSION)) of = self.temporary_file(u".epub") @@ -276,7 +277,7 @@ class DeDRM(FileTypePlugin): try: result = ignobleepub.decryptBook(userkey, inf.name, of.name) except: - print u"{0} v{1}: Exception when trying to decrypt after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Exception when trying to decrypt after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) traceback.print_exc() result = 1 @@ -285,59 +286,59 @@ class DeDRM(FileTypePlugin): if result == 0: # Decryption was a success # Store the new successful key in the defaults - print u"{0} v{1}: Saving a new default key".format(PLUGIN_NAME, PLUGIN_VERSION) + print(u"{0} v{1}: Saving a new default key".format(PLUGIN_NAME, PLUGIN_VERSION)) try: dedrmprefs.addnamedvaluetoprefs('bandnkeys','nook_Study_key',keyvalue) dedrmprefs.writeprefs() - print u"{0} v{1}: Saved a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Saved a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) except: - print u"{0} v{1}: Exception saving a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Exception saving a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) traceback.print_exc() # Return the modified PersistentTemporary file to calibre. return of.name - print u"{0} v{1}: Failed to decrypt with new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Failed to decrypt with new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) except Exception, e: pass - print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) # import the Adobe Adept ePub handler import calibre_plugins.dedrm.ineptepub as ineptepub if ineptepub.adeptBook(inf.name): - print u"{0} v{1}: {2} is a secure Adobe Adept ePub".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + print(u"{0} v{1}: {2} is a secure Adobe Adept ePub".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))) # Attempt to decrypt epub with each encryption key (generated or provided). for keyname, userkeyhex in dedrmprefs['adeptkeys'].items(): userkey = userkeyhex.decode('hex') - print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname) + print(u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname)) of = self.temporary_file(u".epub") # Give the user key, ebook and TemporaryPersistent file to the decryption function. try: result = ineptepub.decryptBook(userkey, inf.name, of.name) except: - print u"{0} v{1}: Exception when decrypting after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Exception when decrypting after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) traceback.print_exc() result = 1 try: of.close() except: - print u"{0} v{1}: Exception closing temporary file after {2:.1f} seconds. Ignored.".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Exception closing temporary file after {2:.1f} seconds. Ignored.".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) if result == 0: # Decryption was successful. # Return the modified PersistentTemporary file to calibre. - print u"{0} v{1}: Decrypted with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime) + print(u"{0} v{1}: Decrypted with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime)) return of.name - print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime) + print(u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime)) # perhaps we need to get a new default ADE key - print u"{0} v{1}: Looking for new default Adobe Digital Editions Keys after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Looking for new default Adobe Digital Editions Keys after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) # get the default Adobe keys defaultkeys = [] @@ -355,7 +356,7 @@ class DeDRM(FileTypePlugin): self.default_key = defaultkeys[0] except: - print u"{0} v{1}: Exception when getting default Adobe Key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Exception when getting default Adobe Key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) traceback.print_exc() self.default_key = u"" @@ -367,14 +368,14 @@ class DeDRM(FileTypePlugin): if len(newkeys) > 0: try: for i,userkey in enumerate(newkeys): - print u"{0} v{1}: Trying a new default key".format(PLUGIN_NAME, PLUGIN_VERSION) + print(u"{0} v{1}: Trying a new default key".format(PLUGIN_NAME, PLUGIN_VERSION)) of = self.temporary_file(u".epub") # Give the user key, ebook and TemporaryPersistent file to the decryption function. try: result = ineptepub.decryptBook(userkey, inf.name, of.name) except: - print u"{0} v{1}: Exception when decrypting after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Exception when decrypting after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) traceback.print_exc() result = 1 @@ -383,31 +384,31 @@ class DeDRM(FileTypePlugin): if result == 0: # Decryption was a success # Store the new successful key in the defaults - print u"{0} v{1}: Saving a new default key".format(PLUGIN_NAME, PLUGIN_VERSION) + print(u"{0} v{1}: Saving a new default key".format(PLUGIN_NAME, PLUGIN_VERSION)) try: dedrmprefs.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex')) dedrmprefs.writeprefs() - print u"{0} v{1}: Saved a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Saved a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) except: - print u"{0} v{1}: Exception when saving a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Exception when saving a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) traceback.print_exc() - print u"{0} v{1}: Decrypted with new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Decrypted with new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) # Return the modified PersistentTemporary file to calibre. return of.name - print u"{0} v{1}: Failed to decrypt with new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Failed to decrypt with new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) except Exception, e: - print u"{0} v{1}: Unexpected Exception trying a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Unexpected Exception trying a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) traceback.print_exc() pass # Something went wrong with decryption. - print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) # Not a Barnes & Noble nor an Adobe Adept # Import the fixed epub. - print u"{0} v{1}: “{2}” is neither an Adobe Adept nor a Barnes & Noble encrypted ePub".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + print(u"{0} v{1}: “{2}” is neither an Adobe Adept nor a Barnes & Noble encrypted ePub".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))) raise DeDRMError(u"{0} v{1}: Couldn't decrypt after {2:.1f} seconds. DRM free perhaps?".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) def PDFDecrypt(self,path_to_ebook): @@ -416,17 +417,17 @@ class DeDRM(FileTypePlugin): dedrmprefs = prefs.DeDRM_Prefs() # Attempt to decrypt epub with each encryption key (generated or provided). - print u"{0} v{1}: {2} is a PDF ebook".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + print(u"{0} v{1}: {2} is a PDF ebook".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))) for keyname, userkeyhex in dedrmprefs['adeptkeys'].items(): userkey = userkeyhex.decode('hex') - print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname) + print(u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname)) of = self.temporary_file(u".pdf") # Give the user key, ebook and TemporaryPersistent file to the decryption function. try: result = ineptpdf.decryptBook(userkey, path_to_ebook, of.name) except: - print u"{0} v{1}: Exception when decrypting after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Exception when decrypting after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) traceback.print_exc() result = 1 @@ -437,10 +438,10 @@ class DeDRM(FileTypePlugin): # Return the modified PersistentTemporary file to calibre. return of.name - print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime) + print(u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime)) # perhaps we need to get a new default ADE key - print u"{0} v{1}: Looking for new default Adobe Digital Editions Keys after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Looking for new default Adobe Digital Editions Keys after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) # get the default Adobe keys defaultkeys = [] @@ -458,7 +459,7 @@ class DeDRM(FileTypePlugin): self.default_key = defaultkeys[0] except: - print u"{0} v{1}: Exception when getting default Adobe Key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Exception when getting default Adobe Key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) traceback.print_exc() self.default_key = u"" @@ -470,14 +471,14 @@ class DeDRM(FileTypePlugin): if len(newkeys) > 0: try: for i,userkey in enumerate(newkeys): - print u"{0} v{1}: Trying a new default key".format(PLUGIN_NAME, PLUGIN_VERSION) + print(u"{0} v{1}: Trying a new default key".format(PLUGIN_NAME, PLUGIN_VERSION)) of = self.temporary_file(u".pdf") # Give the user key, ebook and TemporaryPersistent file to the decryption function. try: result = ineptpdf.decryptBook(userkey, path_to_ebook, of.name) except: - print u"{0} v{1}: Exception when decrypting after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Exception when decrypting after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) traceback.print_exc() result = 1 @@ -486,23 +487,23 @@ class DeDRM(FileTypePlugin): if result == 0: # Decryption was a success # Store the new successful key in the defaults - print u"{0} v{1}: Saving a new default key".format(PLUGIN_NAME, PLUGIN_VERSION) + print(u"{0} v{1}: Saving a new default key".format(PLUGIN_NAME, PLUGIN_VERSION)) try: dedrmprefs.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex')) dedrmprefs.writeprefs() - print u"{0} v{1}: Saved a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Saved a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) except: - print u"{0} v{1}: Exception when saving a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Exception when saving a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) traceback.print_exc() # Return the modified PersistentTemporary file to calibre. return of.name - print u"{0} v{1}: Failed to decrypt with new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Failed to decrypt with new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) except Exception, e: pass # Something went wrong with decryption. - print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) @@ -533,8 +534,8 @@ class DeDRM(FileTypePlugin): decoded = False # perhaps we need to get a new default Kindle for Mac/PC key defaultkeys = [] - print u"{0} v{1}: Failed to decrypt with error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION,e.args[0]) - print u"{0} v{1}: Looking for new default Kindle Key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Failed to decrypt with error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION,e.args[0])) + print(u"{0} v{1}: Looking for new default Kindle Key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) try: if iswindows or isosx: @@ -547,7 +548,7 @@ class DeDRM(FileTypePlugin): scriptpath = os.path.join(self.alfdir,u"kindlekey.py") defaultkeys = WineGetKeys(scriptpath, u".k4i",dedrmprefs['kindlewineprefix']) except: - print u"{0} v{1}: Exception when getting default Kindle Key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + print(u"{0} v{1}: Exception when getting default Kindle Key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) traceback.print_exc() pass @@ -557,12 +558,12 @@ class DeDRM(FileTypePlugin): if keyvalue not in dedrmprefs['kindlekeys'].values(): newkeys[keyname] = keyvalue if len(newkeys) > 0: - print u"{0} v{1}: Found {2} new {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(newkeys), u"key" if len(newkeys)==1 else u"keys") + print(u"{0} v{1}: Found {2} new {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(newkeys), u"key" if len(newkeys)==1 else u"keys")) try: book = k4mobidedrm.GetDecryptedBook(path_to_ebook,newkeys.items(),[],[],[],self.starttime) decoded = True # store the new successful keys in the defaults - print u"{0} v{1}: Saving {2} new {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(newkeys), u"key" if len(newkeys)==1 else u"keys") + print(u"{0} v{1}: Saving {2} new {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(newkeys), u"key" if len(newkeys)==1 else u"keys")) for keyvalue in newkeys.values(): dedrmprefs.addnamedvaluetoprefs('kindlekeys','default_key',keyvalue) dedrmprefs.writeprefs() @@ -570,7 +571,7 @@ class DeDRM(FileTypePlugin): pass if not decoded: #if you reached here then no luck raise and exception - print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) of = self.temporary_file(book.getBookExtension()) @@ -589,7 +590,7 @@ class DeDRM(FileTypePlugin): # Attempt to decrypt epub with each encryption key (generated or provided). for keyname, userkey in dedrmprefs['ereaderkeys'].items(): keyname_masked = u"".join((u'X' if (x.isdigit()) else x) for x in keyname) - print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked) + print(u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked)) of = self.temporary_file(u".pmlz") # Give the userkey, ebook and TemporaryPersistent file to the decryption function. @@ -600,12 +601,12 @@ class DeDRM(FileTypePlugin): # Decryption was successful return the modified PersistentTemporary # file to Calibre's import process. if result == 0: - print u"{0} v{1}: Successfully decrypted with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname_masked,time.time()-self.starttime) + print(u"{0} v{1}: Successfully decrypted with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname_masked,time.time()-self.starttime)) return of.name - print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname_masked,time.time()-self.starttime) + print(u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname_masked,time.time()-self.starttime)) - print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) @@ -615,7 +616,7 @@ class DeDRM(FileTypePlugin): sys.stdout=SafeUnbuffered(sys.stdout) sys.stderr=SafeUnbuffered(sys.stderr) - print u"{0} v{1}: Trying to decrypt {2}".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + print(u"{0} v{1}: Trying to decrypt {2}".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))) self.starttime = time.time() booktype = os.path.splitext(path_to_ebook)[1].lower()[1:] @@ -634,9 +635,9 @@ class DeDRM(FileTypePlugin): # Adobe Adept or B&N ePub decrypted_ebook = self.ePubDecrypt(path_to_ebook) else: - print u"Unknown booktype {0}. Passing back to calibre unchanged".format(booktype) + print(u"Unknown booktype {0}. Passing back to calibre unchanged".format(booktype)) return path_to_ebook - print u"{0} v{1}: Finished after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print(u"{0} v{1}: Finished after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) return decrypted_ebook def is_customizable(self): diff --git a/dedrm_src/adobekey.py b/dedrm_src/adobekey.py index 7fbd516..2ede7c2 100644 --- a/dedrm_src/adobekey.py +++ b/dedrm_src/adobekey.py @@ -52,6 +52,7 @@ from __future__ import with_statement """ Retrieve Adobe ADEPT user key. """ +from __future__ import print_function __license__ = 'GPL v3' __version__ = '6.0' @@ -407,7 +408,7 @@ if iswindows: keys.append(userkey) if len(keys) == 0: raise ADEPTError('Could not locate privateLicenseKey') - print u"Found {0:d} keys".format(len(keys)) + print(u"Found {0:d} keys".format(len(keys))) return keys @@ -465,7 +466,7 @@ def getkey(outpath): outfile = outpath with file(outfile, 'wb') as keyfileout: keyfileout.write(keys[0]) - print u"Saved a key to {0}".format(outfile) + print(u"Saved a key to {0}".format(outfile)) else: keycount = 0 for key in keys: @@ -476,28 +477,28 @@ def getkey(outpath): break with file(outfile, 'wb') as keyfileout: keyfileout.write(key) - print u"Saved a key to {0}".format(outfile) + print(u"Saved a key to {0}".format(outfile)) return True return False def usage(progname): - print u"Finds, decrypts and saves the default Adobe Adept encryption key(s)." - print u"Keys are saved to the current directory, or a specified output directory." - print u"If a file name is passed instead of a directory, only the first key is saved, in that file." - print u"Usage:" - print u" {0:s} [-h] []".format(progname) + print(u"Finds, decrypts and saves the default Adobe Adept encryption key(s).") + print(u"Keys are saved to the current directory, or a specified output directory.") + print(u"If a file name is passed instead of a directory, only the first key is saved, in that file.") + print(u"Usage:") + print(u" {0:s} [-h] []".format(progname)) def cli_main(): sys.stdout=SafeUnbuffered(sys.stdout) sys.stderr=SafeUnbuffered(sys.stderr) argv=unicode_argv() progname = os.path.basename(argv[0]) - print u"{0} v{1}\nCopyright © 2009-2013 i♥cabbages and Apprentice Alf".format(progname,__version__) + print(u"{0} v{1}\nCopyright © 2009-2013 i♥cabbages and Apprentice Alf".format(progname,__version__)) try: opts, args = getopt.getopt(argv[1:], "h") except getopt.GetoptError, err: - print u"Error in options or arguments: {0}".format(err.args[0]) + print(u"Error in options or arguments: {0}".format(err.args[0])) usage(progname) sys.exit(2) @@ -528,7 +529,7 @@ def cli_main(): outfile = outpath with file(outfile, 'wb') as keyfileout: keyfileout.write(keys[0]) - print u"Saved a key to {0}".format(outfile) + print(u"Saved a key to {0}".format(outfile)) else: keycount = 0 for key in keys: @@ -539,9 +540,9 @@ def cli_main(): break with file(outfile, 'wb') as keyfileout: keyfileout.write(key) - print u"Saved a key to {0}".format(outfile) + print(u"Saved a key to {0}".format(outfile)) else: - print u"Could not retrieve Adobe Adept key." + print(u"Could not retrieve Adobe Adept key.") return 0 diff --git a/dedrm_src/alfcrypto.py b/dedrm_src/alfcrypto.py index 036ba10..5d5e508 100644 --- a/dedrm_src/alfcrypto.py +++ b/dedrm_src/alfcrypto.py @@ -8,6 +8,7 @@ # pbkdf2.py Copyright © 2009 Daniel Holth # pbkdf2.py This code may be freely used and modified for any purpose. +from __future__ import print_function import sys, os import hmac from struct import pack @@ -158,7 +159,7 @@ def _load_libalfcrypto(): topazCryptoDecrypt(ctx, data, out, len(data)) return out.raw - print u"Using Library AlfCrypto DLL/DYLIB/SO" + print(u"Using Library AlfCrypto DLL/DYLIB/SO") return (AES_CBC, Pukall_Cipher, Topaz_Cipher) @@ -244,7 +245,7 @@ def _load_python_alfcrypto(): cleartext = self.aes.decrypt(iv + data) return cleartext - print u"Using Library AlfCrypto Python" + print(u"Using Library AlfCrypto Python") return (AES_CBC, Pukall_Cipher, Topaz_Cipher) diff --git a/dedrm_src/androidkindlekey.py b/dedrm_src/androidkindlekey.py index ff8d1ee..a264c7d 100644 --- a/dedrm_src/androidkindlekey.py +++ b/dedrm_src/androidkindlekey.py @@ -21,6 +21,7 @@ from __future__ import with_statement """ Retrieve Kindle for Android Serial Number. """ +from __future__ import print_function __license__ = 'GPL v3' __version__ = '1.5' @@ -228,7 +229,7 @@ def get_serials2(path=STORAGE2): if len(userdata_utf8) > 0: dsns.append(userdata_utf8) except: - print "Error getting one of the device serial name keys" + print("Error getting one of the device serial name keys") traceback.print_exc() pass dsns = list(set(dsns)) @@ -243,7 +244,7 @@ def get_serials2(path=STORAGE2): if len(userdata_utf8) > 0: tokens.append(userdata_utf8) except: - print "Error getting one of the account token keys" + print("Error getting one of the account token keys") traceback.print_exc() pass tokens = list(set(tokens)) @@ -321,13 +322,13 @@ def getkey(outfile, inpath): def usage(progname): - print u"Decrypts the serial number(s) of Kindle For Android from Android backup or file" - print u"Get backup.ab file using adb backup com.amazon.kindle for Android 4.0+." - print u"Otherwise extract AmazonSecureStorage.xml from /data/data/com.amazon.kindle/shared_prefs/AmazonSecureStorage.xml" - print u"Or map_data_storage.db from /data/data/com.amazon.kindle/databases/map_data_storage.db" - print u"" - print u"Usage:" - print u" {0:s} [-h] [-b ] []".format(progname) + print(u"Decrypts the serial number(s) of Kindle For Android from Android backup or file") + print(u"Get backup.ab file using adb backup com.amazon.kindle for Android 4.0+.") + print(u"Otherwise extract AmazonSecureStorage.xml from /data/data/com.amazon.kindle/shared_prefs/AmazonSecureStorage.xml") + print(u"Or map_data_storage.db from /data/data/com.amazon.kindle/databases/map_data_storage.db") + print(u"") + print(u"Usage:") + print(u" {0:s} [-h] [-b ] []".format(progname)) def cli_main(): @@ -335,13 +336,13 @@ def cli_main(): sys.stderr=SafeUnbuffered(sys.stderr) argv=unicode_argv() progname = os.path.basename(argv[0]) - print u"{0} v{1}\nCopyright © 2010-2015 Thom, some_updates, Apprentice Alf and Apprentice Harper".format(progname,__version__) + print(u"{0} v{1}\nCopyright © 2010-2015 Thom, some_updates, Apprentice Alf and Apprentice Harper".format(progname,__version__)) try: opts, args = getopt.getopt(argv[1:], "hb:") except getopt.GetoptError, err: usage(progname) - print u"\nError in options or arguments: {0}".format(err.args[0]) + print(u"\nError in options or arguments: {0}".format(err.args[0])) return 2 inpath = "" @@ -373,13 +374,13 @@ def cli_main(): if not os.path.isfile(inpath): usage(progname) - print u"\n{0:s} file not found".format(inpath) + print(u"\n{0:s} file not found".format(inpath)) return 2 if getkey(outfile, inpath): - print u"\nSaved Kindle for Android key to {0}".format(outfile) + print(u"\nSaved Kindle for Android key to {0}".format(outfile)) else: - print u"\nCould not retrieve Kindle for Android key." + print(u"\nCould not retrieve Kindle for Android key.") return 0 @@ -390,7 +391,7 @@ def gui_main(): import tkMessageBox import tkFileDialog except: - print "Tkinter not installed" + print("Tkinter not installed") return cli_main() class DecryptionDialog(Tkinter.Frame): diff --git a/dedrm_src/config.py b/dedrm_src/config.py index 3a56e44..49afbda 100644 --- a/dedrm_src/config.py +++ b/dedrm_src/config.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- from __future__ import with_statement +from __future__ import print_function __license__ = 'GPL v3' @@ -457,7 +458,7 @@ class ManageKeysDialog(QDialog): class RenameKeyDialog(QDialog): def __init__(self, parent=None,): - print repr(self), repr(parent) + print(repr(self), repr(parent)) QDialog.__init__(self, parent) self.parent = parent self.setWindowTitle("{0} {1}: Rename {0}".format(PLUGIN_NAME, PLUGIN_VERSION, parent.key_type_name)) diff --git a/dedrm_src/convert2xml.py b/dedrm_src/convert2xml.py index 8c2d0f3..3b65c54 100644 --- a/dedrm_src/convert2xml.py +++ b/dedrm_src/convert2xml.py @@ -2,6 +2,7 @@ # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab # For use with Topaz Scripts Version 2.6 +from __future__ import print_function class Unbuffered: def __init__(self, stream): self.stream = stream @@ -139,7 +140,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 of string table limits') # sys.exit(-1) @@ -151,7 +152,7 @@ class Dictionary(object): def dumpDict(self): for i in xrange(self.size): - print "%d %s %s" % (i, convert(i), self.stable[i]) + print("%d %s %s" % (i, convert(i), self.stable[i])) return # parses the xml snippets that are represented by each page*.dat file. @@ -457,7 +458,7 @@ class PageParser(object): elif (argtype == 'snippets') : result = arg else : - print "Error Unknown argtype %s" % argtype + print("Error Unknown argtype %s" % argtype) sys.exit(-2) return result @@ -469,7 +470,7 @@ class PageParser(object): known_token = False self.tag_push(token) - if self.debug : print 'Processing: ', self.get_tagpath(0) + if self.debug : print('Processing: ', self.get_tagpath(0)) cnt = self.tagpath_len() for j in xrange(cnt): tkn = self.get_tagpath(j) @@ -495,7 +496,7 @@ class PageParser(object): if (subtags == 1): ntags = readEncodedNumber(self.fo) - if self.debug : print 'subtags: ' + token + ' has ' + str(ntags) + if self.debug : print('subtags: ' + token + ' has ' + str(ntags)) for j in xrange(ntags): val = readEncodedNumber(self.fo) subtagres.append(self.procToken(self.dict.lookup(val))) @@ -529,7 +530,7 @@ class PageParser(object): else: result = [] if (self.debug or self.first_unknown): - print 'Unknown Token:', token + print('Unknown Token:', token) self.first_unknown = False self.tag_pop() return result @@ -544,9 +545,9 @@ class PageParser(object): result = 'Set of '+ str(cnt) + ' xml snippets. The overall structure \n' result += 'of the document is indicated by snippet number sets at the\n' result += 'end of each snippet. \n' - print result + print(result) for i in xrange(cnt): - if self.debug: print 'Snippet:',str(i) + if self.debug: print('Snippet:',str(i)) snippet = [] snippet.append(i) val = readEncodedNumber(self.fo) @@ -588,10 +589,10 @@ class PageParser(object): cnt = readEncodedNumber(self.fo) mode = readEncodedNumber(self.fo) - if self.debug : print 'Loop for', cnt, 'with mode', mode, ': ' + if self.debug : print('Loop for', cnt, 'with mode', mode, ': ') return self.doLoop76Mode(argtype, cnt, mode) - if self.dbug: print "Unknown command", cmd + if self.dbug: print("Unknown command", cmd) result = [] return result @@ -720,7 +721,7 @@ class PageParser(object): else: rlst.append(self.formatTag(j)) result = "".join(rlst) - if self.debug : print result + if self.debug : print(result) return result @@ -775,7 +776,7 @@ class PageParser(object): self.doc.append(tag) else: if self.debug: - print "Main Loop: Unknown value: %x" % v + print("Main Loop: Unknown value: %x" % v) if (v == 0): if (self.peek(1) == 0x5f): skip = self.fo.read(1) @@ -783,11 +784,11 @@ class PageParser(object): # now do snippet injection if len(self.snippetList) > 0 : - if self.debug : print 'Injecting Snippets:' + if self.debug : print('Injecting Snippets:') snippet = self.injectSnippets(self.snippetList[0]) snipno = snippet[0] tag_add = snippet[1] - if self.debug : print self.formatTag(tag_add) + if self.debug : print(self.formatTag(tag_add)) if len(tag_add) > 0: self.doc.append(tag_add) @@ -812,19 +813,19 @@ def getXML(dict, fname): return xmlpage def usage(): - print 'Usage: ' - print ' convert2xml.py dict0000.dat infile.dat ' - print ' ' - print ' Options:' - print ' -h print this usage help message ' - print ' -d turn on debug output to check for potential errors ' - print ' --flat-xml output the flattened xml page description only ' - print ' ' - print ' This program will attempt to convert a page*.dat file or ' - print ' glyphs*.dat file, using the dict0000.dat file, to its xml description. ' - print ' ' - print ' Use "cmbtc_dump.py" first to unencrypt, uncompress, and dump ' - print ' the *.dat files from a Topaz format e-book.' + print('Usage: ') + print(' convert2xml.py dict0000.dat infile.dat ') + print(' ') + print(' Options:') + print(' -h print this usage help message ') + print(' -d turn on debug output to check for potential errors ') + print(' --flat-xml output the flattened xml page description only ') + print(' ') + print(' This program will attempt to convert a page*.dat file or ') + print(' glyphs*.dat file, using the dict0000.dat file, to its xml description. ') + print(' ') + print(' Use "cmbtc_dump.py" first to unencrypt, uncompress, and dump ') + print(' the *.dat files from a Topaz format e-book.') # # Main @@ -846,7 +847,7 @@ def main(argv): except getopt.GetoptError, err: # print help information and exit: - print str(err) # will print something like "option -a not recognized" + print(str(err)) # will print something like "option -a not recognized" usage() sys.exit(2) @@ -875,7 +876,7 @@ def main(argv): xmlpage = pp.process() if printOutput: - print xmlpage + print(xmlpage) return 0 return xmlpage diff --git a/dedrm_src/encodebase64.py b/dedrm_src/encodebase64.py index 6bb8c37..cfe0d26 100644 --- a/dedrm_src/encodebase64.py +++ b/dedrm_src/encodebase64.py @@ -15,6 +15,7 @@ Provide base64 encoding. """ from __future__ import with_statement +from __future__ import print_function __license__ = 'GPL v3' @@ -23,9 +24,9 @@ import os import base64 def usage(progname): - print "Applies base64 encoding to the supplied file, sending to standard output" - print "Usage:" - print " %s " % progname + print("Applies base64 encoding to the supplied file, sending to standard output") + print("Usage:") + print(" %s " % progname) def cli_main(argv=sys.argv): progname = os.path.basename(argv[0]) @@ -37,7 +38,7 @@ def cli_main(argv=sys.argv): keypath = argv[1] with open(keypath, 'rb') as f: keyder = f.read() - print keyder.encode('base64') + print(keyder.encode('base64')) return 0 diff --git a/dedrm_src/epubtest.py b/dedrm_src/epubtest.py index 11f1427..01c3602 100644 --- a/dedrm_src/epubtest.py +++ b/dedrm_src/epubtest.py @@ -45,6 +45,7 @@ # from __future__ import with_statement +from __future__ import print_function __version__ = '1.01' @@ -199,7 +200,7 @@ def encryption(infile): def main(): argv=unicode_argv() - print encryption(argv[1]) + print(encryption(argv[1])) return 0 if __name__ == "__main__": diff --git a/dedrm_src/flatxml2html.py b/dedrm_src/flatxml2html.py index 991591b..78cff11 100644 --- a/dedrm_src/flatxml2html.py +++ b/dedrm_src/flatxml2html.py @@ -2,6 +2,7 @@ # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab # For use with Topaz Scripts Version 2.6 +from __future__ import print_function import sys import csv import os @@ -750,11 +751,11 @@ class DocParser(object): hlst.append('
' % int(simgsrc)) else : - print ' Making region type', regtype, + print(' Making region type', regtype, end=' ') (pos, temp) = self.findinDoc('paragraph',start,end) (pos2, temp) = self.findinDoc('span',start,end) if pos != -1 or pos2 != -1: - print ' a "text" region' + print(' a "text" region') orig_regtype = regtype regtype = 'fixed' ptype = 'full' @@ -779,7 +780,7 @@ class DocParser(object): else : hlst.append(self.buildParagraph(pclass, pdesc, ptype, regtype)) else : - print ' a "graphic" region' + print(' a "graphic" region') (pos, simgsrc) = self.findinDoc('img.src',start,end) if simgsrc: hlst.append('
' % int(simgsrc)) diff --git a/dedrm_src/genbook.py b/dedrm_src/genbook.py index 4036896..9795510 100644 --- a/dedrm_src/genbook.py +++ b/dedrm_src/genbook.py @@ -1,6 +1,7 @@ #! /usr/bin/python # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab +from __future__ import print_function class Unbuffered: def __init__(self, stream): self.stream = stream @@ -117,7 +118,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): @@ -268,32 +269,32 @@ class GlyphDict(object): def generateBook(bookDir, raw, fixedimage): # sanity check Topaz file extraction if not os.path.exists(bookDir) : - print "Can not find directory with unencrypted book" + print("Can not find directory with unencrypted book") return 1 dictFile = os.path.join(bookDir,'dict0000.dat') if not os.path.exists(dictFile) : - print "Can not find dict0000.dat file" + print("Can not find dict0000.dat file") return 1 pageDir = os.path.join(bookDir,'page') if not os.path.exists(pageDir) : - print "Can not find page directory in unencrypted book" + print("Can not find page directory in unencrypted book") return 1 imgDir = os.path.join(bookDir,'img') if not os.path.exists(imgDir) : - print "Can not find image directory in unencrypted book" + print("Can not find image directory in unencrypted book") return 1 glyphsDir = os.path.join(bookDir,'glyphs') if not os.path.exists(glyphsDir) : - print "Can not find glyphs directory in unencrypted book" + print("Can not find glyphs directory in unencrypted book") return 1 metaFile = os.path.join(bookDir,'metadata0000.dat') if not os.path.exists(metaFile) : - print "Can not find metadata0000.dat in unencrypted book" + print("Can not find metadata0000.dat in unencrypted book") return 1 svgDir = os.path.join(bookDir,'svg') @@ -307,10 +308,10 @@ def generateBook(bookDir, raw, fixedimage): otherFile = os.path.join(bookDir,'other0000.dat') if not os.path.exists(otherFile) : - print "Can not find other0000.dat in unencrypted book" + print("Can not find other0000.dat in unencrypted book") return 1 - print "Updating to color images if available" + print("Updating to color images if available") spath = os.path.join(bookDir,'color_img') dpath = os.path.join(bookDir,'img') filenames = os.listdir(spath) @@ -322,7 +323,7 @@ def generateBook(bookDir, raw, fixedimage): imgdata = file(sfile,'rb').read() file(dfile,'wb').write(imgdata) - print "Creating cover.jpg" + print("Creating cover.jpg") isCover = False cpath = os.path.join(bookDir,'img') cpath = os.path.join(cpath,'img0000.jpg') @@ -333,10 +334,10 @@ def generateBook(bookDir, raw, fixedimage): isCover = True - print 'Processing Dictionary' + print('Processing Dictionary') dict = Dictionary(dictFile) - print 'Processing Meta Data and creating OPF' + print('Processing Meta Data and creating OPF') meta_array = getMetaArray(metaFile) # replace special chars in title and authors like & < > @@ -360,7 +361,7 @@ def generateBook(bookDir, raw, fixedimage): mlst = None file(xname, 'wb').write(metastr) - print 'Processing StyleSheet' + print('Processing StyleSheet') # get some scaling info from metadata to use while processing styles # and first page info @@ -426,7 +427,7 @@ def generateBook(bookDir, raw, fixedimage): xname = os.path.join(xmlDir, 'other0000.xml') file(xname, 'wb').write(convert2xml.getXML(dict, otherFile)) - print 'Processing Glyphs' + print('Processing Glyphs') gd = GlyphDict() filenames = os.listdir(glyphsDir) filenames = sorted(filenames) @@ -440,7 +441,7 @@ def generateBook(bookDir, raw, fixedimage): counter = 0 for filename in filenames: # print ' ', filename - print '.', + print('.', end=' ') fname = os.path.join(glyphsDir,filename) flat_xml = convert2xml.fromData(dict, fname) @@ -459,7 +460,7 @@ def generateBook(bookDir, raw, fixedimage): glyfile.write('\n') glyfile.write('\n') glyfile.close() - print " " + print(" ") # start up the html @@ -481,7 +482,7 @@ def generateBook(bookDir, raw, fixedimage): hlst.append('\n') hlst.append('\n\n') - print 'Processing Pages' + print('Processing Pages') # Books are at 1440 DPI. This is rendering at twice that size for # readability when rendering to the screen. scaledpi = 1440.0 @@ -495,7 +496,7 @@ def generateBook(bookDir, raw, fixedimage): for filename in filenames: # print ' ', filename - print ".", + print(".", end=' ') fname = os.path.join(pageDir,filename) flat_xml = convert2xml.fromData(dict, fname) @@ -517,8 +518,8 @@ def generateBook(bookDir, raw, fixedimage): hlst = None file(os.path.join(bookDir, htmlFileName), 'wb').write(htmlstr) - print " " - print 'Extracting Table of Contents from Amazon OCR' + print(" ") + print('Extracting Table of Contents from Amazon OCR') # first create a table of contents file for the svg images tlst = [] @@ -550,7 +551,7 @@ def generateBook(bookDir, raw, fixedimage): toclst = tocentries.split('\n') toclst.pop() for entry in toclst: - print entry + print(entry) title, pagenum = entry.split('|') id = pageidnums[int(pagenum)] if (raw): @@ -580,7 +581,7 @@ def generateBook(bookDir, raw, fixedimage): slst.append('\n') slst.append('\n') - print "Building svg images of each book page" + print("Building svg images of each book page") slst.append('

List of Pages

\n') slst.append('
\n') idlst = sorted(pageIDMap.keys()) @@ -593,7 +594,7 @@ def generateBook(bookDir, raw, fixedimage): nextid = idlst[j+1] else: nextid = None - print '.', + print('.', end=' ') pagelst = pageIDMap[pageid] flst = [] for page in pagelst: @@ -618,7 +619,7 @@ def generateBook(bookDir, raw, fixedimage): slst = None file(os.path.join(bookDir, 'index_svg.xhtml'), 'wb').write(svgindex) - print " " + print(" ") # build the opf file opfname = os.path.join(bookDir, 'book.opf') @@ -667,20 +668,20 @@ def generateBook(bookDir, raw, fixedimage): olst = None file(opfname, 'wb').write(opfstr) - print 'Processing Complete' + print('Processing Complete') return 0 def usage(): - print "genbook.py generates a book from the extract Topaz Files" - print "Usage:" - print " genbook.py [-r] [-h [--fixed-image] " - print " " - print "Options:" - print " -h : help - print this usage message" - print " -r : generate raw svg files (not wrapped in xhtml)" - print " --fixed-image : genearate any Fixed Area as an svg image in the html" - print " " + print("genbook.py generates a book from the extract Topaz Files") + print("Usage:") + print(" genbook.py [-r] [-h [--fixed-image] ") + print(" ") + print("Options:") + print(" -h : help - print this usage message") + print(" -r : generate raw svg files (not wrapped in xhtml)") + print(" --fixed-image : genearate any Fixed Area as an svg image in the html") + print(" ") def main(argv): @@ -692,7 +693,7 @@ def main(argv): opts, args = getopt.getopt(argv[1:], "rh:",["fixed-image"]) except getopt.GetoptError, err: - print str(err) + print(str(err)) usage() return 1 diff --git a/dedrm_src/ignobleepub.py b/dedrm_src/ignobleepub.py index 1dda116..c16d88b 100644 --- a/dedrm_src/ignobleepub.py +++ b/dedrm_src/ignobleepub.py @@ -41,6 +41,7 @@ from __future__ import with_statement """ Decrypt Barnes & Noble encrypted ePub books. """ +from __future__ import print_function __license__ = 'GPL v3' __version__ = "4.1" @@ -262,7 +263,7 @@ def decryptBook(keyb64, inpath, outpath): namelist = set(inf.namelist()) if 'META-INF/rights.xml' not in namelist or \ 'META-INF/encryption.xml' not in namelist: - print u"{0:s} is DRM-free.".format(os.path.basename(inpath)) + print(u"{0:s} is DRM-free.".format(os.path.basename(inpath))) return 1 for name in META_NAMES: namelist.remove(name) @@ -272,7 +273,7 @@ def decryptBook(keyb64, inpath, outpath): expr = './/%s' % (adept('encryptedKey'),) bookkey = ''.join(rights.findtext(expr)) if len(bookkey) != 64: - print u"{0:s} is not a secure Barnes & Noble ePub.".format(os.path.basename(inpath)) + 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])] @@ -315,7 +316,7 @@ def decryptBook(keyb64, inpath, outpath): pass outf.writestr(zi, decryptor.decrypt(path, data)) except: - print u"Could not decrypt {0:s} because of an exception:\n{1:s}".format(os.path.basename(inpath), traceback.format_exc()) + 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 @@ -326,13 +327,13 @@ def cli_main(): argv=unicode_argv() progname = os.path.basename(argv[0]) if len(argv) != 4: - print u"usage: {0} ".format(progname) + print(u"usage: {0} ".format(progname)) return 1 keypath, inpath, outpath = argv[1:] userkey = open(keypath,'rb').read() result = decryptBook(userkey, inpath, outpath) if result == 0: - print u"Successfully decrypted {0:s} as {1:s}".format(os.path.basename(inpath),os.path.basename(outpath)) + print(u"Successfully decrypted {0:s} as {1:s}".format(os.path.basename(inpath),os.path.basename(outpath))) return result def gui_main(): diff --git a/dedrm_src/ignoblekey.py b/dedrm_src/ignoblekey.py index dbadc5d..fb7c6a8 100644 --- a/dedrm_src/ignoblekey.py +++ b/dedrm_src/ignoblekey.py @@ -18,6 +18,7 @@ from __future__ import with_statement """ Get Barnes & Noble EPUB user key from nook Studio log file """ +from __future__ import print_function __license__ = 'GPL v3' __version__ = "1.1" @@ -198,7 +199,7 @@ def nookkeys(files = []): for file in files: fileKeys = getKeysFromLog(file) if fileKeys: - print u"Found {0} keys in the Nook Study log files".format(len(fileKeys)) + print(u"Found {0} keys in the Nook Study log files".format(len(fileKeys))) keys.extend(fileKeys) return list(set(keys)) @@ -211,7 +212,7 @@ def getkey(outpath, files=[]): outfile = outpath with file(outfile, 'w') as keyfileout: keyfileout.write(keys[-1]) - print u"Saved a key to {0}".format(outfile) + print(u"Saved a key to {0}".format(outfile)) else: keycount = 0 for key in keys: @@ -222,16 +223,16 @@ def getkey(outpath, files=[]): break with file(outfile, 'w') as keyfileout: keyfileout.write(key) - print u"Saved a key to {0}".format(outfile) + print(u"Saved a key to {0}".format(outfile)) return True return False def usage(progname): - print u"Finds the nook Study encryption keys." - print u"Keys are saved to the current directory, or a specified output directory." - print u"If a file name is passed instead of a directory, only the first key is saved, in that file." - print u"Usage:" - print u" {0:s} [-h] [-k ] []".format(progname) + print(u"Finds the nook Study encryption keys.") + print(u"Keys are saved to the current directory, or a specified output directory.") + print(u"If a file name is passed instead of a directory, only the first key is saved, in that file.") + print(u"Usage:") + print(u" {0:s} [-h] [-k ] []".format(progname)) def cli_main(): @@ -239,12 +240,12 @@ def cli_main(): sys.stderr=SafeUnbuffered(sys.stderr) argv=unicode_argv() progname = os.path.basename(argv[0]) - print u"{0} v{1}\nCopyright © 2015 Apprentice Alf".format(progname,__version__) + print(u"{0} v{1}\nCopyright © 2015 Apprentice Alf".format(progname,__version__)) try: opts, args = getopt.getopt(argv[1:], "hk:") except getopt.GetoptError, err: - print u"Error in options or arguments: {0}".format(err.args[0]) + print(u"Error in options or arguments: {0}".format(err.args[0])) usage(progname) sys.exit(2) @@ -273,7 +274,7 @@ def cli_main(): outpath = os.path.realpath(os.path.normpath(outpath)) if not getkey(outpath, files): - print u"Could not retrieve nook Study key." + print(u"Could not retrieve nook Study key.") return 0 @@ -307,7 +308,7 @@ def gui_main(): keys = nookkeys() keycount = 0 for key in keys: - print key + print(key) while True: keycount += 1 outfile = os.path.join(progpath,u"nookkey{0:d}.b64".format(keycount)) diff --git a/dedrm_src/ignoblekeyfetch.py b/dedrm_src/ignoblekeyfetch.py index e9637a1..dd714fc 100644 --- a/dedrm_src/ignoblekeyfetch.py +++ b/dedrm_src/ignoblekeyfetch.py @@ -28,6 +28,7 @@ from __future__ import with_statement """ Fetch Barnes & Noble EPUB user key from B&N servers using email and password """ +from __future__ import print_function __license__ = 'GPL v3' __version__ = "1.1" @@ -155,14 +156,14 @@ def cli_main(): argv=unicode_argv() progname = os.path.basename(argv[0]) if len(argv) != 4: - print u"usage: {0} ".format(progname) + print(u"usage: {0} ".format(progname)) return 1 email, password, keypath = argv[1:] userkey = fetch_key(email, password) if len(userkey) == 28: open(keypath,'wb').write(userkey) return 0 - print u"Failed to fetch key." + print(u"Failed to fetch key.") return 1 diff --git a/dedrm_src/ignoblekeygen.py b/dedrm_src/ignoblekeygen.py index d2917c7..5ddcd80 100644 --- a/dedrm_src/ignoblekeygen.py +++ b/dedrm_src/ignoblekeygen.py @@ -38,6 +38,7 @@ from __future__ import with_statement """ Generate Barnes & Noble EPUB user key from name and credit card number. """ +from __future__ import print_function __license__ = 'GPL v3' __version__ = "2.8" @@ -223,12 +224,12 @@ def cli_main(): argv=unicode_argv() progname = os.path.basename(argv[0]) if AES is None: - print "%s: This script requires OpenSSL or PyCrypto, which must be installed " \ + print("%s: This script requires OpenSSL or PyCrypto, which must be installed " \ "separately. Read the top-of-script comment for details." % \ - (progname,) + (progname,)) return 1 if len(argv) != 4: - print u"usage: {0} ".format(progname) + print(u"usage: {0} ".format(progname)) return 1 name, ccn, keypath = argv[1:] userkey = generate_key(name, ccn) diff --git a/dedrm_src/kfxdedrm.py b/dedrm_src/kfxdedrm.py index 98ae9f2..aed38d9 100644 --- a/dedrm_src/kfxdedrm.py +++ b/dedrm_src/kfxdedrm.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- from __future__ import with_statement +from __future__ import print_function # Engine to remove drm from Kindle KFX ebooks @@ -43,7 +44,7 @@ class KFXZipBook: data += fh.read() if self.voucher is None: self.decrypt_voucher(totalpids) - print u'Decrypting KFX DRMION: {0}'.format(filename) + print(u'Decrypting KFX DRMION: {0}'.format(filename)) outfile = StringIO() ion.DrmIon(StringIO(data[8:-8]), lambda name: self.voucher).parse(outfile) self.decrypted[filename] = outfile.getvalue() @@ -65,7 +66,7 @@ class KFXZipBook: else: raise Exception(u'The .kfx-zip archive contains an encrypted DRMION file without a DRM voucher') - print u'Decrypting KFX DRM voucher: {0}'.format(info.filename) + print(u'Decrypting KFX DRM voucher: {0}'.format(info.filename)) for pid in [''] + totalpids: for dsn_len,secret_len in [(0,0), (16,0), (16,40), (32,40), (40,40)]: @@ -84,7 +85,7 @@ class KFXZipBook: else: raise Exception(u'Failed to decrypt KFX DRM voucher with any key') - print u'KFX DRM voucher successfully decrypted' + print(u'KFX DRM voucher successfully decrypted') license_type = voucher.getlicensetype() if license_type != "Purchase": diff --git a/dedrm_src/kgenpids.py b/dedrm_src/kgenpids.py index 9b4373e..529d13d 100644 --- a/dedrm_src/kgenpids.py +++ b/dedrm_src/kgenpids.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- from __future__ import with_statement +from __future__ import print_function # kgenpids.py # Copyright © 2008-2017 Apprentice Harper et al. @@ -214,7 +215,7 @@ def getK4Pids(rec209, token, kindleDatabase): try: # Get the DSN token, if present DSN = (kindleDatabase[1])['DSN'].decode('hex') - print u"Got DSN key from database {0}".format(kindleDatabase[0]) + print(u"Got DSN key from database {0}".format(kindleDatabase[0])) except KeyError: # See if we have the info to generate the DSN try: @@ -225,7 +226,7 @@ def getK4Pids(rec209, token, kindleDatabase): try: # Get the SerialNumber token, if present IDString = (kindleDatabase[1])['SerialNumber'].decode('hex') - print u"Got SerialNumber from database {0}".format(kindleDatabase[0]) + print(u"Got SerialNumber from database {0}".format(kindleDatabase[0])) except KeyError: # Get the IDString we added IDString = (kindleDatabase[1])['IDString'].decode('hex') @@ -233,7 +234,7 @@ def getK4Pids(rec209, token, kindleDatabase): try: # Get the UsernameHash token, if present encodedUsername = (kindleDatabase[1])['UsernameHash'].decode('hex') - print u"Got UsernameHash from database {0}".format(kindleDatabase[0]) + print(u"Got UsernameHash from database {0}".format(kindleDatabase[0])) except KeyError: # Get the UserName we added UserName = (kindleDatabase[1])['UserName'].decode('hex') @@ -241,7 +242,7 @@ def getK4Pids(rec209, token, kindleDatabase): encodedUsername = encodeHash(UserName,charMap1) #print u"encodedUsername",encodedUsername.encode('hex') except KeyError: - print u"Keys not found in the database {0}.".format(kindleDatabase[0]) + print(u"Keys not found in the database {0}.".format(kindleDatabase[0])) return pids # Get the ID string used @@ -297,14 +298,14 @@ def getPidList(md1, md2, serials=[], kDatabases=[]): try: pidlst.extend(getK4Pids(md1, md2, kDatabase)) except Exception, e: - print u"Error getting PIDs from database {0}: {1}".format(kDatabase[0],e.args[0]) + print(u"Error getting PIDs from database {0}: {1}".format(kDatabase[0],e.args[0])) traceback.print_exc() for serialnum in serials: try: pidlst.extend(getKindlePids(md1, md2, serialnum)) except Exception, e: - print u"Error getting PIDs from serial number {0}: {1}".format(serialnum ,e.args[0]) + print(u"Error getting PIDs from serial number {0}: {1}".format(serialnum ,e.args[0])) traceback.print_exc() return pidlst diff --git a/dedrm_src/kindlepid.py b/dedrm_src/kindlepid.py index 8bbcf69..726554f 100644 --- a/dedrm_src/kindlepid.py +++ b/dedrm_src/kindlepid.py @@ -11,6 +11,7 @@ # 0.4 Added support for serial numbers starting with '9', fixed unicode bugs. # 0.5 moved unicode_argv call inside main for Windows DeDRM compatibility +from __future__ import print_function import sys import binascii @@ -73,7 +74,7 @@ def unicode_argv(): return [arg if (type(arg) == unicode) else unicode(arg,argvencoding) for arg in sys.argv] if sys.hexversion >= 0x3000000: - print 'This script is incompatible with Python 3.x. Please install Python 2.7.x.' + print('This script is incompatible with Python 3.x. Please install Python 2.7.x.') sys.exit(2) letters = 'ABCDEFGHIJKLMNPQRSTUVWXYZ123456789' @@ -113,28 +114,28 @@ def pidFromSerial(s, l): return pid def cli_main(): - print u"Mobipocket PID calculator for Amazon Kindle. Copyright © 2007, 2009 Igor Skochinsky" + print(u"Mobipocket PID calculator for Amazon Kindle. Copyright © 2007, 2009 Igor Skochinsky") argv=unicode_argv() if len(argv)==2: serial = argv[1] else: - print u"Usage: kindlepid.py /" + print(u"Usage: kindlepid.py /") return 1 if len(serial)==16: if serial.startswith("B") or serial.startswith("9"): - print u"Kindle serial number detected" + print(u"Kindle serial number detected") else: - print u"Warning: unrecognized serial number. Please recheck input." + print(u"Warning: unrecognized serial number. Please recheck input.") return 1 pid = pidFromSerial(serial.encode("utf-8"),7)+'*' - print u"Mobipocket PID for Kindle serial#{0} is {1}".format(serial,checksumPid(pid)) + print(u"Mobipocket PID for Kindle serial#{0} is {1}".format(serial,checksumPid(pid))) return 0 elif len(serial)==40: - print u"iPhone serial number (UDID) detected" + print(u"iPhone serial number (UDID) detected") pid = pidFromSerial(serial.encode("utf-8"),8) - print u"Mobipocket PID for iPhone serial#{0} is {1}".format(serial,checksumPid(pid)) + print(u"Mobipocket PID for iPhone serial#{0} is {1}".format(serial,checksumPid(pid))) return 0 - print u"Warning: unrecognized serial number. Please recheck input." + print(u"Warning: unrecognized serial number. Please recheck input.") return 1 diff --git a/dedrm_src/mobidedrm.py b/dedrm_src/mobidedrm.py index 501aa2d..df702a1 100644 --- a/dedrm_src/mobidedrm.py +++ b/dedrm_src/mobidedrm.py @@ -5,6 +5,7 @@ # Copyright © 2008 The Dark Reverser # Portions © 2008–2017 Apprentice Harper et al. +from __future__ import print_function __license__ = 'GPL v3' __version__ = u"0.42" @@ -80,7 +81,7 @@ import binascii try: from alfcrypto import Pukall_Cipher except: - print u"AlfCrypto not found. Using python PC1 implementation." + print(u"AlfCrypto not found. Using python PC1 implementation.") # Wrap a stream so that output gets flushed immediately # and also make sure that any unicode strings get @@ -244,12 +245,12 @@ class MobiBook: pass def __init__(self, infile): - print u"MobiDeDrm v{0:s}.\nCopyright © 2008-2017 The Dark Reverser, Apprentice Harper et al.".format(__version__) + print(u"MobiDeDrm v{0:s}.\nCopyright © 2008-2017 The Dark Reverser, Apprentice Harper et al.".format(__version__)) try: from alfcrypto import Pukall_Cipher except: - print u"AlfCrypto not found. Using python PC1 implementation." + print(u"AlfCrypto not found. Using python PC1 implementation.") # initial sanity check on file self.data_file = file(infile, 'rb').read() @@ -282,7 +283,7 @@ class MobiBook: self.mobi_version = -1 if self.magic == 'TEXtREAd': - print u"PalmDoc format book detected." + print(u"PalmDoc format book detected.") return self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18]) @@ -424,10 +425,10 @@ class MobiBook: def processBook(self, pidlist): crypto_type, = struct.unpack('>H', self.sect[0xC:0xC+2]) - print u"Crypto Type is: {0:d}".format(crypto_type) + print(u"Crypto Type is: {0:d}".format(crypto_type)) self.crypto_type = crypto_type if crypto_type == 0: - print u"This book is not encrypted." + print(u"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 @@ -444,12 +445,12 @@ class MobiBook: for pid in pidlist: if len(pid)==10: if checksumPid(pid[0:-2]) != pid: - print u"Warning: PID {0} has incorrect checksum, should have been {1}".format(pid,checksumPid(pid[0:-2])) + print(u"Warning: PID {0} has incorrect checksum, should have been {1}".format(pid,checksumPid(pid[0:-2]))) goodpids.append(pid[0:-2]) elif len(pid)==8: goodpids.append(pid) else: - print u"Warning: PID {0} has wrong number of digits".format(pid) + print(u"Warning: PID {0} has wrong number of digits".format(pid)) if self.crypto_type == 1: t1_keyvec = 'QDCVEPMU675RUBSZ' @@ -475,22 +476,22 @@ class MobiBook: self.patchSection(0, '\xff' * 4 + '\0' * 12, 0xA8) if pid=='00000000': - print u"File has default encryption, no specific key needed." + print(u"File has default encryption, no specific key needed.") else: - print u"File is encoded with PID {0}.".format(checksumPid(pid)) + print(u"File is encoded with PID {0}.".format(checksumPid(pid))) # clear the crypto type self.patchSection(0, "\0" * 2, 0xC) # decrypt sections - print u"Decrypting. Please wait . . .", + print(u"Decrypting. Please wait . . .", end=' ') mobidataList = [] mobidataList.append(self.data_file[:self.sections[1][0]]) for i in xrange(1, self.records+1): data = self.loadSection(i) extra_size = getSizeOfTrailingDataEntries(data, len(data), self.extra_data_flags) if i%100 == 0: - print u".", + print(u".", end=' ') # print "record %d, extra_size %d" %(i,extra_size) decoded_data = PC1(found_key, data[0:len(data) - extra_size]) if i==1: @@ -501,7 +502,7 @@ class MobiBook: if self.num_sections > self.records+1: mobidataList.append(self.data_file[self.sections[self.records+1][0]:]) self.mobi_data = "".join(mobidataList) - print u"done" + print(u"done") return def getUnencryptedBook(infile,pidlist): @@ -516,10 +517,10 @@ def cli_main(): argv=unicode_argv() progname = os.path.basename(argv[0]) if len(argv)<3 or len(argv)>4: - print u"MobiDeDrm v{0:s}.\nCopyright © 2008-2017 The Dark Reverser, Apprentice Harper et al.".format(__version__) - print u"Removes protection from Kindle/Mobipocket, Kindle/KF8 and Kindle/Print Replica ebooks" - print u"Usage:" - print u" {0} []".format(progname) + print(u"MobiDeDrm v{0:s}.\nCopyright © 2008-2017 The Dark Reverser, Apprentice Harper et al.".format(__version__)) + print(u"Removes protection from Kindle/Mobipocket, Kindle/KF8 and Kindle/Print Replica ebooks") + print(u"Usage:") + print(u" {0} []".format(progname)) return 1 else: infile = argv[1] @@ -532,7 +533,7 @@ def cli_main(): stripped_file = getUnencryptedBook(infile, pidlist) file(outfile, 'wb').write(stripped_file) except DrmException, e: - print u"MobiDeDRM v{0} Error: {1:s}".format(__version__,e.args[0]) + print(u"MobiDeDRM v{0} Error: {1:s}".format(__version__,e.args[0])) return 1 return 0 diff --git a/dedrm_src/scriptinterface.py b/dedrm_src/scriptinterface.py index ec86b13..0996b68 100644 --- a/dedrm_src/scriptinterface.py +++ b/dedrm_src/scriptinterface.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab +from __future__ import print_function import sys import os import re @@ -23,7 +24,7 @@ def decryptepub(infile, outdir, rscpath): zippath = os.path.join(bpath,name + '_temp.zip') rv = zipfix.repairBook(infile, zippath) if rv != 0: - print "Error while trying to fix epub" + print("Error while trying to fix epub") return rv # determine a good name for the output file @@ -43,7 +44,7 @@ def decryptepub(infile, outdir, rscpath): try: rv = ineptepub.decryptBook(userkey, zippath, outfile) if rv == 0: - print "Decrypted Adobe ePub with key file {0}".format(filename) + print("Decrypted Adobe ePub with key file {0}".format(filename)) break except Exception, e: errlog += traceback.format_exc() @@ -63,7 +64,7 @@ def decryptepub(infile, outdir, rscpath): try: rv = ignobleepub.decryptBook(userkey, zippath, outfile) if rv == 0: - print "Decrypted B&N ePub with key file {0}".format(filename) + print("Decrypted B&N ePub with key file {0}".format(filename)) break except Exception, e: errlog += traceback.format_exc() @@ -72,14 +73,14 @@ def decryptepub(infile, outdir, rscpath): else: encryption = epubtest.encryption(zippath) if encryption == "Unencrypted": - print "{0} is not DRMed.".format(name) + print("{0} is not DRMed.".format(name)) rv = 0 else: - print "{0} has an unknown encryption.".format(name) + print("{0} has an unknown encryption.".format(name)) os.remove(zippath) if rv != 0: - print errlog + print(errlog) return rv @@ -109,7 +110,7 @@ def decryptpdf(infile, outdir, rscpath): rv = 1 if rv != 0: - print errlog + print(errlog) return rv @@ -126,7 +127,7 @@ def decryptpdb(infile, outdir, rscpath): try: name, cc8 = i.split(':') except ValueError: - print ' Error parsing user supplied social drm data.' + print(' Error parsing user supplied social drm data.') return 1 try: rv = erdr2pml.decryptBook(infile, outpath, True, erdr2pml.getuser_key(name, cc8)) diff --git a/dedrm_src/stylexml2css.py b/dedrm_src/stylexml2css.py index daa108a..40b95a6 100644 --- a/dedrm_src/stylexml2css.py +++ b/dedrm_src/stylexml2css.py @@ -2,6 +2,7 @@ # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab # For use with Topaz Scripts Version 2.6 +from __future__ import print_function import csv import sys import os @@ -114,9 +115,9 @@ class DocParser(object): # process each style converting what you can - if debug: print ' ', 'Processing styles.' + if debug: print(' ', 'Processing styles.') for j in xrange(stylecnt): - if debug: print ' ', 'Processing style %d' %(j) + if debug: print(' ', 'Processing style %d' %(j)) start = styleList[j] end = styleList[j+1] @@ -135,7 +136,7 @@ class DocParser(object): else : sclass = '' - if debug: print 'sclass', sclass + if debug: print('sclass', sclass) # check for any "after class" specifiers (pos, aftclass) = self.findinDoc('style._after_class',start,end) @@ -145,7 +146,7 @@ class DocParser(object): else : aftclass = '' - if debug: print 'aftclass', aftclass + if debug: print('aftclass', aftclass) cssargs = {} @@ -154,8 +155,8 @@ class DocParser(object): (pos1, attr) = self.findinDoc('style.rule.attr', start, end) (pos2, val) = self.findinDoc('style.rule.value', start, end) - if debug: print 'attr', attr - if debug: print 'val', val + if debug: print('attr', attr) + if debug: print('val', val) if attr == None : break @@ -182,7 +183,7 @@ class DocParser(object): try: f = float(val) except: - print "Warning: unrecognised val, ignoring" + print("Warning: unrecognised val, ignoring") val = 0 pv = float(val)/scale cssargs[attr] = (self.attr_val_map[attr], pv) @@ -194,7 +195,7 @@ class DocParser(object): if aftclass != "" : keep = False if keep : - if debug: print 'keeping style' + if debug: print('keeping style') # make sure line-space does not go below 100% or above 300% since # it can be wacky in some styles if 'line-space' in cssargs: @@ -266,15 +267,15 @@ class DocParser(object): def convert2CSS(flatxml, fontsize, ph, pw): - print ' ', 'Using font size:',fontsize - print ' ', 'Using page height:', ph - print ' ', 'Using page width:', pw + print(' ', 'Using font size:',fontsize) + print(' ', 'Using page height:', ph) + print(' ', 'Using page width:', pw) # create a document parser dp = DocParser(flatxml, fontsize, ph, pw) - if debug: print ' ', 'Created DocParser.' + if debug: print(' ', 'Created DocParser.') csspage = dp.process() - if debug: print ' ', 'Processed DocParser.' + if debug: print(' ', 'Processed DocParser.') return csspage diff --git a/dedrm_src/topazextract.py b/dedrm_src/topazextract.py index 5b6709f..7d91f2c 100644 --- a/dedrm_src/topazextract.py +++ b/dedrm_src/topazextract.py @@ -8,6 +8,7 @@ # 4.9 - moved unicode_argv call inside main for Windows DeDRM compatibility # 5.0 - Fixed potential unicode problem with command line interface +from __future__ import print_function __version__ = '5.0' import sys @@ -213,7 +214,7 @@ class TopazBook: # Read and return the data of one header record at the current book file position # [[offset,decompressedLength,compressedLength],...] nbValues = bookReadEncodedNumber(self.fo) - if debug: print "%d records in header " % nbValues, + if debug: print("%d records in header " % nbValues, end=' ') values = [] for i in range (0,nbValues): values.append([bookReadEncodedNumber(self.fo),bookReadEncodedNumber(self.fo),bookReadEncodedNumber(self.fo)]) @@ -227,10 +228,10 @@ class TopazBook: record = bookReadHeaderRecordData() return [tag,record] nbRecords = bookReadEncodedNumber(self.fo) - if debug: print "Headers: %d" % nbRecords + if debug: print("Headers: %d" % nbRecords) for i in range (0,nbRecords): result = parseTopazHeaderRecord() - if debug: print result[0], ": ", result[1] + if debug: print(result[0], ": ", result[1]) self.bookHeaderRecords[result[0]] = result[1] if ord(self.fo.read(1)) != 0x64 : raise DrmException(u"Parse Error : Invalid Header") @@ -244,12 +245,12 @@ class TopazBook: raise DrmException(u"Parse Error : Record Names Don't Match") flags = ord(self.fo.read(1)) nbRecords = ord(self.fo.read(1)) - if debug: print "Metadata Records: %d" % nbRecords + if debug: print("Metadata Records: %d" % nbRecords) for i in range (0,nbRecords) : keyval = bookReadString(self.fo) content = bookReadString(self.fo) - if debug: print keyval - if debug: print content + if debug: print(keyval) + if debug: print(content) self.bookMetadata[keyval] = content return self.bookMetadata @@ -319,11 +320,11 @@ class TopazBook: try: keydata = self.getBookPayloadRecord('dkey', 0) except DrmException, e: - print u"no dkey record found, book may not be encrypted" - print u"attempting to extrct files without a book key" + print(u"no dkey record found, book may not be encrypted") + print(u"attempting to extrct files without a book key") self.createBookDirectory() self.extractFiles() - print u"Successfully Extracted Topaz contents" + print(u"Successfully Extracted Topaz contents") if inCalibre: from calibre_plugins.dedrm import genbook else: @@ -331,7 +332,7 @@ class TopazBook: rv = genbook.generateBook(self.outdir, raw, fixedimage) if rv == 0: - print u"Book Successfully generated." + print(u"Book Successfully generated.") return rv # try each pid to decode the file @@ -339,7 +340,7 @@ class TopazBook: for pid in pidlst: # use 8 digit pids here pid = pid[0:8] - print u"Trying: {0}".format(pid) + print(u"Trying: {0}".format(pid)) bookKeys = [] data = keydata try: @@ -348,7 +349,7 @@ class TopazBook: pass else: bookKey = bookKeys[0] - print u"Book Key Found! ({0})".format(bookKey.encode('hex')) + print(u"Book Key Found! ({0})".format(bookKey.encode('hex'))) break if not bookKey: @@ -357,7 +358,7 @@ class TopazBook: self.setBookKey(bookKey) self.createBookDirectory() self.extractFiles() - print u"Successfully Extracted Topaz contents" + print(u"Successfully Extracted Topaz contents") if inCalibre: from calibre_plugins.dedrm import genbook else: @@ -365,7 +366,7 @@ class TopazBook: rv = genbook.generateBook(self.outdir, raw, fixedimage) if rv == 0: - print u"Book Successfully generated" + print(u"Book Successfully generated") return rv def createBookDirectory(self): @@ -394,7 +395,7 @@ class TopazBook: ext = u".dat" if name == 'img': ext = u".jpg" if name == 'color' : ext = u".jpg" - print u"Processing Section: {0}\n. . .".format(name), + print(u"Processing Section: {0}\n. . .".format(name), end=' ') for index in range (0,len(self.bookHeaderRecords[name])) : fname = u"{0}{1:04d}{2}".format(name,index,ext) destdir = outdir @@ -407,11 +408,11 @@ class TopazBook: if name == 'glyphs': destdir = os.path.join(outdir,u"glyphs") outputFile = os.path.join(destdir,fname) - print u".", + print(u".", end=' ') record = self.getBookPayloadRecord(name,index) if record != '': file(outputFile, 'wb').write(record) - print u" " + print(u" ") def getFile(self, zipname): htmlzip = zipfile.ZipFile(zipname,'w',zipfile.ZIP_DEFLATED, False) @@ -441,20 +442,20 @@ class TopazBook: shutil.rmtree(self.outdir, True) def usage(progname): - print u"Removes DRM protection from Topaz ebooks and extracts the contents" - print u"Usage:" - print u" {0} [-k ] [-p ] [-s ] ".format(progname) + print(u"Removes DRM protection from Topaz ebooks and extracts the contents") + print(u"Usage:") + print(u" {0} [-k ] [-p ] [-s ] ".format(progname)) # Main def cli_main(): argv=unicode_argv() progname = os.path.basename(argv[0]) - print u"TopazExtract v{0}.".format(__version__) + print(u"TopazExtract v{0}.".format(__version__)) try: opts, args = getopt.getopt(argv[1:], "k:p:s:x") except getopt.GetoptError, err: - print u"Error in options or arguments: {0}".format(err.args[0]) + print(u"Error in options or arguments: {0}".format(err.args[0])) usage(progname) return 1 if len(args)<2: @@ -464,11 +465,11 @@ def cli_main(): infile = args[0] outdir = args[1] if not os.path.isfile(infile): - print u"Input File {0} Does Not Exist.".format(infile) + print(u"Input File {0} Does Not Exist.".format(infile)) return 1 if not os.path.exists(outdir): - print u"Output Directory {0} Does Not Exist.".format(outdir) + print(u"Output Directory {0} Does Not Exist.".format(outdir)) return 1 kDatabaseFiles = [] @@ -493,19 +494,19 @@ def cli_main(): tb = TopazBook(infile) title = tb.getBookTitle() - print u"Processing Book: {0}".format(title) + print(u"Processing Book: {0}".format(title)) md1, md2 = tb.getPIDMetaInfo() pids.extend(kgenpids.getPidList(md1, md2, serials, kDatabaseFiles)) try: - print u"Decrypting Book" + print(u"Decrypting Book") tb.processBook(pids) - print u" Creating HTML ZIP Archive" + print(u" Creating HTML ZIP Archive") zipname = os.path.join(outdir, bookname + u"_nodrm.htmlz") tb.getFile(zipname) - print u" Creating SVG ZIP Archive" + print(u" Creating SVG ZIP Archive") zipname = os.path.join(outdir, bookname + u"_SVG.zip") tb.getSVGZip(zipname) @@ -513,7 +514,7 @@ def cli_main(): tb.cleanup() except DrmException, e: - print u"Decryption failed\n{0}".format(traceback.format_exc()) + print(u"Decryption failed\n{0}".format(traceback.format_exc())) try: tb.cleanup() @@ -522,7 +523,7 @@ def cli_main(): return 1 except Exception, e: - print u"Decryption failed\m{0}".format(traceback.format_exc()) + print(u"Decryption failed\m{0}".format(traceback.format_exc())) try: tb.cleanup() except: diff --git a/dedrm_src/wineutils.py b/dedrm_src/wineutils.py index 0485e5e..692724d 100644 --- a/dedrm_src/wineutils.py +++ b/dedrm_src/wineutils.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- from __future__ import with_statement +from __future__ import print_function __license__ = 'GPL v3' @@ -20,7 +21,7 @@ def WineGetKeys(scriptpath, extension, wineprefix=""): import json basepath, script = os.path.split(scriptpath) - print u"{0} v{1}: Running {2} under Wine".format(PLUGIN_NAME, PLUGIN_VERSION, script) + print(u"{0} v{1}: Running {2} under Wine".format(PLUGIN_NAME, PLUGIN_VERSION, script)) outdirpath = os.path.join(basepath, u"winekeysdir") if not os.path.exists(outdirpath): @@ -31,26 +32,26 @@ def WineGetKeys(scriptpath, extension, wineprefix=""): cmdline = u"WINEPREFIX=\"{2}\" wine python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath,wineprefix) else: cmdline = u"wine python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath) - print u"{0} v{1}: Command line: '{2}'".format(PLUGIN_NAME, PLUGIN_VERSION, cmdline) + print(u"{0} v{1}: Command line: '{2}'".format(PLUGIN_NAME, PLUGIN_VERSION, cmdline)) try: cmdline = cmdline.encode(sys.getfilesystemencoding()) p2 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=sys.stdout, stderr=STDOUT, close_fds=False) result = p2.wait("wait") except Exception, e: - print u"{0} v{1}: Wine subprocess call error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]) + print(u"{0} v{1}: Wine subprocess call error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0])) if wineprefix != "" and os.path.exists(wineprefix): cmdline = u"WINEPREFIX=\"{2}\" wine C:\\Python27\\python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath,wineprefix) else: cmdline = u"wine C:\\Python27\\python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath) - print u"{0} v{1}: Command line: “{2}”".format(PLUGIN_NAME, PLUGIN_VERSION, cmdline) + print(u"{0} v{1}: Command line: “{2}”".format(PLUGIN_NAME, PLUGIN_VERSION, cmdline)) try: cmdline = cmdline.encode(sys.getfilesystemencoding()) p2 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=sys.stdout, stderr=STDOUT, close_fds=False) result = p2.wait("wait") except Exception, e: - print u"{0} v{1}: Wine subprocess call error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]) + print(u"{0} v{1}: Wine subprocess call error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0])) # try finding winekeys anyway, even if above code errored winekeys = [] @@ -66,8 +67,8 @@ def WineGetKeys(scriptpath, extension, wineprefix=""): new_key_value = keyfile.read() winekeys.append(new_key_value) except: - print u"{0} v{1}: Error loading file {2}".format(PLUGIN_NAME, PLUGIN_VERSION, filename) + print(u"{0} v{1}: Error loading file {2}".format(PLUGIN_NAME, PLUGIN_VERSION, filename)) traceback.print_exc() os.remove(fpath) - print u"{0} v{1}: Found and decrypted {2} {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(winekeys), u"key file" if len(winekeys) == 1 else u"key files") + print(u"{0} v{1}: Found and decrypted {2} {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(winekeys), u"key file" if len(winekeys) == 1 else u"key files")) return winekeys diff --git a/dedrm_src/zipfix.py b/dedrm_src/zipfix.py index 8ddfae3..d3371f2 100644 --- a/dedrm_src/zipfix.py +++ b/dedrm_src/zipfix.py @@ -14,6 +14,7 @@ """ Re-write zip (or ePub) fixing problems with file names (and mimetype entry). """ +from __future__ import print_function __license__ = 'GPL v3' __version__ = "1.1" @@ -156,22 +157,22 @@ class fixZip: def usage(): - print """usage: zipfix.py inputzip outputzip + print("""usage: zipfix.py inputzip outputzip inputzip is the source zipfile to fix outputzip is the fixed zip archive - """ + """) def repairBook(infile, outfile): if not os.path.exists(infile): - print "Error: Input Zip File does not exist" + print("Error: Input Zip File does not exist") return 1 try: fr = fixZip(infile, outfile) fr.fix() return 0 except Exception, e: - print "Error Occurred ", e + print("Error Occurred ", e) return 2 diff --git a/obok_src/obok/obok.py b/obok_src/obok/obok.py index 033c67a..b2fb253 100644 --- a/obok_src/obok/obok.py +++ b/obok_src/obok/obok.py @@ -150,6 +150,7 @@ # after all. # """Manage all Kobo books, either encrypted or DRM-free.""" +from __future__ import print_function __version__ = '3.2.4' __about__ = u"Obok v{0}\nCopyright © 2012-2016 Physisticated et al.".format(__version__) @@ -291,7 +292,7 @@ class KoboLibrary(object): of books, their titles, and the user's encryption key(s).""" def __init__ (self, serials = [], device_path = None): - print __about__ + print(__about__) self.kobodir = u"" kobodb = u"" @@ -374,7 +375,7 @@ class KoboLibrary(object): # make a copy of the database in a temporary file # so we can ensure it's not using WAL logging which sqlite3 can't do. self.newdb = tempfile.NamedTemporaryFile(mode='wb', delete=False) - print self.newdb.name + print(self.newdb.name) olddb = open(kobodb, 'rb') self.newdb.write(olddb.read(18)) self.newdb.write('\x01\x01') @@ -591,32 +592,32 @@ class KoboFile(object): # assume utf-8 with no BOM textoffset = 0 stride = 1 - print u"Checking text:{0}:".format(contents[:10]) + print(u"Checking text:{0}:".format(contents[:10])) # check for byte order mark if contents[:3]=="\xef\xbb\xbf": # seems to be utf-8 with BOM - print u"Could be utf-8 with BOM" + print(u"Could be utf-8 with BOM") textoffset = 3 elif contents[:2]=="\xfe\xff": # seems to be utf-16BE - print u"Could be utf-16BE" + print(u"Could be utf-16BE") textoffset = 3 stride = 2 elif contents[:2]=="\xff\xfe": # seems to be utf-16LE - print u"Could be utf-16LE" + print(u"Could be utf-16LE") textoffset = 2 stride = 2 else: - print u"Perhaps utf-8 without BOM" + print(u"Perhaps utf-8 without BOM") # now check that the first few characters are in the ASCII range for i in xrange(textoffset,textoffset+5*stride,stride): if ord(contents[i])<32 or ord(contents[i])>127: # Non-ascii, so decryption probably failed - print u"Bad character at {0}, value {1}".format(i,ord(contents[i])) + print(u"Bad character at {0}, value {1}".format(i,ord(contents[i]))) raise ValueError - print u"Seems to be good text" + print(u"Seems to be good text") return True if contents[:5]==" Date: Mon, 15 Jul 2019 20:19:40 +0800 Subject: [PATCH 06/32] Fix typo --- contrib/Obok_calibre_plugin/obok_plugin_ReadMe.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/Obok_calibre_plugin/obok_plugin_ReadMe.txt b/contrib/Obok_calibre_plugin/obok_plugin_ReadMe.txt index 0170f7c..a7b8f1b 100644 --- a/contrib/Obok_calibre_plugin/obok_plugin_ReadMe.txt +++ b/contrib/Obok_calibre_plugin/obok_plugin_ReadMe.txt @@ -11,7 +11,7 @@ Open calibre's Preferences dialog. Click on the "Plugins" button. Next, click Customization ------------- -No customization is required, except choosing which menus will show the plugin. Altough the ability to enter a device serial number is given, this should not need to be filled in, as the serial number should be picked up automatically from the attached Kobo reader. +No customization is required, except choosing which menus will show the plugin. Although the ability to enter a device serial number is given, this should not need to be filled in, as the serial number should be picked up automatically from the attached Kobo reader. Using the plugin From 666af55404ec492c245e398c92f87f80f9de9717 Mon Sep 17 00:00:00 2001 From: taroxd Date: Mon, 15 Jul 2019 20:27:00 +0800 Subject: [PATCH 07/32] Update DeDRM_plugin_ReadMe.txt --- contrib/DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt b/contrib/DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt index 7dde68d..698f72a 100644 --- a/contrib/DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt +++ b/contrib/DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt @@ -50,7 +50,7 @@ When you have finished entering your configuration information, you must click t Troubleshooting --------------- -If you find that the DeDRM plugin is not working for you (imported ebooks still have DRM - that is, they won't convert or open in the calibre ebook viewer), you should make a log of the import process by deleting the DRMed ebook from calibre and then adding the ebook to calibre when it's running in debug mode. This will generate a lot of helpful debugging info that can be copied into any online help requests. Here's how to do it: +If you find that the DeDRM plugin is not working for you (imported ebooks still have DRM - that is, they won't convert or open in the calibre ebook viewer), you should make a log of the import process by deleting the DRMed ebook from calibre and then adding the ebook to calibre when it's running in debug mode. This will generate a lot of helpful debugging info that can be copied into any online help requests. Here's how to do it: - Remove the DRMed book from calibre. - Click the Preferences drop-down menu and choose 'Restart in debug mode'. From 57702b7d1763f32761850a78c0e2729aff356053 Mon Sep 17 00:00:00 2001 From: "Andrew (Paradi) Alexander" Date: Thu, 5 Sep 2019 12:04:40 -0400 Subject: [PATCH 08/32] Update link --- CALIBRE_CLI_INSTRUCTIONS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CALIBRE_CLI_INSTRUCTIONS.md b/CALIBRE_CLI_INSTRUCTIONS.md index d579348..dbda688 100644 --- a/CALIBRE_CLI_INSTRUCTIONS.md +++ b/CALIBRE_CLI_INSTRUCTIONS.md @@ -27,7 +27,7 @@ platforms. #### Enter your keys - Figure out what format DeDRM wants your key in by looking in - [the code that handles that](src/prefs.py). + [the code that handles that](dedrm_src/prefs.py). - For Kindle eInk devices, DeDRM expects you to put a list of serial numbers in the `serials` field: `"serials": ["012345689abcdef"]` or `"serials": ["1111111111111111", "2222222222222222"]`. From 0e9e3cf7ca252bedbc4966ebf6c9bcfa3f17068d Mon Sep 17 00:00:00 2001 From: Cory Solovewicz Date: Sat, 5 Oct 2019 12:03:59 -0700 Subject: [PATCH 09/32] Update FAQs.md Update formatting: Wrap all filenames, file paths, and terminal commands in code quotes and cleaned up the file hashes by putting them in an unordered ist. --- FAQs.md | 76 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/FAQs.md b/FAQs.md index dd43f19..0791d3a 100644 --- a/FAQs.md +++ b/FAQs.md @@ -22,30 +22,32 @@ But otherwise, if your ebook is from Amazon, Kobo, Barnes & Noble or any of the ### A Recent Change to Kindle for PC/Kindle for Mac Starting with version 1.19, Kindle for PC/Mac uses Amazon's new KFX format which isn't quite as good a source fro conversion to ePub as the older KF8 (& MOBI) formats. There are two options to get the older formats. Either stick with version 1.17 or earlier, or modify the executable by changing a file name. Note that with Kindle for PC/Mac 1.25 and later, there is no current solution even for FKX. You must use 1.24 or earlier. -Version 1.17 of Kindle is are no longer available directly from Amazon, so you will need to search for the proper file name and find it on a third party site. The name is "KindleForPC-installer-1.17.44170.exe" for PC and "KindleForMac-44182.dmg" for Mac. +Version 1.17 of Kindle is are no longer available directly from Amazon, so you will need to search for the proper file name and find it on a third party site. The name is `KindleForPC-installer-1.17.44170.exe` for PC and `KindleForMac-44182.dmg` for Mac. Verify the one of the following cryptographic hash values, using software of your choice, before installing the downloaded file in order to avoid viruses. If the hash does not match, delete the downloaded file and try again from another site. -Kindle for PC: -MD-5: 53F793B562F4823721AA47D7DE099869 -SHA-1: 73C404D719F0DD8D4AE1C2C96612B095D6C86255 -SHA-256: 14E0F0053F1276C0C7C446892DC170344F707FBFE99B695176 2C120144163200 -Kindle for Mac: -MD-5: E7E36D5369E1F3CF1D28E5D9115DF15F -SHA-1: 7AB9A86B954CB23D622BD79E3257F8E2182D791C -SHA-256: 28DC21246A9C7CDEDD2D6F0F4082E6BF7EF9DB9CE9D485548E 8A9E1D19EAE2AC. + +#### Kindle for PC `KindleForPC-installer-1.17.44170.exe`: +* MD-5: 53F793B562F4823721AA47D7DE099869 +* SHA-1: 73C404D719F0DD8D4AE1C2C96612B095D6C86255 +* SHA-256: 14E0F0053F1276C0C7C446892DC170344F707FBFE99B695176 2C120144163200 + +#### Kindle for Mac `KindleForMac-44182.dmg`: +* MD-5: E7E36D5369E1F3CF1D28E5D9115DF15F +* SHA-1: 7AB9A86B954CB23D622BD79E3257F8E2182D791C +* SHA-256: 28DC21246A9C7CDEDD2D6F0F4082E6BF7EF9DB9CE9D485548E 8A9E1D19EAE2AC. You will need to go to the preferences and uncheck the auto update checkbox. Then download and install 1.17 over the top of the 1.19 installation. You'll also need to delete the KFX folders from your My Kindle Content folder. A other possible solution is to use 1.19 or later, but disable KFX by renaming or disabling a necessary component of the application. This may or may not work on versions after 1.20. In a command window, enter the following commands when Kindle for PC/Mac is not running: #### Windows -ren %localappdata%\Amazon\Kindle\application\renderer-test.exe renderer-test.xxx +`ren %localappdata%\Amazon\Kindle\application\renderer-test.exe renderer-test.xxx` -PC Note: The renderer-test program may be in a different location in some Kindle for PC installations. If the rename command fails look in other folders, such as C:\Program Files\Amazon\Kindle. +PC Note: The renderer-test program may be in a different location in some Kindle for PC installations. If the rename command fails look in other folders, such as `C:\Program Files\Amazon\Kindle`. #### Macintosh -chmod -x /Applications/Kindle.app/Contents/MacOS/renderer-test +`chmod -x /Applications/Kindle.app/Contents/MacOS/renderer-test` -Mac Note: If the chmod command fails with a permission error try again using sudo before chmod - sudo chmod [...] +Mac Note: If the chmod command fails with a permission error try again using `sudo` before `chmod` - `sudo chmod` [...] After restarting the Kindle program any books previously downloaded in KFX format will no longer open. You will need to remove them from your device and re-download them. All future downloads will use the older Kindle formats instead of KFX although they will continue to be placed in one individual subdirectory per book. @@ -56,10 +58,10 @@ Thanks to work by several people, the tools can now decrypt KFX format ebooks fr Thanks to jhowell for his investigations into KFX format and the KFX Input plugin. Some of these instructions are from [his thread on the subject](https://www.mobileread.com/forums/showthread.php?t=283371) at MobileRead. ## Where can I get the latest version of these free DRM removal tools? -Right here at github. Just go to the [releases page](https://github.com/apprenticeharper/DeDRM_tools/releases) and download the latest zip archive of the tools, named DeDRM\_tools\_X.X.X.zip, where X.X.X is the version number. You do not need to download the source code archive. +Right here at github. Just go to the [releases page](https://github.com/apprenticeharper/DeDRM_tools/releases) and download the latest zip archive of the tools, named `DeDRM\_tools\_X.X.X.zip`, where X.X.X is the version number. You do not need to download the source code archive. ## I've downloaded the tools archive. Now what? -First, unzip the archive. You should now have a DeDRM folder containing several other folders and a ReadMe\_First.txt file. Please read the ReadMe\_First file! That will explain what the folders are, and you'll be able to work out which of the tools you need. +First, unzip the archive. You should now have a DeDRM folder containing several other folders and a `ReadMe_First.txt` file. Please read the `ReadMe_First.txt` file! That will explain what the folders are, and you'll be able to work out which of the tools you need. ## That's a big complicated ReadMe file! Isn't there a quick guide? Install calibre. Install the DeDRM\_plugin in calibre. Install the Obok\_plugin in calibre. Restart calibre. In the DeDRM_plugin customisation dialog add in any E-Ink Kindle serial numbers and your B&N account email address and password. Remember that the plugin only tries to remove DRM when ebooks are imported. @@ -67,14 +69,14 @@ Install calibre. Install the DeDRM\_plugin in calibre. Install the Obok\_plugin # Installing the Tools ## The calibre plugin ### I am trying to install the calibre plugin, but calibre says "ERROR: Unhandled exception: InvalidPlugin: The plugin in u’[path]DeDRM\_tools\_6.5.3.zip’ is invalid. It does not contain a top-level \_\_init\_\_.py file" -You are trying to add the tools archive (e.g. DeDRM\_tools\_6.5.3.zip) instead of the plugin. The tools archive is not the plugin. It is a collection of DRM removal tools which includes the plugin. You must unzip the archive, and install the calibre plugin (DeDRM\_plugin.zip) from a folder called “DeDRM\_calibre_plugin” in the unzipped archive. +You are trying to add the tools archive (e.g. `DeDRM_tools_6.5.3.zip`) instead of the plugin. The tools archive is not the plugin. It is a collection of DRM removal tools which includes the plugin. You must unzip the archive, and install the calibre plugin `DeDRM_plugin.zip` from a folder called `DeDRM_calibre_plugin` in the unzipped archive. ### I’ve unzipped the tools archive, but I can’t find the calibre plugin when I try to add them to calibre. I use Windows. -You should select the zip file that is in the “DeDRM\_calibre\_plugin” folder, not any files inside the plugin’s zip archive. Make sure you are selecting from the folder that you created when you unzipped the tools archive and not selecting a file inside the still-zipped tools archive. +You should select the zip file that is in the `DeDRM_calibre_plugin` folder, not any files inside the plugin’s zip archive. Make sure you are selecting from the folder that you created when you unzipped the tools archive and not selecting a file inside the still-zipped tools archive. -(The problem is that Windows will allow apps to browse inside zip archives without needing to unzip them first. If there are zip archives inside the main zip archives, Windows will show them as unzipped as well. So what happens is people will unzip the DeDRM\_tools\_X.X.X.zip to a folder, but when using calibre they will actually navigate to the still zipped file by mistake and cannot tell they have done so because they do not have file extensions showing. So to the unwary Windows user, it appears that the zip archive was unzipped and that everything inside it was unzipped as well so there is no way to install the plugins. +(The problem is that Windows will allow apps to browse inside zip archives without needing to unzip them first. If there are zip archives inside the main zip archives, Windows will show them as unzipped as well. So what happens is people will unzip the `DeDRM_tools_X.X.X.zip` to a folder, but when using calibre they will actually navigate to the still zipped file by mistake and cannot tell they have done so because they do not have file extensions showing. So to the unwary Windows user, it appears that the zip archive was unzipped and that everything inside it was unzipped as well so there is no way to install the plugins. -We strongly recommend renaming the DeDRM\_tools\_X.X.X.zip archive (after extracting its contents) to DeDRM\_tools\_X.X.X_archive.zip. If you do that, you are less likely to navigate to the wrong location from inside calibre.) +We strongly recommend renaming the `DeDRM_tools_X.X.X.zip` archive (after extracting its contents) to `DeDRM_tools_X.X.X_archive.zip`. If you do that, you are less likely to navigate to the wrong location from inside calibre.) ## The Windows Application ### I've installed ActiveState Python and PyCrypto, but the Windows application won't run. What have I done wrong? @@ -87,7 +89,7 @@ Try right-clicking and select open. That might give you the option to open it an ### I can't open the Macintosh Application at all. I get 'The aplication "DeDRM" can't be opened' Some unzip applications do not respect the execution bit setting. Try unzipping the main tools archive using the built-in Mac unzip utility. -Alternatively, sometimes the execution bit isn't set correctly in the archive. If you put the extracted DeDRM application in your Applications folder, you can set the executable bit on the 'droplet' file from the terminal using the command chmod +x /Applications/DeDRM.app/Contents/MacOS/droplet +Alternatively, sometimes the execution bit isn't set correctly in the archive. If you put the extracted DeDRM application in your Applications folder, you can set the executable bit on the 'droplet' file from the terminal using the command `chmod +x /Applications/DeDRM.app/Contents/MacOS/droplet` ### I can't open the Macintosh Application at all. I get 'spawn_via_launchd() failed, errno=111' There seems to be a bug in Apple's launch services. Try using the free [Maintenance utility](https://www.titanium-software.fr/en/maintenance.html) from Titanium Software to clear the launch cache and database. @@ -95,28 +97,28 @@ There seems to be a bug in Apple's launch services. Try using the free [Maintena ### The application opens, but always gives an error in the log 'ImportError: No module named Crypto.Cipher' Some version of MacOS don't include PyCrpto. You'll need to install it manually. In Terminal window: -sudo python -m pip install pycrypto +`sudo python -m pip install pycrypto` if error “No module named pip”, type: -sudo easy_install pip +`sudo easy_install pip` -try again: sudo python -m pip install pycrypto +try again: `sudo python -m pip install pycrypto` if installation fails because “C compiler cannot create executables” and pop-up window asks you to install Command Line Tools for XCode, agree by clicking “Continue” -try again: sudo python -m pip install pycrypto +try again: `sudo python -m pip install pycrypto` If after installing pycrypto decryption still fails with something about pylzma in error log, try: -sudo python -m pip install pylzma +`sudo python -m pip install pylzma` # Using the Tools ## I can’t get the tools to work on my rented or library ebooks. The tools are not designed to remove DRM from rented or library ebooks. ## I've unzipped the tools, but what are all the different files, and how do I use them? -Read the ReadMe_First.txt file and then the ReadMe files included in the tools folder(s) you're interested in. That's what they're for. +Read the `ReadMe_First.txt` file and then the ReadMe files included in the tools folder(s) you're interested in. That's what they're for. ## I have installed the calibre plugin, but my books still have DRM. When I try to view or convert my books, calibre says they have DRM. DRM only gets removed when an ebook is imported into calibre. Also, if the book is already in calibre, by default calibre will discard the newly imported file. You can change this in calibre's Adding books preferences page (Automerge..../Overwrite....), so that newly imported files overwrite existing ebook formats. Then just re-import your books and the DRM-free versions will overwrite the DRMed versions while retaining your books' metadata. @@ -127,16 +129,16 @@ Your ebooks are stored on your computer or on your ebook reader. You need to fin ### Macintosh Navigating from your home folder, -Kindle for Mac ebooks are in either Library/Application Support/Kindle/My Kindle Content or Documents/My Kindle Content or Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/My Kindle Content, depending on your version of Kindle for Mac. +Kindle for Mac ebooks are in either `Library/Application Support/Kindle/My Kindle Content` or `Documents/My Kindle Content or Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/My Kindle Content`, depending on your version of Kindle for Mac. -Adobe Digital Editions ebooks are in Documents/Digital Editions +Adobe Digital Editions ebooks are in `Documents/Digital Editions` ### Windows -Navigating from your "Documents" folder ("My Documents" folder, pre-Windows 7) +Navigating from your `Documents` folder (`My Documents` folder, pre-Windows 7) -Kindle for PC ebooks are in My Kindle Content +Kindle for PC ebooks are in `My Kindle Content` -Adobe Digital Editions ebooks are in My Digital Editions +Adobe Digital Editions ebooks are in `My Digital Editions` ## I have installed the calibre plugin, and the book is not already in calibre, but the DRM does not get removed. @@ -150,15 +152,15 @@ If this book is from an eInk Kindle (e.g. Paperwhite), you must enter the serial If this book is from Kindle for Mac or Kindle for PC, you must have the Kindle Software installed on the same computer and user account as your copy of calibre. -If this book is from Kindle for Mac you must be using version 1.24 or below, even if you have the Input plugin installed. +If this book is from Kindle for Mac you must be using version 1.24 or below, even if you have the Input plugin installed. If the book is from Kindle for PC or Kindle for Mac and you think you are doing everything right, and you are getting this message, it is possible that the files containing the encryption key aren’t quite in the format the tools expect. To try to fix this: 1. Deregister Kindle for PC(Mac) from your Amazon account. 1. Uninstall Kindle for PC(Mac) 1. Delete the Kindle for PC(Mac) preferences - * PC: Delete the directory [home folder]\AppData\Local\Amazon (it might be hidden) and [home folder]\My Documents\My Kindle Content - * Mac: Delete the directory [home folder]/Library/Application Support/Kindle/and/or [home folder]/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/ (one or both may be present and should be deleted) + * PC: Delete the directory `[home folder]\AppData\Local\Amazon` (it might be hidden) and `[home folder]\My Documents\My Kindle Content` + * Mac: Delete the directory `[home folder]/Library/Application Support/Kindle/` and/or `[home folder]/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/` (one or both may be present and should be deleted) 1. Reinstall Kindle for PC(Mac) version 1.17 or earlier (see above for download links). 1. Re-register Kindle for PC(Mac) with your Amazon account 1. Download the ebook again. Do not use the files you have downloaded previously. @@ -171,7 +173,7 @@ There are several possible reasons why only some books get their DRM removed. If you are still having problems with particular books, you will need to create a log of the DRM removal attempt for one of the problem books, and post that in a comment at Apprentice Alf's blog or in a new issue at Apprentice Harper's github repository. ## My Kindle book has imported and the DRM has been removed, but all the pictures are gone. -Most likely, this is a book downloaded from Amazon directly to an eInk Kindle (e.g. Paperwhite). Unfortunately, the pictures are probably in a .azw6 file that the tools don't understand. You must download the book manually from Amazon's web site "For transfer via USB" to your Kindle. When you download the eBook in this manner, Amazon will package the pictures in the with text in a single file that the tools will be able to import successfully. +Most likely, this is a book downloaded from Amazon directly to an eInk Kindle (e.g. Paperwhite). Unfortunately, the pictures are probably in a `.azw6` file that the tools don't understand. You must download the book manually from Amazon's web site "For transfer via USB" to your Kindle. When you download the eBook in this manner, Amazon will package the pictures in the with text in a single file that the tools will be able to import successfully. ## My Kindle book has imported, but it's showing up as an AZW4 format. Conversions take a long time and/or are very poor. You have found a Print Replica Kindle ebook. This is a PDF in a Kindle wrapper. Now the DRM has been removed, you can extract the PDF from the wrapper using the KindleUnpack plugin. Conversion of PDFs rarely gives good results. @@ -195,7 +197,7 @@ Remove the DRMed book from calibre. Click the Preferences drop-down menu and cho The Macintosh DeDRM application creates a log file on your desktop every time it is run. After unsuccessfully removing DRM from one ebook, copy the contents of the log file (it is a simple text file) and paste it into your comment at Apprentice Alf's blog or in a new issue at Apprentice Harper's github repository. ## I cannot solve my problem with the Windows DeDRM application, and now I need to ‘post a log’. How do I do that? -The Windows DeDRM application creates a log file in your home directory (C:\Users\[username]) every time it is run. After unsuccessfully removing DRM from one ebook, copy the contents of the log file (it is a simple text file) and paste it into your comment at Apprentice Alf's blog or in a new issue at Apprentice Harper's github repository. +The Windows DeDRM application creates a log file in your home directory `C:\Users\[username]` every time it is run. After unsuccessfully removing DRM from one ebook, copy the contents of the log file (it is a simple text file) and paste it into your comment at Apprentice Alf's blog or in a new issue at Apprentice Harper's github repository. ## Is there a way to use the DeDRM plugin for Calibre from the command line? See the [Calibre command line interface (CLI) instructions](CALIBRE_CLI_INSTRUCTIONS.md). @@ -231,7 +233,7 @@ Amazon turned off backup for Kindle for Android, so the tools can no longer find Apple regularly change the details of their DRM and so the tools in the main tools archive will not work with these ebooks. Apple’s Fairplay DRM scheme can be removed using Requiem if the appropriate version of iTunes can still be installed and used. See the post Apple and ebooks: iBookstore DRM and how to remove it at Apprentice Alf's blog for more details. ## I’ve got the tools archive and I’ve read all the FAQs but I still can’t install the tools and/or the DRM removal doesn’t work -* Read the ReadMe_First.txt file in the top level of the tools archive +* Read the `ReadMe_First.txt` file in the top level of the tools archive * Read the ReadMe file in the folder of the tools you want to use. * If you still can’t remove the DRM, ask in the comments section of Apprentice Alf's blog or create a new issue at Apprentice Harper's github repository, reporting the error as precisely as you can, what platform you use, what tool you have tried, what errors you get, and what versions you are using. If the problem happens when running one of the tools, post a log (see previous questions on how to do this). From 952b7fa7c06b99210a4c1eefb00025adb31cd2d5 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 17 Dec 2019 08:51:25 +0100 Subject: [PATCH 10/32] GitHub Actions: Lint and test our Python code --- .github/workflows/Python_tests.yml | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/Python_tests.yml diff --git a/.github/workflows/Python_tests.yml b/.github/workflows/Python_tests.yml new file mode 100644 index 0000000..a9ad8f8 --- /dev/null +++ b/.github/workflows/Python_tests.yml @@ -0,0 +1,35 @@ +name: Python_tests +on: [push, pull_request] +jobs: + Python_tests: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [macos-latest] + python-version: [2.7, 3.8] + steps: + - uses: actions/checkout@v1 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest -r requirements.txt + #- name: Check formatting with black + # if: matrix.python-version == '3.8' + # run: | + # pip install black + # black --check . + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + #- name: Test with pytest + # run: pytest + #- name: Run doctests with pytest + # run: pytest --doctest-modules From ff51ee82275ae21c0c4bcabbaa594c0b8f1514cb Mon Sep 17 00:00:00 2001 From: Jake Marsden Date: Sun, 29 Dec 2019 23:30:29 +1300 Subject: [PATCH 11/32] Fix very minor typo in contrib README --- contrib/ReadMe_First.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ReadMe_First.txt b/contrib/ReadMe_First.txt index 9511ce4..d9300bf 100644 --- a/contrib/ReadMe_First.txt +++ b/contrib/ReadMe_First.txt @@ -90,7 +90,7 @@ Windows and Python ------------------ We **strongly** recommend using calibre and the plugin. -If you really want to use the WIndows app or the individual scripts, you'll need to install python. +If you really want to use the Windows app or the individual scripts, you'll need to install python. ActiveState's Active Python 2.7 Community Edition for Windowscan be downloaded for free from: http://www.activestate.com/activepython/downloads From fc6f830088992ca7300b5c275db4206905061323 Mon Sep 17 00:00:00 2001 From: Carson Gaspar Date: Sat, 4 Jan 2020 05:20:16 -0800 Subject: [PATCH 12/32] Update lzma import to include calibre >= 4.6.0 --- dedrm_src/ion.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/dedrm_src/ion.py b/dedrm_src/ion.py index 40433ca..c361d20 100644 --- a/dedrm_src/ion.py +++ b/dedrm_src/ion.py @@ -21,19 +21,24 @@ from Crypto.Cipher import AES from Crypto.Util.py3compat import bchr, bord try: - # lzma library from calibre 2.35.0 or later - import lzma.lzma1 as calibre_lzma + # lzma library from calibre 4.6.0 or later + import calibre_lzma.lzma1 as calibre_lzma except ImportError: calibre_lzma = None + # lzma library from calibre 2.35.0 or later try: - import lzma + import lzma.lzma1 as calibre_lzma except ImportError: - # Need pip backports.lzma on Python <3.3 + calibre_lzma = None try: - from backports import lzma + import lzma except ImportError: - # Windows-friendly choice: pylzma wheels - import pylzma as lzma + # Need pip backports.lzma on Python <3.3 + try: + from backports import lzma + except ImportError: + # Windows-friendly choice: pylzma wheels + import pylzma as lzma TID_NULL = 0 From 798a7f9c8e5f0ca0fb6a433b9d0f2dead242949f Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 13:35:10 +0100 Subject: [PATCH 13/32] GitHub Action: There is no requirements.txt --- .github/workflows/Python_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Python_tests.yml b/.github/workflows/Python_tests.yml index a9ad8f8..1a6e422 100644 --- a/.github/workflows/Python_tests.yml +++ b/.github/workflows/Python_tests.yml @@ -17,7 +17,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install flake8 pytest -r requirements.txt + pip install flake8 pytest # -r requirements.txt #- name: Check formatting with black # if: matrix.python-version == '3.8' # run: | From 48dac1421869d51e215cb7d492c4cbb158d788b6 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 13:39:27 +0100 Subject: [PATCH 14/32] builtins=_ --- .github/workflows/Python_tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Python_tests.yml b/.github/workflows/Python_tests.yml index 1a6e422..e07c1b2 100644 --- a/.github/workflows/Python_tests.yml +++ b/.github/workflows/Python_tests.yml @@ -9,7 +9,7 @@ jobs: os: [macos-latest] python-version: [2.7, 3.8] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v1 with: @@ -26,9 +26,9 @@ jobs: - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + flake8 . builtins=_ --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + flake8 . builtins=_ --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics #- name: Test with pytest # run: pytest #- name: Run doctests with pytest From ae703e523cfe5134f4f512e3b0a24d30c2481148 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 13:41:14 +0100 Subject: [PATCH 15/32] flake8 . --builtins=_ --- .github/workflows/Python_tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Python_tests.yml b/.github/workflows/Python_tests.yml index e07c1b2..6d6b10d 100644 --- a/.github/workflows/Python_tests.yml +++ b/.github/workflows/Python_tests.yml @@ -26,9 +26,9 @@ jobs: - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names - flake8 . builtins=_ --count --select=E9,F63,F7,F82 --show-source --statistics + flake8 . --builtins=_ --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . builtins=_ --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + flake8 . --builtins=_ --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics #- name: Test with pytest # run: pytest #- name: Run doctests with pytest From c74f4b20d38411db04514348fd0752b43013e92c Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 13:45:36 +0100 Subject: [PATCH 16/32] Undefined name: from datetime import datetime --- obok_src/common_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/obok_src/common_utils.py b/obok_src/common_utils.py index 964753f..0f2164a 100644 --- a/obok_src/common_utils.py +++ b/obok_src/common_utils.py @@ -8,6 +8,7 @@ __copyright__ = '2012, David Forrester ' __docformat__ = 'restructuredtext en' import os, time, re, sys +from datetime import datetime try: from PyQt5.Qt import (Qt, QIcon, QPixmap, QLabel, QDialog, QHBoxLayout, QProgressBar, QTableWidgetItem, QFont, QLineEdit, QComboBox, From 89cf29cb7835a35c85c7f8c6c595b2b832fb7492 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 13:46:20 +0100 Subject: [PATCH 17/32] flake8 . --builtins=_,I --- .github/workflows/Python_tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Python_tests.yml b/.github/workflows/Python_tests.yml index 6d6b10d..65215df 100644 --- a/.github/workflows/Python_tests.yml +++ b/.github/workflows/Python_tests.yml @@ -26,9 +26,9 @@ jobs: - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names - flake8 . --builtins=_ --count --select=E9,F63,F7,F82 --show-source --statistics + flake8 . --builtins=_,I --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --builtins=_ --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + flake8 . --builtins=_,I --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics #- name: Test with pytest # run: pytest #- name: Run doctests with pytest From e4c1a09d45dd47841b16324a2274752c974fd9d5 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 13:49:02 +0100 Subject: [PATCH 18/32] Undefined name: import traceback --- dedrm_src/epubtest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dedrm_src/epubtest.py b/dedrm_src/epubtest.py index 11f1427..eb9af5a 100644 --- a/dedrm_src/epubtest.py +++ b/dedrm_src/epubtest.py @@ -48,7 +48,7 @@ from __future__ import with_statement __version__ = '1.01' -import sys, struct, os +import sys, struct, os, traceback import zlib import zipfile import xml.etree.ElementTree as etree From 616548a9a8b04810db7da6e463aabebd3e31aea5 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 13:52:54 +0100 Subject: [PATCH 19/32] Undefined name: import traceback for line 70 --- dedrm_src/wineutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dedrm_src/wineutils.py b/dedrm_src/wineutils.py index 0485e5e..df1755f 100644 --- a/dedrm_src/wineutils.py +++ b/dedrm_src/wineutils.py @@ -6,7 +6,7 @@ from __future__ import with_statement __license__ = 'GPL v3' # Standard Python modules. -import os, sys, re, hashlib +import os, sys, re, hashlib, traceback from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION def WineGetKeys(scriptpath, extension, wineprefix=""): From 1fd972ee1735ce48b29c257571e6a7786e73e4b6 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 13:54:20 +0100 Subject: [PATCH 20/32] Identity is not the same thing as equality in Python --- dedrm_src/mobidedrm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dedrm_src/mobidedrm.py b/dedrm_src/mobidedrm.py index 501aa2d..cc7baf2 100644 --- a/dedrm_src/mobidedrm.py +++ b/dedrm_src/mobidedrm.py @@ -524,7 +524,7 @@ def cli_main(): else: infile = argv[1] outfile = argv[2] - if len(argv) is 4: + if len(argv) == 4: pidlist = argv[3].split(',') else: pidlist = [] From e35b37c4f444b9429ddfb0b25839d50dd70c151e Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 14:29:03 +0100 Subject: [PATCH 21/32] Undefined name: from .convert2xml import encodeNumber --- dedrm_src/genbook.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dedrm_src/genbook.py b/dedrm_src/genbook.py index 4036896..3ec6ccf 100644 --- a/dedrm_src/genbook.py +++ b/dedrm_src/genbook.py @@ -1,6 +1,8 @@ #! /usr/bin/python # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab +from .convert2xml import encodeNumber + class Unbuffered: def __init__(self, stream): self.stream = stream From 7edebeef0da779af9c3e8b4daa3a1a0efccde2ac Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 14:33:16 +0100 Subject: [PATCH 22/32] import erdr2pml, ineptpdf, k4mobidedrm --- dedrm_src/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dedrm_src/__init__.py b/dedrm_src/__init__.py index cdd4e7b..ec4c621 100644 --- a/dedrm_src/__init__.py +++ b/dedrm_src/__init__.py @@ -87,6 +87,10 @@ import zipfile import traceback from zipfile import ZipFile +import erdr2pml +import ineptpdf +import k4mobidedrm + class DeDRMError(Exception): pass From a10d9a617ffc31925a8f83ca6836af78cbd792b4 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 14:34:56 +0100 Subject: [PATCH 23/32] Undefined name: Error() --> ValueError() --- dedrm_src/pycrypto_des.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dedrm_src/pycrypto_des.py b/dedrm_src/pycrypto_des.py index 80d7d65..286df9f 100644 --- a/dedrm_src/pycrypto_des.py +++ b/dedrm_src/pycrypto_des.py @@ -11,7 +11,7 @@ def load_pycrypto(): class DES(object): def __init__(self, key): if len(key) != 8 : - raise Error('DES improper key used') + raise ValueError('DES improper key used') self.key = key self._des = _DES.new(key,_DES.MODE_ECB) def desdecrypt(self, data): From 90335bb925a82f1de3ef065120d5b22e7cdb416e Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 14:41:29 +0100 Subject: [PATCH 24/32] Undefined name: Define RegError --- dedrm_src/kindlekey.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dedrm_src/kindlekey.py b/dedrm_src/kindlekey.py index ec0adde..7e02b6c 100644 --- a/dedrm_src/kindlekey.py +++ b/dedrm_src/kindlekey.py @@ -40,6 +40,12 @@ from struct import pack, unpack, unpack_from import json import getopt +try: + RegError +except NameError: + class RegError(Exception): + pass + # Routines common to Mac and PC # Wrap a stream so that output gets flushed immediately From 8c08c67aa801bf9ea06dfc0300555d173ecb37e8 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 14:47:04 +0100 Subject: [PATCH 25/32] Undefined name: import zipfix --- dedrm_src/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dedrm_src/__init__.py b/dedrm_src/__init__.py index ec4c621..ec98886 100644 --- a/dedrm_src/__init__.py +++ b/dedrm_src/__init__.py @@ -90,6 +90,7 @@ from zipfile import ZipFile import erdr2pml import ineptpdf import k4mobidedrm +import zipfix class DeDRMError(Exception): pass From 4e26b9d4e7b42c9f00d033a140199139d8b15208 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 14:55:42 +0100 Subject: [PATCH 26/32] Undefined name: errlog = '' --- dedrm_src/scriptinterface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dedrm_src/scriptinterface.py b/dedrm_src/scriptinterface.py index ec86b13..6154a2a 100644 --- a/dedrm_src/scriptinterface.py +++ b/dedrm_src/scriptinterface.py @@ -114,6 +114,7 @@ def decryptpdf(infile, outdir, rscpath): def decryptpdb(infile, outdir, rscpath): + errlog = '' outname = os.path.splitext(os.path.basename(infile))[0] + ".pmlz" outpath = os.path.join(outdir, outname) rv = 1 From 0955713cd6061ca30f65434f231e1461a8e3c447 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 14:58:03 +0100 Subject: [PATCH 27/32] Undefined name: errlog = '' --- dedrm_src/scriptinterface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dedrm_src/scriptinterface.py b/dedrm_src/scriptinterface.py index 6154a2a..8cadade 100644 --- a/dedrm_src/scriptinterface.py +++ b/dedrm_src/scriptinterface.py @@ -142,6 +142,7 @@ def decryptpdb(infile, outdir, rscpath): def decryptk4mobi(infile, outdir, rscpath): + errlog = '' rv = 1 pidnums = [] pidspath = os.path.join(rscpath,'pidlist.txt') From eddbefcf915009620896d5bf68e87ae6959272c0 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 15:11:14 +0100 Subject: [PATCH 28/32] Undefined name: strip(uuidnum) --> uuidnum.strip() --- dedrm_src/kindlekey.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dedrm_src/kindlekey.py b/dedrm_src/kindlekey.py index 7e02b6c..7b994ed 100644 --- a/dedrm_src/kindlekey.py +++ b/dedrm_src/kindlekey.py @@ -1308,7 +1308,7 @@ elif isosx: uuids = [] uuidnum = os.getenv('MYUUIDNUMBER') if uuidnum != None: - uuids.append(strip(uuidnum)) + uuids.append(uuidnum.strip()) cmdline = '/usr/sbin/ioreg -l -S -w 0 -r -c AppleAHCIDiskDriver' cmdline = cmdline.encode(sys.getfilesystemencoding()) p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) From 0895aeb32370348c1e871af5b378df6a9f0a7f83 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 15:17:06 +0100 Subject: [PATCH 29/32] Undefined name: from ignoblekeygen import generate_key --- dedrm_src/utilities.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dedrm_src/utilities.py b/dedrm_src/utilities.py index c730607..c62b043 100644 --- a/dedrm_src/utilities.py +++ b/dedrm_src/utilities.py @@ -3,6 +3,8 @@ from __future__ import with_statement +from ignoblekeygen import generate_key + __license__ = 'GPL v3' DETAILED_MESSAGE = \ From b35f7775802ffd34a5e34546f18dd6f6cf40ea1f Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 20 Jan 2020 15:23:19 +0100 Subject: [PATCH 30/32] Focus only on legacy Python for now --- .github/workflows/Python_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Python_tests.yml b/.github/workflows/Python_tests.yml index 65215df..57b08ce 100644 --- a/.github/workflows/Python_tests.yml +++ b/.github/workflows/Python_tests.yml @@ -7,7 +7,7 @@ jobs: fail-fast: false matrix: os: [macos-latest] - python-version: [2.7, 3.8] + python-version: [2.7] # , 3.8] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From 795f413ecbe09a3b20edceb9a4627e403a0e2003 Mon Sep 17 00:00:00 2001 From: Apprentice Harper Date: Thu, 23 Jan 2020 12:14:19 +0000 Subject: [PATCH 31/32] Allow Kindle serial numbers to have spaces, allowing copy/paste from Amazon web site (thanks to jakemarsden) --- dedrm_src/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dedrm_src/config.py b/dedrm_src/config.py index 3a56e44..98ce6e0 100644 --- a/dedrm_src/config.py +++ b/dedrm_src/config.py @@ -879,7 +879,7 @@ class AddSerialDialog(QDialog): @property def key_value(self): - return unicode(self.key_ledit.text()).strip() + return unicode(self.key_ledit.text()).replace(' ', '') def accept(self): if len(self.key_name) == 0 or self.key_name.isspace(): From ce8538a2ca81c5e741647d724de9c5fca36db91b Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 23 Jan 2020 13:24:45 +0100 Subject: [PATCH 32/32] Remove the unused rename_key() method --- obok_src/config.py | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/obok_src/config.py b/obok_src/config.py index ae4edc0..645c9e3 100644 --- a/obok_src/config.py +++ b/obok_src/config.py @@ -145,28 +145,6 @@ class ManageKeysDialog(QDialog): self.listy.clear() self.populate_list() - def rename_key(self): - if not self.listy.currentItem(): - errmsg = u"No {0} selected to rename. Highlight a keyfile first.".format(self.key_type_name) - r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), - _(errmsg), show=True, show_copy_button=False) - return - - d = RenameKeyDialog(self) - d.exec_() - - if d.result() != d.Accepted: - # rename cancelled or moot. - return - keyname = unicode(self.listy.currentItem().text()) - if not question_dialog(self, "{0} {1}: Confirm Rename".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to rename the {2} named {0} to {1}?".format(keyname,d.key_name,self.key_type_name), show_copy_button=False, default_yes=False): - return - self.plugin_keys[d.key_name] = self.plugin_keys[keyname] - del self.plugin_keys[keyname] - - self.listy.clear() - self.populate_list() - def delete_key(self): if not self.listy.currentItem(): return