Added help file for Kindle for Android keys to plugin. Copied updated files to Mac and Windows applications.
This commit is contained in:
parent
6b2672ff7c
commit
4c9aacd01e
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
Binary file not shown.
|
@ -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>
|
||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue