You are on page 1of 43

property prefsFileName : "com.apprenticealf.dedrm.

plist"
property tempFileName : "DeDRM_temp.log"
property prefsFolderName : "com.apprenticealf.dedrm"
property newKeysFolderName : "newKeys"
property handledExtensions : {"epub", "pdf", "prc", "azw", "azw1", "tpz", "azw3",
"azw4", "mobi", "pobi", "pdb"}

global python
global oldAppleScript

global eReaderTool
global MobipocketTool
global KindlePIDTool
global BNKeyGenTool
global BNKeyFetchTool
global BNePubTool
global KindleKeyTool
global NookKeyTool
global AdobeKeyGenTool
global AdobeePubTool
global ePubTestTool
global AdobePDFTool
global ZipFixTool
global ProgressApp

global PIDs
global UDIDs
global bnKeys
global KindleSerialList
global AndroidKeyList
global KindleKeyList
global AdeptKeyList

global ErrorList
global WarningList
global CompletedList
global ErrorCount
global WarningCount
global CompletedCount
global totalebooks
global completedebooks
global outputFolder
global logFilePath
global tempfilepath

global paraend

on writetolog(logstring)
try
set fileRef to open for access logFilePath with write permission
write logstring & "
" to fileRef starting at eof as «class utf8»
close access fileRef
end try
end writetolog

on clearlog()
try
set fileRef to open for access logFilePath with write permission
set eof fileRef to 0
close access fileRef
end try
end clearlog

on cleartemp()
try
set fileRef to open for access tempfilepath with write permission
set eof fileRef to 0
close access fileRef
end try
end cleartemp

on readtemp()
set tempContents to ""
try
set fileRef to open for access tempfilepath
if (get eof fileRef) > 0 then
set tempContents to read fileRef from 1 as «class utf8»
end if
close access fileRef
end try
return tempContents
end readtemp

on readtemplist()
set templist to {}
try
set fileRef to open for access tempfilepath
if (get eof fileRef) > 0 then
set tempContents to paragraphs of (read fileRef from 1 as «class
utf8»)
end if
close access fileRef
end try
repeat with nextLine in tempContents
if length of nextLine is greater than 0 then
copy nextLine to the end of templist
end if
end repeat
return templist
end readtemplist

on quotedtemppath()
set tempFile to POSIX path of file tempfilepath
return quoted form of tempFile
end quotedtemppath

on folderexists(inputFolder)
try
--display dialog "test -d " & quoted form of (POSIX path of
inputFolder)
do shell script "test -d " & quoted form of (POSIX path of inputFolder)
return true
end try

return false
end folderexists
on fileexists(inputFile)
try
do shell script "test -f " & quoted form of (POSIX path of inputFile)
return true
end try

return false
end fileexists

on GetFileExtension(fileName)
set fileExtension to ""
if fileName contains "." then
set oldTIDs to AppleScript's text item delimiters
set AppleScript's text item delimiters to "."
set fileExtension to the last text item of fileName
set AppleScript's text item delimiters to oldTIDs
end if
return fileExtension
end GetFileExtension

on GetFileNameOnly(fileName)
set fileNameOnly to fileName
if fileName contains "." then
set oldTIDs to AppleScript's text item delimiters
set AppleScript's text item delimiters to "."
set fileNameOnly to (text items 1 through -2 of fileName) as string
set AppleScript's text item delimiters to oldTIDs
end if
return fileNameOnly
end GetFileNameOnly

on GetTools()
set paraend to "
"
set ASnumber to (text 1 thru 3 of (AppleScript's version as text) as real)
set oldAppleScript to (ASnumber < 2.0)
set python to "/usr/local/bin/python"
if not fileexists(python) then
set python to "/usr/bin/python"
end if
set pythonversion to "2.3"
try
set pythonversion to do shell script python & " -c \"from sys import
version; print version[:3]\""
end try
-- display dialog pythonversion
if (pythonversion is not "2.5") and (pythonversion is not "2.6") and
(pythonversion is not "2.7") then
set dialogresult to (display dialog "This AppleScript requires Python
2.7x.

Please install python 2.7x and try again." buttons {"Quit"} default button 1
with title "DeDRM" with icon stop)
return false
end if
-- we always want a space after the command
set python to python & " "

set eReaderTool to POSIX path of (path to resource "erdr2pml.py")


set MobipocketTool to POSIX path of (path to resource "k4mobidedrm.py")
set KindlePIDTool to POSIX path of (path to resource "kindlepid.py")
set BNKeyGenTool to POSIX path of (path to resource "ignoblekeygen.py")
set BNKeyFetchTool to POSIX path of (path to resource "ignoblekeyfetch.py")
set BNePubTool to POSIX path of (path to resource "ignobleepub.py")
set KindleKeyTool to POSIX path of (path to resource "kindlekey.py")
set NookKeyTool to POSIX path of (path to resource "ignoblekey.py")
set AdobeKeyGenTool to POSIX path of (path to resource "adobekey.py")
set AdobeePubTool to POSIX path of (path to resource "ineptepub.py")
set ePubTestTool to POSIX path of (path to resource "epubtest.py")
set AdobePDFTool to POSIX path of (path to resource "ineptpdf.py")
set ZipFixTool to POSIX path of (path to resource "zipfix.py")
set ProgressApp to POSIX path of (path to resource "DeDRM Progress.app")
if not fileexists(eReaderTool) then
set dialogresult to (display dialog "The eReader script (erdr2pml.py)
is missing from this package. Get a fresh copy." buttons {"Quit", "Continue
Anyway"} default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
if not fileexists(MobipocketTool) then
--display dialog MobipocketTool
set dialogresult to (display dialog "The Mobipocket script
(k4mobidedrm.py) is missing from this package. Get a fresh copy." buttons {"Quit",
"Continue Anyway"} default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
if not fileexists(KindlePIDTool) then
--display dialog KindlePIDTool
set dialogresult to (display dialog "The KindlePID script
(kindlepid.py) is missing from this package. Get a fresh copy." buttons {"Quit",
"Continue Anyway"} default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
if not fileexists(BNKeyGenTool) then
set dialogresult to (display dialog "The B&N Key Generation script
(ignoblekeygen.py) is missing from this package. Get a fresh copy." buttons
{"Quit", "Continue Anyway"} default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
if not fileexists(BNKeyFetchTool) then
set dialogresult to (display dialog "The B&N Key Fetch script
(ignoblekeyfetch.py) is missing from this package. Get a fresh copy." buttons
{"Quit", "Continue Anyway"} default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
if not fileexists(BNePubTool) then
set dialogresult to (display dialog "The B&N script (ignobleepub.py) is
missing from this package. Get a fresh copy." buttons {"Quit", "Continue Anyway"}
default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
if not fileexists(NookKeyTool) then
set dialogresult to (display dialog "The B&N Key Retrieval script
(ignoblekey.py) is missing from this package. Get a fresh copy." buttons {"Quit",
"Continue Anyway"} default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
if not fileexists(KindleKeyTool) then
set dialogresult to (display dialog "The Kindle Key Generation script
(kindlekey.py) is missing from this package. Get a fresh copy." buttons {"Quit",
"Continue Anyway"} default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
if not fileexists(AdobeKeyGenTool) then
set dialogresult to (display dialog "The Adobe Key Generation script
(adobekey.py) is missing from this package. Get a fresh copy." buttons {"Quit",
"Continue Anyway"} default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
if not fileexists(AdobePDFTool) then
set dialogresult to (display dialog "The Adobe PDF script (ineptpdf.py)
is missing from this package. Get a fresh copy." buttons {"Quit", "Continue
Anyway"} default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
if not fileexists(AdobeePubTool) then
set dialogresult to (display dialog "The Adobe ePub script
(ineptepub.py) is missing from this package. Get a fresh copy." buttons {"Quit",
"Continue Anyway"} default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
if not fileexists(ePubTestTool) then
set dialogresult to (display dialog "The ePub encryption test script
(epubtesttool.py) is missing from this package. Get a fresh copy." buttons {"Quit",
"Continue Anyway"} default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
if not folderexists(ProgressApp) then
set dialogresult to (display dialog "The Progress dialog application
(DeDRM Progress.app) is missing from this package. Get a fresh copy." buttons
{"Quit", "Continue Anyway"} default button 1 with title "DeDRM" with icon stop)
if button returned of dialogresult is "Quit" then
return false
end if
end if
return true
end GetTools

on unlockmobifile(encryptedFile)
--check it's a mobi file.
set BOOKMOBI to "NOTAMOBI"
try
set BOOKMOBI to read file encryptedFile from 61 for 8
end try
if BOOKMOBI is not "BOOKMOBI" and BOOKMOBI is not "TEXtREAd" then
set TOPAZ to "NOT"
try
set TOPAZ to read file encryptedFile from 1 for 4
end try
if TOPAZ is not "TPZ0" then
set ErrorCount to ErrorCount + 1
set ErrorList to ErrorList & encryptedFile & " is neither a
Kindle not a Mobipocket file.
"
return
end if
end if
set encryptedFilePath to POSIX path of file encryptedFile
tell application "Finder"
set parent_folder to (container of file encryptedFile) as text
set fileName to (name of file encryptedFile) as text
end tell
set fileExtension to "." & GetFileExtension(fileName)
set fileName to GetFileNameOnly(fileName)
if outputFolder is "" or not folderexists(outputFolder) then
set dedrmFolder to POSIX path of file parent_folder
else
set dedrmFolder to POSIX path of file outputFolder
end if
set shellcommand to python & (quoted form of MobipocketTool)
repeat with KindleKeyPath in KindleKeyList
set shellcommand to shellcommand & " -k " & quoted form of
KindleKeyPath
end repeat
repeat with AndroidKeyPath in AndroidKeyList
set shellcommand to shellcommand & " -a " & quoted form of
AndroidKeyPath
end repeat
set Serialstring to GetSerialstring()
if Serialstring is not "" then set shellcommand to shellcommand & " -s " &
quoted form of Serialstring
set PIDstring to GetPIDstring()
if PIDstring is "" then
set PIDstring to GetUDIDPIDs()
else
set PIDstring to PIDstring & "," & GetUDIDPIDs()
end if

if PIDstring is not "" then set shellcommand to shellcommand & " -p " &
quoted form of PIDstring
set shellcommand to shellcommand & " " & (quoted form of encryptedFilePath) &
" " & (quoted form of dedrmFolder)
set shellcommand to shellcommand & " > " & quotedtemppath()
--display dialog "shellcommand: " default answer shellcommand buttons {"OK"}
default button 1 giving up after 10
writetolog("shellcommand: " & shellcommand)
cleartemp()
set DecodingError to false
set shellresult to ""
set ErrorText to ""
set decoded to true
try
do shell script shellcommand
on error ErrorText number errnum
set DecodingError to true
set decoded to false
end try
set shellresult to readtemp()
writetolog("shellresult: " & shellresult & " " & ErrorText)
if decoded then
set decoded to ((offset of "No key found" in shellresult) is 0)
end if
if not decoded then
DecodingError = true
set newKeyList to GetKindleKeys()
if length of newKeyList > 0 then
set shellcommand to python & (quoted form of MobipocketTool)
repeat with KindleKeyPath in newKeyList
set shellcommand to shellcommand & " -k " & quoted form of
KindleKeyPath
end repeat
set shellcommand to shellcommand & " " & (quoted form of
encryptedFilePath) & " " & (quoted form of dedrmFolder)
set shellcommand to shellcommand & " > " & quotedtemppath()
--display dialog "shellcommand: " default answer shellcommand
buttons {"OK"} default button 1 giving up after 10
writetolog("shellcommand: " & shellcommand)
cleartemp()
set DecodingError to false
set shellresult to ""
set ErrorText to ""
set decoded to true
try
do shell script shellcommand
on error ErrorText number errnum
set DecodingError to true
set decoded to false
end try
set shellresult to readtemp()
writetolog("shellresult: " & shellresult & " " & ErrorText)
if decoded then
set DecodingError to not ((offset of "No key found" in
shellresult) is 0)
end if
if not DecodingError then
set KindleKeyList to KindleKeyList & newKeyList
end if
end if
end if
if DecodingError then
set ErrorCount to ErrorCount + 1
set ErrorList to ErrorList & fileName & fileExtension & " couldn't be
decrypted.
"
else if (offset of "not encrypted" in shellresult) > 0 then
set WarningCount to WarningCount + 1
set WarningList to WarningList & fileName & fileExtension & " is not
encrypted.
"
else
set CompletedCount to CompletedCount + 1
set CompletedList to CompletedList & fileName & fileExtension & paraend
end if
end unlockmobifile

on unlockpdbfile(encryptedFile)
--check it's an eReader file.
set PNRdPPrs to "NOT_eREADER"
try
set PNRdPPrs to read file encryptedFile from 61 for 8
end try
if PNRdPPrs is not "PNRdPPrs" then
set ErrorCount to ErrorCount + 1
set ErrorList to ErrorList & encryptedFile & " is not an eReader file.
"
return
end if
set encryptedFilePath to POSIX path of file encryptedFile
tell application "Finder"
set parent_folder to (container of file encryptedFile) as text
set fileName to (name of file encryptedFile) as text
end tell
set fileExtension to "." & GetFileExtension(fileName)
set fileName to GetFileNameOnly(fileName)
if outputFolder is "" or not folderexists(outputFolder) then
set dedrmFolder to parent_folder
else
set dedrmFolder to outputFolder
end if
set pmlFile to dedrmFolder & fileName & "_Source:" & fileName & ".pml"
set clearFile to dedrmFolder & fileName & "_Source:" & fileName & ".pdb"
set clearFileNew to dedrmFolder & fileName & "_Source:" & fileName &
"_nodrm.pdb"
set clearFileNewName to fileName & "_nodrm.pdb"
set sourcePath to POSIX path of file dedrmFolder & fileName & "_Source/"
set pmlzFilePath to POSIX path of file dedrmFolder & fileName & "_nodrm.pmlz"
if length of GeteReaderKeystring() is 0 then
GeteReaderKeys("DeDRM Configure for eReader")
end if
set shellresult to "Error: No eReader keys supplied. Can't decrypt."
repeat with BNKey in bnKeys
set encryptionName to first item of BNKey
set encryptionNumber to second item of BNKey
if length of encryptionName > 0 and length of encryptionNumber > 0 then
set shellcommand to python & (quoted form of eReaderTool) & " " &
(quoted form of encryptedFilePath) & " " & (quoted form of sourcePath) & " " &
(quoted form of encryptionName) & " " & (quoted form of encryptionNumber)
set shellcommand to shellcommand & " > " & quotedtemppath()
--display dialog "shellcommand: " & shellcommand buttons {"OK"}
default button 1 giving up after 10
writetolog("shellcommand: " & shellcommand)
set shellresult to "no result"
cleartemp()
set DecodingError to false
set ErrorText to ""
try
do shell script shellcommand
on error ErrorText
set DecodingError to true
end try
set shellresult to readtemp()
writetolog("shellresult: " & shellresult & " " & ErrorText)
--display dialog shellresult
if not DecodingError then
-- try to run dropbook and move compiled book to same
folder as encrypted book
try
try
tell application "Finder" to set DropBook to
(application file id "PPDr") as string
on error
error "Couldn't find DropBook application"
end try
-- now also compile back up into pdb file using
DropBook if it's on this system
tell application DropBook to open file pmlFile
delay 1 -- probably don't need this, but just in
case.
tell application DropBook to quit -- DropBook will
quit only after the compilation has happened
try
tell application "Finder"
set name of file clearFile to
clearFileNewName
move clearFileNew to dedrmFolder
end tell
on error errmsg
error "DropBook failed to compile the source
folder into a pdb file."
end try
on error errmsg
set WarningCount to WarningCount + 1
set WarningList to (WarningList & fileName &
fileExtension & " couldn't be compiled back to pdb:
" & errmsg as text) & "
"
end try
-- try to compress source folder contensts to a pmlz file
for easy import into Calibre
try
set shellcommand to "cd " & quoted form of sourcePath
& "; zip -r " & quoted form of pmlzFilePath & " *"
--display dialog shellcommand
writetolog("shellcommand: " & shellcommand)
set zipshellresult to ""
set zipshellresult to do shell script shellcommand
writetolog("shellresult: " & zipshellresult)
--display dialog zipshellresult
tell application "Finder"
-- move source folder to the trash
move dedrmFolder & fileName & "_Source" to
trash
end tell
on error errmsg
set WarningCount to WarningCount + 1
set WarningList to (WarningList & fileName &
fileExtension & "source folder couldn't be compressed to pmlz:
" & errmsg as text) & "

"
end try
-- we've done the decrypting so exit the loop.
exit repeat
end if
end if
end repeat
try
if (offset of "incorrect eReader version 10" in shellresult) > 0 then
set WarningCount to WarningCount + 1
set WarningList to WarningList & fileName & fileExtension & " is
not encrypted.
"
else if DecodingError then
set ErrorCount to ErrorCount + 1
set ErrorList to (ErrorList & fileName & fileExtension & "
couldn't be decoded:
" & ErrorText as text) & "
"
else
set CompletedCount to CompletedCount + 1
set CompletedList to CompletedList & fileName & fileExtension &
paraend
end if
end try
end unlockpdbfile

on unlockepubfile(encryptedFile)
set encryptedFilePath to POSIX path of file encryptedFile
tell application "Finder"
set parent_folder to (container of file encryptedFile) as text
set fileName to (name of file encryptedFile) as text
end tell
set fileExtension to "." & GetFileExtension(fileName)
set fileName to GetFileNameOnly(fileName)

set decoded to false


-- first we must fix any possible zip problems with the epub
if outputFolder is "" or not folderexists(outputFolder) then
set fixedFilePath to POSIX path of file (parent_folder & fileName &
"_fixed" & fileExtension)
else
set fixedFilePath to POSIX path of file (outputFolder & fileName &
"_fixed" & fileExtension)
end if
set shellcommand to python & (quoted form of ZipFixTool) & " " & (quoted form
of encryptedFilePath) & " " & (quoted form of fixedFilePath)
set shellcommand to shellcommand & " > " & quotedtemppath()
writetolog("shellcommand: " & shellcommand)
cleartemp()
set ZipErrorText to ""
set ZipFixError to false
try
--display dialog "shellcommand: " default answer shellcommand buttons
{"OK"} default button 1 giving up after 10
do shell script shellcommand
on error errmsg
set ZipErrorText to errmsg
set ZipFixError to true
end try
set shellresult to readtemp()
writetolog("shellresult: " & shellresult & " " & ZipErrorText)
--display dialog shellresult

if ZipFixError then
set ErrorCount to ErrorCount + 1
set ErrorList to ((ErrorList & fileName & fileExtension & " had a
problem with ZipFix:
" & ZipErrorText as text) & "
")
return
end if

--check it's an ePub file.


set ePubSig to "NOT_ePub"
try
set ePubSig to read POSIX file fixedFilePath from 31 for 28
end try
--display dialog ePubSig
if ePubSig is not "mimetypeapplication/epub+zip" then
set ErrorCount to ErrorCount + 1
set ErrorList to ErrorList & encryptedFile & " is not an ePub file.
"
tell application "Finder"
move alias ((POSIX file fixedFilePath) as text) to trash
end tell
return
end if

if outputFolder is "" or not folderexists(outputFolder) then


set unlockedFilePath to POSIX path of file (parent_folder & fileName &
"_nodrm" & fileExtension)
else
set unlockedFilePath to POSIX path of file (outputFolder & fileName &
"_nodrm" & fileExtension)
end if
set shellresult to "no keys"
set ErrorText to ""

-- get encryption type


set TryBandNePub to true
set TryAdobeePub to true
set shellcommand to python & (quoted form of ePubTestTool) & " " & (quoted
form of fixedFilePath)
set shellcommand to shellcommand & " > " & quotedtemppath()
--display dialog "shellcommand: " & shellcommand buttons {"OK"} default
button 1 giving up after 10
writetolog("shellcommand: " & shellcommand)
cleartemp()
set TestError to false
set ErrorText to ""
try
do shell script shellcommand
on error ErrorText
set TestError to true
end try
set shellresult to readtemp()
writetolog("shellresult: " & shellresult & " " & ErrorText)
--display dialog shellresult
if not TestError then
if (offset of "B&N" in shellresult) > 0 then
set TryAdobeePub to false
else if (offset of "Adobe" in shellresult) > 0 then
set TryBandNePub to false
else if (offset of "Unencrypted" in shellresult) > 0 then
set TryAdobeePub to false
set TryBandNePub to false
end if
end if

-- first we'll try the Barnes & Noble keys


if TryBandNePub then
set decoded to decodebandnepub(fixedFilePath, unlockedFilePath, bnKeys)
if not decoded then
set newKeyList to GetNookKeys()
set decoded to decodebandnepub(fixedFilePath, unlockedFilePath,
newKeyList)
if decoded then
set bnKeys to bnKeys & newKeyList
end if
end if

end if

if (not decoded) and TryAdobeePub then


set decoded to decodeadobeepub(fixedFilePath, unlockedFilePath,
AdeptKeyList)
if not decoded then
set newKeyList to GetAdeptKeys()
set decoded to decodeadobeepub(fixedFilePath, unlockedFilePath,
newKeyList)
if decoded then
set AdeptKeyList to AdeptKeyList & newKeyList
end if
end if
end if

if decoded then
set CompletedCount to CompletedCount + 1
set CompletedList to CompletedList & fileName & fileExtension & paraend
else if not TryAdobeePub and not TryBandNePub then
set WarningCount to WarningCount + 1
set WarningList to (WarningList & fileName & " doesn't seem to be
encrypted.
")
else if shellresult is "no keys" then
set ErrorCount to ErrorCount + 1
set ErrorList to (ErrorList & fileName & fileExtension & " couldn't be
decoded: no keys.
")
else
set ErrorCount to ErrorCount + 1
set ErrorList to ((ErrorList & fileName & fileExtension & " couldn't be
decoded:
" & ErrorText as text) & "
")
end if

tell application "Finder"


move alias ((POSIX file fixedFilePath) as text) to trash
end tell
end unlockepubfile

on decodebandnepub(fixedFilePath, unlockedFilePath, keyList)


set decoded to false
repeat with BNKey in keyList
set keyfilepath to third item of BNKey
if length of keyfilepath > 0 then
set shellcommand to python & (quoted form of BNePubTool) & " " &
(quoted form of keyfilepath) & " " & (quoted form of fixedFilePath) & " " & (quoted
form of unlockedFilePath)
set shellcommand to shellcommand & " > " & quotedtemppath()
--display dialog "shellcommand: " & shellcommand buttons {"OK"}
default button 1 giving up after 10
writetolog("shellcommand: " & shellcommand)
cleartemp()
set DecodingError to false
set ErrorText to ""
try
do shell script shellcommand
on error ErrorText
set DecodingError to true
end try
set shellresult to readtemp()
writetolog("shellresult: " & shellresult & " " & ErrorText)
--display dialog shellresult
if not DecodingError then
set decoded to true
exit repeat
end if
end if
end repeat
return decoded
end decodebandnepub

on decodeadobeepub(fixedFilePath, unlockedFilePath, keyList)


set decoded to false
repeat with AdeptKey in keyList
set shellcommand to python & (quoted form of AdobeePubTool) & " " &
(quoted form of AdeptKey) & " " & (quoted form of fixedFilePath) & " " & (quoted
form of unlockedFilePath)
set shellcommand to shellcommand & " > " & quotedtemppath()
--display dialog "shellcommand: " default answer shellcommand buttons
{"OK"} default button 1 giving up after 10
writetolog("shellcommand: " & shellcommand)
cleartemp()
set DecodingError to false
set ErrorText to ""
try
do shell script shellcommand
on error ErrorText
set DecodingError to true
end try
set shellresult to readtemp() as text
writetolog("shellresult: " & shellresult & " " & ErrorText)
--display dialog shellresult
if not DecodingError then
set decoded to true
exit repeat
end if
end repeat
return decoded
end decodeadobeepub

on unlockpdffile(encryptedFile)
--check it's an ePub file.
set PDFSig to "NOT_PDF"
try
set PDFSig to read file encryptedFile from 1 for 4
end try
--display dialog PDFSig
if PDFSig is not "%PDF" then
set ErrorCount to ErrorCount + 1
set ErrorList to ErrorList & encryptedFile & " is not a PDF file.
"
return
end if
set encryptedFilePath to POSIX path of file encryptedFile
tell application "Finder"
set parent_folder to (container of file encryptedFile) as text
set fileName to (name of file encryptedFile) as text
end tell
set fileExtension to "." & GetFileExtension(fileName)
set fileName to GetFileNameOnly(fileName)

set decoded to "NO"


-- first we must check we have a PDF script
if not fileexists(AdobePDFTool) then
set ErrorCount to ErrorCount + 1
set ErrorList to ErrorList & encryptedFile & " is a PDF file and no
ineptpdf script found.
"
return
end if

if outputFolder is "" or not folderexists(outputFolder) then


set unlockedFilePath to POSIX path of file (parent_folder & fileName &
"_nodrm" & fileExtension)
else
set unlockedFilePath to POSIX path of file (outputFolder & fileName &
"_nodrm" & fileExtension)
end if
set decoded to false
set shellresult to "no keys"
set ErrorText to ""

repeat with AdeptKey in AdeptKeyList


set shellcommand to python & (quoted form of AdobePDFTool) & " " &
(quoted form of AdeptKey) & " " & (quoted form of encryptedFilePath) & " " &
(quoted form of unlockedFilePath)
set shellcommand to shellcommand & " > " & quotedtemppath()
--display dialog "shellcommand: " default answer shellcommand buttons
{"OK"} default button 1 giving up after 10
writetolog("shellcommand: " & shellcommand)
cleartemp()
set DecodingError to false
set ErrorText to ""
try
do shell script shellcommand
on error ErrorText
set DecodingError to true
end try
set shellresult to readtemp()
writetolog("shellresult: " & shellresult & " " & ErrorText)
--display dialog shellresult
if not DecodingError then
set decoded to true
exit repeat
end if
end repeat

if decoded then
set CompletedCount to CompletedCount + 1
set CompletedList to CompletedList & fileName & fileExtension & paraend
else if shellresult is "no keys" then
set ErrorCount to ErrorCount + 1
set ErrorList to (ErrorList & fileName & fileExtension & " couldn't be
decoded: no keys.
")
else
set ErrorCount to ErrorCount + 1
set ErrorList to ((ErrorList & fileName & fileExtension & " couldn't be
decoded:
" & ErrorText as text) & "
")
end if
end unlockpdffile

on handlefile(droppedFile)
tell application "Finder"
set fileName to (name of file droppedFile) as text
end tell
writetolog("Processing file: " & fileName)
set fileExtension to GetFileExtension(fileName)
set fileName to GetFileNameOnly(fileName)
if fileExtension is "prc" or fileExtension is "mobi" or fileExtension is
"pobi" or fileExtension is "azw" or fileExtension is "azw1" or fileExtension is
"tpz" or fileExtension is "azw3" or fileExtension is "azw4" then
set completedebooks to completedebooks + 1
IncProgress(fileName, completedebooks)
unlockmobifile(droppedFile as text)
else if fileExtension is "pdb" then
set completedebooks to completedebooks + 1
IncProgress(fileName, completedebooks)
unlockpdbfile(droppedFile as text)
else if fileExtension is "epub" then
set completedebooks to completedebooks + 1
IncProgress(fileName, completedebooks)
unlockepubfile(droppedFile as text)
else if fileExtension is "pdf" then
set completedebooks to completedebooks + 1
IncProgress(fileName, completedebooks)
unlockpdffile(droppedFile as text)
end if
end handlefile

on handlefolder(droppedFolder)
tell application "Finder" to set fileList to (every file in folder
droppedFolder)
tell application "Finder" to set folderList to (every folder in folder
droppedFolder)
repeat with this_item in fileList
if not ProgressActive() then
exit repeat
end if
handlefile(this_item as text)
end repeat
repeat with this_item in folderList
if not ProgressActive() then
exit repeat
end if
handlefolder(this_item as text)
end repeat
end handlefolder

on countfile(droppedFile)
tell application "Finder"
set fileName to (name of file droppedFile) as text
end tell
set fileExtension to GetFileExtension(fileName)
set fileName to GetFileNameOnly(fileName)
--display dialog "fileName: " & fileName & "
--extension: " & fileExtension
if fileExtension is in handledExtensions then
set totalebooks to totalebooks + 1
end if
end countfile

on GetSerialstring()
set Serialstring to ""
repeat with Serial in KindleSerialList
if Serialstring is "" then
set Serialstring to Serial
else
set Serialstring to Serialstring & "," & Serial
end if
end repeat
return Serialstring
end GetSerialstring

on GetPIDstring()
set PIDstring to ""
repeat with PID in PIDs
if PIDstring is "" then
set PIDstring to PID
else
set PIDstring to PIDstring & "," & PID
end if
end repeat
return PIDstring
end GetPIDstring

on GetUDIDstring()
set UDIDstring to ""
repeat with UDIDPair in UDIDs
if UDIDstring is "" then
set UDIDstring to first item of UDIDPair
else
set UDIDstring to UDIDstring & "," & first item of UDIDPair
end if
end repeat
return UDIDstring
end GetUDIDstring

on GetUDIDPIDs()
set UDIDPIDs to ""
repeat with UDIDPair in UDIDs
if UDIDPIDs is "" then
set UDIDPIDs to second item of UDIDPair
else
set UDIDPIDs to UDIDPIDs & "," & second item of UDIDPair
end if
end repeat
return UDIDPIDs
end GetUDIDPIDs

on GetAdeptstring()
set Adeptstring to ""
repeat with AdeptKeyFile in AdeptKeyList
set AppleTypeFile to POSIX file (AdeptKeyFile as text)
tell application "Finder"
set fileName to name of file (AppleTypeFile as text)
end tell

if Adeptstring is "" then


set Adeptstring to fileName
else
set Adeptstring to Adeptstring & "
" & fileName
end if
end repeat
return Adeptstring
end GetAdeptstring

on GetAndroidstring()
set Androidstring to ""
repeat with AndroidKeyFile in AndroidKeyList
set AppleTypeFile to POSIX file (AndroidKeyFile as text)
tell application "Finder"
set fileName to name of file (AppleTypeFile as text)
end tell
if Androidstring is "" then
set Androidstring to fileName
else
set Androidstring to Androidstring & "
" & fileName
end if
end repeat
return Androidstring
end GetAndroidstring

on GetKindlestring()
set Kindlestring to ""
repeat with KindleKeyFile in KindleKeyList
set AppleTypeFile to POSIX file (KindleKeyFile as text)
tell application "Finder"
set fileName to name of file (AppleTypeFile as text)
end tell

if Kindlestring is "" then


set Kindlestring to fileName
else
set Kindlestring to Kindlestring & "
" & fileName
end if
end repeat
return Kindlestring
end GetKindlestring

on GeteReaderKeystring()
set Keystring to ""
repeat with key in bnKeys
if length of first item of key > 0 and length of second item of key > 0
then
if Keystring is "" then
set Keystring to first item of key & ":" & second item of
key
else
set Keystring to Keystring & "
" & first item of key & ":" & second item of key
end if
end if
end repeat
return Keystring
end GeteReaderKeystring

on GetBNKeystring()
set BNKeystring to ""
repeat with BNKey in bnKeys
if (length of BNKey > 2) and ((length of (third item of BNKey)) > 0)
then
if BNKeystring is "" then
set BNKeystring to first item of BNKey
else
set BNKeystring to BNKeystring & "
" & first item of BNKey
end if
end if
end repeat
return BNKeystring
end GetBNKeystring

on DeleteeReaderKeys()
set newKeys to {}
repeat with BNKey in bnKeys
if length of third item of BNKey > 0 then

set newKeys to newKeys & {{first item of BNKey, "", third item of
BNKey}}
end if
end repeat
set bnKeys to newKeys
end DeleteeReaderKeys

on DeleteBNKeys()
set newKeys to {}
repeat with BNKey in bnKeys
if length of second item of BNKey > 0 then

set newKeys to newKeys & {{first item of BNKey, second item of


BNKey, ""}}
end if
end repeat
set bnKeys to newKeys
end DeleteBNKeys

on GetUDIDs(DialogTitle)
set UDID to ""
repeat
set UDIDstring to GetUDIDstring()
if UDIDstring is "" then
set DialogPrompt to "Enter any iPod/iPhone/iPad UDIDs (40
characters) one at a time. Note: This only works for older versions of Kindle for
iOS."
set FinishedButton to "Close"
else
set DialogPrompt to "Current UDIDs: " & UDIDstring & ".

Enter any additional iPod/iPhone/iPad UDIDs (40 characters) one at a time:"


set FinishedButton to "Close"
end if
set dialogresult to (display dialog DialogPrompt default answer UDID
buttons {"Delete All", "Add", FinishedButton} with title DialogTitle default button
2)
if button returned of dialogresult is "Add" then
set UDID to text returned of dialogresult
set UDIDlength to length of UDID
if UDIDlength is 40 then
set shellresult to ""
set scriptError to ""
set shellcommand to python & (quoted form of KindlePIDTool)
& " " & (quoted form of UDID)
writetolog("shellcommand: " & shellcommand)
try
set shellresult to do shell script shellcommand
on error errmsg
set shellresult to ""
set scriptError to "KindlePID Script failed:" & " " &
errmsg
end try
writetolog("shellresult: " & scriptError & " " &
shellresult)
--display dialog shellresult

if shellresult is not "" then


set PID to (text -10 thru -1 of shellresult)
if UDIDs contains {{UDID, PID}} then
display dialog "UDID " & UDID & " is already in
your list of UDIDs." buttons {"OK"} default button 1 with title "DeDRM" with icon
caution
else
display dialog "The equivalent UDID for UDID "
& UDID & " is " & PID & ". Adding to list." buttons {"OK"} default button 1 with
title "DeDRM" with icon note
set UDIDs to UDIDs & {{UDID, PID}}
set UDID to ""
end if
else
writetolog(scriptError)
display dialog "Error generating PID from this UDID,
error message was: " & scriptError buttons {"OK"} default button 1 with title
"DeDRM" with icon caution
end if
else
display dialog "UDIDs must be 40 characters." buttons
{"OK"} default button 1 with title "DeDRM" with icon caution
end if
else if button returned of dialogresult is "Delete All" then
if UDIDstring is not "" then
try
set dialogresult to (display dialog "Are you sure you
want to delete all stored UDIDs?" buttons {"Cancel", "Delete"} default button 1
with title "DeDRM")
end try
if button returned of dialogresult is "Delete" then
set UDIDs to {}
end if
end if
else
set UDID to text returned of dialogresult
if UDID is not "" then
try
set dialogresult to (display dialog "You entered some
text, but didn't click Add. Are you sure you want to more on to the next dialog?"
buttons {"Whoops", "Yes, Move on"} default button 1 with title "DeDRM")
end try
if button returned of dialogresult is "Yes, Move on" then
exit repeat
end if
else
exit repeat
end if
end if
end repeat
end GetUDIDs
on GetPIDs(DialogTitle)
set PID to ""
repeat
set PIDstring to GetPIDstring()
if PIDstring is "" then
set DialogPrompt to "Enter any Mobipocket PIDs one at a time:"
set FinishedButton to "Close"
else
set DialogPrompt to "Current PIDs: " & PIDstring & ".

Enter any additional Mobipocket PIDs one at a time:"


set FinishedButton to "Close"
end if
set dialogresult to (display dialog DialogPrompt default answer PID
buttons {"Delete All", "Add", FinishedButton} with title DialogTitle default button
2)
if button returned of dialogresult is "Add" then
set PID to text returned of dialogresult
set PIDlength to length of PID
if PIDlength is 8 or PIDlength is 10 then
if PIDs contains PID then
display dialog "PID" & PID & " is already in your
list of PIDs." buttons {"OK"} default button 1 with title "DeDRM" with icon caution
else
set PIDs to PIDs & PID
set PID to ""
end if
else
display dialog "PIDs must be 8 or 10 characters long, and
UDIDs must be 40 characters." buttons {"OK"} default button 1 with title "DeDRM"
with icon caution
end if
else if button returned of dialogresult is "Delete All" then
if PIDstring is not "" then
try
set dialogresult to (display dialog "Are you sure you
want to delete all stored PIDs?" buttons {"Cancel", "Delete"} default button 1 with
title "DeDRM")
end try
if button returned of dialogresult is "Delete" then
set PIDs to {}
end if
end if
else
set PID to text returned of dialogresult
if PID is not "" then
try
set dialogresult to (display dialog "You entered some
text, but didn't click Add. Are you sure you want to more on to the next dialog?"
buttons {"Whoops", "Yes, Move on"} default button 1 with title "DeDRM")
end try
if button returned of dialogresult is "Yes, Move on" then
exit repeat
end if
else
exit repeat
end if
end if
end repeat
end GetPIDs

on GetSerials(DialogTitle)
set Serial to ""
repeat
set Serialstring to GetSerialstring()
if Serialstring is "" then
set DialogPrompt to "Enter any Kindle (not Kindle Fire) Serial
Numbers one at a time:"
set FinishedButton to "Close"
else
set DialogPrompt to "Current Kindle Serial Numbers: " &
Serialstring & ".

Enter any additional Kindle (not Kindle Fire) Serial Numbers one at a time:"
set FinishedButton to "Close"
end if
set dialogresult to (display dialog DialogPrompt default answer Serial
buttons {"Delete All", "Add", FinishedButton} with title DialogTitle default button
2)
if button returned of dialogresult is "Add" then
set Serial to text returned of dialogresult
set Seriallength to length of Serial
if Seriallength is 16 then
set KindleSerialList to KindleSerialList & Serial
set Serial to ""
else
display dialog "Kindle Serial Numbers are 16 characters
long." buttons {"OK"} default button 1 with title "DeDRM" with icon caution
end if
else if button returned of dialogresult is "Delete All" then
if Serialstring is not "" then
try
set dialogresult to (display dialog "Are you sure you
want to delete all stored Kindle Serial Numbers?" buttons {"Cancel", "Delete"}
default button 1 with title "DeDRM")
end try
if button returned of dialogresult is "Delete" then
set KindleSerialList to {}
end if
end if
else
set Serial to text returned of dialogresult
if Serial is not "" then
try
set dialogresult to (display dialog "You entered some
text, but didn't click Add. Are you sure you want to more on to the next dialog?"
buttons {"Whoops", "Yes, Move on"} default button 1 with title "DeDRM")
end try
if button returned of dialogresult is "Yes, Move on" then
exit repeat
end if
else
exit repeat
end if
end if
end repeat
end GetSerials
on GetOutputFolder(DialogTitle)
set newFolder to ""
try
tell me to activate
repeat

if folderexists(outputFolder) then
set DialogPrompt to "The deDRMed ebooks will be saved to
the following folder:
" & (outputFolder) & "

"
else
set outputFolder to ""
set DialogPrompt to "The deDRMed ebooks will be saved in
the same folder as the original DRMed ebooks.

"
end if
set DialogPrompt to DialogPrompt & "To keep this choice, click
'Close', otherwise select the option you want by clicking on one of the other
buttons."
set dialogresult to (display dialog DialogPrompt buttons {"Use
Same Folder as DRMed Ebooks", "Choose Output Folder…", "Close"} with title
DialogTitle default button 3)
if button returned of dialogresult is "Choose Output Folder…"
then
try
if outputFolder is "" then
set outputFolder to ((choose folder with prompt
"DRM Application
Please choose the Output Folder for DeDRMed ebooks.") as text)
else
set outputFolder to ((choose folder with prompt
"DRM Application
Please choose the Output Folder for DeDRMed ebooks." default location alias
outputFolder) as text)
end if
end try
else if button returned of dialogresult is "Use Same Folder as
DRMed Ebooks" then
set outputFolder to ""
else
exit repeat
end if
--on error errormessage
-- display dialog errormessage
end repeat
end try
WritePrefs()
end GetOutputFolder

on GeteReaderKeys(DialogTitle)
set keyText to ""
repeat
set Keystring to GeteReaderKeystring()
if Keystring is "" then
set DialogPrompt to "Please enter any "
set FinishedButton to "Close"
else
set DialogPrompt to "eReader keys:
" & Keystring & "

Please enter any additional "


set FinishedButton to "Close"
end if
set DialogPrompt to DialogPrompt & "eReader Name,Number key pairs one
at a time. The name is usually your name as on your credit card, but might be your
user name. Only the last 8 digits of the Number are needed. If you enter more
digits, only the last eight will be stored or displayed. Please separate the name
and number with a colon (:) and click \"Add\"."
set dialogresult to (display dialog DialogPrompt default answer keyText
with title DialogTitle buttons {"Delete All", "Add", FinishedButton} default button
2)
if button returned of dialogresult is "Add" then
set keyText to text returned of dialogresult
if not (keyText contains ":") then
display dialog "Name and Number must be separated by a
colon (:)." buttons {"OK"} default button 1 with title "DeDRM" with icon caution
else
set oldTIDs to AppleScript's text item delimiters
set AppleScript's text item delimiters to ":"
set keyNumber to the last text item of keyText
set keyName to (text items 1 through -2 of keyText) as
string
set AppleScript's text item delimiters to oldTIDs

if ((length of keyNumber) = 16 or (length of keyNumber) =


15 or (length of keyNumber) = 8) and (length of keyName) > 0 then
set bnKeys to bnKeys & {{keyName, (text -8 thru -1 of
keyNumber), ""}}
set keyText to ""
else
display dialog "Key numbers must be 8 or 15 or 16
characters long (no spaces) and the key name must not be absent." buttons {"OK"}
default button 1 with title "DeDRM" with icon caution
end if
end if
else if button returned of dialogresult is "Delete All" then
if Keystring is not "" then
try
set dialogresult to (display dialog "Are you sure you
want to delete all stored Name:Number key pairs?" buttons {"Cancel", "Delete"}
default button 1 with title "DeDRM")
end try
if button returned of dialogresult is "Delete" then
DeleteeReaderKeys()
GetNookKey()
end if
end if
set keyText to ""
else
set keyText to text returned of dialogresult
if keyText is not "" then
try
set dialogresult to (display dialog "You entered some
text, but didn't click Add. Are you sure you want to more on to the next dialog?"
buttons {"Whoops", "Yes, Move on"} default button 1 with title "DeDRM")
end try
if button returned of dialogresult is "Yes, Move on" then
exit repeat
end if
else
exit repeat
end if
end if
end repeat
end GeteReaderKeys

on GetBNKeys(DialogTitle)
set bnKeyText to ""
repeat
set BNKeystring to GetBNKeystring()
if BNKeystring is "" then
set DialogPrompt to "Please enter any "
set FinishedButton to "Close"
else
set DialogPrompt to "Current B&N/Nook keys:
" & BNKeystring & "

Please enter any additional "


set FinishedButton to "Close"
end if
set DialogPrompt to DialogPrompt & "Barnes & Noble/Nook account email
addresses and passwords one at a time. Please separate the address and password
with a colon (:)and click \"Add\". Note that your account password will only be
used to retrieve the key and will not be stored.

*** Retrieving the account key may take a couple of minutes, please be patient. ***

Or to add a an already generated .b64 file, just click \"Add\" with nothing in the
text field."
set dialogresult to (display dialog DialogPrompt default answer
bnKeyText with title DialogTitle buttons {"Forget All", "Add", FinishedButton}
default button 2)
if button returned of dialogresult is "Add" then
set bnKeyText to text returned of dialogresult
if bnKeyText is "" then
try
set newFile to (choose file with prompt "Please
select a Barnes & Noble (.b64) key file") as text
-- copy to prefs
AddbnKey(newFile)
on error message
if message does not contain "cancel" then
display dialog message
end if
end try
else if not (bnKeyText contains ":") then
display dialog "Email address and password must be
separated by a colon (:)." buttons {"OK"} default button 1 with title "DeDRM" with
icon caution
else
set oldTIDs to AppleScript's text item delimiters
set AppleScript's text item delimiters to ":"
set keyEmail to the first text item of bnKeyText
set keyPassword to (text items 2 through -1 of bnKeyText)
as string
set AppleScript's text item delimiters to oldTIDs

if (keyEmail contains "@") and (length of keyPassword) > 0


then
-- get the B&N key from this pair
set shellresult to ""
set scriptError to ""
set success to true
set prefsFolder to (path to preferences from user
domain as string) & prefsFolderName & ":"
set keyfileName to GetUniqueName(prefsFolder,
keyEmail & ".b64")
set keyfilepath to POSIX path of (prefsFolder &
keyfileName)
set shellcommand to python & (quoted form of
BNKeyFetchTool) & " " & (quoted form of keyEmail) & " " & (quoted form of
keyPassword) & " " & quoted form of keyfilepath
set shellcommand to shellcommand & " > " &
quotedtemppath()

writetolog("shellcommand: " & shellcommand)


cleartemp()
try
do shell script shellcommand
on error scriptError
set success to false
end try
set shellresult to readtemp()
writetolog("shellresult: " & scriptError & " " &
shellresult)
--display dialog shellresult
if success then
set bnKeys to bnKeys & {{keyEmail, "",
keyfilepath}}
set bnKeyText to ""
else
display dialog "Error generating key from this
info, error message was: " & scriptError buttons {"OK"} default button 1 with title
"DeDRM" with icon caution
end if
else
display dialog "Key numbers must be 8 or 15 or 16
characters long (no spaces) and the key name must not be absent." buttons {"OK"}
default button 1 with title "DeDRM" with icon caution
end if
end if
else if button returned of dialogresult is "Forget All" then
if BNKeystring is not "" then
try
set dialogresult to (display dialog "Are you sure you
want to forget all stored Barnes & Noble/Nook keys?" buttons {"Cancel", "Forget"}
default button 1 with title "DeDRM")
end try
if button returned of dialogresult is "Forget" then
DeleteBNKeys()
end if
end if
set bnKeyText to ""
else
set bnKeyText to text returned of dialogresult
if bnKeyText is not "" then
try
set dialogresult to (display dialog "You entered some
text, but didn't click Add. Are you sure you want to more on to the next dialog?"
buttons {"Whoops", "Yes, Move on"} default button 1 with title "DeDRM")
end try
if button returned of dialogresult is "Yes, Move on" then
exit repeat
end if
else
exit repeat
end if
end if
end repeat
end GetBNKeys

on GetAdeptKeyFiles(DialogTitle)
repeat
set Adeptstring to GetAdeptstring()
if Adeptstring is "" then
set DialogPrompt to "To add Adobe Digital Editions (Adept) key
files, click the Add… button. "
set dialogresult to (display dialog DialogPrompt buttons {"Add…",
"Close"} with title DialogTitle default button 1)
else
set DialogPrompt to "Current Adobe Digital Editions (Adept) key
files:
" & Adeptstring & "

To add extra key files (.der), click the Add… button."


set dialogresult to (display dialog DialogPrompt buttons {"Forget
All", "Add…", "Close"} with title DialogTitle default button 2)
end if
if button returned of dialogresult is "Add…" then
try
set newFile to (choose file with prompt "Please select an
Adobe Digital Editions (.der) key file") as text
-- copy to prefs
AddAdeptKey(newFile)
on error message
if message does not contain "cancel" then
display dialog message
end if
end try

else if button returned of dialogresult is "Forget All" then


try
set dialogresult to (display dialog "Are you sure you want
to forget all extra Adobe Digital Editions Adept key files?" buttons {"Cancel",
"Forget"} default button 1 with title "DeDRM")
end try
if button returned of dialogresult is "Forget" then
set AdeptKeyList to {}
end if
else
exit repeat
end if
end repeat
end GetAdeptKeyFiles

on GetKindleKeyFiles(DialogTitle)
repeat
set Kindlestring to GetKindlestring()
if Kindlestring is "" then
set DialogPrompt to "To add Kindle for Mac key files (.k4i),
click the Add… button. "
set FinishedButton to "Close"
else
set DialogPrompt to "Current Kindle for Mac key files:
" & Kindlestring & "

To add extra key files (.k4i), click the Add… button."


set FinishedButton to "Close"
end if
set dialogresult to (display dialog DialogPrompt buttons {"Forget All",
"Add…", FinishedButton} with title DialogTitle default button 2)
if button returned of dialogresult is "Add…" then
try
set newFile to (choose file with prompt "Please select a
Kindle for Mac/PC (.k4i) key file") as text
-- copy to prefs
AddKindleKey(newFile)
on error message
if message does not contain "cancel" then
display dialog message
end if
end try

else if button returned of dialogresult is "Forget All" then


if Kindlestring is not "" then
try
set dialogresult to (display dialog "Are you sure you
want to forget all extra Kindle for Mac key files?" buttons {"Cancel", "Forget"}
default button 1 with title "DeDRM")
end try
if button returned of dialogresult is "Forget" then
set KindleKeyList to {}
end if
end if
else
exit repeat
end if
end repeat
end GetKindleKeyFiles

on GetAndroidKeyFiles(DialogTitle)
repeat
set Androidstring to GetAndroidstring()
if Androidstring is "" then
set DialogPrompt to "To add Kindle for Android backup files
(.ab), click the Add… button. "
set FinishedButton to "Close"
else
set DialogPrompt to "Current Kindle for Android backup files:
" & Androidstring & "

To add extra backup files (.ab), click the Add… button."


set FinishedButton to "Close"
end if
set dialogresult to (display dialog DialogPrompt buttons {"Forget All",
"Add…", FinishedButton} with title DialogTitle default button 2)
if button returned of dialogresult is "Add…" then
try
set newFile to (choose file with prompt "Please select a
Kindle for Android backup (.ab) file") as text
-- copy to prefs
AddAndroidKey(newFile)
on error message
if message does not contain "cancel" then
display dialog message
end if
end try

else if button returned of dialogresult is "Forget All" then


if Androidstring is not "" then
try
set dialogresult to (display dialog "Are you sure you
want to forget all Kindle for Android backup files?" buttons {"Cancel", "Forget"}
default button 1 with title "DeDRM")
end try
if button returned of dialogresult is "Forget" then
set AndroidKeyList to {}
end if
end if
else
exit repeat
end if
end repeat
end GetAndroidKeyFiles

on GetAdeptKeys()
set newKeyList to {}
set userPrefsPath to path to preferences from user domain as string
set preferencesFolderPath to userPrefsPath & prefsFolderName & ":"
if not folderexists(preferencesFolderPath) then
tell application "Finder"
set preferencesFolder to make new folder at userPrefsPath with
properties {name:prefsFolderName}
end tell
end if
set newKeysFolderPath to preferencesFolderPath & newKeysFolderName & ":"
if not folderexists(newKeysFolderPath) then
tell application "Finder"
set newKeysFolder to make new folder at preferencesFolderPath
with properties {name:newKeysFolderName}
end tell
end if
set scriptError to ""
set shellresult to ""
set success to true
set shellcommand to python & (quoted form of AdobeKeyGenTool) & " " & quoted
form of (POSIX path of (newKeysFolderPath))
set shellcommand to shellcommand & " > " & quotedtemppath()
writetolog("shellcommand: " & shellcommand)
cleartemp()
try
do shell script shellcommand
on error scriptError
set success to false
end try
set shellresult to readtemp()
writetolog("shellresult: " & shellresult & " " & scriptError)
--display dialog shellresult
if success then
--get all the files from newKeysFolder and add those that aren't
duplicates
tell application "Finder" to set fileList to (every file in folder
newKeysFolderPath)
repeat with this_item in fileList
set userAdeptKeyPath to this_item as text
set dupfile to false
repeat with AdeptKey in AdeptKeyList
set shellcommand to "cmp -s " & (quoted form of AdeptKey) &
" " & quoted form of (POSIX path of (userAdeptKeyPath))
try
--writetolog("shellcommand: " & shellcommand)
do shell script shellcommand
-- shellcommand will error on the files being
different
--writetolog("result: duplicate")

set dupfile to true


exit repeat
on error scriptError
--writetolog("result: different")
-- do nothing
end try
end repeat
if not dupfile then
repeat with AdeptKey in newKeyList
set shellcommand to "cmp -s " & (quoted form of
AdeptKey) & " " & quoted form of (POSIX path of (userAdeptKeyPath))
try
--writetolog("shellcommand: " & shellcommand)
do shell script shellcommand
-- shellcommand will error on the files being
different
--writetolog("result: duplicate")

set dupfile to true


exit repeat
on error scriptError
--writetolog("result: different")
-- do nothing
end try
end repeat
end if
if not dupfile then
-- move to the preferences folder, making sure the name's
unique
set newFilename to GetUniqueName(preferencesFolderPath,
"AdobeKey.der")
tell application "Finder"
set name of file userAdeptKeyPath to newFilename
set userAdeptKeyPath to newKeysFolderPath &
newFilename
move file userAdeptKeyPath to preferencesFolderPath
with replacing
end tell
set newKeyList to newKeyList & (POSIX path of
(preferencesFolderPath & newFilename))
end if
end repeat
end if
-- delete new keys folder
tell application "Finder" to move newKeysFolderPath to trash
--display dialog newKeyList as text
return newKeyList
end GetAdeptKeys

on GetKindleKeys()
set newKeyList to {}
set userPrefsPath to path to preferences from user domain as string
set preferencesFolderPath to userPrefsPath & prefsFolderName & ":"
if not folderexists(preferencesFolderPath) then
tell application "Finder"
set preferencesFolder to make new folder at userPrefsPath with
properties {name:prefsFolderName}
end tell
end if
set newKeysFolderPath to preferencesFolderPath & newKeysFolderName & ":"
if not folderexists(newKeysFolderPath) then
tell application "Finder"
set newKeysFolder to make new folder at preferencesFolderPath
with properties {name:newKeysFolderName}
end tell
end if
set scriptError to ""
set shellresult to ""
set success to true
set shellcommand to python & (quoted form of KindleKeyTool) & " " & quoted
form of (POSIX path of (newKeysFolderPath))
set shellcommand to shellcommand & " > " & quotedtemppath()
writetolog("shellcommand: " & shellcommand)
cleartemp()
try
do shell script shellcommand
on error scriptError
set success to false
end try
set shellresult to readtemp()
writetolog("shellresult: " & shellresult & " " & scriptError)
--display dialog shellresult
if success then
--get all the files from newKeysFolder and add those that aren't
duplicates
tell application "Finder" to set fileList to (every file in folder
newKeysFolderPath)
repeat with this_item in fileList
set userKeyPath to this_item as text
set dupfile to false
repeat with key in KindleKeyList
set shellcommand to "cmp -s " & (quoted form of key) & " "
& quoted form of (POSIX path of (userKeyPath))
try
--writetolog("shellcommand: " & shellcommand)
do shell script shellcommand
-- shellcommand will error on the files being
different
--writetolog("result: duplicate")

set dupfile to true


exit repeat
on error scriptError
--writetolog("result: different")
-- do nothing
end try
end repeat
if not dupfile then
repeat with key in newKeyList
set shellcommand to "cmp -s " & (quoted form of key)
& " " & quoted form of (POSIX path of (userKeyPath))
try
--writetolog("shellcommand: " & shellcommand)
do shell script shellcommand
-- shellcommand will error on the files being
different
--writetolog("result: duplicate")

set dupfile to true


exit repeat
on error scriptError
--writetolog("result: different")
-- do nothing
end try
end repeat
end if
if not dupfile then
-- move to the preferences folder, making sure the name's
unique
set newFilename to GetUniqueName(preferencesFolderPath,
"KindleKey.der")
tell application "Finder"
set name of file userKeyPath to newFilename
set userKeyPath to newKeysFolderPath & newFilename
move file userKeyPath to preferencesFolderPath with
replacing
end tell
set newKeyList to newKeyList & (POSIX path of
(preferencesFolderPath & newFilename))
end if
end repeat
end if
-- delete new keys folder
tell application "Finder" to move newKeysFolderPath to trash
return newKeyList
end GetKindleKeys

on GetNookKeys()
set newKeyList to {}
set userPrefsPath to path to preferences from user domain as string
set preferencesFolderPath to userPrefsPath & prefsFolderName & ":"
if not folderexists(preferencesFolderPath) then
tell application "Finder"
set preferencesFolder to make new folder at userPrefsPath with
properties {name:prefsFolderName}
end tell
end if
set newKeysFolderPath to preferencesFolderPath & newKeysFolderName & ":"
if not folderexists(newKeysFolderPath) then
tell application "Finder"
set newKeysFolder to make new folder at preferencesFolderPath
with properties {name:newKeysFolderName}
end tell
end if
set scriptError to ""
set shellresult to ""
set success to true
set shellcommand to python & (quoted form of NookKeyTool) & " " & quoted form
of (POSIX path of (newKeysFolderPath))
set shellcommand to shellcommand & " > " & quotedtemppath()
writetolog("shellcommand: " & shellcommand)
cleartemp()
try
do shell script shellcommand
on error scriptError
set success to false
end try
set shellresult to readtemp()
writetolog("shellresult: " & shellresult & " " & scriptError)
--display dialog shellresult
if success then
--get all the files from newKeysFolder and add those that aren't
duplicates
tell application "Finder" to set fileList to (every file in folder
newKeysFolderPath)
--display dialog (count of fileList)
repeat with this_item in fileList
set userKeyPath to this_item as text
set dupfile to false
repeat with key in bnKeys
set keyfilepath to third item of key
if length of keyfilepath > 0 then
set shellcommand to "cmp -s " & (quoted form of
keyfilepath) & " " & quoted form of (POSIX path of (userKeyPath))
try
--writetolog("shellcommand: " & shellcommand)
do shell script shellcommand
-- shellcommand will error on the files being
different
--writetolog("result: duplicate")
--display dialog "Deuplicate: " & userKeyPath &
"//" & keyfilepath
set dupfile to true
exit repeat
on error scriptError
--writetolog("result: different")
-- do nothing
end try
end if
end repeat
if not dupfile then
repeat with key in newKeyList
set keyfilepath to third item of key
if length of keyfilepath > 0 then
set shellcommand to "cmp -s " & (quoted form of
keyfilepath) & " " & quoted form of (POSIX path of (userKeyPath))
try
--writetolog("shellcommand: " &
shellcommand)
do shell script shellcommand
-- shellcommand will error on the files
being different
--writetolog("result: duplicate")
--display dialog "Deuplicate: " &
userKeyPath & "//" & keyfilepath
set dupfile to true
exit repeat
on error scriptError
--writetolog("result: different")
-- do nothing
end try
end if
end repeat
end if
if not dupfile then
-- move to the preferences folder, making sure the name's
unique
set newFilename to GetUniqueName(preferencesFolderPath,
"Nook Study Key.b64")
tell application "Finder"
set name of file userKeyPath to newFilename
set userKeyPath to newKeysFolderPath & newFilename
move file userKeyPath to preferencesFolderPath with
replacing
end tell
set newKeyList to newKeyList & {{newFilename, "", (POSIX
path of (preferencesFolderPath & newFilename))}}
end if
end repeat
end if
-- delete new keys folder
tell application "Finder" to move newKeysFolderPath to trash
return newKeyList
end GetNookKeys

on encodeAsBase64(theFilePath)
set posixfilepath to POSIX path of file theFilePath
set base64path to POSIX path of file ((path to me as text) &
"Contents:Resources:encodebase64.py")
return do shell script python & quoted form of base64path & " " & quoted form
of posixfilepath
end encodeAsBase64

on AddAdeptKey(keyfile)
set fileExtension to GetFileExtension(keyfile)
if fileExtension is "der" then
set newPrefsFile to CopyToPrefs(keyfile)
set AdeptKeyList to AdeptKeyList & POSIX path of newPrefsFile
else
display dialog "Adobe Adept key files generated by adeptkey.py must
have a .der extension." buttons {"OK"} default button 1 with title "DeDRM" with
icon caution
end if
end AddAdeptKey

on AddKindleKey(keyfile)
set fileExtension to GetFileExtension(keyfile)
if fileExtension is "k4i" then
set newPrefsFile to CopyToPrefs(keyfile)
set KindleKeyList to KindleKeyList & POSIX path of newPrefsFile
else
display dialog "Kindle key files generated by kindlekey.py must have
a .k4i extension." buttons {"OK"} default button 1 with title "DeDRM" with icon
caution
end if
end AddKindleKey

on AddAndroidKey(keyfile)
set fileExtension to GetFileExtension(keyfile)
if fileExtension is "ab" or fileExtension is "db" or fileExtension is "xml"
then
set newPrefsFile to CopyToPrefs(keyfile)
set AndroidKeyList to AndroidKeyList & POSIX path of newPrefsFile
else
display dialog "Android back files generated by use of \"adb backup
com.amazon.kindle\" must have a .ab extension." buttons {"OK"} default button 1
with title "DeDRM" with icon caution
end if
end AddAndroidKey

on AddbnKey(keyfile)
set fileExtension to GetFileExtension(keyfile)
if fileExtension is "b64" then
set newPrefsFile to CopyToPrefs(keyfile)
tell application "Finder"
set keyfileName to (name of file newPrefsFile) as text
end tell
set fileName to GetFileNameOnly(keyfileName)
set bnKeys to bnKeys & {{fileName, "", POSIX path of newPrefsFile}}
else
display dialog "Barnes & Noble key files must have a .b64 extension."
buttons {"OK"} default button 1 with title "DeDRM" with icon caution
end if
end AddbnKey

on GetUniqueName(folderPath, fileName)
set newFilename to fileName
if fileexists(folderPath & fileName) then
-- first find new name that's unique to folder
set namecount to 2
set fileExtension to GetFileExtension(fileName)
set fileNameOnly to GetFileNameOnly(fileName)
repeat
set newFilename to fileNameOnly & " " & (namecount as text) & "."
& fileExtension
if not fileexists(folderPath & newFilename) then
exit repeat
end if
set namecount to namecount + 1
end repeat
end if
return newFilename
end GetUniqueName

on CopyToPrefs(keyfilepath)
tell application "Finder"
set keyfileName to (name of file keyfilepath) as text
end tell
set keyfileApplepath to POSIX file (POSIX path of keyfilepath)
set userPrefsPath to path to preferences from user domain as string
set userTempPath to path to temporary items from user domain as string
set preferencesFolderPath to userPrefsPath & prefsFolderName & ":"
if not folderexists(preferencesFolderPath) then
tell application "Finder"
set preferencesFolder to make new folder at userPrefsPath with
properties {name:prefsFolderName}
end tell
end if
if fileexists(preferencesFolderPath & keyfileName) then
-- copy to temporary items folder, rename, and then we can copy from
there to the preferences folder
-- first find new name
set namecount to 2
set fileExtension to GetFileExtension(keyfileName)
set keyfileNameOnly to GetFileNameOnly(keyfileName)
repeat
set newkeyfileName to keyfileNameOnly & " " & (namecount as text)
& "." & fileExtension
if not fileexists(preferencesFolderPath & newkeyfileName) and not
fileexists(userTempPath & newkeyfileName) then
exit repeat
end if
set namecount to namecount + 1
end repeat
-- rename to new name
set newkeyfilepath to userTempPath & newkeyfileName
tell application "Finder"
set tempfilepath to duplicate file keyfileApplepath to folder
userTempPath with replacing
set name of tempfilepath to newkeyfileName
move file newkeyfilepath to preferencesFolderPath
end tell
set newFile to preferencesFolderPath & newkeyfileName
else
tell application "Finder"
set newFile to duplicate file keyfileApplepath to folder
preferencesFolderPath with replacing
end tell
end if

return newFile as text


end CopyToPrefs

on ReadPrefs()
-- read any existing keys from the preferences
set preferencesFilePath to (path to preferences from user domain as string) &
prefsFileName
set PIDs to {}
set UDIDs to {}
set bnKeys to {}
set KindleKeyList to {}
set AndroidKeyList to {}
set KindleSerialList to {}
set AdeptKeyList to {}
set outputFolder to (path to desktop as string)
set logFilePath to (path to desktop as string) & "DeDRM.log"
set tempfilepath to (path to preferences from user domain as string) &
prefsFolderName & ":" & tempFileName
--set tempfilepath to (path to temporary items as string)& "DeDRM_temp.log"

if fileexists(POSIX path of file preferencesFilePath) then


tell application "System Events"
try
set PIDs to value of property list item "PIDs" of property
list file preferencesFilePath
end try
try
set UDIDs to value of property list item "UDIDs" of
property list file preferencesFilePath
end try
try
set KindleSerialList to value of property list item
"KindleSerials" of property list file preferencesFilePath
end try
try
set bnKeys to value of property list item "bnKeys" of
property list file preferencesFilePath
end try
try
set AdeptKeyList to value of property list item "AdeptKeys"
of property list file preferencesFilePath
end try
try
set AndroidKeyList to value of property list item
"AndroidKeys" of property list file preferencesFilePath
end try
try
set KindleKeyList to value of property list item
"KindleKeys" of property list file preferencesFilePath
end try
try
set outputFolder to value of property list item
"OutputFolder" of property list file preferencesFilePath
end try
end tell
end if

set newList to {}
repeat with i from 1 to count AndroidKeyList
if fileexists(AndroidKeyList's item i) then set newList's end to
AndroidKeyList's item i
end repeat
set AndroidKeyList to newList

set newList to {}
repeat with i from 1 to count AdeptKeyList
if fileexists(AdeptKeyList's item i) then set newList's end to
AdeptKeyList's item i
end repeat
set AdeptKeyList to newList

set newList to {}
repeat with i from 1 to count KindleKeyList
if fileexists(KindleKeyList's item i) then set newList's end to
KindleKeyList's item i
end repeat
set KindleKeyList to newList

set newList to {}
repeat with i from 1 to count bnKeys
if (item 3 of bnKeys's item i) is "" or fileexists(item 3 of bnKeys's
item i) then set newList's end to bnKeys's item i
end repeat
set bnKeys to newList

end ReadPrefs

on CreatePlist(filePath)
set theEmptyPListData to "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST
1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict/>
</plist>"

set thePListFile to open for access filePath with write permission


set eof of thePListFile to 0
write theEmptyPListData to thePListFile starting at eof
close access thePListFile

end CreatePlist

on WritePrefsOld()
-- write keys to the preferences from older AppleScript
set preferencesFilePath to (path to preferences from user domain as string) &
prefsFileName
CreatePlist(preferencesFilePath)
tell application "System Events"
tell contents of property list file preferencesFilePath
set value to ({|PIDs|:PIDs} & {|UDIDs|:UDIDs} & {|
AndroidKeys|:AndroidKeyList} & {|KindleSerials|:KindleSerialList} & {|
KindleKeys|:KindleKeyList} & {|bnKeys|:bnKeys} & {|AdeptKeys|:AdeptKeyList} & {|
OutputFolder|:outputFolder})

end tell
end tell
end WritePrefsOld

on WritePrefs()
if oldAppleScript then
WritePrefsOld()
else
-- write keys to the preferences for AppleScript 2.0 and later
set preferencesFilePath to (path to preferences from user domain as
string) & prefsFileName
-- we still need to create an empty file in Yosemite, apparently
CreatePlist(preferencesFilePath)
tell application "System Events"
set the base_dict to make new property list item with properties
{kind:record}
set myPrefs to make new property list file with properties
{contents:base_dict, name:preferencesFilePath}
make new property list item at end of property list items of
contents of myPrefs with properties {kind:list, name:"PIDs", value:PIDs}
make new property list item at end of property list items of
contents of myPrefs with properties {kind:list, name:"UDIDs", value:UDIDs}
make new property list item at end of property list items of
contents of myPrefs with properties {kind:list, name:"AndroidKeys",
value:AndroidKeyList}
make new property list item at end of property list items of
contents of myPrefs with properties {kind:list, name:"KindleSerials",
value:KindleSerialList}
make new property list item at end of property list items of
contents of myPrefs with properties {kind:list, name:"KindleKeys",
value:KindleKeyList}
make new property list item at end of property list items of
contents of myPrefs with properties {kind:list, name:"bnKeys", value:bnKeys}
make new property list item at end of property list items of
contents of myPrefs with properties {kind:list, name:"AdeptKeys",
value:AdeptKeyList}
make new property list item at end of property list items of
contents of myPrefs with properties {kind:string, name:"OutputFolder",
value:outputFolder}
end tell
end if
end WritePrefs

on InitProgress(maxcount)
try
if totalebooks > 1 then
launch application ((path to resource "DeDRM Progress.app") as
string)
tell application ((path to resource "DeDRM Progress.app") as
string)
activate
set contents of «class texF» "maintext" of window "main" to
"Decrypting " & maxcount & " ebooks."
set contents of «class texF» "subtext" of window "main" to
"Decrypting book 0: "
set «class maxV» of «class proI» "bar" of window "main" to
maxcount
set «class conT» of «class proI» "bar" of window "main" to
0
end tell
end if
end try

end InitProgress
on ProcessItems(some_items)
try
set ErrorList to ""
set WarningList to ""
set CompletedList to ""
set ErrorCount to 0
set WarningCount to 0
set CompletedCount to 0
set totalebooks to 0
set completedebooks to 0
repeat with this_item in some_items
if (folder of (info for this_item) is true) then
tell application "Finder" to set totalebooks to totalebooks
+ (count of (every file in entire contents of folder this_item whose name extension
is in handledExtensions))
else
countfile(this_item as text)
end if
end repeat
if totalebooks is 1 then
set TotalText to "There is 1 ebook to be decrypted."
else
set TotalText to "There are " & totalebooks & " ebooks to be
decrypted."
end if
writetolog(TotalText)
InitProgress(totalebooks)
repeat with this_item in some_items
if totalebooks > 1 and not ProgressActive() then
exit repeat
end if
if (folder of (info for this_item) is true) then
handlefolder(this_item as text)
else
handlefile(this_item as text)
end if
end repeat
endProgress()
on error errmsg number errnum
set errorReport to "An unexpected error occurred. Please report on
Apprentice Alf's blog.

Error Message: " & errmsg & "


Error Number: " & errnum
writetolog(errorReport)
display notification errorReport with title "DeDRM" subtitle
"Unexpected Error"
--display dialog errorReport with title "DeDRM" buttons {"Bother"}
default button 1 with icon stop
end try
if WarningList is not "" then
set WarningText to ""
if WarningCount is 1 then
set WarningText to "There was a warning with 1 ebook:"
else
set WarningText to "There were warnings with " & WarningCount & "
ebooks:"
end if
writetolog(WarningText)
writetolog(WarningList)
--set dialogresult to display dialog WarningText & "

--" & WarningList buttons {"OK"} with title "DeDRM" default button 1
display notification WarningList with title "DeDRM" subtitle
WarningText
end if
if ErrorList is not "" then
set ErrorText to ""
if ErrorCount is 1 then
set ErrorText to "There was an error with 1 ebook:"
else
set ErrorText to "There were errors with " & ErrorCount & "
ebooks:"
end if
writetolog(ErrorText)
writetolog(ErrorList)
--set dialogresult to display dialog ErrorText & "

--" & ErrorList buttons {"Bother"} with title "DeDRM" default button 1
display notification ErrorList with title "DeDRM" subtitle ErrorText
end if
if CompletedCount > 0 then
set CompletedText to ""
if CompletedCount is 1 then
set CompletedText to "Successfully de-drmed 1 ebook:"
else
set CompletedText to "Successfully de-drmed " & CompletedCount &
" ebooks:"
end if
writetolog(CompletedText)
writetolog(CompletedList)
--set dialogresult to display dialog CompletedText & "

--" & CompletedList buttons {"Thanks"} with title "DeDRM" default


button 1
display notification CompletedList with title "DeDRM" subtitle
CompletedText
end if
return CompletedCount + WarningCount + ErrorCount
end ProcessItems

on ProgressActive()
tell application "System Events" to set progactive to count (every process
whose name is "DeDRM Progress")
if progactive > 0 then return true
return false
end ProgressActive

on IncProgress(booktitle, doingcount)
try
if ProgressActive() then
tell application ((path to resource "DeDRM Progress.app") as
string)
set contents of «class texF» "subtext" of window "main" to
"Decrypting book " & doingcount & ": " & booktitle
set «class conT» of «class proI» "bar" of window "main" to
doingcount
end tell
end if
end try
end IncProgress

on endProgress()
try
if ProgressActive() then tell application ((path to resource "DeDRM
Progress.app") as string) to quit
end try
end endProgress

on run
if GetTools() then
ReadPrefs()
clearlog()
repeat
set dialogresult to display dialog "To remove DRM from an ebook,
click ‘Select Ebook…’
To configure this software, click ‘Configure…’

When the DeDRM application is not running, you can also remove DRM from ebooks by
dropping them onto the DeDRM application icon in the Finder.

For details of the ebook formats which this application can handle, see the ReadMe
file or visit http://apprenticealf.wordpress.com/
Please only use this application on your own books. Authors, publishers and ebook
stores need to make money to produce more ebooks.
Don't cheat them.

This application is by Apprentice Alf and Apprentice Harper based on an AppleScript


script by Paul Durrant and uses python scripts produced by Apprentice Alf, CMBDTC,
The Dark Reverser, DiapDealer, i♥cabbages, some_updates, Apprentice Harper and
others.
The AppleScript part of this application is free software released into the public
domain, see http://unlicense.org/
The application icon is adapted from the Authors Against DRM logo at
http://readersbillofrights.info/AAD and is under the Creative Commons Attribution-
ShareAlike licence.

The included Python scripts are all free to use, but have a variety of licences.
See the individual files for details.
" with title "DeDRM by Apprentice Alf" buttons {"Quit", "Select Ebook…
", "Configure… "} default button 1 with icon
note
if button returned of dialogresult is "Quit" then exit repeat
if button returned of dialogresult is "Select Ebook…
" then
set DRMebook to ""
try
set DRMebook to {choose file with prompt "Please
select a DRMed ebook"}
end try
if DRMebook is not "" then
if ProcessItems(DRMebook) is 0 then
display dialog "That was a file that this
script cannot process." with title "DeDRM" buttons {"OK"} default button 1 with
icon note
end if
WritePrefs()
end if
else
set choice to true
repeat while choice is not false
set choice to choose from list {"eInk Kindle eBooks",
"Barnes and Noble (nook) ebooks", "Mobipocket eBooks", "eReader ebooks", "Adobe
Digital Editions ebooks", "Kindle for Mac ebooks", "Output Folder"} with prompt
"Choose a Configuration Option:" with title "DeDRM Configuration" OK button name
"Configure..." cancel button name "Finished"
if choice contains "Barnes and Noble (nook) ebooks"
then
GetBNKeys("DeDRM Configure for Barnes and Noble
(nook)")
else if choice contains "eInk Kindle eBooks" then
GetSerials("DeDRM Configure for eInk Kindle")
else if choice contains "Mobipocket eBooks" then
GetPIDs("DeDRM Configure for Mobipocket")
else if choice contains "eReader ebooks" then
GeteReaderKeys("DeDRM Configure for eReader")
else if choice contains "Kindle for Mac ebooks" then
GetKindleKeyFiles("DeDRM Configure Kindle for
Mac")
else if choice contains "Kindle for Android ebooks"
then
GetAndroidKeyFiles("DeDRM Configure Kindle for
Android")
else if choice contains "Adobe Digital Editions
ebooks" then
GetAdeptKeyFiles("DeDRM Configure Adobe Digital
Editions")
else if choice contains "Output Folder" then
GetOutputFolder("DeDRM Configure Output
Folder")
end if
end repeat
WritePrefs()
end if
end repeat
end if
end run

on open some_items
--display dialog (some_items as text)
if GetTools() then
ReadPrefs()
clearlog()

if ProcessItems(some_items) is 0 then
display notification "No ebooks found in the dropped items. DeDRM
can handle Mobipocket, Kindle, eReader, Adobe ePub, Barnes & Noble ePub and Adobe
PDF. Please try again." with title "DeDRM"
end if
WritePrefs()
delay 1 --> allow time for any notifications to trigger
end if
end open

You might also like