mirror of
https://github.com/noDRM/DeDRM_tools.git
synced 2026-03-22 05:48:57 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d05594dcbc | ||
|
|
09a34cf7d9 | ||
|
|
ca6ec8f6d0 | ||
|
|
e9a6e80e5a | ||
|
|
33437073d6 | ||
|
|
2edde54c44 |
3
.github/workflows/main.yml
vendored
3
.github/workflows/main.yml
vendored
@@ -10,10 +10,11 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Package
|
- name: Package
|
||||||
run: python3 make_release.py 10.0.0
|
run: python3 make_release.py
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: plugin
|
name: plugin
|
||||||
path: |
|
path: |
|
||||||
DeDRM_tools_*.zip
|
DeDRM_tools_*.zip
|
||||||
|
DeDRM_tools.zip
|
||||||
|
|||||||
13
CHANGELOG.md
13
CHANGELOG.md
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
List of changes since the fork of Apprentice Harper's repository:
|
List of changes since the fork of Apprentice Harper's repository:
|
||||||
|
|
||||||
|
## Fixes in v10.0.0 (2021-11-17):
|
||||||
|
|
||||||
- CI testing / linting removed as that always failed anyways. The CI now "just" packages the plugin.
|
- CI testing / linting removed as that always failed anyways. The CI now "just" packages the plugin.
|
||||||
- Support for the Readium LCP DRM (also known as "CARE DRM" or "TEA DRM"). This supports EPUB and PDF files. It does not yet support Readium LCPDF/LPF/LCPA/LCPAU/LCPDI files, as I don't have access to any of these. If you have an LCP-protected file in one of these formats that this plugin does not work with, please open [an issue](https://github.com/noDRM/DeDRM_tools/issues) and attach the file to the report.
|
- Support for the Readium LCP DRM (also known as "CARE DRM" or "TEA DRM"). This supports EPUB and PDF files. It does not yet support Readium LCPDF/LPF/LCPA/LCPAU/LCPDI files, as I don't have access to any of these. If you have an LCP-protected file in one of these formats that this plugin does not work with, please open [an issue](https://github.com/noDRM/DeDRM_tools/issues) and attach the file to the report.
|
||||||
- Add new Github issue report form which forces the user to include stuff like their Calibre version to hopefully increase the quality of bug reports.
|
- Add new Github issue report form which forces the user to include stuff like their Calibre version to hopefully increase the quality of bug reports.
|
||||||
@@ -21,3 +23,14 @@ List of changes since the fork of Apprentice Harper's repository:
|
|||||||
- Added back support for Python2 (Calibre 2.0+). Only tested with ADEPT (PDF & EPUB) and Readium LCP so far, please open an issue if there's errors with other book types.
|
- Added back support for Python2 (Calibre 2.0+). Only tested with ADEPT (PDF & EPUB) and Readium LCP so far, please open an issue if there's errors with other book types.
|
||||||
- Begin work on removing some kinds of watermarks from files after DRM removal. This isn't tested a lot, and is disabled by default. You can enable it in the plugin settings.
|
- Begin work on removing some kinds of watermarks from files after DRM removal. This isn't tested a lot, and is disabled by default. You can enable it in the plugin settings.
|
||||||
- If you're using the [ACSM Input Plugin / DeACSM](https://www.mobileread.com/forums/showthread.php?t=341975), the encryption key will automatically be extracted from that plugin if necessary.
|
- If you're using the [ACSM Input Plugin / DeACSM](https://www.mobileread.com/forums/showthread.php?t=341975), the encryption key will automatically be extracted from that plugin if necessary.
|
||||||
|
|
||||||
|
## Fixes in v10.0.1 (2021-11-19):
|
||||||
|
|
||||||
|
- Hotfix update to fix broken EPUB DRM removal due to a typo.
|
||||||
|
|
||||||
|
## Fixes in v10.0.2 (2021-11-29):
|
||||||
|
|
||||||
|
- Fix Kindle for Mac key retrieval (merged [apprenticeharper/DeDRM_tools#1936](https://github.com/apprenticeharper/DeDRM_tools/pull/1936) ), fixing #1.
|
||||||
|
- Fix Adobe key retrieval in case the username has been changed (merged [apprenticeharper/DeDRM_tools#1946](https://github.com/apprenticeharper/DeDRM_tools/pull/1946) ). This should fix the error "failed to decrypt user key key".
|
||||||
|
- Fix small issue with elibri watermark removal.
|
||||||
|
- Adobe key name will now contain account email.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
# Copyright © 2021 NoDRM
|
# Copyright © 2021 NoDRM
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__version__ = '10.0.0'
|
__version__ = '10.0.2'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
|
||||||
@@ -79,6 +79,8 @@ __docformat__ = 'restructuredtext en'
|
|||||||
# 7.2.0 - Update for latest KFX changes, and Python 3 Obok fixes.
|
# 7.2.0 - Update for latest KFX changes, and Python 3 Obok fixes.
|
||||||
# 7.2.1 - Whitespace!
|
# 7.2.1 - Whitespace!
|
||||||
# 10.0.0 - First forked version by NoDRM. See CHANGELOG.md for details.
|
# 10.0.0 - First forked version by NoDRM. See CHANGELOG.md for details.
|
||||||
|
# 10.0.1 - Fixes a bug in the watermark code.
|
||||||
|
# 10.0.2 - Fix Kindle for Mac & update Adobe key retrieval
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Decrypt DRMed ebooks.
|
Decrypt DRMed ebooks.
|
||||||
@@ -210,6 +212,8 @@ class DeDRM(FileTypePlugin):
|
|||||||
# It does stuff like de-obfuscating fonts (by calling checkFonts)
|
# It does stuff like de-obfuscating fonts (by calling checkFonts)
|
||||||
# or removing watermarks.
|
# or removing watermarks.
|
||||||
|
|
||||||
|
postProcessStart = time.time()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import calibre_plugins.dedrm.prefs as prefs
|
import calibre_plugins.dedrm.prefs as prefs
|
||||||
dedrmprefs = prefs.DeDRM_Prefs()
|
dedrmprefs = prefs.DeDRM_Prefs()
|
||||||
@@ -224,12 +228,16 @@ class DeDRM(FileTypePlugin):
|
|||||||
# Remove Tolino's CDP watermark file
|
# Remove Tolino's CDP watermark file
|
||||||
path_to_ebook = watermark.removeCDPwatermark(self, path_to_ebook) or path_to_ebook
|
path_to_ebook = watermark.removeCDPwatermark(self, path_to_ebook) or path_to_ebook
|
||||||
|
|
||||||
# Remove watermarks (currently just Amazon) from the OPF file
|
# Remove watermarks (Amazon or LemonInk) from the OPF file
|
||||||
path_to_ebook = watermark.removeOPFwatermarks(self, path_to_ebook) or path_to_ebook
|
path_to_ebook = watermark.removeOPFwatermarks(self, path_to_ebook) or path_to_ebook
|
||||||
|
|
||||||
# Remove watermarks (currently just Adobe's resource ID) from all HTML and XHTML files
|
# Remove watermarks (Adobe or LemonInk) from all HTML and XHTML files
|
||||||
path_to_ebook = watermark.removeHTMLwatermarks(self, path_to_ebook) or path_to_ebook
|
path_to_ebook = watermark.removeHTMLwatermarks(self, path_to_ebook) or path_to_ebook
|
||||||
|
|
||||||
|
postProcessEnd = time.time()
|
||||||
|
print("{0} v{1}: Post-processing took {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, postProcessEnd-postProcessStart))
|
||||||
|
|
||||||
|
|
||||||
return path_to_ebook
|
return path_to_ebook
|
||||||
|
|
||||||
except:
|
except:
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# adobekey.pyw, version 6.0
|
# adobekey.pyw, version 7.1
|
||||||
# Copyright © 2009-2020 i♥cabbages, Apprentice Harper et al.
|
# Copyright © 2009-2021 i♥cabbages, Apprentice Harper et al.
|
||||||
|
|
||||||
# Released under the terms of the GNU General Public Licence, version 3
|
# Released under the terms of the GNU General Public Licence, version 3
|
||||||
# <http://www.gnu.org/licenses/>
|
# <http://www.gnu.org/licenses/>
|
||||||
@@ -29,13 +29,14 @@
|
|||||||
# 5.9 - moved unicode_argv call inside main for Windows DeDRM compatibility
|
# 5.9 - moved unicode_argv call inside main for Windows DeDRM compatibility
|
||||||
# 6.0 - Work if TkInter is missing
|
# 6.0 - Work if TkInter is missing
|
||||||
# 7.0 - Python 3 for calibre 5
|
# 7.0 - Python 3 for calibre 5
|
||||||
|
# 7.1 - Fix "failed to decrypt user key key" error (read username from registry)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Retrieve Adobe ADEPT user key.
|
Retrieve Adobe ADEPT user key.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__version__ = '7.0'
|
__version__ = '7.1'
|
||||||
|
|
||||||
import sys, os, struct, getopt
|
import sys, os, struct, getopt
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
@@ -237,6 +238,20 @@ if iswindows:
|
|||||||
return GetUserName
|
return GetUserName
|
||||||
GetUserName = GetUserName()
|
GetUserName = GetUserName()
|
||||||
|
|
||||||
|
def GetUserName2():
|
||||||
|
try:
|
||||||
|
import winreg
|
||||||
|
except ImportError:
|
||||||
|
import _winreg as winreg
|
||||||
|
|
||||||
|
try:
|
||||||
|
DEVICE_KEY_PATH = r'Software\Adobe\Adept\Device'
|
||||||
|
regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, DEVICE_KEY_PATH)
|
||||||
|
userREG = winreg.QueryValueEx(regkey, 'username')[0].encode('utf-16-le')[::2]
|
||||||
|
return userREG
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
PAGE_EXECUTE_READWRITE = 0x40
|
PAGE_EXECUTE_READWRITE = 0x40
|
||||||
MEM_COMMIT = 0x1000
|
MEM_COMMIT = 0x1000
|
||||||
MEM_RESERVE = 0x2000
|
MEM_RESERVE = 0x2000
|
||||||
@@ -274,8 +289,13 @@ if iswindows:
|
|||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
if self._buf is not None:
|
if self._buf is not None:
|
||||||
|
try:
|
||||||
VirtualFree(self._buf)
|
VirtualFree(self._buf)
|
||||||
self._buf = None
|
self._buf = None
|
||||||
|
except TypeError:
|
||||||
|
# Apparently this sometimes gets cleared on application exit
|
||||||
|
# Causes a useless exception in the log, so let's just catch and ignore that.
|
||||||
|
pass
|
||||||
|
|
||||||
if struct.calcsize("P") == 4:
|
if struct.calcsize("P") == 4:
|
||||||
CPUID0_INSNS = (
|
CPUID0_INSNS = (
|
||||||
@@ -360,6 +380,8 @@ if iswindows:
|
|||||||
serial = GetVolumeSerialNumber(root)
|
serial = GetVolumeSerialNumber(root)
|
||||||
vendor = cpuid0()
|
vendor = cpuid0()
|
||||||
signature = struct.pack('>I', cpuid1())[1:]
|
signature = struct.pack('>I', cpuid1())[1:]
|
||||||
|
user = GetUserName2()
|
||||||
|
if user is None:
|
||||||
user = GetUserName()
|
user = GetUserName()
|
||||||
entropy = struct.pack('>I12s3s13s', serial, vendor, signature, user)
|
entropy = struct.pack('>I12s3s13s', serial, vendor, signature, user)
|
||||||
cuser = winreg.HKEY_CURRENT_USER
|
cuser = winreg.HKEY_CURRENT_USER
|
||||||
@@ -384,7 +406,7 @@ if iswindows:
|
|||||||
ktype = winreg.QueryValueEx(plkparent, None)[0]
|
ktype = winreg.QueryValueEx(plkparent, None)[0]
|
||||||
if ktype != 'credentials':
|
if ktype != 'credentials':
|
||||||
continue
|
continue
|
||||||
uuid_name = "Unknown"
|
uuid_name = ""
|
||||||
for j in range(0, 16):
|
for j in range(0, 16):
|
||||||
try:
|
try:
|
||||||
plkkey = winreg.OpenKey(plkparent, "%04d" % (j,))
|
plkkey = winreg.OpenKey(plkparent, "%04d" % (j,))
|
||||||
@@ -392,9 +414,19 @@ if iswindows:
|
|||||||
break
|
break
|
||||||
ktype = winreg.QueryValueEx(plkkey, None)[0]
|
ktype = winreg.QueryValueEx(plkkey, None)[0]
|
||||||
if ktype == 'user':
|
if ktype == 'user':
|
||||||
uuid_name = winreg.QueryValueEx(plkkey, 'value')[0]
|
# Add Adobe UUID to key name
|
||||||
if ktype != 'privateLicenseKey':
|
uuid_name = uuid_name + winreg.QueryValueEx(plkkey, 'value')[0][9:] + "_"
|
||||||
continue
|
if ktype == 'username':
|
||||||
|
# Add account type & email to key name, if present
|
||||||
|
try:
|
||||||
|
uuid_name = uuid_name + winreg.QueryValueEx(plkkey, 'method')[0] + "_"
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
uuid_name = uuid_name + winreg.QueryValueEx(plkkey, 'value')[0] + "_"
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if ktype == 'privateLicenseKey':
|
||||||
userkey = winreg.QueryValueEx(plkkey, 'value')[0]
|
userkey = winreg.QueryValueEx(plkkey, 'value')[0]
|
||||||
userkey = b64decode(userkey)
|
userkey = b64decode(userkey)
|
||||||
aes = AES(keykey)
|
aes = AES(keykey)
|
||||||
@@ -402,7 +434,12 @@ if iswindows:
|
|||||||
userkey = userkey[26:-ord(userkey[-1:])]
|
userkey = userkey[26:-ord(userkey[-1:])]
|
||||||
# print ("found " + uuid_name + " key: " + str(userkey))
|
# print ("found " + uuid_name + " key: " + str(userkey))
|
||||||
keys.append(userkey)
|
keys.append(userkey)
|
||||||
names.append(uuid_name[9:])
|
|
||||||
|
if uuid_name == "":
|
||||||
|
names.append("Unknown")
|
||||||
|
else:
|
||||||
|
names.append(uuid_name[:-1])
|
||||||
|
|
||||||
if len(keys) == 0:
|
if len(keys) == 0:
|
||||||
raise ADEPTError('Could not locate privateLicenseKey')
|
raise ADEPTError('Could not locate privateLicenseKey')
|
||||||
print("Found {0:d} keys".format(len(keys)))
|
print("Found {0:d} keys".format(len(keys)))
|
||||||
@@ -445,16 +482,32 @@ elif isosx:
|
|||||||
tree = etree.parse(actpath)
|
tree = etree.parse(actpath)
|
||||||
adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag)
|
adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag)
|
||||||
expr = '//%s/%s' % (adept('credentials'), adept('privateLicenseKey'))
|
expr = '//%s/%s' % (adept('credentials'), adept('privateLicenseKey'))
|
||||||
exprUUID = '//%s/%s' % (adept('credentials'), adept('user'))
|
|
||||||
userkey = tree.findtext(expr)
|
userkey = tree.findtext(expr)
|
||||||
userUUID = "Unknown"
|
|
||||||
|
exprUUID = '//%s/%s' % (adept('credentials'), adept('user'))
|
||||||
|
keyName = ""
|
||||||
try:
|
try:
|
||||||
userUUID = tree.findtext(exprUUID)
|
keyName = tree.findtext(exprUUID)[9:] + "_"
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
exprMail = '//%s/%s' % (adept('credentials'), adept('username'))
|
||||||
|
keyName = keyName + tree.find(exprMail).attrib["method"] + "_"
|
||||||
|
keyName = keyName + tree.findtext(exprMail) + "_"
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if keyName == "":
|
||||||
|
keyName = "Unknown"
|
||||||
|
else:
|
||||||
|
keyName = keyName[:-1]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
userkey = b64decode(userkey)
|
userkey = b64decode(userkey)
|
||||||
userkey = userkey[26:]
|
userkey = userkey[26:]
|
||||||
return [userkey], [userUUID[9:]]
|
return [userkey], [keyName]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
def adeptkeys():
|
def adeptkeys():
|
||||||
|
|||||||
@@ -832,7 +832,7 @@ class AddAdeptDialog(QDialog):
|
|||||||
key_group = QHBoxLayout()
|
key_group = QHBoxLayout()
|
||||||
data_group_box_layout.addLayout(key_group)
|
data_group_box_layout.addLayout(key_group)
|
||||||
key_group.addWidget(QLabel("Unique Key Name:", self))
|
key_group.addWidget(QLabel("Unique Key Name:", self))
|
||||||
self.key_ledit = QLineEdit(self.default_name_A, self)
|
self.key_ledit = QLineEdit("default_ade_key_uuid_" + self.default_name_A, self)
|
||||||
self.key_ledit.setToolTip("<p>Enter an identifying name for the current Adobe key. Note that it's recommended to leave the UUID (the random-looking digits and letters) as it is.")
|
self.key_ledit.setToolTip("<p>Enter an identifying name for the current Adobe key. Note that it's recommended to leave the UUID (the random-looking digits and letters) as it is.")
|
||||||
key_group.addWidget(self.key_ledit)
|
key_group.addWidget(self.key_ledit)
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ def removeHTMLwatermarks(object, path_to_ebook):
|
|||||||
modded_names = []
|
modded_names = []
|
||||||
modded_contents = []
|
modded_contents = []
|
||||||
|
|
||||||
|
count_adept = 0
|
||||||
|
|
||||||
|
count_lemonink_invisible = 0
|
||||||
|
count_lemonink_visible = 0
|
||||||
|
lemonink_trackingID = None
|
||||||
|
|
||||||
for file in namelist:
|
for file in namelist:
|
||||||
if not (file.endswith('.html') or file.endswith('.xhtml') or file.endswith('.xml')):
|
if not (file.endswith('.html') or file.endswith('.xhtml') or file.endswith('.xml')):
|
||||||
continue
|
continue
|
||||||
@@ -40,8 +46,33 @@ def removeHTMLwatermarks(object, path_to_ebook):
|
|||||||
# Remove Adobe ADEPT watermarks
|
# Remove Adobe ADEPT watermarks
|
||||||
# Match optional newline at the beginning, then a "meta" tag with name = "Adept.expected.resource" or "Adept.resource"
|
# Match optional newline at the beginning, then a "meta" tag with name = "Adept.expected.resource" or "Adept.resource"
|
||||||
# and either a "value" or a "content" element with an Adobe UUID
|
# and either a "value" or a "content" element with an Adobe UUID
|
||||||
|
pre_remove = str_new
|
||||||
str_new = re.sub(r'((\r\n|\r|\n)\s*)?\<meta\s+name=\"(Adept\.resource|Adept\.expected\.resource)\"\s+(content|value)=\"urn:uuid:[0-9a-fA-F\-]+\"\s*\/>', '', str_new)
|
str_new = re.sub(r'((\r\n|\r|\n)\s*)?\<meta\s+name=\"(Adept\.resource|Adept\.expected\.resource)\"\s+(content|value)=\"urn:uuid:[0-9a-fA-F\-]+\"\s*\/>', '', str_new)
|
||||||
str_new = re.sub(r'((\r\n|\r|\n)\s*)?\<meta\s+(content|value)=\"urn:uuid:[0-9a-fA-F\-]+\"\s+name=\"(Adept\.resource|Adept\.expected\.resource)\"\s*\/>', '', str_new)
|
str_new = re.sub(r'((\r\n|\r|\n)\s*)?\<meta\s+(content|value)=\"urn:uuid:[0-9a-fA-F\-]+\"\s+name=\"(Adept\.resource|Adept\.expected\.resource)\"\s*\/>', '', str_new)
|
||||||
|
|
||||||
|
if (str_new != pre_remove):
|
||||||
|
count_adept += 1
|
||||||
|
|
||||||
|
# Remove eLibri / LemonInk watermark
|
||||||
|
# Run this in a loop, as it is possible a file has been watermarked twice ...
|
||||||
|
while True:
|
||||||
|
pre_remove = str_new
|
||||||
|
unique_id = re.search(r'<body[^>]+class="[^"]*(t0x[0-9a-fA-F]{25})[^"]*"[^>]*>', str_new)
|
||||||
|
if (unique_id):
|
||||||
|
lemonink_trackingID = unique_id.groups()[0]
|
||||||
|
count_lemonink_invisible += 1
|
||||||
|
str_new = re.sub(lemonink_trackingID, '', str_new)
|
||||||
|
pre_remove = str_new
|
||||||
|
pm = r'(<body[^>]+class="[^"]*"[^>]*>)'
|
||||||
|
pm += r'\<div style\=\'padding\:0\;border\:0\;text\-indent\:0\;line\-height\:normal\;margin\:0 1cm 0.5cm 1cm\;[^\']*text\-decoration\:none\;[^\']*background\:none\;[^\']*\'\>(.*?)</div>'
|
||||||
|
pm += r'\<div style\=\'padding\:0\;border\:0\;text\-indent\:0\;line\-height\:normal\;margin\:0 1cm 0.5cm 1cm\;[^\']*text\-decoration\:none\;[^\']*background\:none\;[^\']*\'\>(.*?)</div>'
|
||||||
|
str_new = re.sub(pm, r'\1', str_new)
|
||||||
|
|
||||||
|
if (str_new != pre_remove):
|
||||||
|
count_lemonink_visible += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
continue
|
continue
|
||||||
@@ -52,13 +83,14 @@ def removeHTMLwatermarks(object, path_to_ebook):
|
|||||||
modded_names.append(file)
|
modded_names.append(file)
|
||||||
modded_contents.append(str_new)
|
modded_contents.append(str_new)
|
||||||
|
|
||||||
|
|
||||||
if len(modded_names) == 0:
|
if len(modded_names) == 0:
|
||||||
# No file modified, return original
|
# No file modified, return original
|
||||||
return path_to_ebook
|
return path_to_ebook
|
||||||
|
|
||||||
if len(modded_names) != len(modded_contents):
|
if len(modded_names) != len(modded_contents):
|
||||||
# Something went terribly wrong, return original
|
# Something went terribly wrong, return original
|
||||||
print("Watermark: Error during ADEPT watermark removal")
|
print("Watermark: Error during watermark removal")
|
||||||
return path_to_ebook
|
return path_to_ebook
|
||||||
|
|
||||||
# Re-package with modified files:
|
# Re-package with modified files:
|
||||||
@@ -105,12 +137,20 @@ def removeHTMLwatermarks(object, path_to_ebook):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return path_to_ebook
|
return path_to_ebook
|
||||||
|
|
||||||
|
if (count_adept > 0):
|
||||||
|
print("Watermark: Successfully stripped {0} ADEPT watermark(s) from ebook.".format(count_adept))
|
||||||
|
|
||||||
|
if (count_lemonink_invisible > 0 or count_lemonink_visible > 0):
|
||||||
|
print("Watermark: Successfully stripped {0} visible and {1} invisible LemonInk watermark(s) (\"{2}\") from ebook."
|
||||||
|
.format(count_lemonink_visible, count_lemonink_invisible, lemonink_trackingID))
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return path_to_ebook
|
return path_to_ebook
|
||||||
|
|
||||||
print("Watermark: Successfully stripped {0} ADEPT watermark(s) from ebook.".format(len(modded_names)))
|
|
||||||
return output
|
|
||||||
|
|
||||||
|
|
||||||
# Finds the main OPF file, then uses RegEx to remove watermarks
|
# Finds the main OPF file, then uses RegEx to remove watermarks
|
||||||
@@ -141,10 +181,29 @@ def removeOPFwatermarks(object, path_to_ebook):
|
|||||||
container_str = inf.read(opf_path).decode("utf-8")
|
container_str = inf.read(opf_path).decode("utf-8")
|
||||||
container_str_new = container_str
|
container_str_new = container_str
|
||||||
|
|
||||||
|
had_amazon = False
|
||||||
|
had_elibri = False
|
||||||
|
|
||||||
# Remove Amazon hex watermarks
|
# Remove Amazon hex watermarks
|
||||||
# Match optional newline at the beginning, then spaces, then a "meta" tag with name = "Watermark" or "Watermark_(hex)" and a "content" element.
|
# Match optional newline at the beginning, then spaces, then a "meta" tag with name = "Watermark" or "Watermark_(hex)" and a "content" element.
|
||||||
container_str_new = re.sub(r'((\r\n|\r|\n)\s*)?\<meta\s+name=\"Watermark(_\(hex\))?\"\s+content=\"[0-9a-fA-F]+\"\s*\/>', '', container_str_new)
|
# This regex also matches DuMont watermarks with meta name="watermark", with the case-insensitive match on the "w" in watermark.
|
||||||
container_str_new = re.sub(r'((\r\n|\r|\n)\s*)?\<meta\s+content=\"[0-9a-fA-F]+\"\s+name=\"Watermark(_\(hex\))?\"\s*\/>', '', container_str_new)
|
pre_remove = container_str_new
|
||||||
|
container_str_new = re.sub(r'((\r\n|\r|\n)\s*)?\<meta\s+name=\"[Ww]atermark(_\(hex\))?\"\s+content=\"[0-9a-fA-F]+\"\s*\/>', '', container_str_new)
|
||||||
|
container_str_new = re.sub(r'((\r\n|\r|\n)\s*)?\<meta\s+content=\"[0-9a-fA-F]+\"\s+name=\"[Ww]atermark(_\(hex\))?\"\s*\/>', '', container_str_new)
|
||||||
|
if pre_remove != container_str_new:
|
||||||
|
had_amazon = True
|
||||||
|
|
||||||
|
# Remove elibri / lemonink watermark
|
||||||
|
# Lemonink replaces all "id" fields in the opf with "idX_Y", with X being the watermark and Y being a number for that particular ID.
|
||||||
|
# This regex replaces all "idX_Y" IDs with "id_Y", removing the watermark IDs.
|
||||||
|
pre_remove = container_str_new
|
||||||
|
container_str_new = re.sub(r'((\r\n|\r|\n)\s*)?\<\!\-\-\s*Wygenerowane przez elibri dla zamówienia numer [0-9a-fA-F]+\s*\-\-\>', '', container_str_new)
|
||||||
|
if pre_remove != container_str_new:
|
||||||
|
# To prevent this Regex from applying to books without that watermark, only do that if the watermark above was found.
|
||||||
|
container_str_new = re.sub(r'\=\"id[0-9]+_([0-9]+)\"', r'="id_\1"', container_str_new)
|
||||||
|
if pre_remove != container_str_new:
|
||||||
|
had_elibri = True
|
||||||
|
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return path_to_ebook
|
return path_to_ebook
|
||||||
@@ -191,7 +250,11 @@ def removeOPFwatermarks(object, path_to_ebook):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return path_to_ebook
|
return path_to_ebook
|
||||||
|
|
||||||
|
if had_elibri:
|
||||||
|
print("Watermark: Successfully stripped eLibri watermark from OPF file.")
|
||||||
|
if had_amazon:
|
||||||
print("Watermark: Successfully stripped Amazon watermark from OPF file.")
|
print("Watermark: Successfully stripped Amazon watermark from OPF file.")
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1526,7 +1526,7 @@ elif isosx:
|
|||||||
b'SerialNumber',\
|
b'SerialNumber',\
|
||||||
b'UsernameHash',\
|
b'UsernameHash',\
|
||||||
b'kindle.directedid.info',\
|
b'kindle.directedid.info',\
|
||||||
b'DSN'
|
b'DSN',\
|
||||||
b'kindle.accounttype.info',\
|
b'kindle.accounttype.info',\
|
||||||
b'krx.flashcardsplugin.data.encryption_key',\
|
b'krx.flashcardsplugin.data.encryption_key',\
|
||||||
b'krx.notebookexportplugin.data.encryption_key',\
|
b'krx.notebookexportplugin.data.encryption_key',\
|
||||||
|
|||||||
@@ -34,7 +34,10 @@ def make_release(version):
|
|||||||
shutil.copy(OBOK_README, RELEASE_DIR)
|
shutil.copy(OBOK_README, RELEASE_DIR)
|
||||||
shutil.copy("ReadMe_Overview.txt", RELEASE_DIR)
|
shutil.copy("ReadMe_Overview.txt", RELEASE_DIR)
|
||||||
|
|
||||||
|
if version is not None:
|
||||||
release_name = 'DeDRM_tools_{}'.format(version)
|
release_name = 'DeDRM_tools_{}'.format(version)
|
||||||
|
else:
|
||||||
|
release_name = 'DeDRM_tools'
|
||||||
result = shutil.make_archive(release_name, 'zip', RELEASE_DIR)
|
result = shutil.make_archive(release_name, 'zip', RELEASE_DIR)
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(RELEASE_DIR)
|
shutil.rmtree(RELEASE_DIR)
|
||||||
@@ -48,6 +51,6 @@ if __name__ == '__main__':
|
|||||||
try:
|
try:
|
||||||
version = sys.argv[1]
|
version = sys.argv[1]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise SystemExit('Usage: {} version'.format(__file__))
|
version = None
|
||||||
|
|
||||||
print(make_release(version))
|
print(make_release(version))
|
||||||
|
|||||||
Reference in New Issue
Block a user