]> xmof Git - DeDRM.git/commitdiff
More generic 3.0 changes, to be tested.
authorApprentice Harper <apprenticeharper@gmail.com>
Sun, 27 Sep 2020 10:54:49 +0000 (11:54 +0100)
committerApprentice Harper <apprenticeharper@gmail.com>
Sun, 27 Sep 2020 10:54:49 +0000 (11:54 +0100)
42 files changed:
DeDRM_plugin/__init__.py
DeDRM_plugin/adobekey.py
DeDRM_plugin/aescbc.py
DeDRM_plugin/alfcrypto.py
DeDRM_plugin/androidkindlekey.py
DeDRM_plugin/argv_utils.py
DeDRM_plugin/askfolder_ed.py
DeDRM_plugin/config.py
DeDRM_plugin/convert2xml.py
DeDRM_plugin/encodebase64.py [deleted file]
DeDRM_plugin/epubtest.py
DeDRM_plugin/erdr2pml.py
DeDRM_plugin/genbook.py
DeDRM_plugin/ignobleepub.py
DeDRM_plugin/ignoblekey.py
DeDRM_plugin/ignoblekeyfetch.py
DeDRM_plugin/ignoblekeygen.py
DeDRM_plugin/ignoblepdf.py
DeDRM_plugin/ineptepub.py
DeDRM_plugin/ineptpdf.py
DeDRM_plugin/ion.py
DeDRM_plugin/k4mobidedrm.py
DeDRM_plugin/kfxdedrm.py
DeDRM_plugin/kgenpids.py
DeDRM_plugin/kindlekey.py
DeDRM_plugin/kindlepid.py
DeDRM_plugin/mobidedrm.py
DeDRM_plugin/prefs.py
DeDRM_plugin/scriptinterface.py
DeDRM_plugin/simpleprefs.py
DeDRM_plugin/topazextract.py
DeDRM_plugin/utilities.py
DeDRM_plugin/wineutils.py
DeDRM_plugin/zipfilerugged.py
DeDRM_plugin/zipfix.py
Obok_plugin/action.py
Obok_plugin/common_utils.py
Obok_plugin/config.py
Obok_plugin/obok/obok.py
Obok_plugin/utilities.py
Other_Tools/Kobo/obok.py
make_release.py

index c20dd1e0270171775573e1fb44ce12f6a3f3ab70..1fe97a10d625ca1e3456317b806a998344201ca4 100644 (file)
@@ -1,8 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-
 # __init__.py for DeDRM_plugin
 # Copyright © 2008-2020 Apprentice Harper et al.
 
@@ -77,9 +75,9 @@ __docformat__ = 'restructuredtext en'
 Decrypt DRMed ebooks.
 """
 
-PLUGIN_NAME = u"DeDRM"
+PLUGIN_NAME = "DeDRM"
 PLUGIN_VERSION_TUPLE = (7, 0, 0)
-PLUGIN_VERSION = u".".join([unicode(str(x)) for x in PLUGIN_VERSION_TUPLE])
+PLUGIN_VERSION = ".".join([str(x)for x in PLUGIN_VERSION_TUPLE])
 # Include an html helpfile in the plugin's zipfile with the following name.
 RESOURCE_NAME = PLUGIN_NAME + '_Help.htm'
 
@@ -109,11 +107,11 @@ class SafeUnbuffered:
         if self.encoding == None:
             self.encoding = "utf-8"
     def write(self, data):
-        if isinstance(data,bytes):
+        if isinstance(data,str):
             data = data.encode(self.encoding,"replace")
         try:
-            self.stream.write(data)
-            self.stream.flush()
+            self.stream.buffer.write(data)
+            self.stream.buffer.flush()
         except:
             # We can do nothing if a write fails
             pass
@@ -122,11 +120,11 @@ class SafeUnbuffered:
 
 class DeDRM(FileTypePlugin):
     name                    = PLUGIN_NAME
-    description             = u"Removes DRM from Amazon Kindle, Adobe Adept (including Kobo), Barnes & Noble, Mobipocket and eReader ebooks. Credit given to i♥cabbages and The Dark Reverser for the original stand-alone scripts."
+    description             = "Removes DRM from Amazon Kindle, Adobe Adept (including Kobo), Barnes & Noble, Mobipocket and eReader ebooks. Credit given to i♥cabbages and The Dark Reverser for the original stand-alone scripts."
     supported_platforms     = ['linux', 'osx', 'windows']
-    author                  = u"Apprentice Alf, Aprentice Harper, The Dark Reverser and i♥cabbages"
+    author                  = "Apprentice Alf, Aprentice Harper, The Dark Reverser and i♥cabbages"
     version                 = PLUGIN_VERSION_TUPLE
-    minimum_calibre_version = (1, 0, 0)  # Compiled python libraries cannot be imported in earlier versions.
+    minimum_calibre_version = (5, 0, 0)  # Python 3.
     file_types              = set(['epub','pdf','pdb','prc','mobi','pobi','azw','azw1','azw3','azw4','azw8','tpz','kfx','kfx-zip'])
     on_import               = True
     on_preprocess           = True
@@ -146,27 +144,27 @@ class DeDRM(FileTypePlugin):
         Also perform upgrade of preferences once per version
         """
         try:
-            self.pluginsdir = os.path.join(config_dir,u"plugins")
+            self.pluginsdir = os.path.join(config_dir,"plugins")
             if not os.path.exists(self.pluginsdir):
                 os.mkdir(self.pluginsdir)
-            self.maindir = os.path.join(self.pluginsdir,u"DeDRM")
+            self.maindir = os.path.join(self.pluginsdir,"DeDRM")
             if not os.path.exists(self.maindir):
                 os.mkdir(self.maindir)
-            self.helpdir = os.path.join(self.maindir,u"help")
+            self.helpdir = os.path.join(self.maindir,"help")
             if not os.path.exists(self.helpdir):
                 os.mkdir(self.helpdir)
-            self.alfdir = os.path.join(self.maindir,u"libraryfiles")
+            self.alfdir = os.path.join(self.maindir,"libraryfiles")
             if not os.path.exists(self.alfdir):
                 os.mkdir(self.alfdir)
             # only continue if we've never run this version of the plugin before
             self.verdir = os.path.join(self.maindir,PLUGIN_VERSION)
             if not os.path.exists(self.verdir):
                 if iswindows:
-                    names = [u"alfcrypto.dll",u"alfcrypto64.dll"]
+                    names = ["alfcrypto.dll","alfcrypto64.dll"]
                 elif isosx:
-                    names = [u"libalfcrypto.dylib"]
+                    names = ["libalfcrypto.dylib"]
                 else:
-                    names = [u"libalfcrypto32.so",u"libalfcrypto64.so",u"kindlekey.py",u"adobekey.py",u"subasyncio.py"]
+                    names = ["libalfcrypto32.so","libalfcrypto64.so","kindlekey.py","adobekey.py","subasyncio.py"]
                 lib_dict = self.load_resources(names)
                 print("{0} v{1}: Copying needed library files from plugin's zip".format(PLUGIN_NAME, PLUGIN_VERSION))
 
@@ -199,13 +197,13 @@ class DeDRM(FileTypePlugin):
         # Check original epub archive for zip errors.
         import calibre_plugins.dedrm.zipfix
 
-        inf = self.temporary_file(u".epub")
+        inf = self.temporary_file(".epub")
         try:
             print("{0} v{1}: Verifying zip archive integrity".format(PLUGIN_NAME, PLUGIN_VERSION))
             fr = zipfix.fixZip(path_to_ebook, inf.name)
             fr.fix()
         except Exception as e:
-            print(u"{0} v{1}: Error \'{2}\' when checking zip archive".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]))
+            print("{0} v{1}: Error \'{2}\' when checking zip archive".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]))
             raise Exception(e)
 
         # import the decryption keys
@@ -222,9 +220,9 @@ class DeDRM(FileTypePlugin):
 
             # Attempt to decrypt epub with each encryption key (generated or provided).
             for keyname, userkey in dedrmprefs['bandnkeys'].items():
-                keyname_masked = u"".join((u'X' if (x.isdigit()) else x) for x in keyname)
+                keyname_masked = u"".join(("X" if (x.isdigit()) else x) for x in keyname)
                 print("{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked))
-                of = self.temporary_file(u".epub")
+                of = self.temporary_file(".epub")
 
                 # Give the user key, ebook and TemporaryPersistent file to the decryption function.
                 try:
@@ -255,10 +253,10 @@ class DeDRM(FileTypePlugin):
 
                     defaultkeys = nookkeys()
                 else: # linux
-                    from wineutils import WineGetKeys
+                    from .wineutils import WineGetKeys
 
-                    scriptpath = os.path.join(self.alfdir,u"ignoblekey.py")
-                    defaultkeys = WineGetKeys(scriptpath, u".b64",dedrmprefs['adobewineprefix'])
+                    scriptpath = os.path.join(self.alfdir,"ignoblekey.py")
+                    defaultkeys = WineGetKeys(scriptpath, ".b64",dedrmprefs['adobewineprefix'])
 
             except:
                 print("{0} v{1}: Exception when getting default NOOK Study Key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime))
@@ -274,7 +272,7 @@ class DeDRM(FileTypePlugin):
                     for i,userkey in enumerate(newkeys):
                         print("{0} v{1}: Trying a new default key".format(PLUGIN_NAME, PLUGIN_VERSION))
 
-                        of = self.temporary_file(u".epub")
+                        of = self.temporary_file(".epub")
 
                         # Give the user key, ebook and TemporaryPersistent file to the decryption function.
                         try:
@@ -300,12 +298,12 @@ class DeDRM(FileTypePlugin):
                             # 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("{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 as e:
                     pass
 
             print("{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))
+            raise DeDRMError("{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
@@ -316,8 +314,8 @@ class DeDRM(FileTypePlugin):
             # Attempt to decrypt epub with each encryption key (generated or provided).
             for keyname, userkeyhex in dedrmprefs['adeptkeys'].items():
                 userkey = codecs.decode(userkeyhex, 'hex')
-                print(u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname))
-                of = self.temporary_file(u".epub")
+                print("{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname))
+                of = self.temporary_file(".epub")
 
                 # Give the user key, ebook and TemporaryPersistent file to the decryption function.
                 try:
@@ -352,10 +350,10 @@ class DeDRM(FileTypePlugin):
 
                     defaultkeys = adeptkeys()
                 else: # linux
-                    from wineutils import WineGetKeys
+                    from .wineutils import WineGetKeys
 
-                    scriptpath = os.path.join(self.alfdir,u"adobekey.py")
-                    defaultkeys = WineGetKeys(scriptpath, u".der",dedrmprefs['adobewineprefix'])
+                    scriptpath = os.path.join(self.alfdir,"adobekey.py")
+                    defaultkeys = WineGetKeys(scriptpath, ".der",dedrmprefs['adobewineprefix'])
 
                 self.default_key = defaultkeys[0]
             except:
@@ -365,14 +363,14 @@ class DeDRM(FileTypePlugin):
 
             newkeys = []
             for keyvalue in defaultkeys:
-                if keyvalue.encode('hex') not in dedrmprefs['adeptkeys'].values():
+                if codecs.encode(keyvalue, 'hex').decode('ascii') not in dedrmprefs['adeptkeys'].values():
                     newkeys.append(keyvalue)
 
             if len(newkeys) > 0:
                 try:
                     for i,userkey in enumerate(newkeys):
                         print("{0} v{1}: Trying a new default key".format(PLUGIN_NAME, PLUGIN_VERSION))
-                        of = self.temporary_file(u".epub")
+                        of = self.temporary_file(".epub")
 
                         # Give the user key, ebook and TemporaryPersistent file to the decryption function.
                         try:
@@ -389,7 +387,7 @@ class DeDRM(FileTypePlugin):
                             # Store the new successful key in the defaults
                             print("{0} v{1}: Saving a new default key".format(PLUGIN_NAME, PLUGIN_VERSION))
                             try:
-                                dedrmprefs.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex'))
+                                dedrmprefs.addnamedvaluetoprefs('adeptkeys','default_key',codecs.encode(keyvalue, 'hex').decode('ascii'))
                                 dedrmprefs.writeprefs()
                                 print("{0} v{1}: Saved a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime))
                             except:
@@ -399,20 +397,20 @@ class DeDRM(FileTypePlugin):
                             # 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("{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 as 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("{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("{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))
+            raise DeDRMError("{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("{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))
+        raise DeDRMError("{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):
         import calibre_plugins.dedrm.prefs as prefs
@@ -422,9 +420,9 @@ class DeDRM(FileTypePlugin):
         # Attempt to decrypt epub with each encryption key (generated or provided).
         print("{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 = codecs.decode(userkeyhex, 'hex')
+            userkey = userkeyhex.decode('hex')
             print("{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname))
-            of = self.temporary_file(u".pdf")
+            of = self.temporary_file(".pdf")
 
             # Give the user key, ebook and TemporaryPersistent file to the decryption function.
             try:
@@ -455,10 +453,10 @@ class DeDRM(FileTypePlugin):
 
                 defaultkeys = adeptkeys()
             else: # linux
-                from wineutils import WineGetKeys
+                from .wineutils import WineGetKeys
 
-                scriptpath = os.path.join(self.alfdir,u"adobekey.py")
-                defaultkeys = WineGetKeys(scriptpath, u".der",dedrmprefs['adobewineprefix'])
+                scriptpath = os.path.join(self.alfdir,"adobekey.py")
+                defaultkeys = WineGetKeys(scriptpath, ".der",dedrmprefs['adobewineprefix'])
 
             self.default_key = defaultkeys[0]
         except:
@@ -475,7 +473,7 @@ class DeDRM(FileTypePlugin):
             try:
                 for i,userkey in enumerate(newkeys):
                     print("{0} v{1}: Trying a new default key".format(PLUGIN_NAME, PLUGIN_VERSION))
-                    of = self.temporary_file(u".pdf")
+                    of = self.temporary_file(".pdf")
 
                     # Give the user key, ebook and TemporaryPersistent file to the decryption function.
                     try:
@@ -501,13 +499,13 @@ class DeDRM(FileTypePlugin):
                         # 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("{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 as e:
                 pass
 
         # Something went wrong with decryption.
         print("{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))
+        raise DeDRMError("{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))
 
 
     def KindleMobiDecrypt(self,path_to_ebook):
@@ -529,7 +527,7 @@ class DeDRM(FileTypePlugin):
             serials.extend(android_serials_list)
         #print serials
         androidFiles = []
-        kindleDatabases = dedrmprefs['kindlekeys'].items()
+        kindleDatabases = list(dedrmprefs['kindlekeys'].items())
 
         try:
             book = k4mobidedrm.GetDecryptedBook(path_to_ebook,kindleDatabases,androidFiles,serials,pids,self.starttime)
@@ -546,10 +544,10 @@ class DeDRM(FileTypePlugin):
 
                     defaultkeys = kindlekeys()
                 else: # linux
-                    from wineutils import WineGetKeys
+                    from .wineutils import WineGetKeys
 
-                    scriptpath = os.path.join(self.alfdir,u"kindlekey.py")
-                    defaultkeys = WineGetKeys(scriptpath, u".k4i",dedrmprefs['kindlewineprefix'])
+                    scriptpath = os.path.join(self.alfdir,"kindlekey.py")
+                    defaultkeys = WineGetKeys(scriptpath, ".k4i",dedrmprefs['kindlewineprefix'])
             except:
                 print("{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()
@@ -557,16 +555,16 @@ class DeDRM(FileTypePlugin):
 
             newkeys = {}
             for i,keyvalue in enumerate(defaultkeys):
-                keyname = u"default_key_{0:d}".format(i+1)
+                keyname = "default_key_{0:d}".format(i+1)
                 if keyvalue not in dedrmprefs['kindlekeys'].values():
                     newkeys[keyname] = keyvalue
             if len(newkeys) > 0:
-                print("{0} v{1}: Found {2} new {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(newkeys), u"key" if len(newkeys)==1 else u"keys"))
+                print("{0} v{1}: Found {2} new {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(newkeys), "key" if len(newkeys)==1 else "keys"))
                 try:
-                    book = k4mobidedrm.GetDecryptedBook(path_to_ebook,newkeys.items(),[],[],[],self.starttime)
+                    book = k4mobidedrm.GetDecryptedBook(path_to_ebook,list(newkeys.items()),[],[],[],self.starttime)
                     decoded = True
                     # store the new successful keys in the defaults
-                    print("{0} v{1}: Saving {2} new {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(newkeys), u"key" if len(newkeys)==1 else u"keys"))
+                    print("{0} v{1}: Saving {2} new {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(newkeys), "key" if len(newkeys)==1 else "keys"))
                     for keyvalue in newkeys.values():
                         dedrmprefs.addnamedvaluetoprefs('kindlekeys','default_key',keyvalue)
                     dedrmprefs.writeprefs()
@@ -575,7 +573,7 @@ class DeDRM(FileTypePlugin):
             if not decoded:
                 #if you reached here then no luck raise and exception
                 print("{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))
+                raise DeDRMError("{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())
         book.getFile(of.name)
@@ -592,9 +590,9 @@ class DeDRM(FileTypePlugin):
         dedrmprefs = prefs.DeDRM_Prefs()
         # 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)
+            keyname_masked = u"".join(("X" if (x.isdigit()) else x) for x in keyname)
             print("{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked))
-            of = self.temporary_file(u".pmlz")
+            of = self.temporary_file(".pmlz")
 
             # Give the userkey, ebook and TemporaryPersistent file to the decryption function.
             result = erdr2pml.decryptBook(path_to_ebook, of.name, True, userkey.decode('hex'))
@@ -610,7 +608,7 @@ class DeDRM(FileTypePlugin):
             print("{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("{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))
+        raise DeDRMError("{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))
 
 
     def run(self, path_to_ebook):
index 5a329dcc012fed0bcc0eafed38cf6901ffa408ba..e462d3d652f8c591098a6d1fe40480bc0acf79f7 100644 (file)
@@ -1,30 +1,12 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 # adobekey.pyw, version 6.0
-# Copyright © 2009-2010 i♥cabbages
+# Copyright © 2009-2020 i♥cabbages, Apprentice Harper et al.
 
 # Released under the terms of the GNU General Public Licence, version 3
 # <http://www.gnu.org/licenses/>
 
-# Modified 2010–2016 by several people
-
-# Windows users: Before running this program, you must first install Python.
-#   We recommend ActiveState Python 2.7.X for Windows (x86) from
-#   http://www.activestate.com/activepython/downloads.
-#   You must also install PyCrypto from
-#   http://www.voidspace.org.uk/python/modules.shtml#pycrypto
-#   (make certain to install the version for Python 2.7).
-#   Then save this script file as adobekey.pyw and double-click on it to run it.
-#   It will create a file named adobekey_1.der in in the same directory as the script.
-#   This is your Adobe Digital Editions user key.
-#
-# Mac OS X users: Save this script file as adobekey.pyw.  You can run this
-#   program from the command line (python adobekey.pyw) or by double-clicking
-#   it when it has been associated with PythonLauncher.  It will create a file
-#   named adobekey_1.der in the same directory as the script.
-#   This is your Adobe Digital Editions user key.
-
 # Revision history:
 #   1 - Initial release, for Adobe Digital Editions 1.7
 #   2 - Better algorithm for finding pLK; improved error handling
@@ -46,7 +28,7 @@
 #   5.8 - Added getkey interface for Windows DeDRM application
 #   5.9 - moved unicode_argv call inside main for Windows DeDRM compatibility
 #   6.0 - Work if TkInter is missing
-#   7.0 - Python 3 compatible for calibre 5
+#   7.0 - Python 3 for calibre 5
 
 """
 Retrieve Adobe ADEPT user key.
index 28e1843d8a0ef08ab5568dfc7000e7f557555af8..59c763e485583cd9c25f6e6094cd64fcbc8699f2 100644 (file)
@@ -1,4 +1,5 @@
-#! /usr/bin/env python
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 
 """
     Routines for doing AES CBC in one file
@@ -14,7 +15,7 @@
     See the wonderful pure python package cryptopy-1.2.5
     and read its LICENSE.txt for complete license details.
 
-    Adjusted for Python 3 compatibility, September 2020
+    Adjusted for Python 3, September 2020
 """
 
 class CryptoError(Exception):
index a5a11a5a9306df4a7b512fd16673ae0ba7d7f7d4..818ec68ec3e6ab4a5493365eee76fd8066cd8e35 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 # crypto library mainly by some_updates
@@ -8,7 +8,6 @@
 # pbkdf2.py Copyright © 2009 Daniel Holth <dholth@fastmail.fm>
 # 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
@@ -159,7 +158,7 @@ def _load_libalfcrypto():
             topazCryptoDecrypt(ctx, data, out, len(data))
             return out.raw
 
-    print(u"Using Library AlfCrypto DLL/DYLIB/SO")
+    print("Using Library AlfCrypto DLL/DYLIB/SO")
     return (AES_CBC, Pukall_Cipher, Topaz_Cipher)
 
 
@@ -245,7 +244,7 @@ def _load_python_alfcrypto():
             cleartext = self.aes.decrypt(iv + data)
             return cleartext
 
-    print(u"Using Library AlfCrypto Python")
+    print("Using Library AlfCrypto Python")
     return (AES_CBC, Pukall_Cipher, Topaz_Cipher)
 
 
index f05c4682b57945b14c8f351d85051faca8876bfe..4759e1bd8d2da5242cf6b940af2cc855304714de 100644 (file)
@@ -1,13 +1,8 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-from __future__ import print_function
-
 # androidkindlekey.py
-# Copyright © 2013-15 by Thom and Apprentice Harper
-# Some portions Copyright © 2010-15 by some_updates and Apprentice Alf
-#
+# Copyright © 2010-20 by Thom, Apprentice  et al.
 
 # Revision history:
 #  1.0   - AmazonSecureStorage.xml decryption to serial number
@@ -18,7 +13,7 @@ from __future__ import print_function
 #  1.3   - added in TkInter interface, output to a file
 #  1.4   - Fix some problems identified by Aldo Bleeker
 #  1.5   - Fix another problem identified by Aldo Bleeker
-#  2.0   - Add Python 3 compatibility
+#  2.0   - Python 3 compatibility
 
 """
 Retrieve Kindle for Android Serial Number.
@@ -53,10 +48,11 @@ class SafeUnbuffered:
         if self.encoding == None:
             self.encoding = "utf-8"
     def write(self, data):
-        if isinstance(data,bytes):
+        if isinstance(data,str):
             data = data.encode(self.encoding,"replace")
-        self.stream.write(data)
-        self.stream.flush()
+        self.stream.buffer.write(data)
+        self.stream.buffer.flush()
+
     def __getattr__(self, attr):
         return getattr(self.stream, attr)
 
@@ -97,7 +93,7 @@ def unicode_argv():
                     range(start, argc.value)]
         # if we don't have any arguments at all, just pass back script name
         # this should never happen
-        return [u"kindlekey.py"]
+        return ["kindlekey.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -107,9 +103,9 @@ def unicode_argv():
 class DrmException(Exception):
     pass
 
-STORAGE  = u"backup.ab"
-STORAGE1 = u"AmazonSecureStorage.xml"
-STORAGE2 = u"map_data_storage.db"
+STORAGE  = "backup.ab"
+STORAGE1 = "AmazonSecureStorage.xml"
+STORAGE2 = "map_data_storage.db"
 
 class AndroidObfuscation(object):
     '''AndroidObfuscation
@@ -326,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("Decrypts the serial number(s) of Kindle For Android from Android backup or file")
+    print("Get backup.ab file using adb backup com.amazon.kindle for Android 4.0+.")
+    print("Otherwise extract AmazonSecureStorage.xml from /data/data/com.amazon.kindle/shared_prefs/AmazonSecureStorage.xml")
+    print("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 <backup.ab>] [<outfile.k4a>]".format(progname))
+    print("Usage:")
+    print("    {0:s} [-h] [-b <backup.ab>] [<outfile.k4a>]".format(progname))
 
 
 def cli_main():
@@ -340,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("{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 as err:
         usage(progname)
-        print(u"\nError in options or arguments: {0}".format(err.args[0]))
+        print("\nError in options or arguments: {0}".format(err.args[0]))
         return 2
 
     inpath = ""
@@ -378,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("\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("\nSaved Kindle for Android key to {0}".format(outfile))
     else:
-        print(u"\nCould not retrieve Kindle for Android key.")
+        print("\nCould not retrieve Kindle for Android key.")
     return 0
 
 
@@ -401,32 +397,32 @@ def gui_main():
     class DecryptionDialog(Tkinter.Frame):
         def __init__(self, root):
             Tkinter.Frame.__init__(self, root, border=5)
-            self.status = Tkinter.Label(self, text=u"Select backup.ab file")
+            self.status = Tkinter.Label(self, text="Select backup.ab file")
             self.status.pack(fill=Tkconstants.X, expand=1)
             body = Tkinter.Frame(self)
             body.pack(fill=Tkconstants.X, expand=1)
             sticky = Tkconstants.E + Tkconstants.W
             body.grid_columnconfigure(1, weight=2)
-            Tkinter.Label(body, text=u"Backup file").grid(row=0, column=0)
+            Tkinter.Label(body, text="Backup file").grid(row=0, column=0)
             self.keypath = Tkinter.Entry(body, width=40)
             self.keypath.grid(row=0, column=1, sticky=sticky)
-            self.keypath.insert(2, u"backup.ab")
-            button = Tkinter.Button(body, text=u"...", command=self.get_keypath)
+            self.keypath.insert(2, "backup.ab")
+            button = Tkinter.Button(body, text="...", command=self.get_keypath)
             button.grid(row=0, column=2)
             buttons = Tkinter.Frame(self)
             buttons.pack()
             button2 = Tkinter.Button(
-                buttons, text=u"Extract", width=10, command=self.generate)
+                buttons, text="Extract", width=10, command=self.generate)
             button2.pack(side=Tkconstants.LEFT)
             Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT)
             button3 = Tkinter.Button(
-                buttons, text=u"Quit", width=10, command=self.quit)
+                buttons, text="Quit", width=10, command=self.quit)
             button3.pack(side=Tkconstants.RIGHT)
 
         def get_keypath(self):
             keypath = tkFileDialog.askopenfilename(
-                parent=None, title=u"Select backup.ab file",
-                defaultextension=u".ab",
+                parent=None, title="Select backup.ab file",
+                defaultextension=".ab",
                 filetypes=[('adb backup com.amazon.kindle', '.ab'),
                            ('All Files', '.*')])
             if keypath:
@@ -437,30 +433,30 @@ def gui_main():
 
         def generate(self):
             inpath = self.keypath.get()
-            self.status['text'] = u"Getting key..."
+            self.status['text'] = "Getting key..."
             try:
                 keys = get_serials(inpath)
                 keycount = 0
                 for key in keys:
                     while True:
                         keycount += 1
-                        outfile = os.path.join(progpath,u"kindlekey{0:d}.k4a".format(keycount))
+                        outfile = os.path.join(progpath,"kindlekey{0:d}.k4a".format(keycount))
                         if not os.path.exists(outfile):
                             break
 
                     with open(outfile, 'w') as keyfileout:
                         keyfileout.write(key)
                     success = True
-                    tkMessageBox.showinfo(progname, u"Key successfully retrieved to {0}".format(outfile))
+                    tkMessageBox.showinfo(progname, "Key successfully retrieved to {0}".format(outfile))
             except Exception as e:
-                self.status['text'] = u"Error: {0}".format(e.args[0])
+                self.status['text'] = "Error: {0}".format(e.args[0])
                 return
-            self.status['text'] = u"Select backup.ab file"
+            self.status['text'] = "Select backup.ab file"
 
     argv=unicode_argv()
     progpath, progname = os.path.split(argv[0])
     root = Tkinter.Tk()
-    root.title(u"Kindle for Android Key Extraction v.{0}".format(__version__))
+    root.title("Kindle for Android Key Extraction v.{0}".format(__version__))
     root.resizable(True, False)
     root.minsize(300, 0)
     DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1)
index 71f079491a670b7c36cdf2a9ed098e66a2ca1fcd..b904903c8b32626ff6af5c78d5c7e442defb3d29 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 import sys, os
@@ -37,7 +37,7 @@ def unicode_argv():
                     xrange(start, argc.value)]
         # if we don't have any arguments at all, just pass back script name
         # this should never happen
-        return [u"DeDRM.py"]
+        return ["DeDRM.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
index 1a85513f0abbaee185661eecdf4ab8c6a6d4f517..4f64c1f200f133a8a4a2642eaee898a1ffec1140 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
 
@@ -202,7 +202,7 @@ def AskFolder(
     if not pidl:
         result = None
     else:
-        path = LPCWSTR(u" " * (MAX_PATH+1))
+        path = LPCWSTR(" " * (MAX_PATH+1))
         shell32.SHGetPathFromIDListW(pidl, path)
         ole32.CoTaskMemFree(pidl)
         result = path.value
index 2ef3223d844d0ecc663bb46a2eb2362f781c426a..93f69ae11ab1e30c827b3cc6698e3dfc0d791079 100644 (file)
@@ -1,30 +1,18 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-from __future__ import print_function
-
 __license__ = 'GPL v3'
 
-# Added Python 3 compatibility, September 2020
+# Python 3, September 2020
 
 # Standard Python modules.
 import os, traceback, json
 
-# PyQT4 modules (part of calibre).
-try:
-    from PyQt5.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
-                      QGroupBox, QPushButton, QListWidget, QListWidgetItem,
-                      QAbstractItemView, QIcon, QDialog, QDialogButtonBox, QUrl)
-except ImportError:
-    from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
+from PyQt5.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
                       QGroupBox, QPushButton, QListWidget, QListWidgetItem,
                       QAbstractItemView, QIcon, QDialog, QDialogButtonBox, QUrl)
-try:
-    from PyQt5 import Qt as QtGui
-except ImportError:
-    from PyQt4 import QtGui
 
+from PyQt5 import Qt as QtGui
 from zipfile import ZipFile
 
 # calibre modules and constants.
@@ -85,32 +73,32 @@ class ConfigWidget(QWidget):
         button_layout = QVBoxLayout()
         keys_group_box_layout.addLayout(button_layout)
         self.bandn_button = QtGui.QPushButton(self)
-        self.bandn_button.setToolTip(_(u"Click to manage keys for Barnes and Noble ebooks"))
-        self.bandn_button.setText(u"Barnes and Noble ebooks")
+        self.bandn_button.setToolTip(_("Click to manage keys for Barnes and Noble ebooks"))
+        self.bandn_button.setText("Barnes and Noble ebooks")
         self.bandn_button.clicked.connect(self.bandn_keys)
         self.kindle_android_button = QtGui.QPushButton(self)
-        self.kindle_android_button.setToolTip(_(u"Click to manage keys for Kindle for Android ebooks"))
-        self.kindle_android_button.setText(u"Kindle for Android ebooks")
+        self.kindle_android_button.setToolTip(_("Click to manage keys for Kindle for Android ebooks"))
+        self.kindle_android_button.setText("Kindle for Android ebooks")
         self.kindle_android_button.clicked.connect(self.kindle_android)
         self.kindle_serial_button = QtGui.QPushButton(self)
-        self.kindle_serial_button.setToolTip(_(u"Click to manage eInk Kindle serial numbers for Kindle ebooks"))
-        self.kindle_serial_button.setText(u"eInk Kindle ebooks")
+        self.kindle_serial_button.setToolTip(_("Click to manage eInk Kindle serial numbers for Kindle ebooks"))
+        self.kindle_serial_button.setText("eInk Kindle ebooks")
         self.kindle_serial_button.clicked.connect(self.kindle_serials)
         self.kindle_key_button = QtGui.QPushButton(self)
-        self.kindle_key_button.setToolTip(_(u"Click to manage keys for Kindle for Mac/PC ebooks"))
-        self.kindle_key_button.setText(u"Kindle for Mac/PC ebooks")
+        self.kindle_key_button.setToolTip(_("Click to manage keys for Kindle for Mac/PC ebooks"))
+        self.kindle_key_button.setText("Kindle for Mac/PC ebooks")
         self.kindle_key_button.clicked.connect(self.kindle_keys)
         self.adept_button = QtGui.QPushButton(self)
-        self.adept_button.setToolTip(_(u"Click to manage keys for Adobe Digital Editions ebooks"))
-        self.adept_button.setText(u"Adobe Digital Editions ebooks")
+        self.adept_button.setToolTip(_("Click to manage keys for Adobe Digital Editions ebooks"))
+        self.adept_button.setText("Adobe Digital Editions ebooks")
         self.adept_button.clicked.connect(self.adept_keys)
         self.mobi_button = QtGui.QPushButton(self)
-        self.mobi_button.setToolTip(_(u"Click to manage PIDs for Mobipocket ebooks"))
-        self.mobi_button.setText(u"Mobipocket ebooks")
+        self.mobi_button.setToolTip(_("Click to manage PIDs for Mobipocket ebooks"))
+        self.mobi_button.setText("Mobipocket ebooks")
         self.mobi_button.clicked.connect(self.mobi_keys)
         self.ereader_button = QtGui.QPushButton(self)
-        self.ereader_button.setToolTip(_(u"Click to manage keys for eReader ebooks"))
-        self.ereader_button.setText(u"eReader ebooks")
+        self.ereader_button.setToolTip(_("Click to manage keys for eReader ebooks"))
+        self.ereader_button.setText("eReader ebooks")
         self.ereader_button.clicked.connect(self.ereader_keys)
         button_layout.addWidget(self.kindle_serial_button)
         button_layout.addWidget(self.kindle_android_button)
@@ -123,48 +111,48 @@ class ConfigWidget(QWidget):
         self.resize(self.sizeHint())
 
     def kindle_serials(self):
-        d = ManageKeysDialog(self,u"EInk Kindle Serial Number",self.tempdedrmprefs['serials'], AddSerialDialog)
+        d = ManageKeysDialog(self,"EInk Kindle Serial Number",self.tempdedrmprefs['serials'], AddSerialDialog)
         d.exec_()
 
     def kindle_android(self):
-        d = ManageKeysDialog(self,u"Kindle for Android Key",self.tempdedrmprefs['androidkeys'], AddAndroidDialog, 'k4a')
+        d = ManageKeysDialog(self,"Kindle for Android Key",self.tempdedrmprefs['androidkeys'], AddAndroidDialog, 'k4a')
         d.exec_()
 
     def kindle_keys(self):
         if isosx or iswindows:
-            d = ManageKeysDialog(self,u"Kindle for Mac and PC Key",self.tempdedrmprefs['kindlekeys'], AddKindleDialog, 'k4i')
+            d = ManageKeysDialog(self,"Kindle for Mac and PC Key",self.tempdedrmprefs['kindlekeys'], AddKindleDialog, 'k4i')
         else:
             # linux
-            d = ManageKeysDialog(self,u"Kindle for Mac and PC Key",self.tempdedrmprefs['kindlekeys'], AddKindleDialog, 'k4i', self.tempdedrmprefs['kindlewineprefix'])
+            d = ManageKeysDialog(self,"Kindle for Mac and PC Key",self.tempdedrmprefs['kindlekeys'], AddKindleDialog, 'k4i', self.tempdedrmprefs['kindlewineprefix'])
         d.exec_()
         self.tempdedrmprefs['kindlewineprefix'] = d.getwineprefix()
 
     def adept_keys(self):
         if isosx or iswindows:
-            d = ManageKeysDialog(self,u"Adobe Digital Editions Key",self.tempdedrmprefs['adeptkeys'], AddAdeptDialog, 'der')
+            d = ManageKeysDialog(self,"Adobe Digital Editions Key",self.tempdedrmprefs['adeptkeys'], AddAdeptDialog, 'der')
         else:
             # linux
-            d = ManageKeysDialog(self,u"Adobe Digital Editions Key",self.tempdedrmprefs['adeptkeys'], AddAdeptDialog, 'der', self.tempdedrmprefs['adobewineprefix'])
+            d = ManageKeysDialog(self,"Adobe Digital Editions Key",self.tempdedrmprefs['adeptkeys'], AddAdeptDialog, 'der', self.tempdedrmprefs['adobewineprefix'])
         d.exec_()
         self.tempdedrmprefs['adobewineprefix'] = d.getwineprefix()
 
     def mobi_keys(self):
-        d = ManageKeysDialog(self,u"Mobipocket PID",self.tempdedrmprefs['pids'], AddPIDDialog)
+        d = ManageKeysDialog(self,"Mobipocket PID",self.tempdedrmprefs['pids'], AddPIDDialog)
         d.exec_()
 
     def bandn_keys(self):
-        d = ManageKeysDialog(self,u"Barnes and Noble Key",self.tempdedrmprefs['bandnkeys'], AddBandNKeyDialog, 'b64')
+        d = ManageKeysDialog(self,"Barnes and Noble Key",self.tempdedrmprefs['bandnkeys'], AddBandNKeyDialog, 'b64')
         d.exec_()
 
     def ereader_keys(self):
-        d = ManageKeysDialog(self,u"eReader Key",self.tempdedrmprefs['ereaderkeys'], AddEReaderDialog, 'b63')
+        d = ManageKeysDialog(self,"eReader Key",self.tempdedrmprefs['ereaderkeys'], AddEReaderDialog, 'b63')
         d.exec_()
 
     def help_link_activated(self, url):
         def get_help_file_resource():
             # Copy the HTML helpfile to the plugin directory each time the
             # link is clicked in case the helpfile is updated in newer plugins.
-            file_path = os.path.join(config_dir, u"plugins", u"DeDRM", u"help", help_file_name)
+            file_path = os.path.join(config_dir, "plugins", "DeDRM", "help", help_file_name)
             with open(file_path,'w') as f:
                 f.write(self.load_resource(help_file_name))
             return file_path
@@ -201,9 +189,9 @@ class ManageKeysDialog(QDialog):
         self.create_key = create_key
         self.keyfile_ext = keyfile_ext
         self.import_key = (keyfile_ext != u"")
-        self.binary_file = (keyfile_ext == u"der")
-        self.json_file = (keyfile_ext == u"k4i")
-        self.android_file = (keyfile_ext == u"k4a")
+        self.binary_file = (keyfile_ext == "der")
+        self.json_file = (keyfile_ext == "k4i")
+        self.android_file = (keyfile_ext == "k4a")
         self.wineprefix = wineprefix
 
         self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name))
@@ -221,13 +209,13 @@ class ManageKeysDialog(QDialog):
         help_label.linkActivated.connect(self.help_link_activated)
         help_layout.addWidget(help_label)
 
-        keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self)
+        keys_group_box = QGroupBox(_("{0}s".format(self.key_type_name)), self)
         layout.addWidget(keys_group_box)
         keys_group_box_layout = QHBoxLayout()
         keys_group_box.setLayout(keys_group_box_layout)
 
         self.listy = QListWidget(self)
-        self.listy.setToolTip(u"{0}s that will be used to decrypt ebooks".format(self.key_type_name))
+        self.listy.setToolTip("{0}s that will be used to decrypt ebooks".format(self.key_type_name))
         self.listy.setSelectionMode(QAbstractItemView.SingleSelection)
         self.populate_list()
         keys_group_box_layout.addWidget(self.listy)
@@ -236,25 +224,25 @@ class ManageKeysDialog(QDialog):
         keys_group_box_layout.addLayout(button_layout)
         self._add_key_button = QtGui.QToolButton(self)
         self._add_key_button.setIcon(QIcon(I('plus.png')))
-        self._add_key_button.setToolTip(u"Create new {0}".format(self.key_type_name))
+        self._add_key_button.setToolTip("Create new {0}".format(self.key_type_name))
         self._add_key_button.clicked.connect(self.add_key)
         button_layout.addWidget(self._add_key_button)
 
         self._delete_key_button = QtGui.QToolButton(self)
-        self._delete_key_button.setToolTip(_(u"Delete highlighted key"))
+        self._delete_key_button.setToolTip(_("Delete highlighted key"))
         self._delete_key_button.setIcon(QIcon(I('list_remove.png')))
         self._delete_key_button.clicked.connect(self.delete_key)
         button_layout.addWidget(self._delete_key_button)
 
         if type(self.plugin_keys) == dict and self.import_key:
             self._rename_key_button = QtGui.QToolButton(self)
-            self._rename_key_button.setToolTip(_(u"Rename highlighted key"))
+            self._rename_key_button.setToolTip(_("Rename highlighted key"))
             self._rename_key_button.setIcon(QIcon(I('edit-select-all.png')))
             self._rename_key_button.clicked.connect(self.rename_key)
             button_layout.addWidget(self._rename_key_button)
 
             self.export_key_button = QtGui.QToolButton(self)
-            self.export_key_button.setToolTip(u"Save highlighted key to a .{0} file".format(self.keyfile_ext))
+            self.export_key_button.setToolTip("Save highlighted key to a .{0} file".format(self.keyfile_ext))
             self.export_key_button.setIcon(QIcon(I('save.png')))
             self.export_key_button.clicked.connect(self.export_key)
             button_layout.addWidget(self.export_key_button)
@@ -266,7 +254,7 @@ class ManageKeysDialog(QDialog):
             wineprefix_layout = QHBoxLayout()
             layout.addLayout(wineprefix_layout)
             wineprefix_layout.setAlignment(Qt.AlignCenter)
-            self.wp_label = QLabel(u"WINEPREFIX:")
+            self.wp_label = QLabel("WINEPREFIX:")
             wineprefix_layout.addWidget(self.wp_label)
             self.wp_lineedit = QLineEdit(self)
             wineprefix_layout.addWidget(self.wp_lineedit)
@@ -278,8 +266,8 @@ class ManageKeysDialog(QDialog):
         layout.addLayout(migrate_layout)
         if self.import_key:
             migrate_layout.setAlignment(Qt.AlignJustify)
-            self.migrate_btn = QPushButton(u"Import Existing Keyfiles", self)
-            self.migrate_btn.setToolTip(u"Import *.{0} files (created using other tools).".format(self.keyfile_ext))
+            self.migrate_btn = QPushButton("Import Existing Keyfiles", self)
+            self.migrate_btn.setToolTip("Import *.{0} files (created using other tools).".format(self.keyfile_ext))
             self.migrate_btn.clicked.connect(self.migrate_wrapper)
             migrate_layout.addWidget(self.migrate_btn)
         migrate_layout.addStretch()
@@ -314,13 +302,13 @@ class ManageKeysDialog(QDialog):
             if new_key_value in self.plugin_keys.values():
                 old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0]
                 info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name),
-                                    u"The new {1} is the same as the existing {1} named <strong>{0}</strong> and has not been added.".format(old_key_name,self.key_type_name), show=True)
+                                    "The new {1} is the same as the existing {1} named <strong>{0}</strong> and has not been added.".format(old_key_name,self.key_type_name), show=True)
                 return
             self.plugin_keys[d.key_name] = new_key_value
         else:
             if new_key_value in self.plugin_keys:
                 info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name),
-                                    u"This {0} is already in the list of {0}s has not been added.".format(self.key_type_name), show=True)
+                                    "This {0} is already in the list of {0}s has not been added.".format(self.key_type_name), show=True)
                 return
 
             self.plugin_keys.append(d.key_value)
@@ -329,7 +317,7 @@ class ManageKeysDialog(QDialog):
 
     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)
+            errmsg = "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
@@ -341,7 +329,7 @@ class ManageKeysDialog(QDialog):
             # rename cancelled or moot.
             return
         keyname = 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 <strong>{0}</strong> to <strong>{1}</strong>?".format(keyname,d.key_name,self.key_type_name), show_copy_button=False, default_yes=False):
+        if not question_dialog(self, "{0} {1}: Confirm Rename".format(PLUGIN_NAME, PLUGIN_VERSION), "Do you really want to rename the {2} named <strong>{0}</strong> to <strong>{1}</strong>?".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]
@@ -353,7 +341,7 @@ class ManageKeysDialog(QDialog):
         if not self.listy.currentItem():
             return
         keyname = self.listy.currentItem().text()
-        if not question_dialog(self, "{0} {1}: Confirm Delete".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to delete the {1} <strong>{0}</strong>?".format(keyname, self.key_type_name), show_copy_button=False, default_yes=False):
+        if not question_dialog(self, "{0} {1}: Confirm Delete".format(PLUGIN_NAME, PLUGIN_VERSION), "Do you really want to delete the {1} <strong>{0}</strong>?".format(keyname, self.key_type_name), show_copy_button=False, default_yes=False):
             return
         if type(self.plugin_keys) == dict:
             del self.plugin_keys[keyname]
@@ -367,8 +355,8 @@ class ManageKeysDialog(QDialog):
         def get_help_file_resource():
             # Copy the HTML helpfile to the plugin directory each time the
             # link is clicked in case the helpfile is updated in newer plugins.
-            help_file_name = u"{0}_{1}_Help.htm".format(PLUGIN_NAME, self.key_type_name)
-            file_path = os.path.join(config_dir, u"plugins", u"DeDRM", u"help", help_file_name)
+            help_file_name = "{0}_{1}_Help.htm".format(PLUGIN_NAME, self.key_type_name)
+            file_path = os.path.join(config_dir, "plugins", "DeDRM", "help", help_file_name)
             with open(file_path,'w') as f:
                 f.write(self.parent.load_resource(help_file_name))
             return file_path
@@ -376,9 +364,9 @@ class ManageKeysDialog(QDialog):
         open_url(QUrl(url))
 
     def migrate_files(self):
-        unique_dlg_name = PLUGIN_NAME + u"import {0} keys".format(self.key_type_name).replace(' ', '_') #takes care of automatically remembering last directory
-        caption = u"Select {0} files to import".format(self.key_type_name)
-        filters = [(u"{0} files".format(self.key_type_name), [self.keyfile_ext])]
+        unique_dlg_name = PLUGIN_NAME + "import {0} keys".format(self.key_type_name).replace(' ', '_') #takes care of automatically remembering last directory
+        caption = "Select {0} files to import".format(self.key_type_name)
+        filters = [("{0} files".format(self.key_type_name), [self.keyfile_ext])]
         files = choose_files(self, unique_dlg_name, caption, filters, all_files=False)
         counter = 0
         skipped = 0
@@ -400,7 +388,7 @@ class ManageKeysDialog(QDialog):
                 for key in self.plugin_keys.keys():
                     if uStrCmp(new_key_name, key, True):
                         skipped += 1
-                        msg = u"A key with the name <strong>{0}</strong> already exists!\nSkipping key file  <strong>{1}</strong>.\nRename the existing key and import again".format(new_key_name,filename)
+                        msg = "A key with the name <strong>{0}</strong> already exists!\nSkipping key file  <strong>{1}</strong>.\nRename the existing key and import again".format(new_key_name,filename)
                         inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                                 _(msg), show_copy_button=False, show=True)
                         match = True
@@ -410,7 +398,7 @@ class ManageKeysDialog(QDialog):
                         old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0]
                         skipped += 1
                         info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
-                                            u"The key in file {0} is the same as the existing key <strong>{1}</strong> and has been skipped.".format(filename,old_key_name), show_copy_button=False, show=True)
+                                            "The key in file {0} is the same as the existing key <strong>{1}</strong> and has been skipped.".format(filename,old_key_name), show_copy_button=False, show=True)
                     else:
                         counter += 1
                         self.plugin_keys[new_key_name] = new_key_value
@@ -418,9 +406,9 @@ class ManageKeysDialog(QDialog):
             msg = u""
             if counter+skipped > 1:
                 if counter > 0:
-                    msg += u"Imported <strong>{0:d}</strong> key {1}. ".format(counter, u"file" if counter == 1 else u"files")
+                    msg += "Imported <strong>{0:d}</strong> key {1}. ".format(counter, "file" if counter == 1 else "files")
                 if skipped > 0:
-                    msg += u"Skipped <strong>{0:d}</strong> key {1}.".format(skipped, u"file" if counter == 1 else u"files")
+                    msg += "Skipped <strong>{0:d}</strong> key {1}.".format(skipped, "file" if counter == 1 else "files")
                 inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                                     _(msg), show_copy_button=False, show=True)
         return counter > 0
@@ -432,15 +420,15 @@ class ManageKeysDialog(QDialog):
 
     def export_key(self):
         if not self.listy.currentItem():
-            errmsg = u"No keyfile selected to export. Highlight a keyfile first."
+            errmsg = "No keyfile selected to export. Highlight a keyfile first."
             r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                                     _(errmsg), show=True, show_copy_button=False)
             return
         keyname = self.listy.currentItem().text()
-        unique_dlg_name = PLUGIN_NAME + u"export {0} keys".format(self.key_type_name).replace(' ', '_') #takes care of automatically remembering last directory
-        caption = u"Save {0} File as...".format(self.key_type_name)
-        filters = [(u"{0} Files".format(self.key_type_name), [u"{0}".format(self.keyfile_ext)])]
-        defaultname = u"{0}.{1}".format(keyname, self.keyfile_ext)
+        unique_dlg_name = PLUGIN_NAME + "export {0} keys".format(self.key_type_name).replace(' ', '_') #takes care of automatically remembering last directory
+        caption = "Save {0} File as...".format(self.key_type_name)
+        filters = [("{0} Files".format(self.key_type_name), ["{0}".format(self.keyfile_ext)])]
+        defaultname = "{0}.{1}".format(keyname, self.keyfile_ext)
         filename = choose_save_file(self, unique_dlg_name,  caption, filters, all_files=False, initial_filename=defaultname)
         if filename:
             with file(filename, 'wb') as fname:
@@ -474,7 +462,7 @@ class RenameKeyDialog(QDialog):
 
         data_group_box_layout.addWidget(QLabel('New Key Name:', self))
         self.key_ledit = QLineEdit(self.parent.listy.currentItem().text(), self)
-        self.key_ledit.setToolTip(u"Enter a new name for this existing {0}.".format(parent.key_type_name))
+        self.key_ledit.setToolTip("Enter a new name for this existing {0}.".format(parent.key_type_name))
         data_group_box_layout.addWidget(self.key_ledit)
 
         layout.addSpacing(20)
@@ -488,11 +476,11 @@ class RenameKeyDialog(QDialog):
 
     def accept(self):
         if not self.key_ledit.text() or self.key_ledit.text().isspace():
-            errmsg = u"Key name field cannot be empty!"
+            errmsg = "Key name field cannot be empty!"
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                                     _(errmsg), show=True, show_copy_button=False)
         if len(self.key_ledit.text()) < 4:
-            errmsg = u"Key name must be at <i>least</i> 4 characters long!"
+            errmsg = "Key name must be at <i>least</i> 4 characters long!"
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                                     _(errmsg), show=True, show_copy_button=False)
         if uStrCmp(self.key_ledit.text(), self.parent.listy.currentItem().text()):
@@ -501,7 +489,7 @@ class RenameKeyDialog(QDialog):
         for k in self.parent.plugin_keys.keys():
             if (uStrCmp(self.key_ledit.text(), k, True) and
                         not uStrCmp(k, self.parent.listy.currentItem().text(), True)):
-                errmsg = u"The key name <strong>{0}</strong> is already being used.".format(self.key_ledit.text())
+                errmsg = "The key name <strong>{0}</strong> is already being used.".format(self.key_ledit.text())
                 return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                                     _(errmsg), show=True, show_copy_button=False)
         QDialog.accept(self)
@@ -521,7 +509,7 @@ class AddBandNKeyDialog(QDialog):
     def __init__(self, parent=None,):
         QDialog.__init__(self, parent)
         self.parent = parent
-        self.setWindowTitle(u"{0} {1}: Create New Barnes & Noble Key".format(PLUGIN_NAME, PLUGIN_VERSION))
+        self.setWindowTitle("{0} {1}: Create New Barnes & Noble Key".format(PLUGIN_NAME, PLUGIN_VERSION))
         layout = QVBoxLayout(self)
         self.setLayout(layout)
 
@@ -532,37 +520,37 @@ class AddBandNKeyDialog(QDialog):
 
         key_group = QHBoxLayout()
         data_group_box_layout.addLayout(key_group)
-        key_group.addWidget(QLabel(u"Unique Key Name:", self))
+        key_group.addWidget(QLabel("Unique Key Name:", self))
         self.key_ledit = QLineEdit("", self)
-        self.key_ledit.setToolTip(_(u"<p>Enter an identifying name for this new key.</p>" +
-                                u"<p>It should be something that will help you remember " +
-                                u"what personal information was used to create it."))
+        self.key_ledit.setToolTip(_("<p>Enter an identifying name for this new key.</p>" +
+                                "<p>It should be something that will help you remember " +
+                                "what personal information was used to create it."))
         key_group.addWidget(self.key_ledit)
 
         name_group = QHBoxLayout()
         data_group_box_layout.addLayout(name_group)
-        name_group.addWidget(QLabel(u"B&N/nook account email address:", self))
+        name_group.addWidget(QLabel("B&N/nook account email address:", self))
         self.name_ledit = QLineEdit(u"", self)
-        self.name_ledit.setToolTip(_(u"<p>Enter your email address as it appears in your B&N " +
-                                u"account.</p>" +
-                                u"<p>It will only be used to generate this " +
-                                u"key and won\'t be stored anywhere " +
-                                u"in calibre or on your computer.</p>" +
-                                u"<p>eg: apprenticeharper@gmail.com</p>"))
+        self.name_ledit.setToolTip(_("<p>Enter your email address as it appears in your B&N " +
+                                "account.</p>" +
+                                "<p>It will only be used to generate this " +
+                                "key and won\'t be stored anywhere " +
+                                "in calibre or on your computer.</p>" +
+                                "<p>eg: apprenticeharper@gmail.com</p>"))
         name_group.addWidget(self.name_ledit)
-        name_disclaimer_label = QLabel(_(u"(Will not be saved in configuration data)"), self)
+        name_disclaimer_label = QLabel(_("(Will not be saved in configuration data)"), self)
         name_disclaimer_label.setAlignment(Qt.AlignHCenter)
         data_group_box_layout.addWidget(name_disclaimer_label)
 
         ccn_group = QHBoxLayout()
         data_group_box_layout.addLayout(ccn_group)
-        ccn_group.addWidget(QLabel(u"B&N/nook account password:", self))
+        ccn_group.addWidget(QLabel("B&N/nook account password:", self))
         self.cc_ledit = QLineEdit(u"", self)
-        self.cc_ledit.setToolTip(_(u"<p>Enter the password " +
-                                u"for your B&N account.</p>" +
-                                u"<p>The password will only be used to generate this " +
-                                u"key and won\'t be stored anywhere in " +
-                                u"calibre or on your computer."))
+        self.cc_ledit.setToolTip(_("<p>Enter the password " +
+                                "for your B&N account.</p>" +
+                                "<p>The password will only be used to generate this " +
+                                "key and won\'t be stored anywhere in " +
+                                "calibre or on your computer."))
         ccn_group.addWidget(self.cc_ledit)
         ccn_disclaimer_label = QLabel(_('(Will not be saved in configuration data)'), self)
         ccn_disclaimer_label.setAlignment(Qt.AlignHCenter)
@@ -571,13 +559,13 @@ class AddBandNKeyDialog(QDialog):
 
         key_group = QHBoxLayout()
         data_group_box_layout.addLayout(key_group)
-        key_group.addWidget(QLabel(u"Retrieved key:", self))
+        key_group.addWidget(QLabel("Retrieved key:", self))
         self.key_display = QLabel(u"", self)
-        self.key_display.setToolTip(_(u"Click the Retrieve Key button to fetch your B&N encryption key from the B&N servers"))
+        self.key_display.setToolTip(_("Click the Retrieve Key button to fetch your B&N encryption key from the B&N servers"))
         key_group.addWidget(self.key_display)
         self.retrieve_button = QtGui.QPushButton(self)
-        self.retrieve_button.setToolTip(_(u"Click to retrieve your B&N encryption key from the B&N servers"))
-        self.retrieve_button.setText(u"Retrieve Key")
+        self.retrieve_button.setToolTip(_("Click to retrieve your B&N encryption key from the B&N servers"))
+        self.retrieve_button.setText("Retrieve Key")
         self.retrieve_button.clicked.connect(self.retrieve_key)
         key_group.addWidget(self.retrieve_button)
         layout.addSpacing(10)
@@ -609,17 +597,17 @@ class AddBandNKeyDialog(QDialog):
         from calibre_plugins.dedrm.ignoblekeyfetch import fetch_key as fetch_bandn_key
         fetched_key = fetch_bandn_key(self.user_name,self.cc_number)
         if fetched_key == "":
-            errmsg = u"Could not retrieve key. Check username, password and intenet connectivity and try again."
+            errmsg = "Could not retrieve key. Check username, password and intenet connectivity and try again."
             error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         else:
             self.key_display.setText(fetched_key)
 
     def accept(self):
         if len(self.key_name) == 0 or len(self.user_name) == 0 or len(self.cc_number) == 0 or self.key_name.isspace() or self.user_name.isspace() or self.cc_number.isspace():
-            errmsg = u"All fields are required!"
+            errmsg = "All fields are required!"
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         if len(self.key_name) < 4:
-            errmsg = u"Key name must be at <i>least</i> 4 characters long!"
+            errmsg = "Key name must be at <i>least</i> 4 characters long!"
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         if len(self.key_value) == 0:
             self.retrieve_key()
@@ -631,7 +619,7 @@ class AddEReaderDialog(QDialog):
     def __init__(self, parent=None,):
         QDialog.__init__(self, parent)
         self.parent = parent
-        self.setWindowTitle(u"{0} {1}: Create New eReader Key".format(PLUGIN_NAME, PLUGIN_VERSION))
+        self.setWindowTitle("{0} {1}: Create New eReader Key".format(PLUGIN_NAME, PLUGIN_VERSION))
         layout = QVBoxLayout(self)
         self.setLayout(layout)
 
@@ -642,26 +630,26 @@ class AddEReaderDialog(QDialog):
 
         key_group = QHBoxLayout()
         data_group_box_layout.addLayout(key_group)
-        key_group.addWidget(QLabel(u"Unique Key Name:", self))
+        key_group.addWidget(QLabel("Unique Key Name:", self))
         self.key_ledit = QLineEdit("", self)
-        self.key_ledit.setToolTip(u"<p>Enter an identifying name for this new key.\nIt should be something that will help you remember what personal information was used to create it.")
+        self.key_ledit.setToolTip("<p>Enter an identifying name for this new key.\nIt should be something that will help you remember what personal information was used to create it.")
         key_group.addWidget(self.key_ledit)
 
         name_group = QHBoxLayout()
         data_group_box_layout.addLayout(name_group)
-        name_group.addWidget(QLabel(u"Your Name:", self))
+        name_group.addWidget(QLabel("Your Name:", self))
         self.name_ledit = QLineEdit(u"", self)
-        self.name_ledit.setToolTip(u"Enter the name for this eReader key, usually the name on your credit card.\nIt will only be used to generate this one-time key and won\'t be stored anywhere in calibre or on your computer.\n(ex: Mr Jonathan Q Smith)")
+        self.name_ledit.setToolTip("Enter the name for this eReader key, usually the name on your credit card.\nIt will only be used to generate this one-time key and won\'t be stored anywhere in calibre or on your computer.\n(ex: Mr Jonathan Q Smith)")
         name_group.addWidget(self.name_ledit)
-        name_disclaimer_label = QLabel(_(u"(Will not be saved in configuration data)"), self)
+        name_disclaimer_label = QLabel(_("(Will not be saved in configuration data)"), self)
         name_disclaimer_label.setAlignment(Qt.AlignHCenter)
         data_group_box_layout.addWidget(name_disclaimer_label)
 
         ccn_group = QHBoxLayout()
         data_group_box_layout.addLayout(ccn_group)
-        ccn_group.addWidget(QLabel(u"Credit Card#:", self))
+        ccn_group.addWidget(QLabel("Credit Card#:", self))
         self.cc_ledit = QLineEdit(u"", self)
-        self.cc_ledit.setToolTip(u"<p>Enter the last 8 digits of credit card number for this eReader key.\nThey will only be used to generate this one-time key and won\'t be stored anywhere in calibre or on your computer.")
+        self.cc_ledit.setToolTip("<p>Enter the last 8 digits of credit card number for this eReader key.\nThey will only be used to generate this one-time key and won\'t be stored anywhere in calibre or on your computer.")
         ccn_group.addWidget(self.cc_ledit)
         ccn_disclaimer_label = QLabel(_('(Will not be saved in configuration data)'), self)
         ccn_disclaimer_label.setAlignment(Qt.AlignHCenter)
@@ -695,13 +683,13 @@ class AddEReaderDialog(QDialog):
 
     def accept(self):
         if len(self.key_name) == 0 or len(self.user_name) == 0 or len(self.cc_number) == 0 or self.key_name.isspace() or self.user_name.isspace() or self.cc_number.isspace():
-            errmsg = u"All fields are required!"
+            errmsg = "All fields are required!"
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         if not self.cc_number.isdigit():
-            errmsg = u"Numbers only in the credit card number field!"
+            errmsg = "Numbers only in the credit card number field!"
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         if len(self.key_name) < 4:
-            errmsg = u"Key name must be at <i>least</i> 4 characters long!"
+            errmsg = "Key name must be at <i>least</i> 4 characters long!"
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         QDialog.accept(self)
 
@@ -710,7 +698,7 @@ class AddAdeptDialog(QDialog):
     def __init__(self, parent=None,):
         QDialog.__init__(self, parent)
         self.parent = parent
-        self.setWindowTitle(u"{0} {1}: Getting Default Adobe Digital Editions Key".format(PLUGIN_NAME, PLUGIN_VERSION))
+        self.setWindowTitle("{0} {1}: Getting Default Adobe Digital Editions Key".format(PLUGIN_NAME, PLUGIN_VERSION))
         layout = QVBoxLayout(self)
         self.setLayout(layout)
 
@@ -722,8 +710,8 @@ class AddAdeptDialog(QDialog):
             else:  # linux
                 from wineutils import WineGetKeys
 
-                scriptpath = os.path.join(parent.parent.alfdir,u"adobekey.py")
-                defaultkeys = WineGetKeys(scriptpath, u".der",parent.getwineprefix())
+                scriptpath = os.path.join(parent.parent.alfdir,"adobekey.py")
+                defaultkeys = WineGetKeys(scriptpath, ".der",parent.getwineprefix())
 
             self.default_key = defaultkeys[0]
         except:
@@ -740,14 +728,14 @@ class AddAdeptDialog(QDialog):
 
             key_group = QHBoxLayout()
             data_group_box_layout.addLayout(key_group)
-            key_group.addWidget(QLabel(u"Unique Key Name:", self))
-            self.key_ledit = QLineEdit(u"default_key", self)
-            self.key_ledit.setToolTip(u"<p>Enter an identifying name for the current default Adobe Digital Editions key.")
+            key_group.addWidget(QLabel("Unique Key Name:", self))
+            self.key_ledit = QLineEdit("default_key", self)
+            self.key_ledit.setToolTip("<p>Enter an identifying name for the current default Adobe Digital Editions key.")
             key_group.addWidget(self.key_ledit)
 
             self.button_box.accepted.connect(self.accept)
         else:
-            default_key_error = QLabel(u"The default encryption key for Adobe Digital Editions could not be found.", self)
+            default_key_error = QLabel("The default encryption key for Adobe Digital Editions could not be found.", self)
             default_key_error.setAlignment(Qt.AlignHCenter)
             layout.addWidget(default_key_error)
             # if no default, bot buttons do the same
@@ -769,10 +757,10 @@ class AddAdeptDialog(QDialog):
 
     def accept(self):
         if len(self.key_name) == 0 or self.key_name.isspace():
-            errmsg = u"All fields are required!"
+            errmsg = "All fields are required!"
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         if len(self.key_name) < 4:
-            errmsg = u"Key name must be at <i>least</i> 4 characters long!"
+            errmsg = "Key name must be at <i>least</i> 4 characters long!"
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         QDialog.accept(self)
 
@@ -781,7 +769,7 @@ class AddKindleDialog(QDialog):
     def __init__(self, parent=None,):
         QDialog.__init__(self, parent)
         self.parent = parent
-        self.setWindowTitle(u"{0} {1}: Getting Default Kindle for Mac/PC Key".format(PLUGIN_NAME, PLUGIN_VERSION))
+        self.setWindowTitle("{0} {1}: Getting Default Kindle for Mac/PC Key".format(PLUGIN_NAME, PLUGIN_VERSION))
         layout = QVBoxLayout(self)
         self.setLayout(layout)
 
@@ -793,8 +781,8 @@ class AddKindleDialog(QDialog):
             else: # linux
                 from wineutils import WineGetKeys
 
-                scriptpath = os.path.join(parent.parent.alfdir,u"kindlekey.py")
-                defaultkeys = WineGetKeys(scriptpath, u".k4i",parent.getwineprefix())
+                scriptpath = os.path.join(parent.parent.alfdir,"kindlekey.py")
+                defaultkeys = WineGetKeys(scriptpath, ".k4i",parent.getwineprefix())
 
             self.default_key = defaultkeys[0]
         except:
@@ -811,14 +799,14 @@ class AddKindleDialog(QDialog):
 
             key_group = QHBoxLayout()
             data_group_box_layout.addLayout(key_group)
-            key_group.addWidget(QLabel(u"Unique Key Name:", self))
-            self.key_ledit = QLineEdit(u"default_key", self)
-            self.key_ledit.setToolTip(u"<p>Enter an identifying name for the current default Kindle for Mac/PC key.")
+            key_group.addWidget(QLabel("Unique Key Name:", self))
+            self.key_ledit = QLineEdit("default_key", self)
+            self.key_ledit.setToolTip("<p>Enter an identifying name for the current default Kindle for Mac/PC key.")
             key_group.addWidget(self.key_ledit)
 
             self.button_box.accepted.connect(self.accept)
         else:
-            default_key_error = QLabel(u"The default encryption key for Kindle for Mac/PC could not be found.", self)
+            default_key_error = QLabel("The default encryption key for Kindle for Mac/PC could not be found.", self)
             default_key_error.setAlignment(Qt.AlignHCenter)
             layout.addWidget(default_key_error)
 
@@ -841,10 +829,10 @@ class AddKindleDialog(QDialog):
 
     def accept(self):
         if len(self.key_name) == 0 or self.key_name.isspace():
-            errmsg = u"All fields are required!"
+            errmsg = "All fields are required!"
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         if len(self.key_name) < 4:
-            errmsg = u"Key name must be at <i>least</i> 4 characters long!"
+            errmsg = "Key name must be at <i>least</i> 4 characters long!"
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         QDialog.accept(self)
 
@@ -853,7 +841,7 @@ class AddSerialDialog(QDialog):
     def __init__(self, parent=None,):
         QDialog.__init__(self, parent)
         self.parent = parent
-        self.setWindowTitle(u"{0} {1}: Add New EInk Kindle Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
+        self.setWindowTitle("{0} {1}: Add New EInk Kindle Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
         layout = QVBoxLayout(self)
         self.setLayout(layout)
 
@@ -864,9 +852,9 @@ class AddSerialDialog(QDialog):
 
         key_group = QHBoxLayout()
         data_group_box_layout.addLayout(key_group)
-        key_group.addWidget(QLabel(u"EInk Kindle Serial Number:", self))
+        key_group.addWidget(QLabel("EInk Kindle Serial Number:", self))
         self.key_ledit = QLineEdit("", self)
-        self.key_ledit.setToolTip(u"Enter an eInk Kindle serial number. EInk Kindle serial numbers are 16 characters long and usually start with a 'B' or a '9'. Kindle Serial Numbers are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
+        self.key_ledit.setToolTip("Enter an eInk Kindle serial number. EInk Kindle serial numbers are 16 characters long and usually start with a 'B' or a '9'. Kindle Serial Numbers are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
         key_group.addWidget(self.key_ledit)
 
         self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
@@ -886,10 +874,10 @@ class AddSerialDialog(QDialog):
 
     def accept(self):
         if len(self.key_name) == 0 or self.key_name.isspace():
-            errmsg = u"Please enter an eInk Kindle Serial Number or click Cancel in the dialog."
+            errmsg = "Please enter an eInk Kindle Serial Number or click Cancel in the dialog."
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         if len(self.key_name) != 16:
-            errmsg = u"EInk Kindle Serial Numbers must be 16 characters long. This is {0:d} characters long.".format(len(self.key_name))
+            errmsg = "EInk Kindle Serial Numbers must be 16 characters long. This is {0:d} characters long.".format(len(self.key_name))
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         QDialog.accept(self)
 
@@ -899,7 +887,7 @@ class AddAndroidDialog(QDialog):
 
         QDialog.__init__(self, parent)
         self.parent = parent
-        self.setWindowTitle(u"{0} {1}: Add new Kindle for Android Key".format(PLUGIN_NAME, PLUGIN_VERSION))
+        self.setWindowTitle("{0} {1}: Add new Kindle for Android Key".format(PLUGIN_NAME, PLUGIN_VERSION))
         layout = QVBoxLayout(self)
         self.setLayout(layout)
         self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
@@ -911,8 +899,8 @@ class AddAndroidDialog(QDialog):
 
         file_group = QHBoxLayout()
         data_group_box_layout.addLayout(file_group)
-        add_btn = QPushButton(u"Choose Backup File", self)
-        add_btn.setToolTip(u"Import Kindle for Android backup file.")
+        add_btn = QPushButton("Choose Backup File", self)
+        add_btn.setToolTip("Import Kindle for Android backup file.")
         add_btn.clicked.connect(self.get_android_file)
         file_group.addWidget(add_btn)
         self.selected_file_name = QLabel(u"",self)
@@ -921,9 +909,9 @@ class AddAndroidDialog(QDialog):
 
         key_group = QHBoxLayout()
         data_group_box_layout.addLayout(key_group)
-        key_group.addWidget(QLabel(u"Unique Key Name:", self))
+        key_group.addWidget(QLabel("Unique Key Name:", self))
         self.key_ledit = QLineEdit(u"", self)
-        self.key_ledit.setToolTip(u"<p>Enter an identifying name for the Android for Kindle key.")
+        self.key_ledit.setToolTip("<p>Enter an identifying name for the Android for Kindle key.")
         key_group.addWidget(self.key_ledit)
         #key_label = QLabel(_(''), self)
         #key_label.setAlignment(Qt.AlignHCenter)
@@ -947,9 +935,9 @@ class AddAndroidDialog(QDialog):
         return self.serials_from_file
 
     def get_android_file(self):
-        unique_dlg_name = PLUGIN_NAME + u"Import Kindle for Android backup file" #takes care of automatically remembering last directory
-        caption = u"Select Kindle for Android backup file to add"
-        filters = [(u"Kindle for Android backup files", ['db','ab','xml'])]
+        unique_dlg_name = PLUGIN_NAME + "Import Kindle for Android backup file" #takes care of automatically remembering last directory
+        caption = "Select Kindle for Android backup file to add"
+        filters = [("Kindle for Android backup files", ['db','ab','xml'])]
         files = choose_files(self, unique_dlg_name, caption, filters, all_files=False)
         self.serials_from_file = []
         file_name = u""
@@ -967,13 +955,13 @@ class AddAndroidDialog(QDialog):
 
     def accept(self):
         if len(self.file_name) == 0 or len(self.key_value) == 0:
-            errmsg = u"Please choose a Kindle for Android backup file."
+            errmsg = "Please choose a Kindle for Android backup file."
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         if len(self.key_name) == 0 or self.key_name.isspace():
-            errmsg = u"Please enter a key name."
+            errmsg = "Please enter a key name."
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         if len(self.key_name) < 4:
-            errmsg = u"Key name must be at <i>least</i> 4 characters long!"
+            errmsg = "Key name must be at <i>least</i> 4 characters long!"
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         QDialog.accept(self)
 
@@ -981,7 +969,7 @@ class AddPIDDialog(QDialog):
     def __init__(self, parent=None,):
         QDialog.__init__(self, parent)
         self.parent = parent
-        self.setWindowTitle(u"{0} {1}: Add New Mobipocket PID".format(PLUGIN_NAME, PLUGIN_VERSION))
+        self.setWindowTitle("{0} {1}: Add New Mobipocket PID".format(PLUGIN_NAME, PLUGIN_VERSION))
         layout = QVBoxLayout(self)
         self.setLayout(layout)
 
@@ -992,9 +980,9 @@ class AddPIDDialog(QDialog):
 
         key_group = QHBoxLayout()
         data_group_box_layout.addLayout(key_group)
-        key_group.addWidget(QLabel(u"PID:", self))
+        key_group.addWidget(QLabel("PID:", self))
         self.key_ledit = QLineEdit("", self)
-        self.key_ledit.setToolTip(u"Enter a Mobipocket PID. Mobipocket PIDs are 8 or 10 characters long. Mobipocket PIDs are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
+        self.key_ledit.setToolTip("Enter a Mobipocket PID. Mobipocket PIDs are 8 or 10 characters long. Mobipocket PIDs are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
         key_group.addWidget(self.key_ledit)
 
         self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
@@ -1014,10 +1002,10 @@ class AddPIDDialog(QDialog):
 
     def accept(self):
         if len(self.key_name) == 0 or self.key_name.isspace():
-            errmsg = u"Please enter a Mobipocket PID or click Cancel in the dialog."
+            errmsg = "Please enter a Mobipocket PID or click Cancel in the dialog."
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         if len(self.key_name) != 8 and len(self.key_name) != 10:
-            errmsg = u"Mobipocket PIDs must be 8 or 10 characters long. This is {0:d} characters long.".format(len(self.key_name))
+            errmsg = "Mobipocket PIDs must be 8 or 10 characters long. This is {0:d} characters long.".format(len(self.key_name))
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         QDialog.accept(self)
 
index aa794b1f68175256a57cf1b4da10345259692d19..a0bf188216f010de9e87e8549d1b8a30a841a532 100644 (file)
@@ -1,15 +1,16 @@
-#! /usr/bin/python
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
+
 # For use with Topaz Scripts Version 2.6
-# Added Python 3 compatibility, September 2020
+# Python 3, September 2020
 
-from __future__ import print_function
 class Unbuffered:
     def __init__(self, stream):
         self.stream = stream
     def write(self, data):
-        self.stream.write(data)
-        self.stream.flush()
+        self.stream.buffer.write(data)
+        self.stream.buffer.flush()
     def __getattr__(self, attr):
         return getattr(self.stream, attr)
 
diff --git a/DeDRM_plugin/encodebase64.py b/DeDRM_plugin/encodebase64.py
deleted file mode 100644 (file)
index cfe0d26..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# base64.py, version 1.0
-# Copyright © 2010 Apprentice Alf
-
-# Released under the terms of the GNU General Public Licence, version 3 or
-# later.  <http://www.gnu.org/licenses/>
-
-# Revision history:
-#   1 - Initial release. To allow Applescript to do base64 encoding
-
-"""
-Provide base64 encoding.
-"""
-
-from __future__ import with_statement
-from __future__ import print_function
-
-__license__ = 'GPL v3'
-
-import sys
-import os
-import base64
-
-def usage(progname):
-    print("Applies base64 encoding to the supplied file, sending to standard output")
-    print("Usage:")
-    print("    %s <infile>" % progname)
-
-def cli_main(argv=sys.argv):
-    progname = os.path.basename(argv[0])
-
-    if len(argv)<2:
-        usage(progname)
-        sys.exit(2)
-
-    keypath = argv[1]
-    with open(keypath, 'rb') as f:
-        keyder = f.read()
-        print(keyder.encode('base64'))
-    return 0
-
-
-if __name__ == '__main__':
-    sys.exit(cli_main())
index 1a08e61acc2f2afd6f64137d0d0711438a897f5a..baede6aba9a53a1f0b05d4b330cf916d6fd745f0 100644 (file)
@@ -1,4 +1,5 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 #
 # This is a python script. You need a Python interpreter to run it.
 # For example, ActiveState Python, which exists for windows.
@@ -10,7 +11,7 @@
 # Changelog epubtest
 #  1.00 - Cut to epubtest.py, testing ePub files only by Apprentice Alf
 #  1.01 - Added routine for use by Windows DeDRM
-#  2.00 - Added Python 3 compatibility, September 2020
+#  2.00 - Python 3, September 2020
 #
 # Written in 2011 by Paul Durrant
 # Released with unlicense. See http://unlicense.org/
@@ -45,9 +46,6 @@
 # It's still polite to give attribution if you do reuse this code.
 #
 
-from __future__ import with_statement
-from __future__ import print_function
-
 __version__ = '2.0'
 
 import sys, struct, os, traceback
@@ -112,7 +110,7 @@ def unicode_argv():
                     xrange(start, argc.value)]
         # if we don't have any arguments at all, just pass back script name
         # this should never happen
-        return [u"epubtest.py"]
+        return ["epubtest.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
index b02a494a6994e3bfddc1490bbce224275ebbc6fa..401fecc6e8f02b5d7c232a4067affe9fe58918b8 100644 (file)
@@ -1,13 +1,9 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 # erdr2pml.py
-# Copyright © 2008 The Dark Reverser
+# Copyright © 2008-2020 The Dark Reverser, Apprentice Harper et al.
 #
-# Modified 2008–2012 by some_updates, DiapDealer and Apprentice Alf
-
-# This is a python script. You need a Python interpreter to run it.
-# For example, ActiveState Python, which exists for windows.
 # Changelog
 #
 #  Based on ereader2html version 0.08 plus some later small fixes
@@ -89,10 +85,10 @@ class SafeUnbuffered:
         if self.encoding == None:
             self.encoding = "utf-8"
     def write(self, data):
-        if isinstance(data,bytes):
+        if isinstance(data,str):
             data = data.encode(self.encoding,"replace")
-        self.stream.write(data)
-        self.stream.flush()
+        self.stream.buffer.write(data)
+        self.stream.buffer.flush()
     def __getattr__(self, attr):
         return getattr(self.stream, attr)
 
@@ -130,7 +126,7 @@ def unicode_argv():
                     range(start, argc.value)]
         # if we don't have any arguments at all, just pass back script name
         # this should never happen
-        return [u"mobidedrm.py"]
+        return ["mobidedrm.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -230,16 +226,16 @@ class Sectionizer(object):
 # and with some (heavily edited) code from Paul Durrant's kindlenamer.py
 def sanitizeFileName(name):
     # substitute filename unfriendly characters
-    name = name.replace(u"<",u"[").replace(u">",u"]").replace(u" : ",u" – ").replace(u": ",u" – ").replace(u":",u"—").replace(u"/",u"_").replace(u"\\",u"_").replace(u"|",u"_").replace(u"\"",u"\'")
+    name = name.replace("<","[").replace(">","]").replace(" : "," – ").replace(": "," – ").replace(":","—").replace("/","_").replace("\\","_").replace("|","_").replace("\"","\'")
     # delete control characters
-    name = u"".join(char for char in name if ord(char)>=32)
+    name = "".join(char for char in name if ord(char)>=32)
     # white space to single space, delete leading and trailing while space
-    name = re.sub(r"\s", u" ", name).strip()
+    name = re.sub(r"\s", " ", name).strip()
     # remove leading dots
-    while len(name)>0 and name[0] == u".":
+    while len(name)>0 and name[0] == ".":
         name = name[1:]
     # remove trailing dots (Windows doesn't like them)
-    if name.endswith(u'.'):
+    if name.endswith("."):
         name = name[:-1]
     return name
 
@@ -472,35 +468,35 @@ def decryptBook(infile, outpath, make_pmlz, user_key):
         # outpath is actually pmlz name
         pmlzname = outpath
         outdir = tempfile.mkdtemp()
-        imagedirpath = os.path.join(outdir,u"images")
+        imagedirpath = os.path.join(outdir,"images")
     else:
         pmlzname = None
         outdir = outpath
-        imagedirpath = os.path.join(outdir,bookname + u"_img")
+        imagedirpath = os.path.join(outdir,bookname + "_img")
 
     try:
         if not os.path.exists(outdir):
             os.makedirs(outdir)
-        print(u"Decoding File")
-        sect Sectionizer(infile, 'PNRdPPrs')
+        print("Decoding File")
+        sect  =Sectionizer(infile, 'PNRdPPrs')
         er = EreaderProcessor(sect, user_key)
 
         if er.getNumImages() > 0:
-            print(u"Extracting images")
+            print("Extracting images")
             if not os.path.exists(imagedirpath):
                 os.makedirs(imagedirpath)
             for i in range(er.getNumImages()):
                 name, contents = er.getImage(i)
                 open(os.path.join(imagedirpath, name), 'wb').write(contents)
 
-        print(u"Extracting pml")
+        print("Extracting pml")
         pml_string = er.getText()
         pmlfilename = bookname + ".pml"
         open(os.path.join(outdir, pmlfilename),'wb').write(cleanPML(pml_string))
         if pmlzname is not None:
             import zipfile
             import shutil
-            print(u"Creating PMLZ file {0}".format(os.path.basename(pmlzname)))
+            print("Creating PMLZ file {0}".format(os.path.basename(pmlzname)))
             myZipFile = zipfile.ZipFile(pmlzname,'w',zipfile.ZIP_STORED, False)
             list = os.listdir(outdir)
             for filename in list:
@@ -519,33 +515,33 @@ def decryptBook(infile, outpath, make_pmlz, user_key):
             myZipFile.close()
             # remove temporary directory
             shutil.rmtree(outdir, True)
-            print(u"Output is {0}".format(pmlzname))
-        else :
-            print(u"Output is in {0}".format(outdir))
+            print("Output is {0}".format(pmlzname))
+        else 
+            print("Output is in {0}".format(outdir))
         print("done")
     except ValueError as e:
-        print(u"Error: {0}".format(e))
+        print("Error: {0}".format(e))
         traceback.print_exc()
         return 1
     return 0
 
 
 def usage():
-    print(u"Converts DRMed eReader books to PML Source")
-    print(u"Usage:")
-    print(u"  erdr2pml [options] infile.pdb [outpath] \"your name\" credit_card_number")
-    print(u" ")
-    print(u"Options: ")
-    print(u"  -h             prints this message")
-    print(u"  -p             create PMLZ instead of source folder")
-    print(u"  --make-pmlz    create PMLZ instead of source folder")
-    print(u" ")
-    print(u"Note:")
-    print(u"  if outpath is ommitted, creates source in 'infile_Source' folder")
-    print(u"  if outpath is ommitted and pmlz option, creates PMLZ 'infile.pmlz'")
-    print(u"  if source folder created, images are in infile_img folder")
-    print(u"  if pmlz file created, images are in images folder")
-    print(u"  It's enough to enter the last 8 digits of the credit card number")
+    print("Converts DRMed eReader books to PML Source")
+    print("Usage:")
+    print("  erdr2pml [options] infile.pdb [outpath] \"your name\" credit_card_number")
+    print(" ")
+    print("Options: ")
+    print("  -h             prints this message")
+    print("  -p             create PMLZ instead of source folder")
+    print("  --make-pmlz    create PMLZ instead of source folder")
+    print(" ")
+    print("Note:")
+    print("  if outpath is ommitted, creates source in 'infile_Source' folder")
+    print("  if outpath is ommitted and pmlz option, creates PMLZ 'infile.pmlz'")
+    print("  if source folder created, images are in infile_img folder")
+    print("  if pmlz file created, images are in images folder")
+    print("  It's enough to enter the last 8 digits of the credit card number")
     return
 
 def getuser_key(name,cc):
@@ -554,7 +550,7 @@ def getuser_key(name,cc):
     return struct.pack('>LL', binascii.crc32(newname) & 0xffffffff,binascii.crc32(cc[-8:])& 0xffffffff)
 
 def cli_main():
-    print(u"eRdr2Pml v{0}. Copyright © 2009–2012 The Dark Reverser et al.".format(__version__))
+    print("eRdr2Pml v{0}. Copyright © 2009–2020 The Dark Reverser et al.".format(__version__))
 
     argv=unicode_argv()
     try:
@@ -580,9 +576,9 @@ def cli_main():
     if len(args)==3:
         infile, name, cc = args
         if make_pmlz:
-            outpath = os.path.splitext(infile)[0] + u".pmlz"
+            outpath = os.path.splitext(infile)[0] + ".pmlz"
         else:
-            outpath = os.path.splitext(infile)[0] + u"_Source"
+            outpath = os.path.splitext(infile)[0] + "_Source"
     elif len(args)==4:
         infile, outpath, name, cc = args
 
index 6667e4937c35385297351c607d87ee64636bf608..791bc5e309867e7c21ff20320aac64f4a8cdb3e8 100644 (file)
@@ -1,16 +1,14 @@
-#! /usr/bin/python
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
-# Added Python 3 compatibility for calibre 5.0
-
-from __future__ import print_function
-from .convert2xml import encodeNumber
+# Python 3 for calibre 5.0
 
 class Unbuffered:
     def __init__(self, stream):
         self.stream = stream
     def write(self, data):
-        self.stream.write(data)
-        self.stream.flush()
+        self.stream.buffer.write(data)
+        self.stream.buffer.flush()
     def __getattr__(self, attr):
         return getattr(self.stream, attr)
 
index 9ec9459f96c0ebb36712b2c65c4bf8faeea4f671..d10b20960b343fb83e820e89284b25ab111f79d2 100644 (file)
@@ -1,28 +1,13 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-from __future__ import print_function
-
-# ignobleepub.pyw, version 4.1
-# Copyright © 2009-2010 by i♥cabbages
+# ignobleepub.py
+# Copyright © 2009-2020 by i♥cabbages, Apprentice Harper et al.
 
 # Released under the terms of the GNU General Public Licence, version 3
 # <http://www.gnu.org/licenses/>
 
-# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf
-# Modified 2015–2017 by Apprentice Harper
-
-# Windows users: Before running this program, you must first install Python 2.6
-#   from <http://www.python.org/download/> and PyCrypto from
-#   <http://www.voidspace.org.uk/python/modules.shtml#pycrypto> (make sure to
-#   install the version for Python 2.6).  Save this script file as
-#   ineptepub.pyw and double-click on it to run it.
 #
-# Mac OS X users: Save this script file as ineptepub.pyw.  You can run this
-#   program from the command line (pythonw ineptepub.pyw) or by double-clicking
-#   it when it has been associated with PythonLauncher.
-
 # Revision history:
 #   1 - Initial release
 #   2 - Added OS X support by using OpenSSL when available
@@ -38,7 +23,7 @@ from __future__ import print_function
 #   3.9 - moved unicode_argv call inside main for Windows DeDRM compatibility
 #   4.0 - Work if TkInter is missing
 #   4.1 - Import tkFileDialog, don't assume something else will import it.
-#   5.0 - Added Python 3 compatibility for calibre 5.0
+#   5.0 - Python 3 for calibre 5.0
 
 """
 Decrypt Barnes & Noble encrypted ePub books.
@@ -66,10 +51,10 @@ class SafeUnbuffered:
         if self.encoding == None:
             self.encoding = "utf-8"
     def write(self, data):
-        if isinstance(data,bytes):
+        if isinstance(data,str):
             data = data.encode(self.encoding,"replace")
-        self.stream.write(data)
-        self.stream.flush()
+        self.stream.buffer.write(data)
+        self.stream.buffer.flush()
     def __getattr__(self, attr):
         return getattr(self.stream, attr)
 
@@ -108,7 +93,7 @@ def unicode_argv():
             start = argc.value - len(sys.argv)
             return [argv[i] for i in
                     range(start, argc.value)]
-        return [u"ineptepub.py"]
+        return ["ineptepub.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -257,14 +242,14 @@ def ignobleBook(inpath):
 
 def decryptBook(keyb64, inpath, outpath):
     if AES is None:
-        raise IGNOBLEError(u"PyCrypto or OpenSSL must be installed.")
+        raise IGNOBLEError("PyCrypto or OpenSSL must be installed.")
     key = keyb64.decode('base64')[:16]
     aes = AES(key)
     with closing(ZipFile(open(inpath, 'rb'))) as inf:
         namelist = set(inf.namelist())
         if 'META-INF/rights.xml' not in namelist or \
            'META-INF/encryption.xml' not in namelist:
-            print(u"{0:s} is DRM-free.".format(os.path.basename(inpath)))
+            print("{0:s} is DRM-free.".format(os.path.basename(inpath)))
             return 1
         for name in META_NAMES:
             namelist.remove(name)
@@ -274,7 +259,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("{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])]
@@ -317,7 +302,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("Could not decrypt {0:s} because of an exception:\n{1:s}".format(os.path.basename(inpath), traceback.format_exc()))
             return 2
     return 0
 
@@ -328,13 +313,13 @@ def cli_main():
     argv=unicode_argv()
     progname = os.path.basename(argv[0])
     if len(argv) != 4:
-        print(u"usage: {0} <keyfile.b64> <inbook.epub> <outbook.epub>".format(progname))
+        print("usage: {0} <keyfile.b64> <inbook.epub> <outbook.epub>".format(progname))
         return 1
     keypath, inpath, outpath = argv[1:]
     userkey = open(keypath,'rb').read()
     result = decryptBook(userkey, inpath, outpath)
     if result == 0:
-        print(u"Successfully decrypted {0:s} as {1:s}".format(os.path.basename(inpath),os.path.basename(outpath)))
+        print("Successfully decrypted {0:s} as {1:s}".format(os.path.basename(inpath),os.path.basename(outpath)))
     return result
 
 def gui_main():
@@ -350,43 +335,43 @@ def gui_main():
     class DecryptionDialog(Tkinter.Frame):
         def __init__(self, root):
             Tkinter.Frame.__init__(self, root, border=5)
-            self.status = Tkinter.Label(self, text=u"Select files for decryption")
+            self.status = Tkinter.Label(self, text="Select files for decryption")
             self.status.pack(fill=Tkconstants.X, expand=1)
             body = Tkinter.Frame(self)
             body.pack(fill=Tkconstants.X, expand=1)
             sticky = Tkconstants.E + Tkconstants.W
             body.grid_columnconfigure(1, weight=2)
-            Tkinter.Label(body, text=u"Key file").grid(row=0)
+            Tkinter.Label(body, text="Key file").grid(row=0)
             self.keypath = Tkinter.Entry(body, width=30)
             self.keypath.grid(row=0, column=1, sticky=sticky)
-            if os.path.exists(u"bnepubkey.b64"):
-                self.keypath.insert(0, u"bnepubkey.b64")
-            button = Tkinter.Button(body, text=u"...", command=self.get_keypath)
+            if os.path.exists("bnepubkey.b64"):
+                self.keypath.insert(0, "bnepubkey.b64")
+            button = Tkinter.Button(body, text="...", command=self.get_keypath)
             button.grid(row=0, column=2)
-            Tkinter.Label(body, text=u"Input file").grid(row=1)
+            Tkinter.Label(body, text="Input file").grid(row=1)
             self.inpath = Tkinter.Entry(body, width=30)
             self.inpath.grid(row=1, column=1, sticky=sticky)
-            button = Tkinter.Button(body, text=u"...", command=self.get_inpath)
+            button = Tkinter.Button(body, text="...", command=self.get_inpath)
             button.grid(row=1, column=2)
-            Tkinter.Label(body, text=u"Output file").grid(row=2)
+            Tkinter.Label(body, text="Output file").grid(row=2)
             self.outpath = Tkinter.Entry(body, width=30)
             self.outpath.grid(row=2, column=1, sticky=sticky)
-            button = Tkinter.Button(body, text=u"...", command=self.get_outpath)
+            button = Tkinter.Button(body, text="...", command=self.get_outpath)
             button.grid(row=2, column=2)
             buttons = Tkinter.Frame(self)
             buttons.pack()
             botton = Tkinter.Button(
-                buttons, text=u"Decrypt", width=10, command=self.decrypt)
+                buttons, text="Decrypt", width=10, command=self.decrypt)
             botton.pack(side=Tkconstants.LEFT)
             Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT)
             button = Tkinter.Button(
-                buttons, text=u"Quit", width=10, command=self.quit)
+                buttons, text="Quit", width=10, command=self.quit)
             button.pack(side=Tkconstants.RIGHT)
 
         def get_keypath(self):
             keypath = tkFileDialog.askopenfilename(
-                parent=None, title=u"Select Barnes & Noble \'.b64\' key file",
-                defaultextension=u".b64",
+                parent=None, title="Select Barnes & Noble \'.b64\' key file",
+                defaultextension=".b64",
                 filetypes=[('base64-encoded files', '.b64'),
                            ('All Files', '.*')])
             if keypath:
@@ -397,8 +382,8 @@ def gui_main():
 
         def get_inpath(self):
             inpath = tkFileDialog.askopenfilename(
-                parent=None, title=u"Select B&N-encrypted ePub file to decrypt",
-                defaultextension=u".epub", filetypes=[('ePub files', '.epub')])
+                parent=None, title="Select B&N-encrypted ePub file to decrypt",
+                defaultextension=".epub", filetypes=[('ePub files', '.epub')])
             if inpath:
                 inpath = os.path.normpath(inpath)
                 self.inpath.delete(0, Tkconstants.END)
@@ -407,8 +392,8 @@ def gui_main():
 
         def get_outpath(self):
             outpath = tkFileDialog.asksaveasfilename(
-                parent=None, title=u"Select unencrypted ePub file to produce",
-                defaultextension=u".epub", filetypes=[('ePub files', '.epub')])
+                parent=None, title="Select unencrypted ePub file to produce",
+                defaultextension=".epub", filetypes=[('ePub files', '.epub')])
             if outpath:
                 outpath = os.path.normpath(outpath)
                 self.outpath.delete(0, Tkconstants.END)
@@ -420,31 +405,31 @@ def gui_main():
             inpath = self.inpath.get()
             outpath = self.outpath.get()
             if not keypath or not os.path.exists(keypath):
-                self.status['text'] = u"Specified key file does not exist"
+                self.status['text'] = "Specified key file does not exist"
                 return
             if not inpath or not os.path.exists(inpath):
-                self.status['text'] = u"Specified input file does not exist"
+                self.status['text'] = "Specified input file does not exist"
                 return
             if not outpath:
-                self.status['text'] = u"Output file not specified"
+                self.status['text'] = "Output file not specified"
                 return
             if inpath == outpath:
-                self.status['text'] = u"Must have different input and output files"
+                self.status['text'] = "Must have different input and output files"
                 return
             userkey = open(keypath,'rb').read()
-            self.status['text'] = u"Decrypting..."
+            self.status['text'] = "Decrypting..."
             try:
                 decrypt_status = decryptBook(userkey, inpath, outpath)
             except Exception as e:
-                self.status['text'] = u"Error: {0}".format(e.args[0])
+                self.status['text'] = "Error: {0}".format(e.args[0])
                 return
             if decrypt_status == 0:
-                self.status['text'] = u"File successfully decrypted"
+                self.status['text'] = "File successfully decrypted"
             else:
-                self.status['text'] = u"The was an error decrypting the file."
+                self.status['text'] = "The was an error decrypting the file."
 
     root = Tkinter.Tk()
-    root.title(u"Barnes & Noble ePub Decrypter v.{0}".format(__version__))
+    root.title("Barnes & Noble ePub Decrypter v.{0}".format(__version__))
     root.resizable(True, False)
     root.minsize(300, 0)
     DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1)
index 0b3e60f2379167ada7bfc380e9e74f045311ba58..b47a07a445f9fd79bf1d6597cd131796403bee8b 100644 (file)
@@ -1,9 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-from __future__ import print_function
-
 # ignoblekey.py
 # Copyright © 2015-2020 Apprentice Alf, Apprentice Harper et al.
 
@@ -15,7 +12,7 @@ from __future__ import print_function
 # Revision history:
 #   1.0 - Initial release
 #   1.1 - remove duplicates and return last key as single key
-#   2.0 - Added Python 3 compatibility for calibre 5.0
+#   2.0 - Python 3 for calibre 5.0
 
 """
 Get Barnes & Noble EPUB user key from nook Studio log file
@@ -40,10 +37,10 @@ class SafeUnbuffered:
         if self.encoding == None:
             self.encoding = "utf-8"
     def write(self, data):
-        if isinstance(data,bytes):
+        if isinstance(data,str):
             data = data.encode(self.encoding,"replace")
-        self.stream.write(data)
-        self.stream.flush()
+        self.stream.buffer.write(data)
+        self.stream.buffer.flush()
     def __getattr__(self, attr):
         return getattr(self.stream, attr)
 
@@ -84,7 +81,7 @@ def unicode_argv():
                     range(start, argc.value)]
         # if we don't have any arguments at all, just pass back script name
         # this should never happen
-        return [u"ignoblekey.py"]
+        return ["ignoblekey.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -106,15 +103,15 @@ def getNookLogFiles():
         paths = set()
         if 'LOCALAPPDATA' in os.environ.keys():
             # Python 2.x does not return unicode env. Use Python 3.x
-            path = winreg.ExpandEnvironmentStrings(u"%LOCALAPPDATA%")
+            path = winreg.ExpandEnvironmentStrings("%LOCALAPPDATA%")
             if os.path.isdir(path):
                 paths.add(path)
         if 'USERPROFILE' in os.environ.keys():
             # Python 2.x does not return unicode env. Use Python 3.x
-            path = winreg.ExpandEnvironmentStrings(u"%USERPROFILE%")+u"\\AppData\\Local"
+            path = winreg.ExpandEnvironmentStrings("%USERPROFILE%")+"\\AppData\\Local"
             if os.path.isdir(path):
                 paths.add(path)
-            path = winreg.ExpandEnvironmentStrings(u"%USERPROFILE%")+u"\\AppData\\Roaming"
+            path = winreg.ExpandEnvironmentStrings("%USERPROFILE%")+"\\AppData\\Roaming"
             if os.path.isdir(path):
                 paths.add(path)
         # User Shell Folders show take precedent over Shell Folders if present
@@ -200,7 +197,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("Found {0} keys in the Nook Study log files".format(len(fileKeys)))
             keys.extend(fileKeys)
     return list(set(keys))
 
@@ -213,27 +210,27 @@ def getkey(outpath, files=[]):
             outfile = outpath
             with open(outfile, 'w') as keyfileout:
                 keyfileout.write(keys[-1])
-            print(u"Saved a key to {0}".format(outfile))
+            print("Saved a key to {0}".format(outfile))
         else:
             keycount = 0
             for key in keys:
                 while True:
                     keycount += 1
-                    outfile = os.path.join(outpath,u"nookkey{0:d}.b64".format(keycount))
+                    outfile = os.path.join(outpath,"nookkey{0:d}.b64".format(keycount))
                     if not os.path.exists(outfile):
                         break
                 with open(outfile, 'w') as keyfileout:
                     keyfileout.write(key)
-                print(u"Saved a key to {0}".format(outfile))
+                print("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 <logFile>] [<outpath>]".format(progname))
+    print("Finds the nook Study encryption keys.")
+    print("Keys are saved to the current directory, or a specified output directory.")
+    print("If a file name is passed instead of a directory, only the first key is saved, in that file.")
+    print("Usage:")
+    print("    {0:s} [-h] [-k <logFile>] [<outpath>]".format(progname))
 
 
 def cli_main():
@@ -241,12 +238,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("{0} v{1}\nCopyright © 2015 Apprentice Alf".format(progname,__version__))
 
     try:
         opts, args = getopt.getopt(argv[1:], "hk:")
     except getopt.GetoptError as err:
-        print(u"Error in options or arguments: {0}".format(err.args[0]))
+        print("Error in options or arguments: {0}".format(err.args[0]))
         usage(progname)
         sys.exit(2)
 
@@ -275,7 +272,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("Could not retrieve nook Study key.")
     return 0
 
 
@@ -291,7 +288,7 @@ def gui_main():
     class ExceptionDialog(Tkinter.Frame):
         def __init__(self, root, text):
             Tkinter.Frame.__init__(self, root, border=5)
-            label = Tkinter.Label(self, text=u"Unexpected error:",
+            label = Tkinter.Label(self, text="Unexpected error:",
                                   anchor=Tkconstants.W, justify=Tkconstants.LEFT)
             label.pack(fill=Tkconstants.X, expand=0)
             self.text = Tkinter.Text(self)
@@ -312,16 +309,16 @@ def gui_main():
             print(key)
             while True:
                 keycount += 1
-                outfile = os.path.join(progpath,u"nookkey{0:d}.b64".format(keycount))
+                outfile = os.path.join(progpath,"nookkey{0:d}.b64".format(keycount))
                 if not os.path.exists(outfile):
                     break
 
             with open(outfile, 'w') as keyfileout:
                 keyfileout.write(key)
             success = True
-            tkMessageBox.showinfo(progname, u"Key successfully retrieved to {0}".format(outfile))
+            tkMessageBox.showinfo(progname, "Key successfully retrieved to {0}".format(outfile))
     except DrmException as e:
-        tkMessageBox.showerror(progname, u"Error: {0}".format(str(e)))
+        tkMessageBox.showerror(progname, "Error: {0}".format(str(e)))
     except Exception:
         root.wm_state('normal')
         root.title(progname)
index ffaf153c625a2fcceade586e7d46feb96d402d3b..a844fd8d06a95ab347a5037e45defbe831b05b70 100644 (file)
@@ -1,10 +1,7 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-from __future__ import print_function
-
-# ignoblekeyfetch.pyw, version 2.0
+# ignoblekeyfetch.py
 # Copyright © 2015-2020 Apprentice Harper et al.
 
 # Released under the terms of the GNU General Public Licence, version 3
@@ -25,14 +22,14 @@ from __future__ import print_function
 # Revision history:
 #   1.0 - Initial  version
 #   1.1 - Try second URL if first one fails
-#   2.0 - Added Python 3 compatibility for calibre 5.0
+#   2.0 - Python 3 for calibre 5.0
 
 """
 Fetch Barnes & Noble EPUB user key from B&N servers using email and password
 """
 
 __license__ = 'GPL v3'
-__version__ = "1.1"
+__version__ = "2.0"
 
 import sys
 import os
@@ -91,7 +88,7 @@ def unicode_argv():
                     range(start, argc.value)]
         # if we don't have any arguments at all, just pass back script name
         # this should never happen
-        return [u"ignoblekeyfetch.py"]
+        return ["ignoblekeyfetch.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -157,14 +154,14 @@ def cli_main():
     argv=unicode_argv()
     progname = os.path.basename(argv[0])
     if len(argv) != 4:
-        print(u"usage: {0} <email> <password> <keyfileout.b64>".format(progname))
+        print("usage: {0} <email> <password> <keyfileout.b64>".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("Failed to fetch key.")
     return 1
 
 
@@ -181,38 +178,38 @@ def gui_main():
     class DecryptionDialog(Tkinter.Frame):
         def __init__(self, root):
             Tkinter.Frame.__init__(self, root, border=5)
-            self.status = Tkinter.Label(self, text=u"Enter parameters")
+            self.status = Tkinter.Label(self, text="Enter parameters")
             self.status.pack(fill=Tkconstants.X, expand=1)
             body = Tkinter.Frame(self)
             body.pack(fill=Tkconstants.X, expand=1)
             sticky = Tkconstants.E + Tkconstants.W
             body.grid_columnconfigure(1, weight=2)
-            Tkinter.Label(body, text=u"Account email address").grid(row=0)
+            Tkinter.Label(body, text="Account email address").grid(row=0)
             self.name = Tkinter.Entry(body, width=40)
             self.name.grid(row=0, column=1, sticky=sticky)
-            Tkinter.Label(body, text=u"Account password").grid(row=1)
+            Tkinter.Label(body, text="Account password").grid(row=1)
             self.ccn = Tkinter.Entry(body, width=40)
             self.ccn.grid(row=1, column=1, sticky=sticky)
-            Tkinter.Label(body, text=u"Output file").grid(row=2)
+            Tkinter.Label(body, text="Output file").grid(row=2)
             self.keypath = Tkinter.Entry(body, width=40)
             self.keypath.grid(row=2, column=1, sticky=sticky)
-            self.keypath.insert(2, u"bnepubkey.b64")
-            button = Tkinter.Button(body, text=u"...", command=self.get_keypath)
+            self.keypath.insert(2, "bnepubkey.b64")
+            button = Tkinter.Button(body, text="...", command=self.get_keypath)
             button.grid(row=2, column=2)
             buttons = Tkinter.Frame(self)
             buttons.pack()
             botton = Tkinter.Button(
-                buttons, text=u"Fetch", width=10, command=self.generate)
+                buttons, text="Fetch", width=10, command=self.generate)
             botton.pack(side=Tkconstants.LEFT)
             Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT)
             button = Tkinter.Button(
-                buttons, text=u"Quit", width=10, command=self.quit)
+                buttons, text="Quit", width=10, command=self.quit)
             button.pack(side=Tkconstants.RIGHT)
 
         def get_keypath(self):
             keypath = tkFileDialog.asksaveasfilename(
-                parent=None, title=u"Select B&N ePub key file to produce",
-                defaultextension=u".b64",
+                parent=None, title="Select B&N ePub key file to produce",
+                defaultextension=".b64",
                 filetypes=[('base64-encoded files', '.b64'),
                            ('All Files', '.*')])
             if keypath:
@@ -226,28 +223,28 @@ def gui_main():
             password = self.ccn.get()
             keypath = self.keypath.get()
             if not email:
-                self.status['text'] = u"Email address not given"
+                self.status['text'] = "Email address not given"
                 return
             if not password:
-                self.status['text'] = u"Account password not given"
+                self.status['text'] = "Account password not given"
                 return
             if not keypath:
-                self.status['text'] = u"Output keyfile path not set"
+                self.status['text'] = "Output keyfile path not set"
                 return
-            self.status['text'] = u"Fetching..."
+            self.status['text'] = "Fetching..."
             try:
                 userkey = fetch_key(email, password)
             except Exception as e:
-                self.status['text'] = u"Error: {0}".format(e.args[0])
+                self.status['text'] = "Error: {0}".format(e.args[0])
                 return
             if len(userkey) == 28:
                 open(keypath,'wb').write(userkey)
-                self.status['text'] = u"Keyfile fetched successfully"
+                self.status['text'] = "Keyfile fetched successfully"
             else:
-                self.status['text'] = u"Keyfile fetch failed."
+                self.status['text'] = "Keyfile fetch failed."
 
     root = Tkinter.Tk()
-    root.title(u"Barnes & Noble ePub Keyfile Fetch v.{0}".format(__version__))
+    root.title("Barnes & Noble ePub Keyfile Fetch v.{0}".format(__version__))
     root.resizable(True, False)
     root.minsize(300, 0)
     DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1)
index 3582f247681facdda85be853a4e2bd9a97eac729..489f2b9fac7529794f93a498fbcd4c7f56933f55 100644 (file)
@@ -1,10 +1,7 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-from __future__ import print_function
-
-# ignoblekeygen.pyw
+# ignoblekeygen.py
 # Copyright © 2009-2020 i♥cabbages, Apprentice Harper et al.
 
 # Released under the terms of the GNU General Public Licence, version 3
@@ -100,7 +97,7 @@ def unicode_argv():
                     range(start, argc.value)]
         # if we don't have any arguments at all, just pass back script name
         # this should never happen
-        return [u"ignoblekeygen.py"]
+        return ["ignoblekeygen.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -228,7 +225,7 @@ def cli_main():
               (progname,))
         return 1
     if len(argv) != 4:
-        print(u"usage: {0} <Name> <CC#> <keyfileout.b64>".format(progname))
+        print("usage: {0} <Name> <CC#> <keyfileout.b64>".format(progname))
         return 1
     name, ccn, keypath = argv[1:]
     userkey = generate_key(name, ccn)
@@ -249,38 +246,38 @@ def gui_main():
     class DecryptionDialog(Tkinter.Frame):
         def __init__(self, root):
             Tkinter.Frame.__init__(self, root, border=5)
-            self.status = Tkinter.Label(self, text=u"Enter parameters")
+            self.status = Tkinter.Label(self, text="Enter parameters")
             self.status.pack(fill=Tkconstants.X, expand=1)
             body = Tkinter.Frame(self)
             body.pack(fill=Tkconstants.X, expand=1)
             sticky = Tkconstants.E + Tkconstants.W
             body.grid_columnconfigure(1, weight=2)
-            Tkinter.Label(body, text=u"Account Name").grid(row=0)
+            Tkinter.Label(body, text="Account Name").grid(row=0)
             self.name = Tkinter.Entry(body, width=40)
             self.name.grid(row=0, column=1, sticky=sticky)
-            Tkinter.Label(body, text=u"CC#").grid(row=1)
+            Tkinter.Label(body, text="CC#").grid(row=1)
             self.ccn = Tkinter.Entry(body, width=40)
             self.ccn.grid(row=1, column=1, sticky=sticky)
-            Tkinter.Label(body, text=u"Output file").grid(row=2)
+            Tkinter.Label(body, text="Output file").grid(row=2)
             self.keypath = Tkinter.Entry(body, width=40)
             self.keypath.grid(row=2, column=1, sticky=sticky)
-            self.keypath.insert(2, u"bnepubkey.b64")
-            button = Tkinter.Button(body, text=u"...", command=self.get_keypath)
+            self.keypath.insert(2, "bnepubkey.b64")
+            button = Tkinter.Button(body, text="...", command=self.get_keypath)
             button.grid(row=2, column=2)
             buttons = Tkinter.Frame(self)
             buttons.pack()
             botton = Tkinter.Button(
-                buttons, text=u"Generate", width=10, command=self.generate)
+                buttons, text="Generate", width=10, command=self.generate)
             botton.pack(side=Tkconstants.LEFT)
             Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT)
             button = Tkinter.Button(
-                buttons, text=u"Quit", width=10, command=self.quit)
+                buttons, text="Quit", width=10, command=self.quit)
             button.pack(side=Tkconstants.RIGHT)
 
         def get_keypath(self):
             keypath = tkFileDialog.asksaveasfilename(
-                parent=None, title=u"Select B&N ePub key file to produce",
-                defaultextension=u".b64",
+                parent=None, title="Select B&N ePub key file to produce",
+                defaultextension=".b64",
                 filetypes=[('base64-encoded files', '.b64'),
                            ('All Files', '.*')])
             if keypath:
@@ -294,22 +291,22 @@ def gui_main():
             ccn = self.ccn.get()
             keypath = self.keypath.get()
             if not name:
-                self.status['text'] = u"Name not specified"
+                self.status['text'] = "Name not specified"
                 return
             if not ccn:
-                self.status['text'] = u"Credit card number not specified"
+                self.status['text'] = "Credit card number not specified"
                 return
             if not keypath:
-                self.status['text'] = u"Output keyfile path not specified"
+                self.status['text'] = "Output keyfile path not specified"
                 return
-            self.status['text'] = u"Generating..."
+            self.status['text'] = "Generating..."
             try:
                 userkey = generate_key(name, ccn)
             except Exception as e:
-                self.status['text'] = u"Error: (0}".format(e.args[0])
+                self.status['text'] = "Error: (0}".format(e.args[0])
                 return
             open(keypath,'wb').write(userkey)
-            self.status['text'] = u"Keyfile successfully generated"
+            self.status['text'] = "Keyfile successfully generated"
 
     root = Tkinter.Tk()
     if AES is None:
@@ -319,7 +316,7 @@ def gui_main():
             "This script requires OpenSSL or PyCrypto, which must be installed "
             "separately.  Read the top-of-script comment for details.")
         return 1
-    root.title(u"Barnes & Noble ePub Keyfile Generator v.{0}".format(__version__))
+    root.title("Barnes & Noble ePub Keyfile Generator v.{0}".format(__version__))
     root.resizable(True, False)
     root.minsize(300, 0)
     DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1)
index 5232b1d263878eb55e1db5a33f1efef0fae25fea..1546fa124819eda9e4407fdbd3579042d9d1a4b5 100644 (file)
@@ -1,7 +1,6 @@
-#! /usr/bin/python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
 
 # ignoblepdf.py
 # Copyright © 2009-2020 by Apprentice Harper et al.
@@ -14,6 +13,7 @@ from __future__ import with_statement
 
 # Revision history:
 #  0.1   - Initial alpha testing release 2020 by Pu D. Pud
+#  0.2   - Python 3 for calibre 5.0 (in testing)
 
 
 """
@@ -82,7 +82,7 @@ def unicode_argv():
             start = argc.value - len(sys.argv)
             return [argv[i] for i in
                     xrange(start, argc.value)]
-        return [u"ignoblepdf.py"]
+        return ["ignoblepdf.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -2005,12 +2005,12 @@ class PDFSerializer(object):
 
 def decryptBook(userkey, inpath, outpath):
     if AES is None:
-        raise IGNOBLEError(u"PyCrypto or OpenSSL must be installed.")
+        raise IGNOBLEError("PyCrypto or OpenSSL must be installed.")
     with open(inpath, 'rb') as inf:
         #try:
         serializer = PDFSerializer(inf, userkey)
         #except:
-        #    print u"Error serializing pdf {0}. Probably wrong key.".format(os.path.basename(inpath))
+        #    print "Error serializing pdf {0}. Probably wrong key.".format(os.path.basename(inpath))
         #    return 2
         # hope this will fix the 'bad file descriptor' problem
         with open(outpath, 'wb') as outf:
@@ -2018,7 +2018,7 @@ def decryptBook(userkey, inpath, outpath):
             try:
                 serializer.dump(outf)
             except Exception, e:
-                print u"error writing pdf: {0}".format(e.args[0])
+                print "error writing pdf: {0}".format(e.args[0])
                 return 2
     return 0
 
@@ -2029,13 +2029,13 @@ def cli_main():
     argv=unicode_argv()
     progname = os.path.basename(argv[0])
     if len(argv) != 4:
-        print u"usage: {0} <keyfile.b64> <inbook.pdf> <outbook.pdf>".format(progname)
+        print "usage: {0} <keyfile.b64> <inbook.pdf> <outbook.pdf>".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 "Successfully decrypted {0:s} as {1:s}".format(os.path.basename(inpath),os.path.basename(outpath))
     return result
 
 
@@ -2052,43 +2052,43 @@ def gui_main():
     class DecryptionDialog(Tkinter.Frame):
         def __init__(self, root):
             Tkinter.Frame.__init__(self, root, border=5)
-            self.status = Tkinter.Label(self, text=u"Select files for decryption")
+            self.status = Tkinter.Label(self, text="Select files for decryption")
             self.status.pack(fill=Tkconstants.X, expand=1)
             body = Tkinter.Frame(self)
             body.pack(fill=Tkconstants.X, expand=1)
             sticky = Tkconstants.E + Tkconstants.W
             body.grid_columnconfigure(1, weight=2)
-            Tkinter.Label(body, text=u"Key file").grid(row=0)
+            Tkinter.Label(body, text="Key file").grid(row=0)
             self.keypath = Tkinter.Entry(body, width=30)
             self.keypath.grid(row=0, column=1, sticky=sticky)
-            if os.path.exists(u"bnpdfkey.b64"):
-                self.keypath.insert(0, u"bnpdfkey.b64")
-            button = Tkinter.Button(body, text=u"...", command=self.get_keypath)
+            if os.path.exists("bnpdfkey.b64"):
+                self.keypath.insert(0, "bnpdfkey.b64")
+            button = Tkinter.Button(body, text="...", command=self.get_keypath)
             button.grid(row=0, column=2)
-            Tkinter.Label(body, text=u"Input file").grid(row=1)
+            Tkinter.Label(body, text="Input file").grid(row=1)
             self.inpath = Tkinter.Entry(body, width=30)
             self.inpath.grid(row=1, column=1, sticky=sticky)
-            button = Tkinter.Button(body, text=u"...", command=self.get_inpath)
+            button = Tkinter.Button(body, text="...", command=self.get_inpath)
             button.grid(row=1, column=2)
-            Tkinter.Label(body, text=u"Output file").grid(row=2)
+            Tkinter.Label(body, text="Output file").grid(row=2)
             self.outpath = Tkinter.Entry(body, width=30)
             self.outpath.grid(row=2, column=1, sticky=sticky)
-            button = Tkinter.Button(body, text=u"...", command=self.get_outpath)
+            button = Tkinter.Button(body, text="...", command=self.get_outpath)
             button.grid(row=2, column=2)
             buttons = Tkinter.Frame(self)
             buttons.pack()
             botton = Tkinter.Button(
-                buttons, text=u"Decrypt", width=10, command=self.decrypt)
+                buttons, text="Decrypt", width=10, command=self.decrypt)
             botton.pack(side=Tkconstants.LEFT)
             Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT)
             button = Tkinter.Button(
-                buttons, text=u"Quit", width=10, command=self.quit)
+                buttons, text="Quit", width=10, command=self.quit)
             button.pack(side=Tkconstants.RIGHT)
 
         def get_keypath(self):
             keypath = tkFileDialog.askopenfilename(
-                parent=None, title=u"Select Barnes & Noble \'.b64\' key file",
-                defaultextension=u".b64",
+                parent=None, title="Select Barnes & Noble \'.b64\' key file",
+                defaultextension=".b64",
                 filetypes=[('base64-encoded files', '.b64'),
                            ('All Files', '.*')])
             if keypath:
@@ -2099,8 +2099,8 @@ def gui_main():
 
         def get_inpath(self):
             inpath = tkFileDialog.askopenfilename(
-                parent=None, title=u"Select B&N-encrypted PDF file to decrypt",
-                defaultextension=u".pdf", filetypes=[('PDF files', '.pdf')])
+                parent=None, title="Select B&N-encrypted PDF file to decrypt",
+                defaultextension=".pdf", filetypes=[('PDF files', '.pdf')])
             if inpath:
                 inpath = os.path.normpath(inpath)
                 self.inpath.delete(0, Tkconstants.END)
@@ -2109,8 +2109,8 @@ def gui_main():
 
         def get_outpath(self):
             outpath = tkFileDialog.asksaveasfilename(
-                parent=None, title=u"Select unencrypted PDF file to produce",
-                defaultextension=u".pdf", filetypes=[('PDF files', '.pdf')])
+                parent=None, title="Select unencrypted PDF file to produce",
+                defaultextension=".pdf", filetypes=[('PDF files', '.pdf')])
             if outpath:
                 outpath = os.path.normpath(outpath)
                 self.outpath.delete(0, Tkconstants.END)
@@ -2122,28 +2122,28 @@ def gui_main():
             inpath = self.inpath.get()
             outpath = self.outpath.get()
             if not keypath or not os.path.exists(keypath):
-                self.status['text'] = u"Specified key file does not exist"
+                self.status['text'] = "Specified key file does not exist"
                 return
             if not inpath or not os.path.exists(inpath):
-                self.status['text'] = u"Specified input file does not exist"
+                self.status['text'] = "Specified input file does not exist"
                 return
             if not outpath:
-                self.status['text'] = u"Output file not specified"
+                self.status['text'] = "Output file not specified"
                 return
             if inpath == outpath:
-                self.status['text'] = u"Must have different input and output files"
+                self.status['text'] = "Must have different input and output files"
                 return
             userkey = open(keypath,'rb').read()
-            self.status['text'] = u"Decrypting..."
+            self.status['text'] = "Decrypting..."
             try:
                 decrypt_status = decryptBook(userkey, inpath, outpath)
             except Exception, e:
-                self.status['text'] = u"Error; {0}".format(e.args[0])
+                self.status['text'] = "Error; {0}".format(e.args[0])
                 return
             if decrypt_status == 0:
-                self.status['text'] = u"File successfully decrypted"
+                self.status['text'] = "File successfully decrypted"
             else:
-                self.status['text'] = u"The was an error decrypting the file."
+                self.status['text'] = "The was an error decrypting the file."
 
 
     root = Tkinter.Tk()
@@ -2154,7 +2154,7 @@ def gui_main():
             "This script requires OpenSSL or PyCrypto, which must be installed "
             "separately.  Read the top-of-script comment for details.")
         return 1
-    root.title(u"Barnes & Noble PDF Decrypter v.{0}".format(__version__))
+    root.title("Barnes & Noble PDF Decrypter v.{0}".format(__version__))
     root.resizable(True, False)
     root.minsize(370, 0)
     DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1)
index c0e4c393bd878bd2fe3ffaf0b2b249197dcd7e0a..f4b9ca3d75d2f3e634ad0e315556a1633351b1a3 100644 (file)
@@ -1,9 +1,7 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-
-# ineptepub.pyw
+# ineptepub.py
 # Copyright © 2009-2020 by i♥cabbages, Apprentice Harper et al.
 
 # Released under the terms of the GNU General Public Licence, version 3
@@ -102,7 +100,7 @@ def unicode_argv():
             start = argc.value - len(sys.argv)
             return [argv[i] for i in
                     range(start, argc.value)]
-        return [u"ineptepub.py"]
+        return ["ineptepub.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -393,13 +391,13 @@ def adeptBook(inpath):
 
 def decryptBook(userkey, inpath, outpath):
     if AES is None:
-        raise ADEPTError(u"PyCrypto or OpenSSL must be installed.")
+        raise ADEPTError("PyCrypto or OpenSSL must be installed.")
     rsa = RSA(userkey)
     with closing(ZipFile(open(inpath, 'rb'))) as inf:
         namelist = set(inf.namelist())
         if 'META-INF/rights.xml' not in namelist or \
            'META-INF/encryption.xml' not in namelist:
-            print(u"{0:s} is DRM-free.".format(os.path.basename(inpath)))
+            print("{0:s} is DRM-free.".format(os.path.basename(inpath)))
             return 1
         for name in META_NAMES:
             namelist.remove(name)
@@ -409,12 +407,12 @@ def decryptBook(userkey, inpath, outpath):
             expr = './/%s' % (adept('encryptedKey'),)
             bookkey = ''.join(rights.findtext(expr))
             if len(bookkey) != 172:
-                print(u"{0:s} is not a secure Adobe Adept ePub.".format(os.path.basename(inpath)))
+                print("{0:s} is not a secure Adobe Adept ePub.".format(os.path.basename(inpath)))
                 return 1
             bookkey = rsa.decrypt(codecs.decode(bookkey.encode('ascii'), 'base64'))
             # Padded as per RSAES-PKCS1-v1_5
             if bookkey[-17] != '\x00' and bookkey[-17] != 0:
-                print(u"Could not decrypt {0:s}. Wrong key".format(os.path.basename(inpath)))
+                print("Could not decrypt {0:s}. Wrong key".format(os.path.basename(inpath)))
                 return 2
             encryption = inf.read('META-INF/encryption.xml')
             decryptor = Decryptor(bookkey[-16:], encryption)
@@ -455,7 +453,7 @@ def decryptBook(userkey, 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("Could not decrypt {0:s} because of an exception:\n{1:s}".format(os.path.basename(inpath), traceback.format_exc()))
             return 2
     return 0
 
@@ -466,13 +464,13 @@ def cli_main():
     argv=unicode_argv()
     progname = os.path.basename(argv[0])
     if len(argv) != 4:
-        print(u"usage: {0} <keyfile.der> <inbook.epub> <outbook.epub>".format(progname))
+        print("usage: {0} <keyfile.der> <inbook.epub> <outbook.epub>".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("Successfully decrypted {0:s} as {1:s}".format(os.path.basename(inpath),os.path.basename(outpath)))
     return result
 
 def gui_main():
@@ -488,43 +486,43 @@ def gui_main():
     class DecryptionDialog(Tkinter.Frame):
         def __init__(self, root):
             Tkinter.Frame.__init__(self, root, border=5)
-            self.status = Tkinter.Label(self, text=u"Select files for decryption")
+            self.status = Tkinter.Label(self, text="Select files for decryption")
             self.status.pack(fill=Tkconstants.X, expand=1)
             body = Tkinter.Frame(self)
             body.pack(fill=Tkconstants.X, expand=1)
             sticky = Tkconstants.E + Tkconstants.W
             body.grid_columnconfigure(1, weight=2)
-            Tkinter.Label(body, text=u"Key file").grid(row=0)
+            Tkinter.Label(body, text="Key file").grid(row=0)
             self.keypath = Tkinter.Entry(body, width=30)
             self.keypath.grid(row=0, column=1, sticky=sticky)
-            if os.path.exists(u"adeptkey.der"):
-                self.keypath.insert(0, u"adeptkey.der")
-            button = Tkinter.Button(body, text=u"...", command=self.get_keypath)
+            if os.path.exists("adeptkey.der"):
+                self.keypath.insert(0, "adeptkey.der")
+            button = Tkinter.Button(body, text="...", command=self.get_keypath)
             button.grid(row=0, column=2)
-            Tkinter.Label(body, text=u"Input file").grid(row=1)
+            Tkinter.Label(body, text="Input file").grid(row=1)
             self.inpath = Tkinter.Entry(body, width=30)
             self.inpath.grid(row=1, column=1, sticky=sticky)
-            button = Tkinter.Button(body, text=u"...", command=self.get_inpath)
+            button = Tkinter.Button(body, text="...", command=self.get_inpath)
             button.grid(row=1, column=2)
-            Tkinter.Label(body, text=u"Output file").grid(row=2)
+            Tkinter.Label(body, text="Output file").grid(row=2)
             self.outpath = Tkinter.Entry(body, width=30)
             self.outpath.grid(row=2, column=1, sticky=sticky)
-            button = Tkinter.Button(body, text=u"...", command=self.get_outpath)
+            button = Tkinter.Button(body, text="...", command=self.get_outpath)
             button.grid(row=2, column=2)
             buttons = Tkinter.Frame(self)
             buttons.pack()
             botton = Tkinter.Button(
-                buttons, text=u"Decrypt", width=10, command=self.decrypt)
+                buttons, text="Decrypt", width=10, command=self.decrypt)
             botton.pack(side=Tkconstants.LEFT)
             Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT)
             button = Tkinter.Button(
-                buttons, text=u"Quit", width=10, command=self.quit)
+                buttons, text="Quit", width=10, command=self.quit)
             button.pack(side=Tkconstants.RIGHT)
 
         def get_keypath(self):
             keypath = tkFileDialog.askopenfilename(
-                parent=None, title=u"Select Adobe Adept \'.der\' key file",
-                defaultextension=u".der",
+                parent=None, title="Select Adobe Adept \'.der\' key file",
+                defaultextension=".der",
                 filetypes=[('Adobe Adept DER-encoded files', '.der'),
                            ('All Files', '.*')])
             if keypath:
@@ -535,8 +533,8 @@ def gui_main():
 
         def get_inpath(self):
             inpath = tkFileDialog.askopenfilename(
-                parent=None, title=u"Select ADEPT-encrypted ePub file to decrypt",
-                defaultextension=u".epub", filetypes=[('ePub files', '.epub')])
+                parent=None, title="Select ADEPT-encrypted ePub file to decrypt",
+                defaultextension=".epub", filetypes=[('ePub files', '.epub')])
             if inpath:
                 inpath = os.path.normpath(inpath)
                 self.inpath.delete(0, Tkconstants.END)
@@ -545,8 +543,8 @@ def gui_main():
 
         def get_outpath(self):
             outpath = tkFileDialog.asksaveasfilename(
-                parent=None, title=u"Select unencrypted ePub file to produce",
-                defaultextension=u".epub", filetypes=[('ePub files', '.epub')])
+                parent=None, title="Select unencrypted ePub file to produce",
+                defaultextension=".epub", filetypes=[('ePub files', '.epub')])
             if outpath:
                 outpath = os.path.normpath(outpath)
                 self.outpath.delete(0, Tkconstants.END)
@@ -558,31 +556,31 @@ def gui_main():
             inpath = self.inpath.get()
             outpath = self.outpath.get()
             if not keypath or not os.path.exists(keypath):
-                self.status['text'] = u"Specified key file does not exist"
+                self.status['text'] = "Specified key file does not exist"
                 return
             if not inpath or not os.path.exists(inpath):
-                self.status['text'] = u"Specified input file does not exist"
+                self.status['text'] = "Specified input file does not exist"
                 return
             if not outpath:
-                self.status['text'] = u"Output file not specified"
+                self.status['text'] = "Output file not specified"
                 return
             if inpath == outpath:
-                self.status['text'] = u"Must have different input and output files"
+                self.status['text'] = "Must have different input and output files"
                 return
             userkey = open(keypath,'rb').read()
-            self.status['text'] = u"Decrypting..."
+            self.status['text'] = "Decrypting..."
             try:
                 decrypt_status = decryptBook(userkey, inpath, outpath)
             except Exception as e:
-                self.status['text'] = u"Error: {0}".format(e.args[0])
+                self.status['text'] = "Error: {0}".format(e.args[0])
                 return
             if decrypt_status == 0:
-                self.status['text'] = u"File successfully decrypted"
+                self.status['text'] = "File successfully decrypted"
             else:
-                self.status['text'] = u"The was an error decrypting the file."
+                self.status['text'] = "The was an error decrypting the file."
 
     root = Tkinter.Tk()
-    root.title(u"Adobe Adept ePub Decrypter v.{0}".format(__version__))
+    root.title("Adobe Adept ePub Decrypter v.{0}".format(__version__))
     root.resizable(True, False)
     root.minsize(300, 0)
     DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1)
index c29a536752bb10945380261e8656e6ceafe4b9cf..5604fae689aff40d17b298887a4be1fb783e6f7f 100644 (file)
@@ -1,8 +1,6 @@
-#! /usr/bin/python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-
 # ineptpdf.py
 # Copyright © 2009-2020 by i♥cabbages, Apprentice Harper et al.
 
@@ -115,7 +113,7 @@ def unicode_argv():
             start = argc.value - len(sys.argv)
             return [argv[i] for i in
                     range(start, argc.value)]
-        return [u"ineptpdf.py"]
+        return ["ineptpdf.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding is None:
@@ -2178,12 +2176,12 @@ class PDFSerializer(object):
 
 def decryptBook(userkey, inpath, outpath):
     if RSA is None:
-        raise ADEPTError(u"PyCrypto or OpenSSL must be installed.")
+        raise ADEPTError("PyCrypto or OpenSSL must be installed.")
     with open(inpath, 'rb') as inf:
         #try:
         serializer = PDFSerializer(inf, userkey)
         #except:
-        #    print u"Error serializing pdf {0}. Probably wrong key.".format(os.path.basename(inpath))
+        #    print "Error serializing pdf {0}. Probably wrong key.".format(os.path.basename(inpath))
         #    return 2
         # hope this will fix the 'bad file descriptor' problem
         with open(outpath, 'wb') as outf:
@@ -2191,7 +2189,7 @@ def decryptBook(userkey, inpath, outpath):
             try:
                 serializer.dump(outf)
             except Exception as e:
-                print(u"error writing pdf: {0}".format(e.args[0]))
+                print("error writing pdf: {0}".format(e.args[0]))
                 return 2
     return 0
 
@@ -2202,13 +2200,13 @@ def cli_main():
     argv=unicode_argv()
     progname = os.path.basename(argv[0])
     if len(argv) != 4:
-        print(u"usage: {0} <keyfile.der> <inbook.pdf> <outbook.pdf>".format(progname))
+        print("usage: {0} <keyfile.der> <inbook.pdf> <outbook.pdf>".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("Successfully decrypted {0:s} as {1:s}".format(os.path.basename(inpath),os.path.basename(outpath)))
     return result
 
 
@@ -2225,43 +2223,43 @@ def gui_main():
     class DecryptionDialog(Tkinter.Frame):
         def __init__(self, root):
             Tkinter.Frame.__init__(self, root, border=5)
-            self.status = Tkinter.Label(self, text=u"Select files for decryption")
+            self.status = Tkinter.Label(self, text="Select files for decryption")
             self.status.pack(fill=Tkconstants.X, expand=1)
             body = Tkinter.Frame(self)
             body.pack(fill=Tkconstants.X, expand=1)
             sticky = Tkconstants.E + Tkconstants.W
             body.grid_columnconfigure(1, weight=2)
-            Tkinter.Label(body, text=u"Key file").grid(row=0)
+            Tkinter.Label(body, text="Key file").grid(row=0)
             self.keypath = Tkinter.Entry(body, width=30)
             self.keypath.grid(row=0, column=1, sticky=sticky)
-            if os.path.exists(u"adeptkey.der"):
-                self.keypath.insert(0, u"adeptkey.der")
-            button = Tkinter.Button(body, text=u"...", command=self.get_keypath)
+            if os.path.exists("adeptkey.der"):
+                self.keypath.insert(0, "adeptkey.der")
+            button = Tkinter.Button(body, text="...", command=self.get_keypath)
             button.grid(row=0, column=2)
-            Tkinter.Label(body, text=u"Input file").grid(row=1)
+            Tkinter.Label(body, text="Input file").grid(row=1)
             self.inpath = Tkinter.Entry(body, width=30)
             self.inpath.grid(row=1, column=1, sticky=sticky)
-            button = Tkinter.Button(body, text=u"...", command=self.get_inpath)
+            button = Tkinter.Button(body, text="...", command=self.get_inpath)
             button.grid(row=1, column=2)
-            Tkinter.Label(body, text=u"Output file").grid(row=2)
+            Tkinter.Label(body, text="Output file").grid(row=2)
             self.outpath = Tkinter.Entry(body, width=30)
             self.outpath.grid(row=2, column=1, sticky=sticky)
-            button = Tkinter.Button(body, text=u"...", command=self.get_outpath)
+            button = Tkinter.Button(body, text="...", command=self.get_outpath)
             button.grid(row=2, column=2)
             buttons = Tkinter.Frame(self)
             buttons.pack()
             botton = Tkinter.Button(
-                buttons, text=u"Decrypt", width=10, command=self.decrypt)
+                buttons, text="Decrypt", width=10, command=self.decrypt)
             botton.pack(side=Tkconstants.LEFT)
             Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT)
             button = Tkinter.Button(
-                buttons, text=u"Quit", width=10, command=self.quit)
+                buttons, text="Quit", width=10, command=self.quit)
             button.pack(side=Tkconstants.RIGHT)
 
         def get_keypath(self):
             keypath = tkFileDialog.askopenfilename(
-                parent=None, title=u"Select Adobe Adept \'.der\' key file",
-                defaultextension=u".der",
+                parent=None, title="Select Adobe Adept \'.der\' key file",
+                defaultextension=".der",
                 filetypes=[('Adobe Adept DER-encoded files', '.der'),
                            ('All Files', '.*')])
             if keypath:
@@ -2272,8 +2270,8 @@ def gui_main():
 
         def get_inpath(self):
             inpath = tkFileDialog.askopenfilename(
-                parent=None, title=u"Select ADEPT-encrypted PDF file to decrypt",
-                defaultextension=u".pdf", filetypes=[('PDF files', '.pdf')])
+                parent=None, title="Select ADEPT-encrypted PDF file to decrypt",
+                defaultextension=".pdf", filetypes=[('PDF files', '.pdf')])
             if inpath:
                 inpath = os.path.normpath(inpath)
                 self.inpath.delete(0, Tkconstants.END)
@@ -2282,8 +2280,8 @@ def gui_main():
 
         def get_outpath(self):
             outpath = tkFileDialog.asksaveasfilename(
-                parent=None, title=u"Select unencrypted PDF file to produce",
-                defaultextension=u".pdf", filetypes=[('PDF files', '.pdf')])
+                parent=None, title="Select unencrypted PDF file to produce",
+                defaultextension=".pdf", filetypes=[('PDF files', '.pdf')])
             if outpath:
                 outpath = os.path.normpath(outpath)
                 self.outpath.delete(0, Tkconstants.END)
@@ -2295,28 +2293,28 @@ def gui_main():
             inpath = self.inpath.get()
             outpath = self.outpath.get()
             if not keypath or not os.path.exists(keypath):
-                self.status['text'] = u"Specified key file does not exist"
+                self.status['text'] = "Specified key file does not exist"
                 return
             if not inpath or not os.path.exists(inpath):
-                self.status['text'] = u"Specified input file does not exist"
+                self.status['text'] = "Specified input file does not exist"
                 return
             if not outpath:
-                self.status['text'] = u"Output file not specified"
+                self.status['text'] = "Output file not specified"
                 return
             if inpath == outpath:
-                self.status['text'] = u"Must have different input and output files"
+                self.status['text'] = "Must have different input and output files"
                 return
             userkey = open(keypath,'rb').read()
-            self.status['text'] = u"Decrypting..."
+            self.status['text'] = "Decrypting..."
             try:
                 decrypt_status = decryptBook(userkey, inpath, outpath)
             except Exception as e:
-                self.status['text'] = u"Error; {0}".format(e.args[0])
+                self.status['text'] = "Error; {0}".format(e.args[0])
                 return
             if decrypt_status == 0:
-                self.status['text'] = u"File successfully decrypted"
+                self.status['text'] = "File successfully decrypted"
             else:
-                self.status['text'] = u"The was an error decrypting the file."
+                self.status['text'] = "The was an error decrypting the file."
 
 
     root = Tkinter.Tk()
@@ -2327,7 +2325,7 @@ def gui_main():
             "This script requires OpenSSL or PyCrypto, which must be installed "
             "separately.  Read the top-of-script comment for details.")
         return 1
-    root.title(u"Adobe Adept PDF Decrypter v.{0}".format(__version__))
+    root.title("Adobe Adept PDF Decrypter v.{0}".format(__version__))
     root.resizable(True, False)
     root.minsize(370, 0)
     DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1)
index f385cc3cb1ceaa5d23b6922c8f66c55ca000d68a..ac1b6ad419a583497dd3709e283486af2a2a5a05 100644 (file)
@@ -1,8 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-
 # ion.py
 # Copyright © 2013-2020 Apprentice Harper et al.
 
index eaaa43b10c0fe8fa46d918a93c6d957210fd2380..18addc2d17beff4cc8875b655a7712666adc29b6 100644 (file)
@@ -1,8 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-
 # k4mobidedrm.py
 # Copyright © 2008-2020 by Apprentice Harper et al.
 
@@ -146,7 +144,7 @@ def unicode_argv():
                     range(start, argc.value)]
         # if we don't have any arguments at all, just pass back script name
         # this should never happen
-        return [u"mobidedrm.py"]
+        return ["mobidedrm.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -161,31 +159,31 @@ def unicode_argv():
 # and some improvements suggested by jhaisley
 def cleanup_name(name):
     # substitute filename unfriendly characters
-    name = name.replace(u"<",u"[").replace(u">",u"]").replace(u" : ",u" – ").replace(u": ",u" – ").replace(u":",u"—").replace(u"/",u"_").replace(u"\\",u"_").replace(u"|",u"_").replace(u"\"",u"\'").replace(u"*",u"_").replace(u"?",u"")
+    name = name.replace("<","[").replace(">","]").replace(" : "," – ").replace(": "," – ").replace(":","—").replace("/","_").replace("\\","_").replace("|","_").replace("\"","\'").replace("*","_").replace("?",u"")
     # white space to single space, delete leading and trailing while space
-    name = re.sub(r"\s", u" ", name).strip()
+    name = re.sub(r"\s", " ", name).strip()
     # delete control characters
     name = u"".join(char for char in name if ord(char)>=32)
     # delete non-ascii characters
     name = u"".join(char for char in name if ord(char)<=126)
     # remove leading dots
-    while len(name)>0 and name[0] == u".":
+    while len(name)>0 and name[0] == ".":
         name = name[1:]
     # remove trailing dots (Windows doesn't like them)
-    while name.endswith(u'.'):
+    while name.endswith("."):
         name = name[:-1]
     if len(name)==0:
-        name=u"DecryptedBook"
+        name="DecryptedBook"
     return name
 
 # must be passed unicode
 def unescape(text):
     def fixup(m):
         text = m.group(0)
-        if text[:2] == u"&#":
+        if text[:2] == "&#":
             # character reference
             try:
-                if text[:3] == u"&#x":
+                if text[:3] == "&#x":
                     return chr(int(text[3:-1], 16))
                 else:
                     return chr(int(text[2:-1]))
@@ -198,17 +196,17 @@ def unescape(text):
             except KeyError:
                 pass
         return text # leave as is
-    return re.sub(u"&#?\\w+;", fixup, text)
+    return re.sub("&#?\\w+;", fixup, text)
 
 def GetDecryptedBook(infile, kDatabases, androidFiles, serials, pids, starttime = time.time()):
     # handle the obvious cases at the beginning
     if not os.path.isfile(infile):
-        raise DrmException(u"Input file does not exist.")
+        raise DrmException("Input file does not exist.")
 
     mobi = True
     magic8 = open(infile,'rb').read(8)
     if magic8 == '\xeaDRMION\xee':
-        raise DrmException(u"The .kfx DRMION file cannot be decrypted by itself. A .kfx-zip archive containing a DRM voucher is required.")
+        raise DrmException("The .kfx DRMION file cannot be decrypted by itself. A .kfx-zip archive containing a DRM voucher is required.")
 
     magic3 = magic8[:3]
     if magic3 == 'TPZ':
@@ -222,7 +220,7 @@ def GetDecryptedBook(infile, kDatabases, androidFiles, serials, pids, starttime
         mb = topazextract.TopazBook(infile)
 
     bookname = unescape(mb.getBookTitle())
-    print(u"Decrypting {1} ebook: {0}".format(bookname, mb.getBookType()))
+    print("Decrypting {1} ebook: {0}".format(bookname, mb.getBookType()))
 
     # copy list of pids
     totalpids = list(pids)
@@ -234,7 +232,7 @@ def GetDecryptedBook(infile, kDatabases, androidFiles, serials, pids, starttime
     totalpids.extend(kgenpids.getPidList(md1, md2, serials, kDatabases))
     # remove any duplicates
     totalpids = list(set(totalpids))
-    print(u"Found {1:d} keys to try after {0:.1f} seconds".format(time.time()-starttime, len(totalpids)))
+    print("Found {1:d} keys to try after {0:.1f} seconds".format(time.time()-starttime, len(totalpids)))
     #print totalpids
 
     try:
@@ -243,7 +241,7 @@ def GetDecryptedBook(infile, kDatabases, androidFiles, serials, pids, starttime
         mb.cleanup
         raise
 
-    print(u"Decryption succeeded after {0:.1f} seconds".format(time.time()-starttime))
+    print("Decryption succeeded after {0:.1f} seconds".format(time.time()-starttime))
     return mb
 
 
@@ -258,7 +256,7 @@ def decryptBook(infile, outdir, kDatabaseFiles, androidFiles, serials, pids):
                 kindleDatabase = json.loads(keyfilein.read())
             kDatabases.append([dbfile,kindleDatabase])
         except Exception as e:
-            print(u"Error getting database from file {0:s}: {1:s}".format(dbfile,e))
+            print("Error getting database from file {0:s}: {1:s}".format(dbfile,e))
             traceback.print_exc()
 
 
@@ -266,7 +264,7 @@ def decryptBook(infile, outdir, kDatabaseFiles, androidFiles, serials, pids):
     try:
         book = GetDecryptedBook(infile, kDatabases, androidFiles, serials, pids, starttime)
     except Exception as e:
-        print(u"Error decrypting book after {1:.1f} seconds: {0}".format(e.args[0],time.time()-starttime))
+        print("Error decrypting book after {1:.1f} seconds: {0}".format(e.args[0],time.time()-starttime))
         traceback.print_exc()
         return 1
 
@@ -277,7 +275,7 @@ def decryptBook(infile, outdir, kDatabaseFiles, androidFiles, serials, pids):
         re.match('^{0-9A-F-}{36}$', orig_fn_root)
     ):  # Kindle for PC / Mac / Android / Fire / iOS
         clean_title = cleanup_name(book.getBookTitle())
-        outfilename = u'{}_{}'.format(orig_fn_root, clean_title)
+        outfilename = "{}_{}".format(orig_fn_root, clean_title)
     else:  # E Ink Kindle, which already uses a reasonable name
         outfilename = orig_fn_root
 
@@ -285,16 +283,16 @@ def decryptBook(infile, outdir, kDatabaseFiles, androidFiles, serials, pids):
     if len(outfilename)>150:
         outfilename = outfilename[:99]+"--"+outfilename[-49:]
 
-    outfilename = outfilename+u"_nodrm"
+    outfilename = outfilename+"_nodrm"
     outfile = os.path.join(outdir, outfilename + book.getBookExtension())
 
     book.getFile(outfile)
-    print(u"Saved decrypted book {1:s} after {0:.1f} seconds".format(time.time()-starttime, outfilename))
+    print("Saved decrypted book {1:s} after {0:.1f} seconds".format(time.time()-starttime, outfilename))
 
-    if book.getBookType()==u"Topaz":
-        zipname = os.path.join(outdir, outfilename + u"_SVG.zip")
+    if book.getBookType()=="Topaz":
+        zipname = os.path.join(outdir, outfilename + "_SVG.zip")
         book.getSVGZip(zipname)
-        print(u"Saved SVG ZIP Archive for {1:s} after {0:.1f} seconds".format(time.time()-starttime, outfilename))
+        print("Saved SVG ZIP Archive for {1:s} after {0:.1f} seconds".format(time.time()-starttime, outfilename))
 
     # remove internal temporary directory of Topaz pieces
     book.cleanup()
@@ -302,9 +300,9 @@ def decryptBook(infile, outdir, kDatabaseFiles, androidFiles, serials, pids):
 
 
 def usage(progname):
-    print(u"Removes DRM protection from Mobipocket, Amazon KF8, Amazon Print Replica and Amazon Topaz ebooks")
-    print(u"Usage:")
-    print(u"    {0} [-k <kindle.k4i>] [-p <comma separated PIDs>] [-s <comma separated Kindle serial numbers>] [ -a <AmazonSecureStorage.xml|backup.ab> ] <infile> <outdir>".format(progname))
+    print("Removes DRM protection from Mobipocket, Amazon KF8, Amazon Print Replica and Amazon Topaz ebooks")
+    print("Usage:")
+    print("    {0} [-k <kindle.k4i>] [-p <comma separated PIDs>] [-s <comma separated Kindle serial numbers>] [ -a <AmazonSecureStorage.xml|backup.ab> ] <infile> <outdir>".format(progname))
 
 #
 # Main
@@ -312,12 +310,12 @@ def usage(progname):
 def cli_main():
     argv=unicode_argv()
     progname = os.path.basename(argv[0])
-    print(u"K4MobiDeDrm v{0}.\nCopyright © 2008-2017 Apprentice Harper et al.".format(__version__))
+    print("K4MobiDeDrm v{0}.\nCopyright © 2008-2017 Apprentice Harper et al.".format(__version__))
 
     try:
         opts, args = getopt.getopt(argv[1:], "k:p:s:a:")
     except getopt.GetoptError as err:
-        print(u"Error in options or arguments: {0}".format(err.args[0]))
+        print("Error in options or arguments: {0}".format(err.args[0]))
         usage(progname)
         sys.exit(2)
     if len(args)<2:
index d3c0f7e76929e0b5ebd2657cbff08c8d506af63d..875c4a183f778027008252133606e1652b57683f 100644 (file)
@@ -1,12 +1,9 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-from __future__ import print_function
-
 # Engine to remove drm from Kindle KFX ebooks
 
-#  2.0   - Added Python 3 compatibility for calibre 5.0
+#  2.0   - Python 3 for calibre 5.0
 
 
 import os
@@ -50,13 +47,13 @@ class KFXZipBook:
                     data += fh.read()
                     if self.voucher is None:
                         self.decrypt_voucher(totalpids)
-                    print(u'Decrypting KFX DRMION: {0}'.format(filename))
+                    print("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()
 
         if not self.decrypted:
-            print(u'The .kfx-zip archive does not contain an encrypted DRMION file')
+            print("The .kfx-zip archive does not contain an encrypted DRMION file")
 
     def decrypt_voucher(self, totalpids):
         with zipfile.ZipFile(self.infile, 'r') as zf:
@@ -70,9 +67,9 @@ class KFXZipBook:
                     if 'ProtectedData' in data:
                         break   # found DRM voucher
             else:
-                raise Exception(u'The .kfx-zip archive contains an encrypted DRMION file without a DRM voucher')
+                raise Exception("The .kfx-zip archive contains an encrypted DRMION file without a DRM voucher")
 
-        print(u'Decrypting KFX DRM voucher: {0}'.format(info.filename))
+        print("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,0), (40,40)]:
@@ -89,13 +86,13 @@ class KFXZipBook:
             except:
                 pass
         else:
-            raise Exception(u'Failed to decrypt KFX DRM voucher with any key')
+            raise Exception("Failed to decrypt KFX DRM voucher with any key")
 
-        print(u'KFX DRM voucher successfully decrypted')
+        print("KFX DRM voucher successfully decrypted")
 
         license_type = voucher.getlicensetype()
         if license_type != "Purchase":
-            raise Exception((u'This book is licensed as {0}. '
+            raise Exception(("This book is licensed as {0}. "
                     'These tools are intended for use on purchased books.').format(license_type))
 
         self.voucher = voucher
index a3efee0cf8d4bd1287458280c7b913c1d6b94b06..3e80598a9a28213d20997f35311acef46ff434e1 100644 (file)
@@ -1,9 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-from __future__ import print_function
-
 # kgenpids.py
 # Copyright © 2008-2020 Apprentice Harper et al.
 
@@ -14,7 +11,7 @@ __version__ = '3.0'
 #  2.0   - Fix for non-ascii Windows user names
 #  2.1   - Actual fix for non-ascii WIndows user names.
 #  2.2   - Return information needed for KFX decryption
-#  3.0   - Added Python 3 compatibility for calibre 5.0
+#  3.0   - Python 3 for calibre 5.0
 
 
 import sys
@@ -217,18 +214,18 @@ def getK4Pids(rec209, token, kindleDatabase):
     try:
         # Get the DSN token, if present
         DSN = bytearray.fromhex((kindleDatabase[1])['DSN']).decode()
-        print(u"Got DSN key from database {0}".format(kindleDatabase[0]))
+        print("Got DSN key from database {0}".format(kindleDatabase[0]))
     except KeyError:
         # See if we have the info to generate the DSN
         try:
             # Get the Mazama Random number
             MazamaRandomNumber = bytearray.fromhex((kindleDatabase[1])['MazamaRandomNumber']).decode()
-            #print u"Got MazamaRandomNumber from database {0}".format(kindleDatabase[0])
+            #print "Got MazamaRandomNumber from database {0}".format(kindleDatabase[0])
 
             try:
                 # Get the SerialNumber token, if present
                 IDString = bytearray.fromhex((kindleDatabase[1])['SerialNumber']).decode()
-                print(u"Got SerialNumber from database {0}".format(kindleDatabase[0]))
+                print("Got SerialNumber from database {0}".format(kindleDatabase[0]))
             except KeyError:
                  # Get the IDString we added
                 IDString = bytearray.fromhex((kindleDatabase[1])['IDString']).decode()
@@ -236,24 +233,24 @@ def getK4Pids(rec209, token, kindleDatabase):
             try:
                 # Get the UsernameHash token, if present
                 encodedUsername = bytearray.fromhex((kindleDatabase[1])['UsernameHash']).decode()
-                print(u"Got UsernameHash from database {0}".format(kindleDatabase[0]))
+                print("Got UsernameHash from database {0}".format(kindleDatabase[0]))
             except KeyError:
                 # Get the UserName we added
                 UserName = bytearray.fromhex((kindleDatabase[1])['UserName']).decode()
                 # encode it
                 encodedUsername = encodeHash(UserName,charMap1)
-                #print u"encodedUsername",encodedUsername.encode('hex')
+                #print "encodedUsername",encodedUsername.encode('hex')
         except KeyError:
-            print(u"Keys not found in the database {0}.".format(kindleDatabase[0]))
+            print("Keys not found in the database {0}.".format(kindleDatabase[0]))
             return pids
 
         # Get the ID string used
         encodedIDString = encodeHash(IDString,charMap1)
-        #print u"encodedIDString",encodedIDString.encode('hex')
+        #print "encodedIDString",encodedIDString.encode('hex')
 
         # concat, hash and encode to calculate the DSN
         DSN = encode(SHA1(MazamaRandomNumber+encodedIDString+encodedUsername),charMap1)
-        #print u"DSN",DSN.encode('hex')
+        #print "DSN",DSN.encode('hex')
         pass
 
     if rec209 is None:
@@ -300,14 +297,14 @@ def getPidList(md1, md2, serials=[], kDatabases=[]):
         try:
             pidlst.extend(getK4Pids(md1, md2, kDatabase))
         except Exception as e:
-            print(u"Error getting PIDs from database {0}: {1}".format(kDatabase[0],e.args[0]))
+            print("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 as e:
-            print(u"Error getting PIDs from serial number {0}: {1}".format(serialnum ,e.args[0]))
+            print("Error getting PIDs from serial number {0}: {1}".format(serialnum ,e.args[0]))
             traceback.print_exc()
 
     return pidlst
index 5e9f5c8f4af11aed7a91744e315a3abd9a8eff4c..05b114231f0442cf5858d8a3572ad6a86ec7d1b6 100644 (file)
@@ -1,8 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-
 # kindlekey.py
 # Copyright © 2008-2020 Apprentice Harper et al.
 
@@ -30,7 +28,7 @@ __version__ = '3.0'
 #  2.5   - Final Fix for Windows user names with non-ascii characters, thanks to oneofusoneofus
 #  2.6   - Start adding support for Kindle 1.25+ .kinf2018 file
 #  2.7   - Finish .kinf2018 support, PC & Mac by Apprentice Sakuya
-#  3.0   - Added Python 3 compatibility for calibre 5.0
+#  3.0   - Python 3 for calibre 5.0
 
 
 """
@@ -104,7 +102,7 @@ def unicode_argv():
                     xrange(start, argc.value)]
         # if we don't have any arguments at all, just pass back script name
         # this should never happen
-        return [u"kindlekey.py"]
+        return ["kindlekey.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -905,11 +903,11 @@ if iswindows:
             
             # replace any non-ASCII values with 0xfffd
             for i in xrange(0,len(buffer)):
-                if buffer[i]>u"\u007f":
-                    #print u"swapping char "+str(i)+" ("+buffer[i]+")"
-                    buffer[i] = u"\ufffd"
+                if buffer[i]>"\u007f":
+                    #print "swapping char "+str(i)+" ("+buffer[i]+")"
+                    buffer[i] = "\ufffd"
             # return utf-8 encoding of modified username
-            #print u"modified username:"+buffer.value
+            #print "modified username:"+buffer.value
             return buffer.value.encode('utf-8')
         return GetUserName
     GetUserName = GetUserName()
@@ -939,7 +937,7 @@ if iswindows:
         n = ctypes.windll.kernel32.GetEnvironmentVariableW(name, None, 0)
         if n == 0:
             return None
-        buf = ctypes.create_unicode_buffer(u'\0'*n)
+        buf = ctypes.create_unicode_buffer("\0"*n)
         ctypes.windll.kernel32.GetEnvironmentVariableW(name, buf, n)
         return buf.value
 
@@ -951,7 +949,7 @@ if iswindows:
         path = ""
         if 'LOCALAPPDATA' in os.environ.keys():
             # Python 2.x does not return unicode env. Use Python 3.x
-            path = winreg.ExpandEnvironmentStrings(u"%LOCALAPPDATA%")
+            path = winreg.ExpandEnvironmentStrings("%LOCALAPPDATA%")
             # this is just another alternative.
             # path = getEnvironmentVariable('LOCALAPPDATA')
             if not os.path.isdir(path):
@@ -979,7 +977,7 @@ if iswindows:
             print ('Could not find the folder in which to look for kinfoFiles.')
         else:
             # Probably not the best. To Fix (shouldn't ignore in encoding) or use utf-8
-            print(u'searching for kinfoFiles in ' + path.encode('ascii', 'ignore'))
+            print("searching for kinfoFiles in " + path.encode('ascii', 'ignore'))
 
             # look for (K4PC 1.25.1 and later) .kinf2018 file
             kinfopath = path +'\\Amazon\\Kindle\\storage\\.kinf2018'
@@ -1166,9 +1164,9 @@ if iswindows:
             # store values used in decryption
             DB['IDString'] = GetIDString()
             DB['UserName'] = GetUserName()
-            print(u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName().encode('hex')))
+            print("Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName().encode('hex')))
         else:
-            print(u"Couldn't decrypt file.")
+            print("Couldn't decrypt file.")
             DB = {}
         return DB
 elif isosx:
@@ -1183,7 +1181,7 @@ elif isosx:
 
         libcrypto = find_library('crypto')
         if libcrypto is None:
-            raise DrmException(u"libcrypto not found")
+            raise DrmException("libcrypto not found")
         libcrypto = CDLL(libcrypto)
 
         # From OpenSSL's crypto aes header
@@ -1241,14 +1239,14 @@ elif isosx:
             def set_decrypt_key(self, userkey, iv):
                 self._blocksize = len(userkey)
                 if (self._blocksize != 16) and (self._blocksize != 24) and (self._blocksize != 32) :
-                    raise DrmException(u"AES improper key used")
+                    raise DrmException("AES improper key used")
                     return
                 keyctx = self._keyctx = AES_KEY()
                 self._iv = iv
                 self._userkey = userkey
                 rv = AES_set_decrypt_key(userkey, len(userkey) * 8, keyctx)
                 if rv < 0:
-                    raise DrmException(u"Failed to initialize AES key")
+                    raise DrmException("Failed to initialize AES key")
 
             def decrypt(self, data):
                 out = create_string_buffer(len(data))
@@ -1256,7 +1254,7 @@ elif isosx:
                 keyctx = self._keyctx
                 rv = AES_cbc_encrypt(data, out, len(data), keyctx, mutable_iv, 0)
                 if rv == 0:
-                    raise DrmException(u"AES decryption failed")
+                    raise DrmException("AES decryption failed")
                 return out.raw
 
             def keyivgen(self, passwd, salt, iter, keylen):
@@ -1649,16 +1647,16 @@ elif isosx:
                 pass
         if len(DB)>6:
             # store values used in decryption
-            print(u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(IDString, GetUserName()))
+            print("Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(IDString, GetUserName()))
             DB['IDString'] = IDString
             DB['UserName'] = GetUserName()
         else:
-            print(u"Couldn't decrypt file.")
+            print("Couldn't decrypt file.")
             DB = {}
         return DB
 else:
     def getDBfromFile(kInfoFile):
-        raise DrmException(u"This script only runs under Windows or Mac OS X.")
+        raise DrmException("This script only runs under Windows or Mac OS X.")
         return {}
 
 def kindlekeys(files = []):
@@ -1683,27 +1681,27 @@ def getkey(outpath, files=[]):
             outfile = outpath
             with file(outfile, 'w') as keyfileout:
                 keyfileout.write(json.dumps(keys[0]))
-            print(u"Saved a key to {0}".format(outfile))
+            print("Saved a key to {0}".format(outfile))
         else:
             keycount = 0
             for key in keys:
                 while True:
                     keycount += 1
-                    outfile = os.path.join(outpath,u"kindlekey{0:d}.k4i".format(keycount))
+                    outfile = os.path.join(outpath,"kindlekey{0:d}.k4i".format(keycount))
                     if not os.path.exists(outfile):
                         break
                 with file(outfile, 'w') as keyfileout:
                     keyfileout.write(json.dumps(key))
-                print(u"Saved a key to {0}".format(outfile))
+                print("Saved a key to {0}".format(outfile))
         return True
     return False
 
 def usage(progname):
-    print(u"Finds, decrypts and saves the default Kindle For Mac/PC 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 <kindle.info>] [<outpath>]".format(progname))
+    print("Finds, decrypts and saves the default Kindle For Mac/PC encryption keys.")
+    print("Keys are saved to the current directory, or a specified output directory.")
+    print("If a file name is passed instead of a directory, only the first key is saved, in that file.")
+    print("Usage:")
+    print("    {0:s} [-h] [-k <kindle.info>] [<outpath>]".format(progname))
 
 
 def cli_main():
@@ -1711,12 +1709,12 @@ def cli_main():
     sys.stderr=SafeUnbuffered(sys.stderr)
     argv=unicode_argv()
     progname = os.path.basename(argv[0])
-    print(u"{0} v{1}\nCopyright © 2010-2016 by some_updates, Apprentice Alf and Apprentice Harper".format(progname,__version__))
+    print("{0} v{1}\nCopyright © 2010-2016 by some_updates, Apprentice Alf and Apprentice Harper".format(progname,__version__))
 
     try:
         opts, args = getopt.getopt(argv[1:], "hk:")
     except getopt.GetoptError as err:
-        print(u"Error in options or arguments: {0}".format(err.args[0]))
+        print("Error in options or arguments: {0}".format(err.args[0]))
         usage(progname)
         sys.exit(2)
 
@@ -1745,7 +1743,7 @@ def cli_main():
     outpath = os.path.realpath(os.path.normpath(outpath))
 
     if not getkey(outpath, files):
-        print(u"Could not retrieve Kindle for Mac/PC key.")
+        print("Could not retrieve Kindle for Mac/PC key.")
     return 0
 
 
@@ -1761,7 +1759,7 @@ def gui_main():
     class ExceptionDialog(Tkinter.Frame):
         def __init__(self, root, text):
             Tkinter.Frame.__init__(self, root, border=5)
-            label = Tkinter.Label(self, text=u"Unexpected error:",
+            label = Tkinter.Label(self, text="Unexpected error:",
                                   anchor=Tkconstants.W, justify=Tkconstants.LEFT)
             label.pack(fill=Tkconstants.X, expand=0)
             self.text = Tkinter.Text(self)
@@ -1781,16 +1779,16 @@ def gui_main():
         for key in keys:
             while True:
                 keycount += 1
-                outfile = os.path.join(progpath,u"kindlekey{0:d}.k4i".format(keycount))
+                outfile = os.path.join(progpath,"kindlekey{0:d}.k4i".format(keycount))
                 if not os.path.exists(outfile):
                     break
 
             with file(outfile, 'w') as keyfileout:
                 keyfileout.write(json.dumps(key))
             success = True
-            tkMessageBox.showinfo(progname, u"Key successfully retrieved to {0}".format(outfile))
+            tkMessageBox.showinfo(progname, "Key successfully retrieved to {0}".format(outfile))
     except DrmException as e:
-        tkMessageBox.showerror(progname, u"Error: {0}".format(str(e)))
+        tkMessageBox.showerror(progname, "Error: {0}".format(str(e)))
     except Exception:
         root.wm_state('normal')
         root.title(progname)
index 069fdc00aa523e1e633fb491e912496c4f79a7cb..b021e972ce2da3a111373b9c0b9d65a6ca4169dd 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 # Mobipocket PID calculator v0.4 for Amazon Kindle.
@@ -10,7 +10,7 @@
 #  0.3 updated for unicode
 #  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
-#  1.0 Added Python 3 compatibility for calibre 5.0
+#  1.0 Python 3 for calibre 5.0
 
 from __future__ import print_function
 import sys
@@ -67,7 +67,7 @@ def unicode_argv():
                     range(start, argc.value)]
         # if we don't have any arguments at all, just pass back script name
         # this should never happen
-        return [u"kindlepid.py"]
+        return ["kindlepid.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -111,28 +111,28 @@ def pidFromSerial(s, l):
     return pid
 
 def cli_main():
-    print(u"Mobipocket PID calculator for Amazon Kindle. Copyright © 2007, 2009 Igor Skochinsky")
+    print("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 <Kindle Serial Number>/<iPhone/iPod Touch UDID>")
+        print("Usage: kindlepid.py <Kindle Serial Number>/<iPhone/iPod Touch UDID>")
         return 1
     if len(serial)==16:
         if serial.startswith("B") or serial.startswith("9"):
-            print(u"Kindle serial number detected")
+            print("Kindle serial number detected")
         else:
-            print(u"Warning: unrecognized serial number. Please recheck input.")
+            print("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("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("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("Mobipocket PID for iPhone serial#{0} is {1}".format(serial,checksumPid(pid)))
         return 0
-    print(u"Warning: unrecognized serial number. Please recheck input.")
+    print("Warning: unrecognized serial number. Please recheck input.")
     return 1
 
 
index cfd8a81343af5fe976ef130cd5326f270696440d..05c7b072d58af9d24716b25a8746adb0138f033d 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 # mobidedrm.py
@@ -7,7 +7,7 @@
 
 from __future__ import print_function
 __license__ = 'GPL v3'
-__version__ = u"1.00"
+__version__ = "1.00"
 
 # This is a python script. You need a Python interpreter to run it.
 # For example, ActiveState Python, which exists for windows.
@@ -82,7 +82,7 @@ import binascii
 try:
     from alfcrypto import Pukall_Cipher
 except:
-    print(u"AlfCrypto not found. Using python PC1 implementation.")
+    print("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
@@ -135,7 +135,7 @@ def unicode_argv():
                     range(start, argc.value)]
         # if we don't have any arguments at all, just pass back script name
         # this should never happen
-        return [u"mobidedrm.py"]
+        return ["mobidedrm.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -166,7 +166,7 @@ def PC1(key, src, decryption=True):
     sum2 = 0;
     keyXorVal = 0;
     if len(key)!=16:
-         DrmException (u"PC1: Bad key length")
+         DrmException ("PC1: Bad key length")
     wkey = []
     for i in range(8):
         wkey.append(key[i*2]<<8 | key[i*2+1])
@@ -246,19 +246,19 @@ 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("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("AlfCrypto not found. Using python PC1 implementation.")
 
         # initial sanity check on file
         self.data_file = open(infile, 'rb').read()
         self.mobi_data = ''
         self.header = self.data_file[0:78]
         if self.header[0x3C:0x3C+8] != b'BOOKMOBI' and self.header[0x3C:0x3C+8] != b'TEXtREAd':
-            raise DrmException(u"Invalid file format")
+            raise DrmException("Invalid file format")
         self.magic = self.header[0x3C:0x3C+8]
         self.crypto_type = -1
 
@@ -284,16 +284,16 @@ class MobiBook:
         self.mobi_version = -1
 
         if self.magic == 'TEXtREAd':
-            print(u"PalmDoc format book detected.")
+            print("PalmDoc format book detected.")
             return
 
         self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18])
         self.mobi_codepage, = struct.unpack('>L',self.sect[0x1c:0x20])
         self.mobi_version, = struct.unpack('>L',self.sect[0x68:0x6C])
-        #print u"MOBI header version {0:d}, header length {1:d}".format(self.mobi_version, self.mobi_length)
+        #print "MOBI header version {0:d}, header length {1:d}".format(self.mobi_version, self.mobi_length)
         if (self.mobi_length >= 0xE4) and (self.mobi_version >= 5):
             self.extra_data_flags, = struct.unpack('>H', self.sect[0xF2:0xF4])
-            #print u"Extra Data Flags: {0:d}".format(self.extra_data_flags)
+            #print "Extra Data Flags: {0:d}".format(self.extra_data_flags)
         if (self.compression != 17480):
             # multibyte utf8 data is included in the encryption for PalmDoc compression
             # so clear that byte so that we leave it to be decrypted.
@@ -322,7 +322,7 @@ class MobiBook:
                     # print type, size, content, content.encode('hex')
                     pos += size
         except Exception as e:
-            print(u"Cannot set meta_array: Error: {:s}".format(e.args[0]))
+            print("Cannot set meta_array: Error: {:s}".format(e.args[0]))
 
     def getBookTitle(self):
         codec_map = {
@@ -411,51 +411,51 @@ class MobiBook:
 
     def getBookType(self):
         if self.print_replica:
-            return u"Print Replica"
+            return "Print Replica"
         if self.mobi_version >= 8:
-            return u"Kindle Format 8"
+            return "Kindle Format 8"
         if self.mobi_version >= 0:
-            return u"Mobipocket {0:d}".format(self.mobi_version)
-        return u"PalmDoc"
+            return "Mobipocket {0:d}".format(self.mobi_version)
+        return "PalmDoc"
 
     def getBookExtension(self):
         if self.print_replica:
-            return u".azw4"
+            return ".azw4"
         if self.mobi_version >= 8:
-            return u".azw3"
-        return u".mobi"
+            return ".azw3"
+        return ".mobi"
 
     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("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("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
             return
         if crypto_type != 2 and crypto_type != 1:
-            raise DrmException(u"Cannot decode unknown Mobipocket encryption type {0:d}".format(crypto_type))
+            raise DrmException("Cannot decode unknown Mobipocket encryption type {0:d}".format(crypto_type))
         if 406 in self.meta_array:
             data406 = self.meta_array[406]
             val406, = struct.unpack('>Q',data406)
             if val406 != 0:
-                raise DrmException(u"Cannot decode library or rented ebooks.")
+                raise DrmException("Cannot decode library or rented ebooks.")
 
         goodpids = []
         # print("DEBUG ==== pidlist = ", pidlist)
         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("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("Warning: PID {0} has wrong number of digits".format(pid))
 
-        # print(u"======= DEBUG good pids = ", goodpids)
+        # print("======= DEBUG good pids = ", goodpids)
 
         if self.crypto_type == 1:
             t1_keyvec = 'QDCVEPMU675RUBSZ'
@@ -471,32 +471,32 @@ class MobiBook:
             # calculate the keys
             drm_ptr, drm_count, drm_size, drm_flags = struct.unpack('>LLLL', self.sect[0xA8:0xA8+16])
             if drm_count == 0:
-                raise DrmException(u"Encryption not initialised. Must be opened with Mobipocket Reader first.")
+                raise DrmException("Encryption not initialised. Must be opened with Mobipocket Reader first.")
             found_key, pid = self.parseDRM(self.sect[drm_ptr:drm_ptr+drm_size], drm_count, goodpids)
             if not found_key:
-                raise DrmException(u"No key found in {0:d} keys tried.".format(len(goodpids)))
+                raise DrmException("No key found in {0:d} keys tried.".format(len(goodpids)))
             # kill the drm keys
             self.patchSection(0, b'\0' * drm_size, drm_ptr)
             # kill the drm pointers
             self.patchSection(0, b'\xff' * 4 + b'\0' * 12, 0xA8)
 
         if pid=='00000000':
-            print(u"File has default encryption, no specific key needed.")
+            print("File has default encryption, no specific key needed.")
         else:
-            print(u"File is encoded with PID {0}.".format(checksumPid(pid)))
+            print("File is encoded with PID {0}.".format(checksumPid(pid)))
 
         # clear the crypto type
         self.patchSection(0, b'\0' * 2, 0xC)
 
         # decrypt sections
-        print(u"Decrypting. Please wait . . .", end=' ')
+        print("Decrypting. Please wait . . .", end=' ')
         mobidataList = []
         mobidataList.append(self.data_file[:self.sections[1][0]])
         for i in range(1, self.records+1):
             data = self.loadSection(i)
             extra_size = getSizeOfTrailingDataEntries(data, len(data), self.extra_data_flags)
             if i%100 == 0:
-                print(u".", end=' ')
+                print(".", end=' ')
             # print "record %d, extra_size %d" %(i,extra_size)
             decoded_data = PC1(found_key, data[0:len(data) - extra_size])
             if i==1:
@@ -507,12 +507,12 @@ class MobiBook:
         if self.num_sections > self.records+1:
             mobidataList.append(self.data_file[self.sections[self.records+1][0]:])
         self.mobi_data = b''.join(mobidataList)
-        print(u"done")
+        print("done")
         return
 
 def getUnencryptedBook(infile,pidlist):
     if not os.path.isfile(infile):
-        raise DrmException(u"Input File Not Found.")
+        raise DrmException("Input File Not Found.")
     book = MobiBook(infile)
     book.processBook(pidlist)
     return book.mobi_data
@@ -522,10 +522,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} <infile> <outfile> [<Comma separated list of PIDs to try>]".format(progname))
+        print("MobiDeDrm v{0:s}.\nCopyright © 2008-2017 The Dark Reverser, Apprentice Harper et al.".format(__version__))
+        print("Removes protection from Kindle/Mobipocket, Kindle/KF8 and Kindle/Print Replica ebooks")
+        print("Usage:")
+        print("    {0} <infile> <outfile> [<Comma separated list of PIDs to try>]".format(progname))
         return 1
     else:
         infile = argv[1]
@@ -538,7 +538,7 @@ def cli_main():
             stripped_file = getUnencryptedBook(infile, pidlist)
             open(outfile, 'wb').write(stripped_file)
         except DrmException as e:
-            print(u"MobiDeDRM v{0} Error: {1:s}".format(__version__,e.args[0]))
+            print("MobiDeDRM v{0} Error: {1:s}".format(__version__,e.args[0]))
             return 1
     return 0
 
index cdbb1893f54a4023c533f52c41401fd1f6745dd2..ee16a308c1b25f81c9869f632b3f7d6af6009d26 100644 (file)
@@ -1,7 +1,7 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
 
-from __future__ import with_statement
 __license__ = 'GPL v3'
 
 # Standard Python modules.
@@ -15,7 +15,7 @@ from calibre.constants import iswindows, isosx
 
 class DeDRM_Prefs():
     def __init__(self):
-        JSON_PATH = os.path.join(u"plugins", PLUGIN_NAME.strip().lower().replace(' ', '_') + '.json')
+        JSON_PATH = os.path.join("plugins", PLUGIN_NAME.strip().lower().replace(' ', '_') + '.json')
         self.dedrmprefs = JSONConfig(JSON_PATH)
 
         self.dedrmprefs.defaults['configured'] = False
@@ -98,7 +98,7 @@ def convertprefs(always = False):
             try:
                 name, ccn = keystring.split(',')
                 # Generate Barnes & Noble EPUB user key from name and credit card number.
-                keyname = u"{0}_{1}".format(name.strip(),ccn.strip()[-4:])
+                keyname = "{0}_{1}".format(name.strip(),ccn.strip()[-4:])
                 keyvalue = generate_key(name, ccn)
                 userkeys.append([keyname,keyvalue])
             except Exception as e:
@@ -115,7 +115,7 @@ def convertprefs(always = False):
             try:
                 name, cc = keystring.split(',')
                 # Generate eReader user key from name and credit card number.
-                keyname = u"{0}_{1}".format(name.strip(),cc.strip()[-4:])
+                keyname = "{0}_{1}".format(name.strip(),cc.strip()[-4:])
                 keyvalue = getuser_key(name,cc).encode('hex')
                 userkeys.append([keyname,keyvalue])
             except Exception as e:
@@ -161,15 +161,15 @@ def convertprefs(always = False):
         return
 
 
-    print(u"{0} v{1}: Importing configuration data from old DeDRM plugins".format(PLUGIN_NAME, PLUGIN_VERSION))
+    print("{0} v{1}: Importing configuration data from old DeDRM plugins".format(PLUGIN_NAME, PLUGIN_VERSION))
 
     IGNOBLEPLUGINNAME = "Ignoble Epub DeDRM"
     EREADERPLUGINNAME = "eReader PDB 2 PML"
     OLDKINDLEPLUGINNAME = "K4PC, K4Mac, Kindle Mobi and Topaz DeDRM"
 
     # get prefs from older tools
-    kindleprefs = JSONConfig(os.path.join(u"plugins", u"K4MobiDeDRM"))
-    ignobleprefs = JSONConfig(os.path.join(u"plugins", u"ignoble_epub_dedrm"))
+    kindleprefs = JSONConfig(os.path.join("plugins", "K4MobiDeDRM"))
+    ignobleprefs = JSONConfig(os.path.join("plugins", "ignoble_epub_dedrm"))
 
     # Handle the old ignoble plugin's customization string by converting the
     # old string to stored keys... get that personal data out of plain sight.
@@ -177,7 +177,7 @@ def convertprefs(always = False):
     sc = config['plugin_customization']
     val = sc.pop(IGNOBLEPLUGINNAME, None)
     if val is not None:
-        print(u"{0} v{1}: Converting old Ignoble plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION))
+        print("{0} v{1}: Converting old Ignoble plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION))
         priorkeycount = len(dedrmprefs['bandnkeys'])
         userkeys = parseIgnobleString(str(val))
         for keypair in userkeys:
@@ -185,7 +185,7 @@ def convertprefs(always = False):
             value = keypair[1]
             dedrmprefs.addnamedvaluetoprefs('bandnkeys', name, value)
         addedkeycount = len(dedrmprefs['bandnkeys'])-priorkeycount
-        print(u"{0} v{1}: {2:d} Barnes and Noble {3} imported from old Ignoble plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys"))
+        print("{0} v{1}: {2:d} Barnes and Noble {3} imported from old Ignoble plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, "key" if addedkeycount==1 else "keys"))
     # Make the json write all the prefs to disk
     dedrmprefs.writeprefs(False)
 
@@ -193,7 +193,7 @@ def convertprefs(always = False):
     # old string to stored keys... get that personal data out of plain sight.
     val = sc.pop(EREADERPLUGINNAME, None)
     if val is not None:
-        print(u"{0} v{1}: Converting old eReader plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION))
+        print("{0} v{1}: Converting old eReader plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION))
         priorkeycount = len(dedrmprefs['ereaderkeys'])
         userkeys = parseeReaderString(str(val))
         for keypair in userkeys:
@@ -201,14 +201,14 @@ def convertprefs(always = False):
             value = keypair[1]
             dedrmprefs.addnamedvaluetoprefs('ereaderkeys', name, value)
         addedkeycount = len(dedrmprefs['ereaderkeys'])-priorkeycount
-        print(u"{0} v{1}: {2:d} eReader {3} imported from old eReader plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys"))
+        print("{0} v{1}: {2:d} eReader {3} imported from old eReader plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, "key" if addedkeycount==1 else "keys"))
     # Make the json write all the prefs to disk
     dedrmprefs.writeprefs(False)
 
     # get old Kindle plugin configuration string
     val = sc.pop(OLDKINDLEPLUGINNAME, None)
     if val is not None:
-        print(u"{0} v{1}: Converting old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION))
+        print("{0} v{1}: Converting old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION))
         priorpidcount = len(dedrmprefs['pids'])
         priorserialcount = len(dedrmprefs['serials'])
         pids, serials = parseKindleString(val)
@@ -218,7 +218,7 @@ def convertprefs(always = False):
             dedrmprefs.addvaluetoprefs('serials',serial)
         addedpidcount = len(dedrmprefs['pids']) - priorpidcount
         addedserialcount = len(dedrmprefs['serials']) - priorserialcount
-        print(u"{0} v{1}: {2:d} {3} and {4:d} {5} imported from old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, u"PID" if addedpidcount==1 else u"PIDs", addedserialcount, u"serial number" if addedserialcount==1 else u"serial numbers"))
+        print("{0} v{1}: {2:d} {3} and {4:d} {5} imported from old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, "PID" if addedpidcount==1 else "PIDs", addedserialcount, "serial number" if addedserialcount==1 else "serial numbers"))
     # Make the json write all the prefs to disk
     dedrmprefs.writeprefs(False)
 
@@ -234,7 +234,7 @@ def convertprefs(always = False):
         dedrmprefs.addnamedvaluetoprefs('bandnkeys', name, value)
     addedkeycount = len(dedrmprefs['bandnkeys'])-priorkeycount
     if addedkeycount > 0:
-        print(u"{0} v{1}: {2:d} Barnes and Noble {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key file" if addedkeycount==1 else u"key files"))
+        print("{0} v{1}: {2:d} Barnes and Noble {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, "key file" if addedkeycount==1 else "key files"))
     # Make the json write all the prefs to disk
     dedrmprefs.writeprefs(False)
 
@@ -247,7 +247,7 @@ def convertprefs(always = False):
         dedrmprefs.addnamedvaluetoprefs('adeptkeys', name, value)
     addedkeycount = len(dedrmprefs['adeptkeys'])-priorkeycount
     if addedkeycount > 0:
-        print(u"{0} v{1}: {2:d} Adobe Adept {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"keyfile" if addedkeycount==1 else u"keyfiles"))
+        print("{0} v{1}: {2:d} Adobe Adept {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, "keyfile" if addedkeycount==1 else "keyfiles"))
     # Make the json write all the prefs to disk
     dedrmprefs.writeprefs(False)
 
@@ -260,7 +260,7 @@ def convertprefs(always = False):
         addedkeycount = len(dedrmprefs['bandnkeys']) - priorkeycount
         # no need to delete old prefs, since they contain no recoverable private data
         if addedkeycount > 0:
-            print(u"{0} v{1}: {2:d} Barnes and Noble {3} imported from Ignoble plugin preferences.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys"))
+            print("{0} v{1}: {2:d} Barnes and Noble {3} imported from Ignoble plugin preferences.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, "key" if addedkeycount==1 else "keys"))
     # Make the json write all the prefs to disk
     dedrmprefs.writeprefs(False)
 
@@ -277,19 +277,19 @@ def convertprefs(always = False):
             dedrmprefs.addvaluetoprefs('serials',serial)
     addedpidcount = len(dedrmprefs['pids']) - priorpidcount
     if addedpidcount > 0:
-        print(u"{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, u"PID" if addedpidcount==1 else u"PIDs"))
+        print("{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, "PID" if addedpidcount==1 else "PIDs"))
     addedserialcount = len(dedrmprefs['serials']) - priorserialcount
     if addedserialcount > 0:
-        print(u"{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedserialcount, u"serial number" if addedserialcount==1 else u"serial numbers"))
+        print("{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedserialcount, "serial number" if addedserialcount==1 else "serial numbers"))
     try:
         if 'wineprefix' in kindleprefs and kindleprefs['wineprefix'] != "":
             dedrmprefs.set('adobewineprefix',kindleprefs['wineprefix'])
             dedrmprefs.set('kindlewineprefix',kindleprefs['wineprefix'])
-            print(u"{0} v{1}: WINEPREFIX ‘(2)’ imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, kindleprefs['wineprefix']))
+            print("{0} v{1}: WINEPREFIX ‘(2)’ imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, kindleprefs['wineprefix']))
     except:
         traceback.print_exc()
 
 
     # Make the json write all the prefs to disk
     dedrmprefs.writeprefs()
-    print(u"{0} v{1}: Finished setting up configuration data.".format(PLUGIN_NAME, PLUGIN_VERSION))
+    print("{0} v{1}: Finished setting up configuration data.".format(PLUGIN_NAME, PLUGIN_VERSION))
index 25f23ad29d903d4f4a7c9d428c6af0a8fdd99070..2b70266908e3e2638359eaa4c872c8a6452839fb 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
 
index 55246639eabac52f20be09ba18b261362d15a9f5..34aa6dcfba0cf747dcbb0ccd8eaed8fad54b9f46 100644 (file)
@@ -1,4 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
 
 import sys
index ca0101d46bb04c1c4caafab68d0c03f98bab638b..e1b97e068829d3b2dd1aec5caec41b4b953e8877 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 # topazextract.py
@@ -68,7 +68,7 @@ def unicode_argv():
                     range(start, argc.value)]
         # if we don't have any arguments at all, just pass back script name
         # this should never happen
-        return [u"mobidedrm.py"]
+        return ["mobidedrm.py"]
     else:
         argvencoding = sys.stdin.encoding
         if argvencoding == None:
@@ -170,11 +170,11 @@ def decryptDkeyRecord(data,PID):
     record = decryptRecord(data,PID)
     fields = unpack('3sB8sB8s3s',record)
     if fields[0] != 'PID' or fields[5] != 'pid' :
-        raise DrmException(u"Didn't find PID magic numbers in record")
+        raise DrmException("Didn't find PID magic numbers in record")
     elif fields[1] != 8 or fields[3] != 8 :
-        raise DrmException(u"Record didn't contain correct length fields")
+        raise DrmException("Record didn't contain correct length fields")
     elif fields[2] != PID :
-        raise DrmException(u"Record didn't contain PID")
+        raise DrmException("Record didn't contain PID")
     return fields[4]
 
 # Decrypt all dkey records (contain the book PID)
@@ -191,7 +191,7 @@ def decryptDkeyRecords(data,PID):
             pass
         data = data[1+length:]
     if len(records) == 0:
-        raise DrmException(u"BookKey Not Found")
+        raise DrmException("BookKey Not Found")
     return records
 
 
@@ -206,7 +206,7 @@ class TopazBook:
         self.bookKey = None
         magic = unpack('4s',self.fo.read(4))[0]
         if magic != 'TPZ0':
-            raise DrmException(u"Parse Error : Invalid Header, not a Topaz file")
+            raise DrmException("Parse Error : Invalid Header, not a Topaz file")
         self.parseTopazHeaders()
         self.parseMetadata()
 
@@ -224,7 +224,7 @@ class TopazBook:
             # Read and parse one header record at the current book file position and return the associated data
             # [[offset,decompressedLength,compressedLength],...]
             if ord(self.fo.read(1)) != 0x63:
-                raise DrmException(u"Parse Error : Invalid Header")
+                raise DrmException("Parse Error : Invalid Header")
             tag = bookReadString(self.fo)
             record = bookReadHeaderRecordData()
             return [tag,record]
@@ -235,7 +235,7 @@ class TopazBook:
             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")
+            raise DrmException("Parse Error : Invalid Header")
         self.bookPayloadOffset = self.fo.tell()
 
     def parseMetadata(self):
@@ -243,7 +243,7 @@ class TopazBook:
         self.fo.seek(self.bookPayloadOffset + self.bookHeaderRecords['metadata'][0][0])
         tag = bookReadString(self.fo)
         if tag != 'metadata' :
-            raise DrmException(u"Parse Error : Record Names Don't Match")
+            raise DrmException("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)
@@ -321,11 +321,11 @@ class TopazBook:
         try:
             keydata = self.getBookPayloadRecord('dkey', 0)
         except DrmException as e:
-            print(u"no dkey record found, book may not be encrypted")
-            print(u"attempting to extrct files without a book key")
+            print("no dkey record found, book may not be encrypted")
+            print("attempting to extrct files without a book key")
             self.createBookDirectory()
             self.extractFiles()
-            print(u"Successfully Extracted Topaz contents")
+            print("Successfully Extracted Topaz contents")
             if inCalibre:
                 from calibre_plugins.dedrm import genbook
             else:
@@ -333,7 +333,7 @@ class TopazBook:
 
             rv = genbook.generateBook(self.outdir, raw, fixedimage)
             if rv == 0:
-                print(u"Book Successfully generated.")
+                print("Book Successfully generated.")
             return rv
 
         # try each pid to decode the file
@@ -341,7 +341,7 @@ class TopazBook:
         for pid in pidlst:
             # use 8 digit pids here
             pid = pid[0:8]
-            print(u"Trying: {0}".format(pid))
+            print("Trying: {0}".format(pid))
             bookKeys = []
             data = keydata
             try:
@@ -350,16 +350,16 @@ class TopazBook:
                 pass
             else:
                 bookKey = bookKeys[0]
-                print(u"Book Key Found! ({0})".format(bookKey.encode('hex')))
+                print("Book Key Found! ({0})".format(bookKey.encode('hex')))
                 break
 
         if not bookKey:
-            raise DrmException(u"No key found in {0:d} keys tried. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(len(pidlst)))
+            raise DrmException("No key found in {0:d} keys tried. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(len(pidlst)))
 
         self.setBookKey(bookKey)
         self.createBookDirectory()
         self.extractFiles()
-        print(u"Successfully Extracted Topaz contents")
+        print("Successfully Extracted Topaz contents")
         if inCalibre:
             from calibre_plugins.dedrm import genbook
         else:
@@ -367,7 +367,7 @@ class TopazBook:
 
         rv = genbook.generateBook(self.outdir, raw, fixedimage)
         if rv == 0:
-            print(u"Book Successfully generated")
+            print("Book Successfully generated")
         return rv
 
     def createBookDirectory(self):
@@ -375,16 +375,16 @@ class TopazBook:
         # create output directory structure
         if not os.path.exists(outdir):
             os.makedirs(outdir)
-        destdir =  os.path.join(outdir,u"img")
+        destdir =  os.path.join(outdir,"img")
         if not os.path.exists(destdir):
             os.makedirs(destdir)
-        destdir =  os.path.join(outdir,u"color_img")
+        destdir =  os.path.join(outdir,"color_img")
         if not os.path.exists(destdir):
             os.makedirs(destdir)
-        destdir =  os.path.join(outdir,u"page")
+        destdir =  os.path.join(outdir,"page")
         if not os.path.exists(destdir):
             os.makedirs(destdir)
-        destdir =  os.path.join(outdir,u"glyphs")
+        destdir =  os.path.join(outdir,"glyphs")
         if not os.path.exists(destdir):
             os.makedirs(destdir)
 
@@ -393,49 +393,49 @@ class TopazBook:
         for headerRecord in self.bookHeaderRecords:
             name = headerRecord
             if name != 'dkey':
-                ext = u".dat"
-                if name == 'img': ext = u".jpg"
-                if name == 'color' : ext = u".jpg"
-                print(u"Processing Section: {0}\n. . .".format(name), end=' ')
+                ext = ".dat"
+                if name == 'img': ext = ".jpg"
+                if name == 'color' : ext = ".jpg"
+                print("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)
+                    fname = "{0}{1:04d}{2}".format(name,index,ext)
                     destdir = outdir
                     if name == 'img':
-                        destdir =  os.path.join(outdir,u"img")
+                        destdir =  os.path.join(outdir,"img")
                     if name == 'color':
-                        destdir =  os.path.join(outdir,u"color_img")
+                        destdir =  os.path.join(outdir,"color_img")
                     if name == 'page':
-                        destdir =  os.path.join(outdir,u"page")
+                        destdir =  os.path.join(outdir,"page")
                     if name == 'glyphs':
-                        destdir =  os.path.join(outdir,u"glyphs")
+                        destdir =  os.path.join(outdir,"glyphs")
                     outputFile = os.path.join(destdir,fname)
-                    print(u".", end=' ')
+                    print(".", end=' ')
                     record = self.getBookPayloadRecord(name,index)
                     if record != '':
                         open(outputFile, 'wb').write(record)
-                print(u" ")
+                print(" ")
 
     def getFile(self, zipname):
         htmlzip = zipfile.ZipFile(zipname,'w',zipfile.ZIP_DEFLATED, False)
-        htmlzip.write(os.path.join(self.outdir,u"book.html"),u"book.html")
-        htmlzip.write(os.path.join(self.outdir,u"book.opf"),u"book.opf")
-        if os.path.isfile(os.path.join(self.outdir,u"cover.jpg")):
-            htmlzip.write(os.path.join(self.outdir,u"cover.jpg"),u"cover.jpg")
-        htmlzip.write(os.path.join(self.outdir,u"style.css"),u"style.css")
-        zipUpDir(htmlzip, self.outdir, u"img")
+        htmlzip.write(os.path.join(self.outdir,"book.html"),"book.html")
+        htmlzip.write(os.path.join(self.outdir,"book.opf"),"book.opf")
+        if os.path.isfile(os.path.join(self.outdir,"cover.jpg")):
+            htmlzip.write(os.path.join(self.outdir,"cover.jpg"),"cover.jpg")
+        htmlzip.write(os.path.join(self.outdir,"style.css"),"style.css")
+        zipUpDir(htmlzip, self.outdir, "img")
         htmlzip.close()
 
     def getBookType(self):
-        return u"Topaz"
+        return "Topaz"
 
     def getBookExtension(self):
-        return u".htmlz"
+        return ".htmlz"
 
     def getSVGZip(self, zipname):
         svgzip = zipfile.ZipFile(zipname,'w',zipfile.ZIP_DEFLATED, False)
-        svgzip.write(os.path.join(self.outdir,u"index_svg.xhtml"),u"index_svg.xhtml")
-        zipUpDir(svgzip, self.outdir, u"svg")
-        zipUpDir(svgzip, self.outdir, u"img")
+        svgzip.write(os.path.join(self.outdir,"index_svg.xhtml"),"index_svg.xhtml")
+        zipUpDir(svgzip, self.outdir, "svg")
+        zipUpDir(svgzip, self.outdir, "img")
         svgzip.close()
 
     def cleanup(self):
@@ -443,20 +443,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 <kindle.k4i>] [-p <comma separated PIDs>] [-s <comma separated Kindle serial numbers>] <infile> <outdir>".format(progname))
+    print("Removes DRM protection from Topaz ebooks and extracts the contents")
+    print("Usage:")
+    print("    {0} [-k <kindle.k4i>] [-p <comma separated PIDs>] [-s <comma separated Kindle serial numbers>] <infile> <outdir>".format(progname))
 
 # Main
 def cli_main():
     argv=unicode_argv()
     progname = os.path.basename(argv[0])
-    print(u"TopazExtract v{0}.".format(__version__))
+    print("TopazExtract v{0}.".format(__version__))
 
     try:
         opts, args = getopt.getopt(argv[1:], "k:p:s:x")
     except getopt.GetoptError as err:
-        print(u"Error in options or arguments: {0}".format(err.args[0]))
+        print("Error in options or arguments: {0}".format(err.args[0]))
         usage(progname)
         return 1
     if len(args)<2:
@@ -466,11 +466,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("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("Output Directory {0} Does Not Exist.".format(outdir))
         return 1
 
     kDatabaseFiles = []
@@ -495,27 +495,27 @@ def cli_main():
 
     tb = TopazBook(infile)
     title = tb.getBookTitle()
-    print(u"Processing Book: {0}".format(title))
+    print("Processing Book: {0}".format(title))
     md1, md2 = tb.getPIDMetaInfo()
     pids.extend(kgenpids.getPidList(md1, md2, serials, kDatabaseFiles))
 
     try:
-        print(u"Decrypting Book")
+        print("Decrypting Book")
         tb.processBook(pids)
 
-        print(u"   Creating HTML ZIP Archive")
-        zipname = os.path.join(outdir, bookname + u"_nodrm.htmlz")
+        print("   Creating HTML ZIP Archive")
+        zipname = os.path.join(outdir, bookname + "_nodrm.htmlz")
         tb.getFile(zipname)
 
-        print(u"   Creating SVG ZIP Archive")
-        zipname = os.path.join(outdir, bookname + u"_SVG.zip")
+        print("   Creating SVG ZIP Archive")
+        zipname = os.path.join(outdir, bookname + "_SVG.zip")
         tb.getSVGZip(zipname)
 
         # removing internal temporary directory of pieces
         tb.cleanup()
 
     except DrmException as e:
-        print(u"Decryption failed\n{0}".format(traceback.format_exc()))
+        print("Decryption failed\n{0}".format(traceback.format_exc()))
 
         try:
             tb.cleanup()
@@ -524,7 +524,7 @@ def cli_main():
         return 1
 
     except Exception as e:
-        print(u"Decryption failed\n{0}".format(traceback.format_exc()))
+        print("Decryption failed\n{0}".format(traceback.format_exc()))
         try:
             tb.cleanup()
         except:
index 56c64fd1effb1cdce202b228d0579a3f04869e00..8472283840aa9a140630d340a4a809d6930e22cc 100644 (file)
@@ -1,8 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-
 from calibre_plugins.dedrm.ignoblekeygen import generate_key
 
 __license__ = 'GPL v3'
index c5d4dee6317dff252ce2bd38dcec0f2bf79bfc76..390e233b1c77be6954d5abccf27abd50907f113d 100644 (file)
@@ -1,9 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-from __future__ import print_function
-
 __license__ = 'GPL v3'
 
 # Standard Python modules.
@@ -17,13 +14,13 @@ def WineGetKeys(scriptpath, extension, wineprefix=""):
     import subasyncio
     from subasyncio import Process
 
-    if extension == u".k4i":
+    if extension == ".k4i":
         import json
 
     basepath, script = os.path.split(scriptpath)
-    print(u"{0} v{1}: Running {2} under Wine".format(PLUGIN_NAME, PLUGIN_VERSION, script))
+    print("{0} v{1}: Running {2} under Wine".format(PLUGIN_NAME, PLUGIN_VERSION, script))
 
-    outdirpath = os.path.join(basepath, u"winekeysdir")
+    outdirpath = os.path.join(basepath, "winekeysdir")
     if not os.path.exists(outdirpath):
         os.makedirs(outdirpath)
 
@@ -31,29 +28,29 @@ def WineGetKeys(scriptpath, extension, 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)
+         cmdline = "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))
+        cmdline = "wine python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath)
+    print("{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 as e:
-        print(u"{0} v{1}: Wine subprocess call error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]))
+        print("{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)
+            cmdline = "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))
+           cmdline = "wine C:\\Python27\\python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath)
+        print("{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 as e:
-           print(u"{0} v{1}: Wine subprocess call error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]))
+           print("{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 = []
@@ -63,14 +60,14 @@ def WineGetKeys(scriptpath, extension, wineprefix=""):
         try:
             fpath = os.path.join(outdirpath, filename)
             with open(fpath, 'rb') as keyfile:
-                if extension == u".k4i":
+                if extension == ".k4i":
                     new_key_value = json.loads(keyfile.read())
                 else:
                     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("{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("{0} v{1}: Found and decrypted {2} {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(winekeys), "key file" if len(winekeys) == 1 else "key files"))
     return winekeys
index d20dab6d8427f19cb7dc0017c6de345574bcd49d..25aed8a47502ebc7c6b77ed89871eaf65608f247 100644 (file)
@@ -1,3 +1,6 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
 """
 Read and write ZIP files.
 """
@@ -824,8 +827,8 @@ class ZipFile:
 
     def open(self, name, mode="r", pwd=None):
         """Return file-like object for 'name'."""
-        if mode not in ("r", "U", "rU"):
-            raise RuntimeError('open() requires mode "r", "U", or "rU"')
+        if mode not in ("r", "", "rU"):
+            raise RuntimeError('open() requires mode "r", "", or "rU"')
         if not self.fp:
             raise RuntimeError(
                   "Attempt to read ZIP archive that was already closed")
index 190cf443a8a4fdaa185a0357c5bc3e625f9939a7..9745495d9c9b0ec860b50e5b67a2b9e4a9aaabff 100644 (file)
@@ -1,8 +1,8 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 # zipfix.py
-# Copyright © 2010-2020 by some_updates, DiapDealer and Apprentice Alf
+# Copyright © 2010-2020 by Apprentice Harper et al.
 
 # Released under the terms of the GNU General Public Licence, version 3
 # <http://www.gnu.org/licenses/>
@@ -10,7 +10,7 @@
 # Revision history:
 #   1.0 - Initial release
 #   1.1 - Updated to handle zip file metadata correctly
-#   2.0 - Added Python 3 compatibility for calibre 5.0
+#   2.0 - Python 3 for calibre 5.0
 
 """
 Re-write zip (or ePub) fixing problems with file names (and mimetype entry).
index 802a833a5e6737b0093655920c57dd1bfee66b3e..e94204f10124581768ca7e1eac5f304c191c2562 100644 (file)
@@ -1,8 +1,8 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
-from __future__ import (unicode_literals, division, absolute_import,
-                        print_function)
 
-__license__   = 'GPL v3'
+_license__   = 'GPL v3'
 __docformat__ = 'restructuredtext en'
 
 
index babad1c5df5570087b3f949a6f0b3822d2fbec43..21b7f195e6d3646e969bc8aafe876ebf63b2ff09 100644 (file)
@@ -1,7 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
-from __future__ import (unicode_literals, division, absolute_import,
-                        print_function)
 
 __license__   = 'GPL v3'
 __copyright__ = '2012, David Forrester <davidfor@internode.on.net>'
@@ -9,13 +8,7 @@ __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,
-                          QVBoxLayout, QDialogButtonBox, QStyledItemDelegate, QDateTime,
-                          QRegExpValidator, QRegExp, QDate, QDateEdit)
-except ImportError:
-    from PyQt4.Qt import (Qt, QIcon, QPixmap, QLabel, QDialog, QHBoxLayout, QProgressBar,
+from PyQt5.Qt import (Qt, QIcon, QPixmap, QLabel, QDialog, QHBoxLayout, QProgressBar,
                           QTableWidgetItem, QFont, QLineEdit, QComboBox,
                           QVBoxLayout, QDialogButtonBox, QStyledItemDelegate, QDateTime,
                           QRegExpValidator, QRegExp, QDate, QDateEdit)
index 522b86a403ad7fa7d6407bf0f974dc825ee3f6b4..2830dad2deb48190da071cd66322a0e062374398 100644 (file)
@@ -1,16 +1,10 @@
-# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
-from __future__ import (unicode_literals, division, absolute_import,
-                        print_function)
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 
-try:
-    from PyQt5.Qt import (Qt, QGroupBox, QListWidget, QLineEdit, QDialogButtonBox, QWidget, QLabel, QDialog, QVBoxLayout, QAbstractItemView, QIcon, QHBoxLayout, QComboBox, QListWidgetItem, QFileDialog)
-except ImportError:
-    from PyQt4.Qt import (Qt, QGroupBox, QListWidget, QLineEdit, QDialogButtonBox, QWidget, QLabel, QDialog, QVBoxLayout, QAbstractItemView, QIcon, QHBoxLayout, QComboBox, QListWidgetItem, QFileDialog)
+# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
 
-try:
-    from PyQt5 import Qt as QtGui
-except ImportError:
-    from PyQt4 import QtGui
+from PyQt5.Qt import (Qt, QGroupBox, QListWidget, QLineEdit, QDialogButtonBox, QWidget, QLabel, QDialog, QVBoxLayout, QAbstractItemView, QIcon, QHBoxLayout, QComboBox, QListWidgetItem, QFileDialog)
+from PyQt5 import Qt as QtGui
 
 from calibre.gui2 import (error_dialog, question_dialog, info_dialog, open_url)
 from calibre.utils.config import JSONConfig, config_dir
@@ -50,25 +44,25 @@ class ConfigWidget(QWidget):
         self.find_homes.setCurrentIndex(index)
 
         self.serials_button = QtGui.QPushButton(self)
-        self.serials_button.setToolTip(_(u"Click to manage Kobo serial numbers for Kobo ebooks"))
-        self.serials_button.setText(u"Kobo devices serials")
+        self.serials_button.setToolTip(_("Click to manage Kobo serial numbers for Kobo ebooks"))
+        self.serials_button.setText("Kobo devices serials")
         self.serials_button.clicked.connect(self.edit_serials)
         layout.addWidget(self.serials_button)
 
         self.kobo_directory_button = QtGui.QPushButton(self)
-        self.kobo_directory_button.setToolTip(_(u"Click to specify the Kobo directory"))
-        self.kobo_directory_button.setText(u"Kobo directory")
+        self.kobo_directory_button.setToolTip(_("Click to specify the Kobo directory"))
+        self.kobo_directory_button.setText("Kobo directory")
         self.kobo_directory_button.clicked.connect(self.edit_kobo_directory)
         layout.addWidget(self.kobo_directory_button)
 
 
     def edit_serials(self):
-        d = ManageKeysDialog(self,u"Kobo device serial number",self.tmpserials, AddSerialDialog)
+        d = ManageKeysDialog(self,"Kobo device serial number",self.tmpserials, AddSerialDialog)
         d.exec_()
 
 
     def edit_kobo_directory(self):
-        tmpkobodirectory = QFileDialog.getExistingDirectory(self, u"Select Kobo directory", self.kobodirectory or "/home", QFileDialog.ShowDirsOnly)
+        tmpkobodirectory = QFileDialog.getExistingDirectory(self, "Select Kobo directory", self.kobodirectory or "/home", QFileDialog.ShowDirsOnly)
 
         if tmpkobodirectory != u"" and tmpkobodirectory is not None:
             self.kobodirectory = tmpkobodirectory
@@ -91,7 +85,7 @@ class ManageKeysDialog(QDialog):
         self.plugin_keys = plugin_keys
         self.create_key = create_key
         self.keyfile_ext = keyfile_ext
-        self.json_file = (keyfile_ext == u"k4i")
+        self.json_file = (keyfile_ext == "k4i")
 
         self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name))
 
@@ -99,13 +93,13 @@ class ManageKeysDialog(QDialog):
         layout = QVBoxLayout(self)
         self.setLayout(layout)
 
-        keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self)
+        keys_group_box = QGroupBox(_("{0}s".format(self.key_type_name)), self)
         layout.addWidget(keys_group_box)
         keys_group_box_layout = QHBoxLayout()
         keys_group_box.setLayout(keys_group_box_layout)
 
         self.listy = QListWidget(self)
-        self.listy.setToolTip(u"{0}s that will be used to decrypt ebooks".format(self.key_type_name))
+        self.listy.setToolTip("{0}s that will be used to decrypt ebooks".format(self.key_type_name))
         self.listy.setSelectionMode(QAbstractItemView.SingleSelection)
         self.populate_list()
         keys_group_box_layout.addWidget(self.listy)
@@ -114,12 +108,12 @@ class ManageKeysDialog(QDialog):
         keys_group_box_layout.addLayout(button_layout)
         self._add_key_button = QtGui.QToolButton(self)
         self._add_key_button.setIcon(QIcon(I('plus.png')))
-        self._add_key_button.setToolTip(u"Create new {0}".format(self.key_type_name))
+        self._add_key_button.setToolTip("Create new {0}".format(self.key_type_name))
         self._add_key_button.clicked.connect(self.add_key)
         button_layout.addWidget(self._add_key_button)
 
         self._delete_key_button = QtGui.QToolButton(self)
-        self._delete_key_button.setToolTip(_(u"Delete highlighted key"))
+        self._delete_key_button.setToolTip(_("Delete highlighted key"))
         self._delete_key_button.setIcon(QIcon(I('list_remove.png')))
         self._delete_key_button.clicked.connect(self.delete_key)
         button_layout.addWidget(self._delete_key_button)
@@ -155,7 +149,7 @@ class ManageKeysDialog(QDialog):
         new_key_value = d.key_value
         if new_key_value in self.plugin_keys:
             info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name),
-                        u"This {0} is already in the list of {0}s has not been added.".format(self.key_type_name), show=True)
+                        "This {0} is already in the list of {0}s has not been added.".format(self.key_type_name), show=True)
             return
 
         self.plugin_keys.append(d.key_value)
@@ -166,7 +160,7 @@ class ManageKeysDialog(QDialog):
         if not self.listy.currentItem():
             return
         keyname = self.listy.currentItem().text()
-        if not question_dialog(self, "{0} {1}: Confirm Delete".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to delete the {1} <strong>{0}</strong>?".format(keyname, self.key_type_name), show_copy_button=False, default_yes=False):
+        if not question_dialog(self, "{0} {1}: Confirm Delete".format(PLUGIN_NAME, PLUGIN_VERSION), "Do you really want to delete the {1} <strong>{0}</strong>?".format(keyname, self.key_type_name), show_copy_button=False, default_yes=False):
             return
         self.plugin_keys.remove(keyname)
 
@@ -177,7 +171,7 @@ class AddSerialDialog(QDialog):
     def __init__(self, parent=None,):
         QDialog.__init__(self, parent)
         self.parent = parent
-        self.setWindowTitle(u"{0} {1}: Add New eInk Kobo Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
+        self.setWindowTitle("{0} {1}: Add New eInk Kobo Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
         layout = QVBoxLayout(self)
         self.setLayout(layout)
 
@@ -188,9 +182,9 @@ class AddSerialDialog(QDialog):
 
         key_group = QHBoxLayout()
         data_group_box_layout.addLayout(key_group)
-        key_group.addWidget(QLabel(u"EInk Kobo Serial Number:", self))
+        key_group.addWidget(QLabel("EInk Kobo Serial Number:", self))
         self.key_ledit = QLineEdit("", self)
-        self.key_ledit.setToolTip(u"Enter an eInk Kobo serial number. EInk Kobo serial numbers are 13 characters long and usually start with a 'N'. Kobo Serial Numbers are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
+        self.key_ledit.setToolTip("Enter an eInk Kobo serial number. EInk Kobo serial numbers are 13 characters long and usually start with a 'N'. Kobo Serial Numbers are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
         key_group.addWidget(self.key_ledit)
 
         self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
@@ -210,9 +204,9 @@ class AddSerialDialog(QDialog):
 
     def accept(self):
         if len(self.key_name) == 0 or self.key_name.isspace():
-            errmsg = u"Please enter an eInk Kindle Serial Number or click Cancel in the dialog."
+            errmsg = "Please enter an eInk Kindle Serial Number or click Cancel in the dialog."
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         if len(self.key_name) != 13:
-            errmsg = u"EInk Kobo Serial Numbers must be 13 characters long. This is {0:d} characters long.".format(len(self.key_name))
+            errmsg = "EInk Kobo Serial Numbers must be 13 characters long. This is {0:d} characters long.".format(len(self.key_name))
             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
         QDialog.accept(self)
index 80bc058f7e34342cfc4e34045360928c4606ecf0..d20f6dc3689edd95deb8a268330ba3fc9f8153c9 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 # Version 4.0.0 September 2020
 from __future__ import print_function
 
 __version__ = '4.0.0'
-__about__ =  u"Obok v{0}\nCopyright © 2012-2020 Physisticated et al.".format(__version__)
+__about__ =  "Obok v{0}\nCopyright © 2012-2020 Physisticated et al.".format(__version__)
 
 import sys
 import os
@@ -176,10 +176,10 @@ import tempfile
 can_parse_xml = True
 try:
   from xml.etree import ElementTree as ET
-  # print u"using xml.etree for xml parsing"
+  # print "using xml.etree for xml parsing"
 except ImportError:
   can_parse_xml = False
-  # print u"Cannot find xml.etree, disabling extraction of serial numbers"
+  # print "Cannot find xml.etree, disabling extraction of serial numbers"
 
 # List of all known hash keys
 KOBO_HASH_KEYS = ['88b3a2e13', 'XzUhGYdFp', 'NoCanLook','QJhwzAtXL']
@@ -279,10 +279,10 @@ class SafeUnbuffered:
         if self.encoding == None:
             self.encoding = "utf-8"
     def write(self, data):
-        if isinstance(data,bytes):
+        if isinstance(data,str):
             data = data.encode(self.encoding,"replace")
-        self.stream.write(data)
-        self.stream.flush()
+        self.stream.buffer.write(data)
+        self.stream.buffer.flush()
     def __getattr__(self, attr):
         return getattr(self.stream, attr)
 
@@ -312,9 +312,9 @@ class KoboLibrary(object):
         # step 1. check whether this looks like a real device
         if (device_path):
             # we got a device path
-            self.kobodir = os.path.join(device_path, u".kobo")
+            self.kobodir = os.path.join(device_path, ".kobo")
             # devices use KoboReader.sqlite
-            kobodb  = os.path.join(self.kobodir, u"KoboReader.sqlite")
+            kobodb  = os.path.join(self.kobodir, "KoboReader.sqlite")
             if (not(os.path.isfile(kobodb))):
                 # device path seems to be wrong, unset it
                 device_path = u""
@@ -326,22 +326,22 @@ class KoboLibrary(object):
             if (len(serials) == 0):
                 # we got a device path but no saved serial
                 # try to get the serial from the device
-                # print u"get_device_settings - device_path = {0}".format(device_path)
+                # print "get_device_settings - device_path = {0}".format(device_path)
                 # get serial from device_path/.adobe-digital-editions/device.xml
                 if can_parse_xml:
                     devicexml = os.path.join(device_path, '.adobe-digital-editions', 'device.xml')
-                    # print u"trying to load {0}".format(devicexml)
+                    # print "trying to load {0}".format(devicexml)
                     if (os.path.exists(devicexml)):
-                        # print u"trying to parse {0}".format(devicexml)
+                        # print "trying to parse {0}".format(devicexml)
                         xmltree = ET.parse(devicexml)
                         for node in xmltree.iter():
                             if "deviceSerial" in node.tag:
                                 serial = node.text
-                                # print u"found serial {0}".format(serial)
+                                # print "found serial {0}".format(serial)
                                 serials.append(serial)
                                 break
                     else:
-                        # print u"cannot get serials from device."
+                        # print "cannot get serials from device."
                         device_path = u""
                         self.kobodir = u""
                         kobodb  = u""
@@ -357,19 +357,19 @@ class KoboLibrary(object):
                     if sys.getwindowsversion().major > 5:
                         if 'LOCALAPPDATA' in os.environ.keys():
                             # Python 2.x does not return unicode env. Use Python 3.x
-                            self.kobodir = winreg.ExpandEnvironmentStrings(u"%LOCALAPPDATA%")
+                            self.kobodir = winreg.ExpandEnvironmentStrings("%LOCALAPPDATA%")
                     if (self.kobodir == u""):
                         if 'USERPROFILE' in os.environ.keys():
                             # Python 2.x does not return unicode env. Use Python 3.x
-                            self.kobodir = os.path.join(winreg.ExpandEnvironmentStrings(u"%USERPROFILE%"), u"Local Settings", u"Application Data")
-                    self.kobodir = os.path.join(self.kobodir, u"Kobo", u"Kobo Desktop Edition")
+                            self.kobodir = os.path.join(winreg.ExpandEnvironmentStrings("%USERPROFILE%"), "Local Settings", "Application Data")
+                    self.kobodir = os.path.join(self.kobodir, "Kobo", "Kobo Desktop Edition")
                 elif sys.platform.startswith('darwin'):
-                    self.kobodir = os.path.join(os.environ['HOME'], u"Library", u"Application Support", u"Kobo", u"Kobo Desktop Edition")
+                    self.kobodir = os.path.join(os.environ['HOME'], "Library", "Application Support", "Kobo", "Kobo Desktop Edition")
             #elif linux_path != None:
                 # Probably Linux, let's get the wine prefix and path to Kobo.
-            #   self.kobodir = os.path.join(linux_path, u"Local Settings", u"Application Data", u"Kobo", u"Kobo Desktop Edition")
+            #   self.kobodir = os.path.join(linux_path, "Local Settings", "Application Data", "Kobo", "Kobo Desktop Edition")
             # desktop versions use Kobo.sqlite
-            kobodb = os.path.join(self.kobodir, u"Kobo.sqlite")
+            kobodb = os.path.join(self.kobodir, "Kobo.sqlite")
             # check for existence of file
             if (not(os.path.isfile(kobodb))):
                 # give up here, we haven't found anything useful
@@ -377,7 +377,7 @@ class KoboLibrary(object):
                 kobodb  = u""
 
         if (self.kobodir != u""):
-            self.bookdir = os.path.join(self.kobodir, u"kepub")
+            self.bookdir = os.path.join(self.kobodir, "kepub")
             # 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)
@@ -437,7 +437,7 @@ class KoboLibrary(object):
 
     def __bookfile (self, volumeid):
         """The filename needed to open a given book."""
-        return os.path.join(self.kobodir, u"kepub", volumeid)
+        return os.path.join(self.kobodir, "kepub", volumeid)
 
     def __getmacaddrs (self):
         """The list of all MAC addresses on this machine."""
@@ -454,7 +454,7 @@ class KoboLibrary(object):
             output = subprocess.check_output('/sbin/ifconfig -a', shell=True)
             matches = c.findall(output)
             for m in matches:
-                # print u"m:{0}".format(m[0])
+                # print "m:{0}".format(m[0])
                 macaddrs.append(m[0].upper())
         else:
             # probably linux
@@ -607,32 +607,32 @@ class KoboFile(object):
             # assume utf-8 with no BOM
             textoffset = 0
             stride = 1
-            print(u"Checking text:{0}:".format(contents[:10]))
+            print("Checking text:{0}:".format(contents[:10]))
             # check for byte order mark
             if contents[:3]==b"\xef\xbb\xbf":
                 # seems to be utf-8 with BOM
-                print(u"Could be utf-8 with BOM")
+                print("Could be utf-8 with BOM")
                 textoffset = 3
             elif contents[:2]==b"\xfe\xff":
                 # seems to be utf-16BE
-                print(u"Could be  utf-16BE")
+                print("Could be  utf-16BE")
                 textoffset = 3
                 stride = 2
             elif contents[:2]==b"\xff\xfe":
                 # seems to be utf-16LE
-                print(u"Could be  utf-16LE")
+                print("Could be  utf-16LE")
                 textoffset = 2
                 stride = 2
             else:
-                print(u"Perhaps utf-8 without BOM")
+                print("Perhaps utf-8 without BOM")
 
             # now check that the first few characters are in the ASCII range
             for i in range(textoffset,textoffset+5*stride,stride):
                 if contents[i]<32 or contents[i]>127:
                     # Non-ascii, so decryption probably failed
-                    print(u"Bad character at {0}, value {1}".format(i,contents[i]))
+                    print("Bad character at {0}, value {1}".format(i,contents[i]))
                     raise ValueError
-            print(u"Seems to be good text")
+            print("Seems to be good text")
             return True
             if contents[:5]==b"<?xml" or contents[:8]==b"\xef\xbb\xbf<?xml":
                 # utf-8
@@ -653,13 +653,13 @@ class KoboFile(object):
                 # utf-16LE of weird <!DOCTYPE start
                 return True
             else:
-                print(u"Bad XML: {0}".format(contents[:8]))
+                print("Bad XML: {0}".format(contents[:8]))
                 raise ValueError
         elif self.mimetype == 'image/jpeg':
             if contents[:3] == b'\xff\xd8\xff':
                 return True
             else:
-                print(u"Bad JPEG: {0}".format(contents[:3].hex()))
+                print("Bad JPEG: {0}".format(contents[:3].hex()))
                 raise ValueError()
         return False
 
@@ -682,18 +682,18 @@ class KoboFile(object):
         return contents
 
 def decrypt_book(book, lib):
-    print(u"Converting {0}".format(book.title))
+    print("Converting {0}".format(book.title))
     zin = zipfile.ZipFile(book.filename, "r")
     # make filename out of Unicode alphanumeric and whitespace equivalents from title
-    outname = u"{0}.epub".format(re.sub('[^\s\w]', '_', book.title, 0, re.UNICODE))
+    outname = "{0}.epub".format(re.sub('[^\s\w]', '_', book.title, 0, re.UNICODE))
     if (book.type == 'drm-free'):
-        print(u"DRM-free book, conversion is not needed")
+        print("DRM-free book, conversion is not needed")
         shutil.copyfile(book.filename, outname)
-        print(u"Book saved as {0}".format(os.path.join(os.getcwd(), outname)))
+        print("Book saved as {0}".format(os.path.join(os.getcwd(), outname)))
         return 0
     result = 1
     for userkey in lib.userkeys:
-        print(u"Trying key: {0}".format(userkey.hex()))
+        print("Trying key: {0}".format(userkey.hex()))
         try:
             zout = zipfile.ZipFile(outname, "w", zipfile.ZIP_DEFLATED)
             for filename in zin.namelist():
@@ -705,12 +705,12 @@ def decrypt_book(book, lib):
                     file.check(contents)
                 zout.writestr(filename, contents)
             zout.close()
-            print(u"Decryption succeeded.")
-            print(u"Book saved as {0}".format(os.path.join(os.getcwd(), outname)))
+            print("Decryption succeeded.")
+            print("Book saved as {0}".format(os.path.join(os.getcwd(), outname)))
             result = 0
             break
         except ValueError:
-            print(u"Decryption failed.")
+            print("Decryption failed.")
             zout.close()
             os.remove(outname)
     zin.close()
@@ -719,7 +719,7 @@ def decrypt_book(book, lib):
 
 def cli_main():
     description = __about__
-    epilog = u"Parsing of arguments failed."
+    epilog = "Parsing of arguments failed."
     parser = argparse.ArgumentParser(prog=sys.argv[0], description=description, epilog=epilog)
     parser.add_argument('--devicedir', default='/media/KOBOeReader', help="directory of connected Kobo device")
     parser.add_argument('--all', action='store_true', help="flag for converting all books on device")
@@ -735,25 +735,25 @@ def cli_main():
         books = lib.books
     else:
         for i, book in enumerate(lib.books):
-            print(u"{0}: {1}".format(i + 1, book.title))
-        print(u"Or 'all'")
+            print("{0}: {1}".format(i + 1, book.title))
+        print("Or 'all'")
 
-        choice = input(u"Convert book number... ")
-        if choice == u'all':
+        choice = input("Convert book number... ")
+        if choice == "all":
             books = list(lib.books)
         else:
             try:
                 num = int(choice)
                 books = [lib.books[num - 1]]
             except (ValueError, IndexError):
-                print(u"Invalid choice. Exiting...")
+                print("Invalid choice. Exiting...")
                 exit()
 
     results = [decrypt_book(book, lib) for book in books]
     lib.close()
     overall_result = all(result != 0 for result in results)
     if overall_result != 0:
-        print(u"Could not decrypt book with any of the keys found.")
+        print("Could not decrypt book with any of the keys found.")
     return overall_result
 
 
index f81bd1c91f3bd99ffa5439e47b8c9eb3795e766c..b2f02ade09943a2f649c6276e14342564a4b61d4 100644 (file)
@@ -1,6 +1,6 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
-from __future__ import (unicode_literals, division, absolute_import,
-                        print_function)
 
 __license__   = 'GPL v3'
 __docformat__ = 'restructuredtext en'
@@ -13,10 +13,7 @@ except ImportError:
     from io import StringIO
 from traceback import print_exc
 
-try:
-    from PyQt5.Qt import (Qt, QDialog, QPixmap, QIcon, QLabel, QHBoxLayout, QFont, QTableWidgetItem)
-except ImportError:
-    from PyQt4.Qt import (Qt, QDialog, QPixmap, QIcon, QLabel, QHBoxLayout, QFont, QTableWidgetItem)
+from PyQt5.Qt import (Qt, QDialog, QPixmap, QIcon, QLabel, QHBoxLayout, QFont, QTableWidgetItem)
 
 from calibre.utils.config import config_dir
 from calibre.constants import iswindows, DEBUG
index fa71c583b666f6701f1b38838c6c27e4f538483d..fc0cabf4297c134fee41534a8ef5c7459699c841 100644 (file)
 from __future__ import print_function
 
 __version__ = '3.2.4'
-__about__ =  u"Obok v{0}\nCopyright © 2012-2016 Physisticated et al.".format(__version__)
+__about__ =  "Obok v{0}\nCopyright © 2012-2016 Physisticated et al.".format(__version__)
 
 import sys
 import os
@@ -173,10 +173,10 @@ import tempfile
 can_parse_xml = True
 try:
   from xml.etree import ElementTree as ET
-  # print u"using xml.etree for xml parsing"
+  # print "using xml.etree for xml parsing"
 except ImportError:
   can_parse_xml = False
-  # print u"Cannot find xml.etree, disabling extraction of serial numbers"
+  # print "Cannot find xml.etree, disabling extraction of serial numbers"
 
 # List of all known hash keys
 KOBO_HASH_KEYS = ['88b3a2e13', 'XzUhGYdFp', 'NoCanLook','QJhwzAtXL']
@@ -309,9 +309,9 @@ class KoboLibrary(object):
         # step 1. check whether this looks like a real device
         if (device_path):
             # we got a device path
-            self.kobodir = os.path.join(device_path, u".kobo")
+            self.kobodir = os.path.join(device_path, ".kobo")
             # devices use KoboReader.sqlite
-            kobodb  = os.path.join(self.kobodir, u"KoboReader.sqlite")
+            kobodb  = os.path.join(self.kobodir, "KoboReader.sqlite")
             if (not(os.path.isfile(kobodb))):
                 # device path seems to be wrong, unset it
                 device_path = u""
@@ -323,22 +323,22 @@ class KoboLibrary(object):
             if (len(serials) == 0):
                 # we got a device path but no saved serial
                 # try to get the serial from the device
-                # print u"get_device_settings - device_path = {0}".format(device_path)
+                # print "get_device_settings - device_path = {0}".format(device_path)
                 # get serial from device_path/.adobe-digital-editions/device.xml
                 if can_parse_xml:
                     devicexml = os.path.join(device_path, '.adobe-digital-editions', 'device.xml')
-                    # print u"trying to load {0}".format(devicexml)
+                    # print "trying to load {0}".format(devicexml)
                     if (os.path.exists(devicexml)):
-                        # print u"trying to parse {0}".format(devicexml)
+                        # print "trying to parse {0}".format(devicexml)
                         xmltree = ET.parse(devicexml)
                         for node in xmltree.iter():
                             if "deviceSerial" in node.tag:
                                 serial = node.text
-                                # print u"found serial {0}".format(serial)
+                                # print "found serial {0}".format(serial)
                                 serials.append(serial)
                                 break
                     else:
-                        # print u"cannot get serials from device."
+                        # print "cannot get serials from device."
                         device_path = u""
                         self.kobodir = u""
                         kobodb  = u""
@@ -350,19 +350,19 @@ class KoboLibrary(object):
                 if sys.getwindowsversion().major > 5:
                     if 'LOCALAPPDATA' in os.environ.keys():
                         # Python 2.x does not return unicode env. Use Python 3.x
-                        self.kobodir = winreg.ExpandEnvironmentStrings(u"%LOCALAPPDATA%")
+                        self.kobodir = winreg.ExpandEnvironmentStrings("%LOCALAPPDATA%")
                 if (self.kobodir == u""):
                     if 'USERPROFILE' in os.environ.keys():
                         # Python 2.x does not return unicode env. Use Python 3.x
-                        self.kobodir = os.path.join(winreg.ExpandEnvironmentStrings(u"%USERPROFILE%"), u"Local Settings", u"Application Data")
-                self.kobodir = os.path.join(self.kobodir, u"Kobo", u"Kobo Desktop Edition")
+                        self.kobodir = os.path.join(winreg.ExpandEnvironmentStrings("%USERPROFILE%"), "Local Settings", "Application Data")
+                self.kobodir = os.path.join(self.kobodir, "Kobo", "Kobo Desktop Edition")
             elif sys.platform.startswith('darwin'):
-                self.kobodir = os.path.join(os.environ['HOME'], u"Library", u"Application Support", u"Kobo", u"Kobo Desktop Edition")
+                self.kobodir = os.path.join(os.environ['HOME'], "Library", "Application Support", "Kobo", "Kobo Desktop Edition")
             #elif linux_path != None:
                 # Probably Linux, let's get the wine prefix and path to Kobo.
-            #   self.kobodir = os.path.join(linux_path, u"Local Settings", u"Application Data", u"Kobo", u"Kobo Desktop Edition")
+            #   self.kobodir = os.path.join(linux_path, "Local Settings", "Application Data", "Kobo", "Kobo Desktop Edition")
             # desktop versions use Kobo.sqlite
-            kobodb = os.path.join(self.kobodir, u"Kobo.sqlite")
+            kobodb = os.path.join(self.kobodir, "Kobo.sqlite")
             # check for existence of file
             if (not(os.path.isfile(kobodb))):
                 # give up here, we haven't found anything useful
@@ -371,7 +371,7 @@ class KoboLibrary(object):
 
         
         if (self.kobodir != u""):
-            self.bookdir = os.path.join(self.kobodir, u"kepub")
+            self.bookdir = os.path.join(self.kobodir, "kepub")
             # 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)
@@ -431,7 +431,7 @@ class KoboLibrary(object):
 
     def __bookfile (self, volumeid):
         """The filename needed to open a given book."""
-        return os.path.join(self.kobodir, u"kepub", volumeid)
+        return os.path.join(self.kobodir, "kepub", volumeid)
 
     def __getmacaddrs (self):
         """The list of all MAC addresses on this machine."""
@@ -448,7 +448,7 @@ class KoboLibrary(object):
             output = subprocess.check_output('/sbin/ifconfig -a', shell=True)
             matches = c.findall(output)
             for m in matches:
-                # print u"m:{0}".format(m[0])
+                # print "m:{0}".format(m[0])
                 macaddrs.append(m[0].upper())
         elif sys.platform.startswith('linux'):
             p_out = subprocess.check_output("ip -br link show | awk '{print $3}'", shell=True)
@@ -596,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("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("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("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("Could be  utf-16LE")
                 textoffset = 2
                 stride = 2
             else:
-                print(u"Perhaps utf-8 without BOM")
+                print("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("Bad character at {0}, value {1}".format(i,ord(contents[i])))
                     raise ValueError
-            print(u"Seems to be good text")
+            print("Seems to be good text")
             return True
             if contents[:5]=="<?xml" or contents[:8]=="\xef\xbb\xbf<?xml":
                 # utf-8
@@ -642,13 +642,13 @@ class KoboFile(object):
                 # utf-16LE of weird <!DOCTYPE start
                 return True
             else:
-                print(u"Bad XML: {0}".format(contents[:8]))
+                print("Bad XML: {0}".format(contents[:8]))
                 raise ValueError
         elif self.mimetype == 'image/jpeg':
             if contents[:3] == '\xff\xd8\xff':
                 return True
             else:
-                print(u"Bad JPEG: {0}".format(contents[:3].encode('hex')))
+                print("Bad JPEG: {0}".format(contents[:3].encode('hex')))
                 raise ValueError()
         return False
 
@@ -671,18 +671,18 @@ class KoboFile(object):
         return contents
 
 def decrypt_book(book, lib):
-    print(u"Converting {0}".format(book.title))
+    print("Converting {0}".format(book.title))
     zin = zipfile.ZipFile(book.filename, "r")
     # make filename out of Unicode alphanumeric and whitespace equivalents from title
-    outname = u"{0}.epub".format(re.sub('[^\s\w]', '_', book.title, 0, re.UNICODE))
+    outname = "{0}.epub".format(re.sub('[^\s\w]', '_', book.title, 0, re.UNICODE))
     if (book.type == 'drm-free'):
-        print(u"DRM-free book, conversion is not needed")
+        print("DRM-free book, conversion is not needed")
         shutil.copyfile(book.filename, outname)
-        print(u"Book saved as {0}".format(os.path.join(os.getcwd(), outname)))
+        print("Book saved as {0}".format(os.path.join(os.getcwd(), outname)))
         return 0
     result = 1
     for userkey in lib.userkeys:
-        print(u"Trying key: {0}".format(userkey.encode('hex_codec')))
+        print("Trying key: {0}".format(userkey.encode('hex_codec')))
         try:
             zout = zipfile.ZipFile(outname, "w", zipfile.ZIP_DEFLATED)
             for filename in zin.namelist():
@@ -694,12 +694,12 @@ def decrypt_book(book, lib):
                     file.check(contents)
                 zout.writestr(filename, contents)
             zout.close()
-            print(u"Decryption succeeded.")
-            print(u"Book saved as {0}".format(os.path.join(os.getcwd(), outname)))
+            print("Decryption succeeded.")
+            print("Book saved as {0}".format(os.path.join(os.getcwd(), outname)))
             result = 0
             break
         except ValueError:
-            print(u"Decryption failed.")
+            print("Decryption failed.")
             zout.close()
             os.remove(outname)
     zin.close()
@@ -708,7 +708,7 @@ def decrypt_book(book, lib):
 
 def cli_main():
     description = __about__
-    epilog = u"Parsing of arguments failed."
+    epilog = "Parsing of arguments failed."
     parser = argparse.ArgumentParser(prog=sys.argv[0], description=description, epilog=epilog)
     parser.add_argument('--devicedir', default='/media/KOBOeReader', help="directory of connected Kobo device")
     parser.add_argument('--all', action='store_true', help="flag for converting all books on device")
@@ -724,25 +724,25 @@ def cli_main():
         books = lib.books
     else:
         for i, book in enumerate(lib.books):
-            print(u"{0}: {1}".format(i + 1, book.title))
-        print(u"Or 'all'")
+            print("{0}: {1}".format(i + 1, book.title))
+        print("Or 'all'")
 
-        choice = raw_input(u"Convert book number... ")
-        if choice == u'all':
+        choice = raw_input("Convert book number... ")
+        if choice == "all":
             books = list(lib.books)
         else:
             try:
                 num = int(choice)
                 books = [lib.books[num - 1]]
             except (ValueError, IndexError):
-                print(u"Invalid choice. Exiting...")
+                print("Invalid choice. Exiting...")
                 exit()
 
     results = [decrypt_book(book, lib) for book in books]
     lib.close()
     overall_result = all(result != 0 for result in results)
     if overall_result != 0:
-        print(u"Could not decrypt book with any of the keys found.")
+        print("Could not decrypt book with any of the keys found.")
     return overall_result
 
 
index bedb956297e8194957e28ebd8535b09878fbfca1..68352fb62d27ce903ce6a09ee370f496ee5ee4a1 100755 (executable)
@@ -1,5 +1,5 @@
-#!/usr/bin/env python
-# code: utf-8
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 
 '''
 A wrapper script to generate zip files for GitHub releases.