mirror of
https://github.com/Leseratte10/acsm-calibre-plugin.git
synced 2024-11-01 04:16:11 +06:00
Prepare v0.0.14, add code to auto-delete ACSM
This commit is contained in:
parent
481e6c8ae9
commit
1ac47e81e7
|
@ -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 anonymous Adobe IDs
|
||||||
- Support for un-authorizing a machine
|
- Support for un-authorizing a machine
|
||||||
- Support to copy an authorization from the plugin to an ADE install
|
- Support to copy an authorization from the plugin to an ADE install
|
||||||
- ...
|
- Support for Adobe's "auth" download method instead of the "simple" method.
|
||||||
|
- ...
|
|
@ -19,15 +19,19 @@
|
||||||
# improve PassHash support, include UUID in key export filename,
|
# improve PassHash support, include UUID in key export filename,
|
||||||
# fix bug that would block other FileTypePlugins
|
# fix bug that would block other FileTypePlugins
|
||||||
# v0.0.12: Fix Calibre Plugin index / updater
|
# 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 import existing activation from ADE (Windows, MacOS or Linux/Wine),
|
||||||
# add code to remove an existing activation from the plugin (Ctrl+Shift+D),
|
# add code to remove an existing activation from the plugin (Ctrl+Shift+D),
|
||||||
# fix race condition when importing multiple ACSMs simultaneously,
|
# fix race condition when importing multiple ACSMs simultaneously,
|
||||||
# fix authorization failing with certain non-ASCII characters in username,
|
# 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_NAME = "DeACSM"
|
||||||
PLUGIN_VERSION_TUPLE = (0, 0, 13)
|
PLUGIN_VERSION_TUPLE = (0, 0, 14)
|
||||||
|
|
||||||
from calibre.customize import FileTypePlugin # type: ignore
|
from calibre.customize import FileTypePlugin # type: ignore
|
||||||
__version__ = PLUGIN_VERSION = ".".join([str(x)for x in PLUGIN_VERSION_TUPLE])
|
__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" }
|
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
||||||
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
||||||
|
|
||||||
download_url = adobe_fulfill_response.find("./%s/%s/%s" % (adNS("fulfillmentResult"), adNS("resourceItemInfo"), adNS("src"))).text
|
|
||||||
|
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")))
|
license_token_node = adobe_fulfill_response.find("./%s/%s/%s" % (adNS("fulfillmentResult"), adNS("resourceItemInfo"), adNS("licenseToken")))
|
||||||
|
|
||||||
rights_xml_str = buildRights(license_token_node)
|
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),
|
# Loop through all plugins (the list is already sorted by priority),
|
||||||
# then execute all of them that can handle EPUB / PDF.
|
# 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:
|
try:
|
||||||
from calibre.customize.ui import _initialized_plugins, is_disabled
|
from calibre.customize.ui import _initialized_plugins, is_disabled
|
||||||
from calibre.customize import FileTypePlugin
|
from calibre.customize import FileTypePlugin
|
||||||
|
@ -376,6 +393,7 @@ class DeACSM(FileTypePlugin):
|
||||||
plugin_ret = None
|
plugin_ret = None
|
||||||
plugin_ret = plugin.run(rpl)
|
plugin_ret = plugin.run(rpl)
|
||||||
except:
|
except:
|
||||||
|
delete_src_file = False
|
||||||
print("{0} v{1}: Running file type plugin failed with traceback:".format(PLUGIN_NAME, PLUGIN_VERSION))
|
print("{0} v{1}: Running file type plugin failed with traceback:".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
traceback.print_exc(file=oe)
|
traceback.print_exc(file=oe)
|
||||||
|
|
||||||
|
@ -393,10 +411,21 @@ class DeACSM(FileTypePlugin):
|
||||||
|
|
||||||
|
|
||||||
except:
|
except:
|
||||||
|
delete_src_file = False
|
||||||
print("{0} v{1}: Error while executing other plugins".format(PLUGIN_NAME, PLUGIN_VERSION))
|
print("{0} v{1}: Error while executing other plugins".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
pass
|
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 path - either the original one or the one modified by the other plugins.
|
||||||
return rpl
|
return rpl
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ class ConfigWidget(QWidget):
|
||||||
|
|
||||||
self.tempdeacsmprefs['notify_fulfillment'] = self.deacsmprefs['notify_fulfillment']
|
self.tempdeacsmprefs['notify_fulfillment'] = self.deacsmprefs['notify_fulfillment']
|
||||||
self.tempdeacsmprefs['detailed_logging'] = self.deacsmprefs['detailed_logging']
|
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']
|
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)
|
self.chkDetailedLogging.toggled.connect(self.toggle_logging)
|
||||||
layout.addWidget(self.chkDetailedLogging)
|
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.
|
# 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 = QShortcut(QKeySequence("Ctrl+Shift+D"), self)
|
||||||
self.deauthShortcut.activated.connect(self.delete_ade_auth)
|
self.deauthShortcut.activated.connect(self.delete_ade_auth)
|
||||||
|
@ -185,12 +192,23 @@ class ConfigWidget(QWidget):
|
||||||
if not self.chkDetailedLogging.isChecked():
|
if not self.chkDetailedLogging.isChecked():
|
||||||
return
|
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 += "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."
|
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)
|
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):
|
def delete_ade_auth(self):
|
||||||
|
@ -830,6 +848,7 @@ class ConfigWidget(QWidget):
|
||||||
def save_settings(self):
|
def save_settings(self):
|
||||||
self.deacsmprefs.set('notify_fulfillment', self.chkNotifyFulfillment.isChecked())
|
self.deacsmprefs.set('notify_fulfillment', self.chkNotifyFulfillment.isChecked())
|
||||||
self.deacsmprefs.set('detailed_logging', self.chkDetailedLogging.isChecked())
|
self.deacsmprefs.set('detailed_logging', self.chkDetailedLogging.isChecked())
|
||||||
|
self.deacsmprefs.set('delete_acsm_after_fulfill', self.chkDeleteAfterFulfill.isChecked())
|
||||||
self.deacsmprefs.writeprefs()
|
self.deacsmprefs.writeprefs()
|
||||||
|
|
||||||
def load_resource(self, name):
|
def load_resource(self, name):
|
||||||
|
|
|
@ -450,9 +450,6 @@ def activateDevice(useVersionIndex: int = 0):
|
||||||
if (result is False):
|
if (result is False):
|
||||||
return False, "Building activation request failed: " + activate_req
|
return False, "Building activation request failed: " + activate_req
|
||||||
|
|
||||||
#print("======================================================")
|
|
||||||
#print("activate")
|
|
||||||
#print(activate_req)
|
|
||||||
|
|
||||||
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
||||||
etree.register_namespace("adept", NSMAP["adept"])
|
etree.register_namespace("adept", NSMAP["adept"])
|
||||||
|
|
|
@ -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
|
device = fulfillmentResultToken.find("./%s/%s/%s/%s" % (adNS("fulfillmentResult"), adNS("resourceItemInfo"), adNS("licenseToken"), adNS("device"))).text
|
||||||
except:
|
except:
|
||||||
# B&N Adobe PassHash fulfillment without device ID.
|
# 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.
|
# 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 understand Adobe's documentation correctly, PassHash books do not support notifications
|
||||||
# If I use the one from the ADE activation, I get E_LIC_USER_UNKNOWN
|
# and are not supposed to contain notify tags, so lets just skip if that's the case.
|
||||||
# Adobe documentation seems to imply that PassHash books don't support notifications,
|
|
||||||
# so lets just skip if that's the case.
|
|
||||||
print("Skipping notify due to passHash")
|
print("Skipping notify due to passHash")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ class DeACSM_Prefs():
|
||||||
|
|
||||||
self.deacsmprefs.defaults['notify_fulfillment'] = True
|
self.deacsmprefs.defaults['notify_fulfillment'] = True
|
||||||
self.deacsmprefs.defaults['detailed_logging'] = False
|
self.deacsmprefs.defaults['detailed_logging'] = False
|
||||||
|
self.deacsmprefs.defaults['delete_acsm_after_fulfill'] = False
|
||||||
|
|
||||||
self.deacsmprefs.defaults['list_of_rented_books'] = []
|
self.deacsmprefs.defaults['list_of_rented_books'] = []
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user