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