mirror of
https://github.com/noDRM/DeDRM_tools.git
synced 2026-03-20 21:08:57 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45a1a64db5 | ||
|
|
bc1c3c2197 | ||
|
|
79cfddfbee | ||
|
|
aa41bba68c | ||
|
|
86a90117e5 | ||
|
|
874a6b8de9 | ||
|
|
01c654cb68 | ||
|
|
5bc28623cb | ||
|
|
c1d7fcbb7f | ||
|
|
45eefd6c80 | ||
|
|
33e37eb375 | ||
|
|
4229b8ff85 | ||
|
|
91e4645315 | ||
|
|
425d8af73e | ||
|
|
0ce86fa8db | ||
|
|
ecc7db09a9 | ||
|
|
d7ddc2ab93 | ||
|
|
fd51422a36 | ||
|
|
cb36ca1b0d | ||
|
|
ffd79d5fe4 | ||
|
|
0b2b81fd23 | ||
|
|
63aecc598f | ||
|
|
51c8be6baf |
@@ -5,7 +5,7 @@
|
||||
# Copyright © 2008-2020 Apprentice Harper et al.
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__version__ = '7.1.0'
|
||||
__version__ = '7.2.0'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ __docformat__ = 'restructuredtext en'
|
||||
# 7.0.2 - More Python 3 changes. Adobe PDF decryption should now work on PC too.
|
||||
# 7.0.3 - More Python 3 changes. Integer division in ineptpdf.py
|
||||
# 7.1.0 - Full release for calibre 5.x
|
||||
# 7.2.0 - Update for latest KFX changes, and Python 3 Obok fixes.
|
||||
|
||||
"""
|
||||
Decrypt DRMed ebooks.
|
||||
|
||||
@@ -115,7 +115,9 @@ if iswindows:
|
||||
|
||||
def _load_crypto_libcrypto():
|
||||
from ctypes.util import find_library
|
||||
libcrypto = find_library('libeay32')
|
||||
libcrypto = find_library('libcrypto-1_1')
|
||||
if libcrypto is None:
|
||||
libcrypto = find_library('libeay32')
|
||||
if libcrypto is None:
|
||||
raise ADEPTError('libcrypto not found')
|
||||
libcrypto = CDLL(libcrypto)
|
||||
|
||||
@@ -559,7 +559,7 @@ class DocParser(object):
|
||||
if (link > 0):
|
||||
linktype = self.link_type[link-1]
|
||||
title = self.link_title[link-1]
|
||||
title = title.rstrip(b'. ')
|
||||
title = title.rstrip(b'. ').decode('utf-8')
|
||||
alt_title = parares[lstart:]
|
||||
alt_title = alt_title.strip()
|
||||
# now strip off the actual printed page number
|
||||
@@ -770,10 +770,10 @@ class DocParser(object):
|
||||
first_para_continued = False
|
||||
(pclass, pdesc) = self.getParaDescription(start,end, regtype)
|
||||
if not pclass:
|
||||
if orig_regtype.endswith(b'.right') : pclass = 'cl-right'
|
||||
elif orig_regtype.endswith(b'.center') : pclass = 'cl-center'
|
||||
elif orig_regtype.endswith(b'.left') : pclass = 'cl-left'
|
||||
elif orig_regtype.endswith(b'.justify') : pclass = 'cl-justify'
|
||||
if orig_regtype.endswith(b'.right') : pclass = b'cl-right'
|
||||
elif orig_regtype.endswith(b'.center') : pclass = b'cl-center'
|
||||
elif orig_regtype.endswith(b'.left') : pclass = b'cl-left'
|
||||
elif orig_regtype.endswith(b'.justify') : pclass = b'cl-justify'
|
||||
if pclass and (ptype == 'full') and (len(pclass) >= 6):
|
||||
tag = 'p'
|
||||
if pclass[3:6] == b'h1-' : tag = 'h4'
|
||||
|
||||
@@ -512,6 +512,8 @@ class BinaryIonParser(object):
|
||||
|
||||
if table is not None:
|
||||
self.symbols.import_(table, min(maxid, len(table.symnames)))
|
||||
if len(table.symnames) < maxid:
|
||||
self.symbols.importunknown(name + "-unknown", maxid - len(table.symnames))
|
||||
else:
|
||||
self.symbols.importunknown(name, maxid)
|
||||
|
||||
@@ -733,7 +735,10 @@ SYM_NAMES = [ 'com.amazon.drm.Envelope@1.0',
|
||||
'com.amazon.drm.EncryptedPage@2.0',
|
||||
'com.amazon.drm.PlainText@2.0', 'compression_algorithm',
|
||||
'com.amazon.drm.Compressed@1.0', 'page_index_table',
|
||||
'com.amazon.drm.VoucherEnvelope@2.0', 'com.amazon.drm.VoucherEnvelope@3.0' ]
|
||||
] + ['com.amazon.drm.VoucherEnvelope@%d.0' % n
|
||||
for n in list(range(2, 29)) + [
|
||||
9708, 1031, 2069, 9041, 3646,
|
||||
6052, 9479, 9888, 4648, 5683]]
|
||||
|
||||
def addprottable(ion):
|
||||
ion.addtocatalog("ProtectedData", 1, SYM_NAMES)
|
||||
@@ -757,9 +762,45 @@ def pkcs7unpad(msg, blocklen):
|
||||
|
||||
|
||||
# every VoucherEnvelope version has a corresponding "word" and magic number, used in obfuscating the shared secret
|
||||
VOUCHER_VERSION_INFOS = {
|
||||
2: [b'Antidisestablishmentarianism', 5],
|
||||
3: [b'Floccinaucinihilipilification', 8]
|
||||
OBFUSCATION_TABLE = {
|
||||
"V1": (0x00, None),
|
||||
"V2": (0x05, b'Antidisestablishmentarianism'),
|
||||
"V3": (0x08, b'Floccinaucinihilipilification'),
|
||||
"V4": (0x07, b'>\x14\x0c\x12\x10-\x13&\x18U\x1d\x05Rlt\x03!\x19\x1b\x13\x04]Y\x19,\t\x1b'),
|
||||
"V5": (0x06, b'~\x18~\x16J\\\x18\x10\x05\x0b\x07\t\x0cZ\r|\x1c\x15\x1d\x11>,\x1b\x0e\x03"4\x1b\x01'),
|
||||
"V6": (0x09, b'3h\x055\x03[^>\x19\x1c\x08\x1b\rtm4\x02Rp\x0c\x16B\n'),
|
||||
"V7": (0x05, b'\x10\x1bJ\x18\nh!\x10"\x03>Z\'\r\x01]W\x06\x1c\x1e?\x0f\x13'),
|
||||
"V8": (0x09, b"K\x0c6\x1d\x1a\x17pO}Rk\x1d'w1^\x1f$\x1c{C\x02Q\x06\x1d`"),
|
||||
"V9": (0x05, b'X.\x0eW\x1c*K\x12\x12\t\n\n\x17Wx\x01\x02Yf\x0f\x18\x1bVXPi\x01'),
|
||||
"V10": (0x07, b'z3\n\x039\x12\x13`\x06=v,\x02MTK\x1e%}L\x1c\x1f\x15\x0c\x11\x02\x0c\n8\x17p'),
|
||||
"V11": (0x05, b'L=\nhVm\x07go\n6\x14\x06\x16L\r\x02\x0b\x0c\x1b\x04#p\t'),
|
||||
"V12": (0x06, b',n\x1d\rl\x13\x1c\x13\x16p\x14\x07U\x0c\x1f\x19w\x16\x16\x1d5T'),
|
||||
"V13": (0x07, b'I\x05\t\x08\x03r)\x01$N\x0fr3n\x0b062D\x0f\x13'),
|
||||
"V14": (0x05, b"\x03\x02\x1c9\x19\x15\x15q\x1057\x08\x16\x0cF\x1b.Fw\x01\x12\x03\x13\x02\x17S'hk6"),
|
||||
"V15": (0x0A, b'&,4B\x1dcI\x0bU\x03I\x07\x04\x1c\t\x05c\x07%ws\x0cj\t\x1a\x08\x0f'),
|
||||
"V16": (0x0A, b'\x06\x18`h,b><\x06PqR\x02Zc\x034\n\x16\x1e\x18\x06#e'),
|
||||
"V17": (0x07, b'y\r\x12\x08fw.[\x02\t\n\x13\x11\x0c\x11b\x1e8L\x10(\x13<Jx6c\x0f'),
|
||||
"V18": (0x07, b'I\x0b\x0e,\x19\x1aIa\x10s\x19g\\\x1b\x11!\x18yf\x0f\t\x1d7[bSp\x03'),
|
||||
"V19": (0x05, b'\n6>)N\x02\x188\x016s\x13\x14\x1b\x16jeN\n\x146\x04\x18\x1c\x0c\x19\x1f,\x02]'),
|
||||
"V20": (0x08, b'_\r\x01\x12]\\\x14*\x17i\x14\r\t!\x1e,~hZ\x12jK\x17\x1e*1'),
|
||||
"V21": (0x07, b'e\x1d\x19|\ty\x1di|N\x13\x0e\x04\x1bj<h\x13\x15k\x12\x08=\x1f\x16~\x13l'),
|
||||
"V22": (0x08, b'?\x17yi$k7Pc\tEo\x0c\x07\x07\t\x1f,*i\x12\x0cI0\x10I\x1a?2\x04'),
|
||||
"V23": (0x08, b'\x16+db\x13\x04\x18\rc%\x14\x17\x0f\x13F\x0c[\t9\x1ay\x01\x1eH'),
|
||||
"V24": (0x06, b'|6\\\x1a\r\x10\nP\x07\x0fu\x1f\t,\rr`uv\\~55\x11]N'),
|
||||
"V25": (0x09, b'\x07\x14w\x1e,^y\x01:\x08\x07\x1fr\tU#j\x16\x12\x1eB\x04\x16=\x06fZ\x07\x02\x06'),
|
||||
"V26": (0x06, b'\x03IL\x1e"K\x1f\x0f\x1fp0\x01`X\x02z0`\x03\x0eN\x07'),
|
||||
"V27": (0x07, b'Xk\x10y\x02\x18\x10\x17\x1d,\x0e\x05e\x10\x15"e\x0fh(\x06s\x1c\x08I\x0c\x1b\x0e'),
|
||||
"V28": (0x0A, b'6P\x1bs\x0f\x06V.\x1cM\x14\x02\n\x1b\x07{P0:\x18zaU\x05'),
|
||||
"V9708": (0x05, b'\x1diIm\x08a\x17\x1e!am\x1d\x1aQ.\x16!\x06*\}x04\x11\t\x06\x04?'),
|
||||
"V1031": (0x08, b'Antidisestablishmentarianism'),
|
||||
"V2069": (0x07, b'Floccinaucinihilipilification'),
|
||||
"V9041": (0x06, b'>\x14\x0c\x12\x10-\x13&\x18U\x1d\x05Rlt\x03!\x19\x1b\x13\x04]Y\x19,\t\x1b'),
|
||||
"V3646": (0x09, b'~\x18~\x16J\\\x18\x10\x05\x0b\x07\t\x0cZ\r|\x1c\x15\x1d\x11>,\x1b\x0e\x03"4\x1b\x01'),
|
||||
"V6052": (0x05, b'3h\x055\x03[^>\x19\x1c\x08\x1b\rtm4\x02Rp\x0c\x16B\n'),
|
||||
"V9479": (0x09, b'\x10\x1bJ\x18\nh!\x10"\x03>Z\'\r\x01]W\x06\x1c\x1e?\x0f\x13'),
|
||||
"V9888": (0x05, b"K\x0c6\x1d\x1a\x17pO}Rk\x1d'w1^\x1f$\x1c{C\x02Q\x06\x1d`"),
|
||||
"V4648": (0x07, b'X.\x0eW\x1c*K\x12\x12\t\n\n\x17Wx\x01\x02Yf\x0f\x18\x1bVXPi\x01'),
|
||||
"V5683": (0x05, b'z3\n\x039\x12\x13`\x06=v,\x02MTK\x1e%}L\x1c\x1f\x15\x0c\x11\x02\x0c\n8\x17p'),
|
||||
}
|
||||
|
||||
|
||||
@@ -768,9 +809,7 @@ def obfuscate(secret, version):
|
||||
if version == 1: # v1 does not use obfuscation
|
||||
return secret
|
||||
|
||||
params = VOUCHER_VERSION_INFOS[version]
|
||||
word = params[0]
|
||||
magic = params[1]
|
||||
magic, word = OBFUSCATION_TABLE["V%d" % version]
|
||||
|
||||
# extend secret so that its length is divisible by the magic number
|
||||
if len(secret) % magic != 0:
|
||||
@@ -993,6 +1032,7 @@ class DrmIon(object):
|
||||
|
||||
elif self.ion.gettypename() in ["com.amazon.drm.EncryptedPage@1.0", "com.amazon.drm.EncryptedPage@2.0"]:
|
||||
decompress = False
|
||||
decrypt = True
|
||||
ct = None
|
||||
civ = None
|
||||
self.ion.stepin()
|
||||
@@ -1006,7 +1046,23 @@ class DrmIon(object):
|
||||
civ = self.ion.lobvalue()
|
||||
|
||||
if ct is not None and civ is not None:
|
||||
self.processpage(ct, civ, outpages, decompress)
|
||||
self.processpage(ct, civ, outpages, decompress, decrypt)
|
||||
self.ion.stepout()
|
||||
|
||||
elif self.ion.gettypename() in ["com.amazon.drm.PlainText@1.0", "com.amazon.drm.PlainText@2.0"]:
|
||||
decompress = False
|
||||
decrypt = False
|
||||
plaintext = None
|
||||
self.ion.stepin()
|
||||
while self.ion.hasnext():
|
||||
self.ion.next()
|
||||
if self.ion.gettypename() == "com.amazon.drm.Compressed@1.0":
|
||||
decompress = True
|
||||
if self.ion.getfieldname() == "data":
|
||||
plaintext = self.ion.lobvalue()
|
||||
|
||||
if plaintext is not None:
|
||||
self.processpage(plaintext, None, outpages, decompress, decrypt)
|
||||
self.ion.stepout()
|
||||
|
||||
self.ion.stepout()
|
||||
@@ -1017,9 +1073,12 @@ class DrmIon(object):
|
||||
def print_(self, lst):
|
||||
self.ion.print_(lst)
|
||||
|
||||
def processpage(self, ct, civ, outpages, decompress):
|
||||
aes = AES.new(self.key[:16], AES.MODE_CBC, civ[:16])
|
||||
msg = pkcs7unpad(aes.decrypt(ct), 16)
|
||||
def processpage(self, ct, civ, outpages, decompress, decrypt):
|
||||
if decrypt:
|
||||
aes = AES.new(self.key[:16], AES.MODE_CBC, civ[:16])
|
||||
msg = pkcs7unpad(aes.decrypt(ct), 16)
|
||||
else:
|
||||
msg = ct
|
||||
|
||||
if not decompress:
|
||||
outpages.write(msg)
|
||||
|
||||
@@ -191,7 +191,7 @@ def unescape(text):
|
||||
else:
|
||||
# named entity
|
||||
try:
|
||||
text = chr(htmlentitydefs.name2codepoint[text[1:-1]])
|
||||
text = chr(html.entities.name2codepoint[text[1:-1]])
|
||||
except KeyError:
|
||||
pass
|
||||
return text # leave as is
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
# Engine to remove drm from Kindle KFX ebooks
|
||||
|
||||
# 2.0 - Python 3 for calibre 5.0
|
||||
# 2.1 - Some fixes for debugging
|
||||
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import traceback
|
||||
import zipfile
|
||||
|
||||
from io import BytesIO
|
||||
@@ -65,6 +67,9 @@ class KFXZipBook:
|
||||
print("Decrypting KFX DRM voucher: {0}".format(info.filename))
|
||||
|
||||
for pid in [''] + totalpids:
|
||||
# Belt and braces. PIDs should be unicode strings, but just in case...
|
||||
if isinstance(pid, bytes):
|
||||
pid = pid.decode('ascii')
|
||||
for dsn_len,secret_len in [(0,0), (16,0), (16,40), (32,40), (40,0), (40,40)]:
|
||||
if len(pid) == dsn_len + secret_len:
|
||||
break # split pid into DSN and account secret
|
||||
@@ -77,7 +82,8 @@ class KFXZipBook:
|
||||
voucher.decryptvoucher()
|
||||
break
|
||||
except:
|
||||
pass
|
||||
traceback.print_exc()
|
||||
pass
|
||||
else:
|
||||
raise Exception("Failed to decrypt KFX DRM voucher with any key")
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ def getK4Pids(rec209, token, kindleDatabase):
|
||||
kindleAccountToken = bytearray.fromhex((kindleDatabase[1])['kindle.account.tokens'])
|
||||
|
||||
except KeyError:
|
||||
kindleAccountToken=""
|
||||
kindleAccountToken = b''
|
||||
pass
|
||||
|
||||
try:
|
||||
|
||||
@@ -153,6 +153,7 @@ class fixZip:
|
||||
nzinfo.internal_attr=zinfo.internal_attr
|
||||
nzinfo.external_attr=zinfo.external_attr
|
||||
nzinfo.create_system=zinfo.create_system
|
||||
nzinfo.flag_bits = zinfo.flag_bits & 0x800 # preserve UTF-8 flag
|
||||
self.outzip.writestr(nzinfo,data)
|
||||
|
||||
self.bzf.close()
|
||||
|
||||
8
FAQs.md
8
FAQs.md
@@ -27,12 +27,12 @@ Verify the one of the following cryptographic hash values, using software of you
|
||||
#### Kindle for PC `KindleForPC-installer-1.17.44170.exe`:
|
||||
* MD-5: 53F793B562F4823721AA47D7DE099869
|
||||
* SHA-1: 73C404D719F0DD8D4AE1C2C96612B095D6C86255
|
||||
* SHA-256: 14E0F0053F1276C0C7C446892DC170344F707FBFE99B695176 2C120144163200
|
||||
* SHA-256: 14E0F0053F1276C0C7C446892DC170344F707FBFE99B6951762C120144163200
|
||||
|
||||
#### Kindle for Mac `KindleForMac-44182.dmg`:
|
||||
* MD-5: E7E36D5369E1F3CF1D28E5D9115DF15F
|
||||
* SHA-1: 7AB9A86B954CB23D622BD79E3257F8E2182D791C
|
||||
* SHA-256: 28DC21246A9C7CDEDD2D6F0F4082E6BF7EF9DB9CE9D485548E 8A9E1D19EAE2AC.
|
||||
* SHA-256: 28DC21246A9C7CDEDD2D6F0F4082E6BF7EF9DB9CE9D485548E8A9E1D19EAE2AC
|
||||
|
||||
You will need to go to the preferences and uncheck the auto update checkbox. Then download and install 1.17 over the top of the newer installation. You'll also need to delete the KFX folders from your My Kindle Content folder. You may also need to take further action to prevent an auto update. The simplest wayis to find the 'updates' folder and replace it with a file. See [this thread] (http://www.mobileread.com/forums/showthread.php?t=283371) at MobileRead for a Script to do this on a PC. On a Mac you can find the folder at ~/Library/Application Support/Kindle/ just delete the folder 'updates' and save a blank text file called 'updates' in its place.
|
||||
|
||||
@@ -51,7 +51,9 @@ Mac Note: If the chmod command fails with a permission error try again using `su
|
||||
After restarting the Kindle program any books previously downloaded in KFX format will no longer open. You will need to remove them from your device and re-download them. All future downloads will use the older Kindle formats instead of KFX although they will continue to be placed in one individual subdirectory per book. Note that books soudl be downoad by right-click and 'Download', not by just opening the book. Recent (1.25+) versions of Kindle for Mac/PC may convert KF8 files to a new format that is not supported by these tools when the book is opened for reading.
|
||||
|
||||
#### Decrypting KFX
|
||||
Thanks to work by several people, the tools can now decrypt KFX format ebooks from Kindle for Mac/PC version 1.26 or earlier (version later than 1.26 use a new encryption scheme for KFX files). In addition to the DeDRM plugin, calibre users will also need to install jhowell's KFX Input plugin which is available through the standard plugin menu in calibre, or directly from [his plugin thread](https://www.mobileread.com/forums/showthread.php?t=291290) on Mobileread.
|
||||
Thanks to work by several people, the tools can now decrypt KFX format ebooks from Kindle for Mac/PC. In addition to the DeDRM plugin, calibre users will also need to install jhowell's KFX Input plugin which is available through the standard plugin menu in calibre, or directly from [his plugin thread](https://www.mobileread.com/forums/showthread.php?t=291290) on Mobileread.
|
||||
|
||||
It's quite possible that Amazon will update their KFX DeDRM to prevent DRM removal from KFX books again. So Remove DRM as soon as possible!
|
||||
|
||||
#### Thanks
|
||||
Thanks to jhowell for his investigations into KFX format and the KFX Input plugin. Some of these instructions are from [his thread on the subject](https://www.mobileread.com/forums/showthread.php?t=283371) at MobileRead.
|
||||
|
||||
@@ -3,7 +3,7 @@ from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__version__ = '7.1.0'
|
||||
__version__ = '7.2.0'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
#####################################################################
|
||||
@@ -20,7 +20,7 @@ except NameError:
|
||||
PLUGIN_NAME = 'Obok DeDRM'
|
||||
PLUGIN_SAFE_NAME = PLUGIN_NAME.strip().lower().replace(' ', '_')
|
||||
PLUGIN_DESCRIPTION = _('Removes DRM from Kobo kepubs and adds them to the library.')
|
||||
PLUGIN_VERSION_TUPLE = (7, 1, 0)
|
||||
PLUGIN_VERSION_TUPLE = (7, 2, 0)
|
||||
PLUGIN_VERSION = '.'.join([str(x) for x in PLUGIN_VERSION_TUPLE])
|
||||
HELPFILE_NAME = PLUGIN_SAFE_NAME + '_Help.htm'
|
||||
PLUGIN_AUTHORS = 'Anon'
|
||||
|
||||
@@ -470,15 +470,15 @@ class KoboLibrary(object):
|
||||
"""The list of all MAC addresses on this machine."""
|
||||
macaddrs = []
|
||||
if sys.platform.startswith('win'):
|
||||
c = re.compile('\s(' + '[0-9a-f]{2}-' * 5 + '[0-9a-f]{2})(\s|$)', re.IGNORECASE)
|
||||
output = subprocess.Popen('ipconfig /all', shell=True, stdout=subprocess.PIPE, text=True).stdout
|
||||
c = re.compile('\s?(' + '[0-9a-f]{2}[:\-]' * 5 + '[0-9a-f]{2})(\s|$)', re.IGNORECASE)
|
||||
output = subprocess.Popen('wmic nic where PhysicalAdapter=True get MACAddress', shell=True, stdout=subprocess.PIPE, text=True).stdout
|
||||
for line in output:
|
||||
m = c.search(line)
|
||||
if m:
|
||||
macaddrs.append(re.sub("-", ":", m.group(1)).upper())
|
||||
elif sys.platform.startswith('darwin'):
|
||||
c = re.compile('\s(' + '[0-9a-f]{2}:' * 5 + '[0-9a-f]{2})(\s|$)', re.IGNORECASE)
|
||||
output = subprocess.check_output('/sbin/ifconfig -a', shell=True)
|
||||
output = subprocess.check_output('/sbin/ifconfig -a', shell=True, encoding='utf-8')
|
||||
matches = c.findall(output)
|
||||
for m in matches:
|
||||
# print "m:{0}".format(m[0])
|
||||
|
||||
@@ -10,14 +10,12 @@ The individual scripts are now released as two plugins for calibre: DeDRM and Ob
|
||||
The DeDRM plugin handles books that use Amazon DRM, Adobe Digital Editions DRM (version 1), Barnes & Noble DRM, and some historical formats.
|
||||
The Obok plugin handles Kobo DRM.
|
||||
|
||||
Users with calibre 5.x or later should use release 7.0.0b2 or later of the tools.
|
||||
Users with calibe 4.x or earlier should use release 6.8.0 of the tools.
|
||||
|
||||
Developers might be interested in forking the repository, as it contains unzipped versions of those tools that are zipped to make the changes over time easier to follow.
|
||||
Users with calibre 5.x or later should use release 7.2.0 or later of the tools.
|
||||
Users with calibe 4.x or earlier should use release 6.8.x of the tools.
|
||||
|
||||
For the latest Amazon KFX format, users of the calibre plugin should also install the KFX Input plugin from the standard calibre plugin menu. It's also available from the MobileRead thread here: https://www.mobileread.com/forums/showthread.php?t=291290
|
||||
|
||||
Note that DRM can only be removed from KFX format files downloaded with Kindle for PC/Mac 1.26 or earlier. Amazon changes the DRM for KFX files in Kindle for PC/Mac 1.27 and later.
|
||||
Note that Amazon changes the DRM for KFX files frequently. What works for KFX today might not work tomorrow.
|
||||
|
||||
I welcome contributions from others to improve these tools, from expanding the range of books handled, improving key retrieval, to just general bug fixes, speed improvements and UI enhancements.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ The tools are provided in the form of plugins for calibre. Calibre is an open so
|
||||
|
||||
DeDRM plugin for calibre (Mac OS X, Windows)
|
||||
-------------------------------------------------------
|
||||
calibe 5.x and later are now written in Python 3, and plugins must also use Python 3. If you have calibre 5, you must use version 7.x or later of the plugins. For calibre 4.x and earlier, use version 6.8.0 of the plugins.
|
||||
calibe 5.x and later are now written in Python 3, and plugins must also use Python 3. If you have calibre 5, you must use version 7.x or later of the plugins. For calibre 4.x and earlier, use version 6.8.x of the plugins.
|
||||
|
||||
The DeDRM plugin for calibre removes DRM from your Kindle and Adobe DRM ebooks when they are imported to calibre. Just install the DeDRM plugin (DeDRM_plugin.zip), following the instructions and configuration directions provided in the ReadMe file and the help links in the plugin's configuration dialogs.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user