Prepare v0.0.14, add code to auto-delete ACSM

This commit is contained in:
Florian Bach 2021-12-11 11:32:37 +01:00
parent 481e6c8ae9
commit 1ac47e81e7
6 changed files with 58 additions and 14 deletions

View File

@ -46,4 +46,5 @@ There's a bunch of features that could still be added, but most of them aren't i
- Support for anonymous Adobe IDs
- Support for un-authorizing a machine
- Support to copy an authorization from the plugin to an ADE install
- Support for Adobe's "auth" download method instead of the "simple" method.
- ...

View File

@ -19,15 +19,19 @@
# improve PassHash support, include UUID in key export filename,
# fix bug that would block other FileTypePlugins
# v0.0.12: Fix Calibre Plugin index / updater
# v0.0.13: Add support for emulating multiple ADE versions (1.7.2, 2.0.1, 3.0.1, 4.0.3, 4.5.11),
# v0.0.13: v0.0.13 was a development / beta version with lots of different published test
# versions. To make support easier there's no "final" v0.0.13 version. Instead,
# all the changes from the various v0.0.13 beta versions are released with v0.0.14.
# v0.0.14: Add support for emulating multiple ADE versions (1.7.2, 2.0.1, 3.0.1, 4.0.3, 4.5.11),
# add code to import existing activation from ADE (Windows, MacOS or Linux/Wine),
# add code to remove an existing activation from the plugin (Ctrl+Shift+D),
# fix race condition when importing multiple ACSMs simultaneously,
# fix authorization failing with certain non-ASCII characters in username,
# add detailed logging toggle setting.
# add detailed logging toggle setting, add auto-delete ACSM setting,
# add useful error message for ACSMs with nonstandard download type.
PLUGIN_NAME = "DeACSM"
PLUGIN_VERSION_TUPLE = (0, 0, 13)
PLUGIN_VERSION_TUPLE = (0, 0, 14)
from calibre.customize import FileTypePlugin # type: ignore
__version__ = PLUGIN_VERSION = ".".join([str(x)for x in PLUGIN_VERSION_TUPLE])
@ -202,7 +206,14 @@ class DeACSM(FileTypePlugin):
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
try:
download_url = adobe_fulfill_response.find("./%s/%s/%s" % (adNS("fulfillmentResult"), adNS("resourceItemInfo"), adNS("src"))).text
except:
print("{0} v{1}: FulfillmentResult does not contain the <src> tag. This may be an ACSM with download type 'auth'?".format(PLUGIN_NAME, PLUGIN_VERSION))
print("{0} v{1}: Please open a bug report and attach the ACSM file if you see this message.".format(PLUGIN_NAME, PLUGIN_VERSION))
return None
license_token_node = adobe_fulfill_response.find("./%s/%s/%s" % (adNS("fulfillmentResult"), adNS("resourceItemInfo"), adNS("licenseToken")))
rights_xml_str = buildRights(license_token_node)
@ -325,6 +336,12 @@ class DeACSM(FileTypePlugin):
# Loop through all plugins (the list is already sorted by priority),
# then execute all of them that can handle EPUB / PDF.
# if the source file is supposed to be deleted after successful fulfillment,
# this is set to True
# If there's any errors whatsoever during export / plugin execution,
# this will be set back to False to prevent deletion.
delete_src_file = deacsmprefs["delete_acsm_after_fulfill"]
try:
from calibre.customize.ui import _initialized_plugins, is_disabled
from calibre.customize import FileTypePlugin
@ -376,6 +393,7 @@ class DeACSM(FileTypePlugin):
plugin_ret = None
plugin_ret = plugin.run(rpl)
except:
delete_src_file = False
print("{0} v{1}: Running file type plugin failed with traceback:".format(PLUGIN_NAME, PLUGIN_VERSION))
traceback.print_exc(file=oe)
@ -393,10 +411,21 @@ class DeACSM(FileTypePlugin):
except:
delete_src_file = False
print("{0} v{1}: Error while executing other plugins".format(PLUGIN_NAME, PLUGIN_VERSION))
traceback.print_exc()
pass
# If enabled, and if we didn't encounter any errors, delete the source ACSM file.
if delete_src_file:
try:
if os.path.exists(path_to_ebook):
print("{0} v{1}: Deleting existing ACSM file {2} ...".format(PLUGIN_NAME, PLUGIN_VERSION, path_to_ebook))
os.remove(path_to_ebook)
except:
print("{0} v{1}: Failed to delete source ACSM after fulfillment.".format(PLUGIN_NAME, PLUGIN_VERSION))
# Return path - either the original one or the one modified by the other plugins.
return rpl

View File

@ -45,6 +45,7 @@ class ConfigWidget(QWidget):
self.tempdeacsmprefs['notify_fulfillment'] = self.deacsmprefs['notify_fulfillment']
self.tempdeacsmprefs['detailed_logging'] = self.deacsmprefs['detailed_logging']
self.tempdeacsmprefs['delete_acsm_after_fulfill'] = self.deacsmprefs['delete_acsm_after_fulfill']
self.tempdeacsmprefs['list_of_rented_books'] = self.deacsmprefs['list_of_rented_books']
@ -134,6 +135,12 @@ class ConfigWidget(QWidget):
self.chkDetailedLogging.toggled.connect(self.toggle_logging)
layout.addWidget(self.chkDetailedLogging)
self.chkDeleteAfterFulfill = QtGui.QCheckBox("Delete ACSM file after successful import")
self.chkDeleteAfterFulfill.setToolTip("Default: False\n\nIf this is enabled, imported ACSM files will be automatically deleted after they've been converted into an EPUB or PDF. \nNote: This is experimental. It is possible that the ACSM will also be deleted if there's errors during import. \nIf you have an important ACSM file that you can't re-download if needed, do not enable this option.")
self.chkDeleteAfterFulfill.setChecked(self.tempdeacsmprefs["delete_acsm_after_fulfill"])
self.chkDeleteAfterFulfill.toggled.connect(self.toggle_acsm_delete)
layout.addWidget(self.chkDeleteAfterFulfill)
# Key shortcut Ctrl+Shift+D / Cmd+Shift+D to remove authorization, just like in ADE.
self.deauthShortcut = QShortcut(QKeySequence("Ctrl+Shift+D"), self)
self.deauthShortcut.activated.connect(self.delete_ade_auth)
@ -185,12 +192,23 @@ class ConfigWidget(QWidget):
if not self.chkDetailedLogging.isChecked():
return
msg = "You have enabled detailed logging.\n"
msg = "You have enabled verbose logging.\n"
msg += "This will cause various data to be included in the logfiles, like encryption keys, account keys and other confidential data.\n"
msg += "With this setting enabled, only share log files privately with the developer and don't make them publicly available."
info_dialog(None, "Warning", msg, show=True, show_copy_button=False)
def toggle_acsm_delete(self):
if not self.chkDeleteAfterFulfill.isChecked():
return
msg = "You have enabled ACSM auto-deletion.\n"
msg += "This means that your source ACSM file will be deleted after import - not just from Calibre, but from the source filesystem, too. "
msg += "As this feature is experimental, it's possible that ACSMs will also sometimes get deleted even when the import failed.\n\n"
msg += "If you're importing an ACSM that you cannot re-download in case of issues, do not enable this option!"
info_dialog(None, "Warning", msg, show=True, show_copy_button=False)
def delete_ade_auth(self):
@ -830,6 +848,7 @@ class ConfigWidget(QWidget):
def save_settings(self):
self.deacsmprefs.set('notify_fulfillment', self.chkNotifyFulfillment.isChecked())
self.deacsmprefs.set('detailed_logging', self.chkDetailedLogging.isChecked())
self.deacsmprefs.set('delete_acsm_after_fulfill', self.chkDeleteAfterFulfill.isChecked())
self.deacsmprefs.writeprefs()
def load_resource(self, name):

View File

@ -450,9 +450,6 @@ def activateDevice(useVersionIndex: int = 0):
if (result is False):
return False, "Building activation request failed: " + activate_req
#print("======================================================")
#print("activate")
#print(activate_req)
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
etree.register_namespace("adept", NSMAP["adept"])

View File

@ -632,12 +632,9 @@ def performFulfillmentNotification(fulfillmentResultToken, forceOptional = False
device = fulfillmentResultToken.find("./%s/%s/%s/%s" % (adNS("fulfillmentResult"), adNS("resourceItemInfo"), adNS("licenseToken"), adNS("device"))).text
except:
# B&N Adobe PassHash fulfillment without device ID.
# Not sure what to do in this case.
# PassHash books aren't linked to a particular device, so there's no ID to send to Adobe.
# If I leave this out, I get E_ADEPT_MISSING_ELEMENT
# If I use the one from the ADE activation, I get E_LIC_USER_UNKNOWN
# Adobe documentation seems to imply that PassHash books don't support notifications,
# so lets just skip if that's the case.
# If I understand Adobe's documentation correctly, PassHash books do not support notifications
# and are not supposed to contain notify tags, so lets just skip if that's the case.
print("Skipping notify due to passHash")
continue

View File

@ -20,6 +20,7 @@ class DeACSM_Prefs():
self.deacsmprefs.defaults['notify_fulfillment'] = True
self.deacsmprefs.defaults['detailed_logging'] = False
self.deacsmprefs.defaults['delete_acsm_after_fulfill'] = False
self.deacsmprefs.defaults['list_of_rented_books'] = []