diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_EInk Kindle Serial Number_Help.htm b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_EInk Kindle Serial Number_Help.htm index e79abd7..5a4692d 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_EInk Kindle Serial Number_Help.htm +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_EInk Kindle Serial Number_Help.htm @@ -1,4 +1,4 @@ - @@ -27,7 +27,7 @@ li {margin-top: 0.5em}

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.

Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.

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 index 0000000..7bdba64 --- /dev/null +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Android_Help.htm @@ -0,0 +1,52 @@ + + + + + + +Managing Kindle for Android serial numbers + + + + + +

Managing Kindle for Android serial numbers

+ +

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.

+ +

Please note that it is not currently known whether the same applies to the Kindle application on the Kindle Fire and Fire HD.

+ +

Getting the Kindle for Android backup file

+ +

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.

+

Enable developer mode on your Android device. Again, look for an on-line guide for your device.

+

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. + +

Adding the Kindle for Android serial number

+ +

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.

+ +

Adding the Kindle for Android serial number manually

+

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.

+ + +

Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.

+ +

Deleting Kindle for Android serial numbers:

+ +

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.

+ +

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.

+ + + + diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py index 37c454c..ef1e1b4 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py @@ -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: diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/androidkindlekey.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/androidkindlekey.py index d5cb01a..fd4c193 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/androidkindlekey.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/androidkindlekey.py @@ -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) diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py index b5c5300..1357b49 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py @@ -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 {0} already exists!\nSkipping key file {1}.\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 {1} 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 {0} already exists!\nSkipping key file {1}.\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 {1} 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) diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/prefs.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/prefs.py index 05065ac..f0f494c 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/prefs.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/prefs.py @@ -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: diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_EInk Kindle Serial Number_Help.htm b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_EInk Kindle Serial Number_Help.htm index e79abd7..5a4692d 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_EInk Kindle Serial Number_Help.htm +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_EInk Kindle Serial Number_Help.htm @@ -1,4 +1,4 @@ - @@ -27,7 +27,7 @@ li {margin-top: 0.5em}

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.

Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.

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 index 0000000..7bdba64 --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Kindle for Android_Help.htm @@ -0,0 +1,52 @@ + + + + + + +Managing Kindle for Android serial numbers + + + + + +

Managing Kindle for Android serial numbers

+ +

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.

+ +

Please note that it is not currently known whether the same applies to the Kindle application on the Kindle Fire and Fire HD.

+ +

Getting the Kindle for Android backup file

+ +

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.

+

Enable developer mode on your Android device. Again, look for an on-line guide for your device.

+

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. + +

Adding the Kindle for Android serial number

+ +

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.

+ +

Adding the Kindle for Android serial number manually

+

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.

+ + +

Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.

+ +

Deleting Kindle for Android serial numbers:

+ +

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.

+ +

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.

+ + + + diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py index 37c454c..ef1e1b4 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py @@ -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: diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/androidkindlekey.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/androidkindlekey.py index d5cb01a..fd4c193 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/androidkindlekey.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/androidkindlekey.py @@ -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) diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/config.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/config.py index b5c5300..1357b49 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/config.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/config.py @@ -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 {0} already exists!\nSkipping key file {1}.\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 {1} 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 {0} already exists!\nSkipping key file {1}.\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 {1} 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) diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/prefs.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/prefs.py index 05065ac..f0f494c 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/prefs.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/prefs.py @@ -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: diff --git a/DeDRM_calibre_plugin/DeDRM_plugin.zip b/DeDRM_calibre_plugin/DeDRM_plugin.zip index 9906f05..6deca12 100644 Binary files a/DeDRM_calibre_plugin/DeDRM_plugin.zip and b/DeDRM_calibre_plugin/DeDRM_plugin.zip differ diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_EInk Kindle Serial Number_Help.htm b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_EInk Kindle Serial Number_Help.htm index e79abd7..5a4692d 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_EInk Kindle Serial Number_Help.htm +++ b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_EInk Kindle Serial Number_Help.htm @@ -1,4 +1,4 @@ - @@ -27,7 +27,7 @@ li {margin-top: 0.5em}

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.

Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.

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 index 0000000..7bdba64 --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Kindle for Android_Help.htm @@ -0,0 +1,52 @@ + + + + + + +Managing Kindle for Android serial numbers + + + + + +

Managing Kindle for Android serial numbers

+ +

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.

+ +

Please note that it is not currently known whether the same applies to the Kindle application on the Kindle Fire and Fire HD.

+ +

Getting the Kindle for Android backup file

+ +

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.

+

Enable developer mode on your Android device. Again, look for an on-line guide for your device.

+

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. + +

Adding the Kindle for Android serial number

+ +

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.

+ +

Adding the Kindle for Android serial number manually

+

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.

+ + +

Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.

+ +

Deleting Kindle for Android serial numbers:

+ +

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.

+ +

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.

+ + + +