mirror of
https://github.com/Leseratte10/acsm-calibre-plugin.git
synced 2024-12-22 09:19:55 +06:00
v0.0.4: Make DeDRM work without modifications
This commit is contained in:
parent
3a4652a462
commit
a930a99c80
1
.github/workflows/main.yml
vendored
1
.github/workflows/main.yml
vendored
@ -20,5 +20,4 @@ jobs:
|
||||
name: linux
|
||||
path: |
|
||||
calibre-plugin.zip
|
||||
libgourou_bundle_raw.tar.xz
|
||||
|
13
README.md
13
README.md
@ -10,21 +10,17 @@ It is a full Python reimplementation of libgourou by Grégory Soutadé (http://i
|
||||
3. Click the "Link to ADE account" button
|
||||
4. Enter your AdobeID and password, then wait a couple seconds for the success message.
|
||||
5. The settings window should now say "Authorized with ADE ID X on device Y".
|
||||
6. Click the "Export account activation data" and "Export account encryption key" buttons to export / backup your keys. Do not skip this step. The first file (ZIP) can be used to re-authorize Calibre after a reset / reinstall without using up one of your Adobe authorizations. The second file (DER) can be imported into Alf.
|
||||
7. Download an EPUB ACSM file from Adobe's test library and see if you can import it into Calibre: https://www.adobe.com/de/solutions/ebook/digital-editions/sample-ebook-library.html
|
||||
6. Click the "Export account activation data" and "Export account encryption key" buttons to export / backup your keys. Do not skip this step. The first file (ZIP) can be used to re-authorize Calibre after a reset / reinstall without using up one of your Adobe authorizations. The second file (DER) can be imported into DeDRM.
|
||||
7. If needed (new AdobeID), import the DER file into the DeDRM plugin.
|
||||
8. Download an EPUB ACSM file from Adobe's test library and see if you can import it into Calibre: https://www.adobe.com/de/solutions/ebook/digital-editions/sample-ebook-library.html
|
||||
|
||||
IMPORTANT:
|
||||
|
||||
- I would suggest creating a new dummy AdobeID to use for Calibre so just in case Adobe detects this and bans you, you don't lose your main AdobeID.
|
||||
- Combined with that I suggest importing the DER file into the Alf plugin to make sure that losing your AdobeID doesn't also mean you'll lose access to all your eBooks. See the section "Combining with Alf" below.
|
||||
- Combined with that I suggest importing the DER file into the DeDRM plugin to make sure that losing your AdobeID doesn't also mean you'll lose access to all your eBooks.
|
||||
- This plugin doesn't yet work with PDFs. Importing an ACSM file for a PDF book will just result in the ACSM file being imported, it won't be converted into a PDF.
|
||||
- This software is not approved by Adobe. I am not responsible if Adobe detects that you're using nonstandard software and bans your account. Do not complain to me if Adobe bans your main ADE account - you have been warned.
|
||||
|
||||
## Combining with Alf
|
||||
|
||||
In order to combine this plugin with Alf, you'll need to go to Alf's settings and import the DER file you've just exported from this plugin.
|
||||
|
||||
Also, there's a small code change needed to Alf's plugin to make it work together with this one. Open up the `__init__.py` file in Alf's ZIP file and search for "file_types". You'll find a list of supported file types. Add "acsm" to that list, save the file, put it back into the ZIP file, then re-import the Alf plugin into Calibre. This is needed due to a bug in Calibre - even though this plugin converts the ACSM file into an EPUB on import, Alf still "thinks" it's an ACSM file and doesn't do anything with it. By forcing Alf to accept ACSM files it will work correctly (since it'll then notice that it's actually an EPUB).
|
||||
|
||||
## To-Do list for the future?
|
||||
|
||||
@ -34,4 +30,5 @@ There's a bunch of features that could still be added, but most of them aren't i
|
||||
- Support for un-authorizing a machine
|
||||
- Support to re-import a backed-up authorization after a reinstallation (right now you can only do that manually)
|
||||
- Support for PDFs
|
||||
- Support for returning loan books
|
||||
- ...
|
||||
|
@ -8,10 +8,11 @@
|
||||
# v0.0.1: First version.
|
||||
# v0.0.2: Allow key extraction without extra binary call (unreleased test version)
|
||||
# v0.0.3: Standalone Calibre plugin for Linux, Windows, MacOS without the need for libgourou.
|
||||
# v0.0.4: Manually execute DeDRM (if installed) after converting ACSM to EPUB.
|
||||
|
||||
|
||||
from calibre.customize import FileTypePlugin # type: ignore
|
||||
__version__ = '0.0.3'
|
||||
__version__ = '0.0.4'
|
||||
|
||||
PLUGIN_NAME = "DeACSM"
|
||||
PLUGIN_VERSION_TUPLE = tuple([int(x) for x in __version__.split(".")])
|
||||
@ -24,7 +25,6 @@ import os, shutil, traceback, sys
|
||||
import zipfile
|
||||
from lxml import etree
|
||||
|
||||
|
||||
class DeACSM(FileTypePlugin):
|
||||
name = PLUGIN_NAME
|
||||
description = "Takes an Adobe ACSM file and converts that into a useable EPUB file. Python reimplementation of libgourou by Grégory Soutadé"
|
||||
@ -101,9 +101,8 @@ class DeACSM(FileTypePlugin):
|
||||
from libadobe import VAR_HOBBES_VERSION, createDeviceKeyFile, update_account_path
|
||||
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
|
||||
except:
|
||||
print("error Account")
|
||||
raise
|
||||
raise
|
||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||
traceback.print_exc()
|
||||
|
||||
# Fulfill:
|
||||
try:
|
||||
@ -114,11 +113,8 @@ class DeACSM(FileTypePlugin):
|
||||
from libadobe import sendHTTPRequest
|
||||
from libadobeFulfill import buildRights, fulfill
|
||||
except:
|
||||
print("error Fulfill")
|
||||
raise
|
||||
raise
|
||||
|
||||
|
||||
print("{0} v{1}: Error while importing Fulfillment stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||
traceback.print_exc()
|
||||
|
||||
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
||||
deacsmprefs = prefs.DeACSM_Prefs()
|
||||
@ -127,9 +123,6 @@ class DeACSM(FileTypePlugin):
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
raise
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def is_customizable(self):
|
||||
@ -178,9 +171,8 @@ class DeACSM(FileTypePlugin):
|
||||
from libadobe import sendHTTPRequest
|
||||
from libadobeFulfill import buildRights, fulfill
|
||||
except:
|
||||
print("error Fulfill")
|
||||
raise
|
||||
raise
|
||||
print("{0} v{1}: Error while importing Fulfillment stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
adobe_fulfill_response = etree.fromstring(replyData)
|
||||
@ -264,9 +256,8 @@ class DeACSM(FileTypePlugin):
|
||||
from libadobe import sendHTTPRequest
|
||||
from libadobeFulfill import buildRights, fulfill
|
||||
except:
|
||||
print("error Fulfill")
|
||||
raise
|
||||
raise
|
||||
print("{0} v{1}: Error while importing Fulfillment stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
success, replyData = fulfill(path_to_ebook)
|
||||
@ -276,6 +267,23 @@ class DeACSM(FileTypePlugin):
|
||||
print("{0} v{1}: Downloading book ...".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||
rpl = self.download(replyData)
|
||||
if (rpl is not None):
|
||||
# Got a file
|
||||
|
||||
# Because Calibre still thinks this is an ACSM file (not an EPUB)
|
||||
# it will not run other plugins like Alf / DeDRM.
|
||||
# So we have to manually check if it's installed,
|
||||
# and if it is, run it to remove DRM.
|
||||
try:
|
||||
from calibre.customize.ui import _initialized_plugins
|
||||
for plugin in _initialized_plugins:
|
||||
if (plugin.name == "DeDRM"):
|
||||
print("{0} v{1}: Executing DeDRM plugin ...".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||
return plugin.run(rpl)
|
||||
except:
|
||||
print("{0} v{1}: Error while checking for DeDRM plugin.".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||
pass
|
||||
|
||||
# Looks like DeDRM is not installed, return book with DRM.
|
||||
return rpl
|
||||
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
# pyright: reportUndefinedVariable=false
|
||||
|
||||
import os, base64
|
||||
import os, base64, traceback
|
||||
|
||||
from lxml import etree
|
||||
|
||||
@ -79,9 +79,9 @@ class ConfigWidget(QWidget):
|
||||
from libadobe import VAR_HOBBES_VERSION, createDeviceKeyFile, update_account_path
|
||||
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
|
||||
except:
|
||||
print("error Account")
|
||||
raise
|
||||
raise
|
||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
update_account_path(self.deacsmprefs["path_to_account_data"])
|
||||
|
||||
@ -126,7 +126,7 @@ class ConfigWidget(QWidget):
|
||||
if (filename is None):
|
||||
return
|
||||
|
||||
print("would export to " + filename)
|
||||
print("{0} v{1}: Exporting activation data to {2}".format(PLUGIN_NAME, PLUGIN_VERSION, filename))
|
||||
|
||||
try:
|
||||
with ZipFile(filename, 'w') as zipfile:
|
||||
@ -148,9 +148,8 @@ class ConfigWidget(QWidget):
|
||||
from libadobe import VAR_HOBBES_VERSION, createDeviceKeyFile, update_account_path
|
||||
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
|
||||
except:
|
||||
print("error Account")
|
||||
raise
|
||||
raise
|
||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||
traceback.print_exc()
|
||||
|
||||
update_account_path(self.deacsmprefs["path_to_account_data"])
|
||||
|
||||
@ -195,9 +194,20 @@ class ConfigWidget(QWidget):
|
||||
|
||||
|
||||
def export_key(self):
|
||||
pluginsdir = os.path.join(config_dir,"plugins")
|
||||
maindir = os.path.join(pluginsdir,"DeACSM")
|
||||
verdir = os.path.join(maindir,PLUGIN_VERSION)
|
||||
|
||||
try:
|
||||
from calibre_plugins.deacsm.libadobe import update_account_path
|
||||
from calibre_plugins.deacsm.libadobeAccount import exportAccountEncryptionKeyDER
|
||||
except:
|
||||
try:
|
||||
from libadobe import update_account_path
|
||||
from libadobeAccount import exportAccountEncryptionKeyDER
|
||||
except:
|
||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
update_account_path(self.deacsmprefs["path_to_account_data"])
|
||||
|
||||
filters = [("DER Files", ["der"])]
|
||||
|
||||
@ -206,38 +216,16 @@ class ConfigWidget(QWidget):
|
||||
if (filename is None):
|
||||
return
|
||||
|
||||
print("would export to " + filename)
|
||||
print("{0} v{1}: Exporting encryption key to {2}".format(PLUGIN_NAME, PLUGIN_VERSION, filename))
|
||||
|
||||
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
||||
deacsmprefs = prefs.DeACSM_Prefs()
|
||||
ret = exportAccountEncryptionKeyDER(filename)
|
||||
|
||||
if ret:
|
||||
return info_dialog(None, "Done", "Key successfully exported", show=True, show_copy_button=False)
|
||||
else:
|
||||
return error_dialog(None, "Export failed", "Export failed", show=True, show_copy_button=False)
|
||||
|
||||
|
||||
activation_xml_path = os.path.join(self.deacsmprefs["path_to_account_data"], "activation.xml")
|
||||
|
||||
container = None
|
||||
try:
|
||||
container = etree.parse(activation_xml_path)
|
||||
except (FileNotFoundError, OSError) as e:
|
||||
return error_dialog(None, "Export failed", "Export failed - Can't open activation.xml", show=True, show_copy_button=False)
|
||||
|
||||
key_binary = None
|
||||
try:
|
||||
adeptNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
||||
usernameXML = container.find(adeptNS("credentials")).find(adeptNS("privateLicenseKey"))
|
||||
key_base64 = usernameXML.text
|
||||
key_binary = base64.decodebytes(key_base64.encode())[26:]
|
||||
except:
|
||||
return error_dialog(None, "Export failed", "Export failed - Can't read key from activation.xml", show=True, show_copy_button=False)
|
||||
|
||||
try:
|
||||
output_file = open(filename, "wb")
|
||||
output_file.write(key_binary)
|
||||
output_file.close()
|
||||
except:
|
||||
return error_dialog(None, "Export failed", "Export failed - Can't write key to file", show=True, show_copy_button=False)
|
||||
|
||||
|
||||
info_dialog(None, "Done", "Key successfully exported", show=True, show_copy_button=False)
|
||||
|
||||
def save_settings(self):
|
||||
#self.deacsmprefs.set('path_to_account_data', self.txtboxUA.text())
|
||||
|
Loading…
Reference in New Issue
Block a user