]> xmof Git - DeDRM.git/commitdiff
Added help file for Kindle for Android keys to plugin. Copied updated files to Mac...
authorApprentice Harper <apprenticeharper@gmail.com>
Wed, 18 Mar 2015 20:37:54 +0000 (20:37 +0000)
committerApprentice Alf <apprenticealf@gmail.com>
Wed, 18 Mar 2015 20:37:54 +0000 (20:37 +0000)
15 files changed:
DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_EInk Kindle Serial Number_Help.htm
DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Android_Help.htm [new file with mode: 0644]
DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py
DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/androidkindlekey.py
DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py
DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/prefs.py
DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_EInk Kindle Serial Number_Help.htm
DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Kindle for Android_Help.htm [new file with mode: 0644]
DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py
DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/androidkindlekey.py
DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/config.py
DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/prefs.py
DeDRM_calibre_plugin/DeDRM_plugin.zip
DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_EInk Kindle Serial Number_Help.htm
DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Kindle for Android_Help.htm [new file with mode: 0644]

index e79abd7009542cd720437c3b9ce63f6f7914f77f..5a4692d791eefff0bb40c64032a0837ba98589cd 100644 (file)
@@ -1,4 +1,4 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/html4/strict.dtd">
 
 <html>
@@ -27,7 +27,7 @@ li {margin-top: 0.5em}
 
 <p>On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Kindle serial number.</p>
 <ul>
-<li><span class="bold">Eink Kindle Serial Number:</span> this is the unique serial number of your device. It usually starts with a ‘B’ or a ‘9’ and is sixteen characters long. For a reference of where to find serial numbers and their ranges, please refere to this <a href="http://wiki.mobileread.com/wiki/Kindle_serial_numbers">mobileread wiki page.</a></li>
+<li><span class="bold">Eink Kindle Serial Number:</span> this is the unique serial number of your device. It usually starts with a ‘B’ or a ‘9’ and is sixteen characters long. For a reference of where to find serial numbers and their ranges, please refer to this <a href="http://wiki.mobileread.com/wiki/Kindle_serial_numbers">mobileread wiki page.</a></li>
 </ul>
 
 <p>Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.</p>
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Android_Help.htm b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Android_Help.htm
new file mode 100644 (file)
index 0000000..7bdba64
--- /dev/null
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+       "http://www.w3.org/TR/html4/strict.dtd">
+
+<html>
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+<title>Managing Kindle for Android serial numbers</title>
+<style type="text/css">
+span.version {font-size: 50%}
+span.bold {font-weight: bold}
+h3 {margin-bottom: 0}
+p {margin-top: 0}
+li {margin-top: 0.5em}
+</style>
+</head>
+
+<body>
+
+<h1>Managing Kindle for Android serial numbers</h1>
+
+<p>Amazon's Kindle for Android application uses an internal serial number that's 72 character long. Extracting that serial number is a little tricky, but worth it, as it then allows the DRM to be removed from any Kindle ebooks that have been downloaded to that Android device.</p>
+
+<p>Please note that it is not currently known whether the same applies to the Kindle application on the Kindle Fire and Fire HD.</p>
+
+<h3>Getting the Kindle for Android backup file</h3>
+
+<p>Obtain and install adb (Android Debug Bridge) on your computer. Details of how to do this are beyond the scope of this help file, but there are plenty of on-line guides.</p>
+<p>Enable developer mode on your Android device. Again, look for an on-line guide for your device.</p>
+<p>Once you have adb installed and your device in developer mode, connect your device to your computer with a USB cable and then open up a command line (Terminal on Mac OS X and cmd.exe on Windows) and enter "adb backup com.amazon.kindle" (without the quotation marks!) and press return. A file "backup.ab" should be created in your home directory.
+
+<h3>Adding the Kindle for Android serial number</h3>
+
+<p>At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import the ‘backup.ab’ file you obtained by using the adb command. The backup file will be processed to extract any serial numbers in it, and the numbers will be added to the list.</p>
+
+<h3>Adding the Kindle for Android serial number manually</h3>
+<p>On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Kindle for Android serial number.</p>
+<ul>
+<li><span class="bold">Kindle for Android Serial Number:</span> this is the unique serial number of your device. You may have obtained this through using the old android.py script.</li>
+</ul>
+
+<p>Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.</p>
+
+<h3>Deleting Kindle for Android serial numbers:</h3>
+
+<p>On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted Kindle serial number from the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.</p>
+
+<p>Once done creating/deleting serial numbers, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.</p>
+
+</body>
+
+</html>
index 37c454cfc02b33bb0fe9b046fa4ce8fdbcde6069..ef1e1b44a5c85004e1c1e361ece179a2fd72c59a 100644 (file)
@@ -39,13 +39,14 @@ __docformat__ = 'restructuredtext en'
 #   6.1.0 - Fixed multiple books import problem and PDF import with no key problem
 #   6.2.0 - Support for getting B&N key from nook Study log. Fix for UTF-8 filenames in Adobe ePubs.
 #           Fix for not copying needed files. Fix for getting default Adobe key for PDFs
+#   6.3.0 - Added in Kindle for Android serial number solution
 
 """
 Decrypt DRMed ebooks.
 """
 
 PLUGIN_NAME = u"DeDRM"
-PLUGIN_VERSION_TUPLE = (6, 2, 0)
+PLUGIN_VERSION_TUPLE = (6, 3, 0)
 PLUGIN_VERSION = u".".join([unicode(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'
@@ -478,6 +479,7 @@ class DeDRM(FileTypePlugin):
         dedrmprefs = prefs.DeDRM_Prefs()
         pids = dedrmprefs['pids']
         serials = dedrmprefs['serials']
+        serials.extend(dedrmprefs['androidserials'])
         kindleDatabases = dedrmprefs['kindlekeys'].items()
 
         try:
index d5cb01ab09d764b1530bffc59af4d3f5502e9b95..fd4c19355fa5938ecf21cc1b24374152ad5c345c 100644 (file)
@@ -256,14 +256,14 @@ def get_serials(path=STORAGE):
     tar = tarfile.open(fileobj=output)
     for member in tar.getmembers():
         if member.name.strip().endswith(STORAGE1):
-            write = tempfile.NamedTemporaryFile(mode='w', delete=False)
+            write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
             write.write(tar.extractfile(member).read())
             write.close()
             write_path = os.path.abspath(write.name)
             serials.extend(get_serials1(write_path))
             os.remove(write_path)
         elif member.name.strip().endswith(STORAGE2):
-            write = tempfile.NamedTemporaryFile(mode='w', delete=False)
+            write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
             write.write(tar.extractfile(member).read())
             write.close()
             write_path = os.path.abspath(write.name)
index b5c5300dc5e313e427c1585fdc11769da109e697..1357b496f469461d881cfeca9c0767bff6b8e513 100644 (file)
@@ -34,6 +34,7 @@ from calibre.constants import iswindows, isosx
 from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION
 from calibre_plugins.dedrm.__init__ import RESOURCE_NAME as help_file_name
 from calibre_plugins.dedrm.utilities import uStrCmp
+from calibre_plugins.dedrm.androidkindlekey import get_serials
 
 import calibre_plugins.dedrm.prefs as prefs
 
@@ -55,6 +56,7 @@ class ConfigWidget(QWidget):
         self.tempdedrmprefs['kindlekeys'] = self.dedrmprefs['kindlekeys'].copy()
         self.tempdedrmprefs['pids'] = list(self.dedrmprefs['pids'])
         self.tempdedrmprefs['serials'] = list(self.dedrmprefs['serials'])
+        self.tempdedrmprefs['androidserials'] = list(self.dedrmprefs['androidserials'])
         self.tempdedrmprefs['adobewineprefix'] = self.dedrmprefs['adobewineprefix']
         self.tempdedrmprefs['kindlewineprefix'] = self.dedrmprefs['kindlewineprefix']
 
@@ -83,6 +85,10 @@ class ConfigWidget(QWidget):
         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.clicked.connect(self.bandn_keys)
+        self.kindle_android_button = QtGui.QPushButton(self)
+        self.kindle_android_button.setToolTip(_(u"Click to manage Kindle for Android serial numbers for Kindle ebooks"))
+        self.kindle_android_button.setText(u"Kindle for Android ebooks")
+        self.kindle_android_button.clicked.connect(self.kindle_android_serials)
         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")
@@ -104,6 +110,7 @@ class ConfigWidget(QWidget):
         self.ereader_button.setText(u"eReader ebooks")
         self.ereader_button.clicked.connect(self.ereader_keys)
         button_layout.addWidget(self.kindle_serial_button)
+        button_layout.addWidget(self.kindle_android_button)
         button_layout.addWidget(self.bandn_button)
         button_layout.addWidget(self.mobi_button)
         button_layout.addWidget(self.ereader_button)
@@ -115,6 +122,10 @@ class ConfigWidget(QWidget):
     def kindle_serials(self):
         d = ManageKeysDialog(self,u"EInk Kindle Serial Number",self.tempdedrmprefs['serials'], AddSerialDialog)
         d.exec_()
+        
+    def kindle_android_serials(self):
+        d = ManageKeysDialog(self,u"Kindle for Andoid Serial Number",self.tempdedrmprefs['androidserials'], AddAndroidSerialDialog, 'ab')
+        d.exec_()
 
     def kindle_keys(self):
         if isosx or iswindows:
@@ -164,6 +175,7 @@ class ConfigWidget(QWidget):
         self.dedrmprefs.set('kindlekeys', self.tempdedrmprefs['kindlekeys'])
         self.dedrmprefs.set('pids', self.tempdedrmprefs['pids'])
         self.dedrmprefs.set('serials', self.tempdedrmprefs['serials'])
+        self.dedrmprefs.set('androidserials', self.tempdedrmprefs['androidserials'])
         self.dedrmprefs.set('adobewineprefix', self.tempdedrmprefs['adobewineprefix'])
         self.dedrmprefs.set('kindlewineprefix', self.tempdedrmprefs['kindlewineprefix'])
         self.dedrmprefs.set('configured', True)
@@ -188,6 +200,7 @@ class ManageKeysDialog(QDialog):
         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"ab")
         self.wineprefix = wineprefix
 
         self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name))
@@ -370,32 +383,43 @@ class ManageKeysDialog(QDialog):
             for filename in files:
                 fpath = os.path.join(config_dir, filename)
                 filename = os.path.basename(filename)
-                new_key_name = os.path.splitext(os.path.basename(filename))[0]
-                with open(fpath,'rb') as keyfile:
-                    new_key_value = keyfile.read()
-                if self.binary_file:
-                    new_key_value = new_key_value.encode('hex')
-                elif self.json_file:
-                    new_key_value = json.loads(new_key_value)
-                match = False
-                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)
-                        inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
-                                _(msg), show_copy_button=False, show=True)
-                        match = True
-                        break
-                if not match:
-                    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]
-                        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)
-                    else:
-                        counter += 1
-                        self.plugin_keys[new_key_name] = new_key_value
-
+                if type(self.plugin_keys) != dict:
+                    # must be the new Kindle for Android section
+                    print u"Getting keys from "+fpath
+                    new_keys = get_serials(fpath)
+                    for key in new_keys:
+                        if key in self.plugin_keys:
+                            skipped += 1
+                        else:
+                            counter += 1
+                            self.plugin_keys.append(key)
+                else:
+                    new_key_name = os.path.splitext(os.path.basename(filename))[0]
+                    with open(fpath,'rb') as keyfile:
+                        new_key_value = keyfile.read()
+                    if self.binary_file:
+                        new_key_value = new_key_value.encode('hex')
+                    elif self.json_file:
+                        new_key_value = json.loads(new_key_value)
+                    match = False
+                    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)
+                            inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
+                                    _(msg), show_copy_button=False, show=True)
+                            match = True
+                            break
+                    if not match:
+                        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]
+                            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)
+                        else:
+                            counter += 1
+                            self.plugin_keys[new_key_name] = new_key_value
+                            
             msg = u""
             if counter+skipped > 1:
                 if counter > 0:
@@ -863,6 +887,51 @@ class AddSerialDialog(QDialog):
         QDialog.accept(self)
 
 
+class AddAndroidSerialDialog(QDialog):
+    def __init__(self, parent=None,):
+        QDialog.__init__(self, parent)
+        self.parent = parent
+        self.setWindowTitle(u"{0} {1}: Add New Kindle for Android Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
+        layout = QVBoxLayout(self)
+        self.setLayout(layout)
+
+        data_group_box = QGroupBox(u"", self)
+        layout.addWidget(data_group_box)
+        data_group_box_layout = QVBoxLayout()
+        data_group_box.setLayout(data_group_box_layout)
+
+        key_group = QHBoxLayout()
+        data_group_box_layout.addLayout(key_group)
+        key_group.addWidget(QLabel(u"Kindle for Android Serial Number:", self))
+        self.key_ledit = QLineEdit("", self)
+        self.key_ledit.setToolTip(u"Enter a Kindle for ANdroid serial number. These can be found using the androidkindlekey.py script.")
+        key_group.addWidget(self.key_ledit)
+        key_label = QLabel(_(''), self)
+        key_label.setAlignment(Qt.AlignHCenter)
+        data_group_box_layout.addWidget(key_label)
+
+        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
+        self.button_box.accepted.connect(self.accept)
+        self.button_box.rejected.connect(self.reject)
+        layout.addWidget(self.button_box)
+
+        self.resize(self.sizeHint())
+
+    @property
+    def key_name(self):
+        return unicode(self.key_ledit.text()).strip()
+
+    @property
+    def key_value(self):
+        return unicode(self.key_ledit.text()).strip()
+
+    def accept(self):
+        if len(self.key_name) == 0 or self.key_name.isspace():
+            errmsg = u"Please enter a Kindle for Android 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)
+        QDialog.accept(self)
+
+
 class AddPIDDialog(QDialog):
     def __init__(self, parent=None,):
         QDialog.__init__(self, parent)
index 05065acd336eb14733026c862e788c6ff036672a..f0f494cfa8db189f9e267b90777247aba837c60d 100644 (file)
@@ -25,6 +25,7 @@ class DeDRM_Prefs():
         self.dedrmprefs.defaults['kindlekeys'] = {}
         self.dedrmprefs.defaults['pids'] = []
         self.dedrmprefs.defaults['serials'] = []
+        self.dedrmprefs.defaults['androidserials'] = []
         self.dedrmprefs.defaults['adobewineprefix'] = ""
         self.dedrmprefs.defaults['kindlewineprefix'] = ""
 
@@ -44,6 +45,8 @@ class DeDRM_Prefs():
             self.dedrmprefs['pids'] = []
         if self.dedrmprefs['serials'] == []:
             self.dedrmprefs['serials'] = []
+        if self.dedrmprefs['androidserials'] == []:
+            self.dedrmprefs['androidserials'] = []
 
     def __getitem__(self,kind = None):
         if kind is not None:
index e79abd7009542cd720437c3b9ce63f6f7914f77f..5a4692d791eefff0bb40c64032a0837ba98589cd 100644 (file)
@@ -1,4 +1,4 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/html4/strict.dtd">
 
 <html>
@@ -27,7 +27,7 @@ li {margin-top: 0.5em}
 
 <p>On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Kindle serial number.</p>
 <ul>
-<li><span class="bold">Eink Kindle Serial Number:</span> this is the unique serial number of your device. It usually starts with a ‘B’ or a ‘9’ and is sixteen characters long. For a reference of where to find serial numbers and their ranges, please refere to this <a href="http://wiki.mobileread.com/wiki/Kindle_serial_numbers">mobileread wiki page.</a></li>
+<li><span class="bold">Eink Kindle Serial Number:</span> this is the unique serial number of your device. It usually starts with a ‘B’ or a ‘9’ and is sixteen characters long. For a reference of where to find serial numbers and their ranges, please refer to this <a href="http://wiki.mobileread.com/wiki/Kindle_serial_numbers">mobileread wiki page.</a></li>
 </ul>
 
 <p>Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.</p>
diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Kindle for Android_Help.htm b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Kindle for Android_Help.htm
new file mode 100644 (file)
index 0000000..7bdba64
--- /dev/null
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+       "http://www.w3.org/TR/html4/strict.dtd">
+
+<html>
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+<title>Managing Kindle for Android serial numbers</title>
+<style type="text/css">
+span.version {font-size: 50%}
+span.bold {font-weight: bold}
+h3 {margin-bottom: 0}
+p {margin-top: 0}
+li {margin-top: 0.5em}
+</style>
+</head>
+
+<body>
+
+<h1>Managing Kindle for Android serial numbers</h1>
+
+<p>Amazon's Kindle for Android application uses an internal serial number that's 72 character long. Extracting that serial number is a little tricky, but worth it, as it then allows the DRM to be removed from any Kindle ebooks that have been downloaded to that Android device.</p>
+
+<p>Please note that it is not currently known whether the same applies to the Kindle application on the Kindle Fire and Fire HD.</p>
+
+<h3>Getting the Kindle for Android backup file</h3>
+
+<p>Obtain and install adb (Android Debug Bridge) on your computer. Details of how to do this are beyond the scope of this help file, but there are plenty of on-line guides.</p>
+<p>Enable developer mode on your Android device. Again, look for an on-line guide for your device.</p>
+<p>Once you have adb installed and your device in developer mode, connect your device to your computer with a USB cable and then open up a command line (Terminal on Mac OS X and cmd.exe on Windows) and enter "adb backup com.amazon.kindle" (without the quotation marks!) and press return. A file "backup.ab" should be created in your home directory.
+
+<h3>Adding the Kindle for Android serial number</h3>
+
+<p>At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import the ‘backup.ab’ file you obtained by using the adb command. The backup file will be processed to extract any serial numbers in it, and the numbers will be added to the list.</p>
+
+<h3>Adding the Kindle for Android serial number manually</h3>
+<p>On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Kindle for Android serial number.</p>
+<ul>
+<li><span class="bold">Kindle for Android Serial Number:</span> this is the unique serial number of your device. You may have obtained this through using the old android.py script.</li>
+</ul>
+
+<p>Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.</p>
+
+<h3>Deleting Kindle for Android serial numbers:</h3>
+
+<p>On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted Kindle serial number from the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.</p>
+
+<p>Once done creating/deleting serial numbers, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.</p>
+
+</body>
+
+</html>
index 37c454cfc02b33bb0fe9b046fa4ce8fdbcde6069..ef1e1b44a5c85004e1c1e361ece179a2fd72c59a 100644 (file)
@@ -39,13 +39,14 @@ __docformat__ = 'restructuredtext en'
 #   6.1.0 - Fixed multiple books import problem and PDF import with no key problem
 #   6.2.0 - Support for getting B&N key from nook Study log. Fix for UTF-8 filenames in Adobe ePubs.
 #           Fix for not copying needed files. Fix for getting default Adobe key for PDFs
+#   6.3.0 - Added in Kindle for Android serial number solution
 
 """
 Decrypt DRMed ebooks.
 """
 
 PLUGIN_NAME = u"DeDRM"
-PLUGIN_VERSION_TUPLE = (6, 2, 0)
+PLUGIN_VERSION_TUPLE = (6, 3, 0)
 PLUGIN_VERSION = u".".join([unicode(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'
@@ -478,6 +479,7 @@ class DeDRM(FileTypePlugin):
         dedrmprefs = prefs.DeDRM_Prefs()
         pids = dedrmprefs['pids']
         serials = dedrmprefs['serials']
+        serials.extend(dedrmprefs['androidserials'])
         kindleDatabases = dedrmprefs['kindlekeys'].items()
 
         try:
index d5cb01ab09d764b1530bffc59af4d3f5502e9b95..fd4c19355fa5938ecf21cc1b24374152ad5c345c 100644 (file)
@@ -256,14 +256,14 @@ def get_serials(path=STORAGE):
     tar = tarfile.open(fileobj=output)
     for member in tar.getmembers():
         if member.name.strip().endswith(STORAGE1):
-            write = tempfile.NamedTemporaryFile(mode='w', delete=False)
+            write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
             write.write(tar.extractfile(member).read())
             write.close()
             write_path = os.path.abspath(write.name)
             serials.extend(get_serials1(write_path))
             os.remove(write_path)
         elif member.name.strip().endswith(STORAGE2):
-            write = tempfile.NamedTemporaryFile(mode='w', delete=False)
+            write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
             write.write(tar.extractfile(member).read())
             write.close()
             write_path = os.path.abspath(write.name)
index b5c5300dc5e313e427c1585fdc11769da109e697..1357b496f469461d881cfeca9c0767bff6b8e513 100644 (file)
@@ -34,6 +34,7 @@ from calibre.constants import iswindows, isosx
 from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION
 from calibre_plugins.dedrm.__init__ import RESOURCE_NAME as help_file_name
 from calibre_plugins.dedrm.utilities import uStrCmp
+from calibre_plugins.dedrm.androidkindlekey import get_serials
 
 import calibre_plugins.dedrm.prefs as prefs
 
@@ -55,6 +56,7 @@ class ConfigWidget(QWidget):
         self.tempdedrmprefs['kindlekeys'] = self.dedrmprefs['kindlekeys'].copy()
         self.tempdedrmprefs['pids'] = list(self.dedrmprefs['pids'])
         self.tempdedrmprefs['serials'] = list(self.dedrmprefs['serials'])
+        self.tempdedrmprefs['androidserials'] = list(self.dedrmprefs['androidserials'])
         self.tempdedrmprefs['adobewineprefix'] = self.dedrmprefs['adobewineprefix']
         self.tempdedrmprefs['kindlewineprefix'] = self.dedrmprefs['kindlewineprefix']
 
@@ -83,6 +85,10 @@ class ConfigWidget(QWidget):
         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.clicked.connect(self.bandn_keys)
+        self.kindle_android_button = QtGui.QPushButton(self)
+        self.kindle_android_button.setToolTip(_(u"Click to manage Kindle for Android serial numbers for Kindle ebooks"))
+        self.kindle_android_button.setText(u"Kindle for Android ebooks")
+        self.kindle_android_button.clicked.connect(self.kindle_android_serials)
         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")
@@ -104,6 +110,7 @@ class ConfigWidget(QWidget):
         self.ereader_button.setText(u"eReader ebooks")
         self.ereader_button.clicked.connect(self.ereader_keys)
         button_layout.addWidget(self.kindle_serial_button)
+        button_layout.addWidget(self.kindle_android_button)
         button_layout.addWidget(self.bandn_button)
         button_layout.addWidget(self.mobi_button)
         button_layout.addWidget(self.ereader_button)
@@ -115,6 +122,10 @@ class ConfigWidget(QWidget):
     def kindle_serials(self):
         d = ManageKeysDialog(self,u"EInk Kindle Serial Number",self.tempdedrmprefs['serials'], AddSerialDialog)
         d.exec_()
+        
+    def kindle_android_serials(self):
+        d = ManageKeysDialog(self,u"Kindle for Andoid Serial Number",self.tempdedrmprefs['androidserials'], AddAndroidSerialDialog, 'ab')
+        d.exec_()
 
     def kindle_keys(self):
         if isosx or iswindows:
@@ -164,6 +175,7 @@ class ConfigWidget(QWidget):
         self.dedrmprefs.set('kindlekeys', self.tempdedrmprefs['kindlekeys'])
         self.dedrmprefs.set('pids', self.tempdedrmprefs['pids'])
         self.dedrmprefs.set('serials', self.tempdedrmprefs['serials'])
+        self.dedrmprefs.set('androidserials', self.tempdedrmprefs['androidserials'])
         self.dedrmprefs.set('adobewineprefix', self.tempdedrmprefs['adobewineprefix'])
         self.dedrmprefs.set('kindlewineprefix', self.tempdedrmprefs['kindlewineprefix'])
         self.dedrmprefs.set('configured', True)
@@ -188,6 +200,7 @@ class ManageKeysDialog(QDialog):
         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"ab")
         self.wineprefix = wineprefix
 
         self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name))
@@ -370,32 +383,43 @@ class ManageKeysDialog(QDialog):
             for filename in files:
                 fpath = os.path.join(config_dir, filename)
                 filename = os.path.basename(filename)
-                new_key_name = os.path.splitext(os.path.basename(filename))[0]
-                with open(fpath,'rb') as keyfile:
-                    new_key_value = keyfile.read()
-                if self.binary_file:
-                    new_key_value = new_key_value.encode('hex')
-                elif self.json_file:
-                    new_key_value = json.loads(new_key_value)
-                match = False
-                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)
-                        inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
-                                _(msg), show_copy_button=False, show=True)
-                        match = True
-                        break
-                if not match:
-                    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]
-                        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)
-                    else:
-                        counter += 1
-                        self.plugin_keys[new_key_name] = new_key_value
-
+                if type(self.plugin_keys) != dict:
+                    # must be the new Kindle for Android section
+                    print u"Getting keys from "+fpath
+                    new_keys = get_serials(fpath)
+                    for key in new_keys:
+                        if key in self.plugin_keys:
+                            skipped += 1
+                        else:
+                            counter += 1
+                            self.plugin_keys.append(key)
+                else:
+                    new_key_name = os.path.splitext(os.path.basename(filename))[0]
+                    with open(fpath,'rb') as keyfile:
+                        new_key_value = keyfile.read()
+                    if self.binary_file:
+                        new_key_value = new_key_value.encode('hex')
+                    elif self.json_file:
+                        new_key_value = json.loads(new_key_value)
+                    match = False
+                    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)
+                            inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
+                                    _(msg), show_copy_button=False, show=True)
+                            match = True
+                            break
+                    if not match:
+                        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]
+                            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)
+                        else:
+                            counter += 1
+                            self.plugin_keys[new_key_name] = new_key_value
+                            
             msg = u""
             if counter+skipped > 1:
                 if counter > 0:
@@ -863,6 +887,51 @@ class AddSerialDialog(QDialog):
         QDialog.accept(self)
 
 
+class AddAndroidSerialDialog(QDialog):
+    def __init__(self, parent=None,):
+        QDialog.__init__(self, parent)
+        self.parent = parent
+        self.setWindowTitle(u"{0} {1}: Add New Kindle for Android Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
+        layout = QVBoxLayout(self)
+        self.setLayout(layout)
+
+        data_group_box = QGroupBox(u"", self)
+        layout.addWidget(data_group_box)
+        data_group_box_layout = QVBoxLayout()
+        data_group_box.setLayout(data_group_box_layout)
+
+        key_group = QHBoxLayout()
+        data_group_box_layout.addLayout(key_group)
+        key_group.addWidget(QLabel(u"Kindle for Android Serial Number:", self))
+        self.key_ledit = QLineEdit("", self)
+        self.key_ledit.setToolTip(u"Enter a Kindle for ANdroid serial number. These can be found using the androidkindlekey.py script.")
+        key_group.addWidget(self.key_ledit)
+        key_label = QLabel(_(''), self)
+        key_label.setAlignment(Qt.AlignHCenter)
+        data_group_box_layout.addWidget(key_label)
+
+        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
+        self.button_box.accepted.connect(self.accept)
+        self.button_box.rejected.connect(self.reject)
+        layout.addWidget(self.button_box)
+
+        self.resize(self.sizeHint())
+
+    @property
+    def key_name(self):
+        return unicode(self.key_ledit.text()).strip()
+
+    @property
+    def key_value(self):
+        return unicode(self.key_ledit.text()).strip()
+
+    def accept(self):
+        if len(self.key_name) == 0 or self.key_name.isspace():
+            errmsg = u"Please enter a Kindle for Android 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)
+        QDialog.accept(self)
+
+
 class AddPIDDialog(QDialog):
     def __init__(self, parent=None,):
         QDialog.__init__(self, parent)
index 05065acd336eb14733026c862e788c6ff036672a..f0f494cfa8db189f9e267b90777247aba837c60d 100644 (file)
@@ -25,6 +25,7 @@ class DeDRM_Prefs():
         self.dedrmprefs.defaults['kindlekeys'] = {}
         self.dedrmprefs.defaults['pids'] = []
         self.dedrmprefs.defaults['serials'] = []
+        self.dedrmprefs.defaults['androidserials'] = []
         self.dedrmprefs.defaults['adobewineprefix'] = ""
         self.dedrmprefs.defaults['kindlewineprefix'] = ""
 
@@ -44,6 +45,8 @@ class DeDRM_Prefs():
             self.dedrmprefs['pids'] = []
         if self.dedrmprefs['serials'] == []:
             self.dedrmprefs['serials'] = []
+        if self.dedrmprefs['androidserials'] == []:
+            self.dedrmprefs['androidserials'] = []
 
     def __getitem__(self,kind = None):
         if kind is not None:
index 9906f05a4d65cdd9d8461caac9ad4699179cc856..6deca12909cf1fce9e8bb1160e048e1918a6ad19 100644 (file)
Binary files a/DeDRM_calibre_plugin/DeDRM_plugin.zip and b/DeDRM_calibre_plugin/DeDRM_plugin.zip differ
index e79abd7009542cd720437c3b9ce63f6f7914f77f..5a4692d791eefff0bb40c64032a0837ba98589cd 100644 (file)
@@ -1,4 +1,4 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/html4/strict.dtd">
 
 <html>
@@ -27,7 +27,7 @@ li {margin-top: 0.5em}
 
 <p>On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Kindle serial number.</p>
 <ul>
-<li><span class="bold">Eink Kindle Serial Number:</span> this is the unique serial number of your device. It usually starts with a ‘B’ or a ‘9’ and is sixteen characters long. For a reference of where to find serial numbers and their ranges, please refere to this <a href="http://wiki.mobileread.com/wiki/Kindle_serial_numbers">mobileread wiki page.</a></li>
+<li><span class="bold">Eink Kindle Serial Number:</span> this is the unique serial number of your device. It usually starts with a ‘B’ or a ‘9’ and is sixteen characters long. For a reference of where to find serial numbers and their ranges, please refer to this <a href="http://wiki.mobileread.com/wiki/Kindle_serial_numbers">mobileread wiki page.</a></li>
 </ul>
 
 <p>Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.</p>
diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Kindle for Android_Help.htm b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Kindle for Android_Help.htm
new file mode 100644 (file)
index 0000000..7bdba64
--- /dev/null
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+       "http://www.w3.org/TR/html4/strict.dtd">
+
+<html>
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+<title>Managing Kindle for Android serial numbers</title>
+<style type="text/css">
+span.version {font-size: 50%}
+span.bold {font-weight: bold}
+h3 {margin-bottom: 0}
+p {margin-top: 0}
+li {margin-top: 0.5em}
+</style>
+</head>
+
+<body>
+
+<h1>Managing Kindle for Android serial numbers</h1>
+
+<p>Amazon's Kindle for Android application uses an internal serial number that's 72 character long. Extracting that serial number is a little tricky, but worth it, as it then allows the DRM to be removed from any Kindle ebooks that have been downloaded to that Android device.</p>
+
+<p>Please note that it is not currently known whether the same applies to the Kindle application on the Kindle Fire and Fire HD.</p>
+
+<h3>Getting the Kindle for Android backup file</h3>
+
+<p>Obtain and install adb (Android Debug Bridge) on your computer. Details of how to do this are beyond the scope of this help file, but there are plenty of on-line guides.</p>
+<p>Enable developer mode on your Android device. Again, look for an on-line guide for your device.</p>
+<p>Once you have adb installed and your device in developer mode, connect your device to your computer with a USB cable and then open up a command line (Terminal on Mac OS X and cmd.exe on Windows) and enter "adb backup com.amazon.kindle" (without the quotation marks!) and press return. A file "backup.ab" should be created in your home directory.
+
+<h3>Adding the Kindle for Android serial number</h3>
+
+<p>At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import the ‘backup.ab’ file you obtained by using the adb command. The backup file will be processed to extract any serial numbers in it, and the numbers will be added to the list.</p>
+
+<h3>Adding the Kindle for Android serial number manually</h3>
+<p>On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Kindle for Android serial number.</p>
+<ul>
+<li><span class="bold">Kindle for Android Serial Number:</span> this is the unique serial number of your device. You may have obtained this through using the old android.py script.</li>
+</ul>
+
+<p>Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.</p>
+
+<h3>Deleting Kindle for Android serial numbers:</h3>
+
+<p>On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted Kindle serial number from the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.</p>
+
+<p>Once done creating/deleting serial numbers, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.</p>
+
+</body>
+
+</html>