mirror of
https://github.com/apprenticeharper/DeDRM_tools
synced 2024-12-31 10:23:20 +01:00
1521 lines
112 KiB
Text
1521 lines
112 KiB
Text
property prefsFileName : "com.apprenticealf.dedrm.plist"
|
|
property tempFileName : "DeDRM_temp.log"
|
|
property prefsFolderName : "com.apprenticealf.dedrm"
|
|
property handledExtensions : {"epub", "pdf", "prc", "azw", "azw1", "tpz", "azw3", "azw4", "mobi", "pdb"}
|
|
|
|
global eReaderTool
|
|
global MobipocketTool
|
|
global KindlePIDTool
|
|
global BNKeyGenTool
|
|
global BNePubTool
|
|
global AdobeKeyGenTool
|
|
global AdobeePubTool
|
|
global AdobePDFTool
|
|
global ZipFixTool
|
|
global ProgressApp
|
|
|
|
global PIDs
|
|
global UDIDs
|
|
global bnKeys
|
|
global KindleInfoList
|
|
global KindleSerialList
|
|
global AdeptKeyList
|
|
|
|
global ErrorList
|
|
global WarningList
|
|
global CompletedList
|
|
global ErrorCount
|
|
global WarningCount
|
|
global CompletedCount
|
|
global totalebooks
|
|
global completedebooks
|
|
global outputFolder
|
|
global logFilePath
|
|
global tempfilepath
|
|
|
|
on writetolog(logstring)
|
|
try
|
|
set fileRef to open for access logFilePath with write permission
|
|
write logstring & "
|
|
" to fileRef starting at eof
|
|
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 tempContentsLines to (read fileRef from 1 using delimiter (character id 10))
|
|
set oldTIDs to AppleScript's text item delimiters
|
|
set AppleScript's text item delimiters to (character id 13)
|
|
set tempContents to tempContentsLines as string
|
|
set AppleScript's text item delimiters to oldTIDs
|
|
end if
|
|
close access fileRef
|
|
end try
|
|
return tempContents
|
|
end readtemp
|
|
|
|
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 eReaderTool to POSIX path of file (path to me as text) & "Contents/Resources/erdr2pml.py"
|
|
set MobipocketTool to POSIX path of file (path to me as text) & "Contents/Resources/k4mobidedrm.py"
|
|
set KindlePIDTool to POSIX path of file (path to me as text) & "Contents/Resources/kindlepid.py"
|
|
set BNKeyGenTool to POSIX path of file (path to me as text) & "Contents/Resources/ignoblekeygen.py"
|
|
set BNePubTool to POSIX path of file (path to me as text) & "Contents/Resources/ignobleepub.py"
|
|
set AdobeKeyGenTool to POSIX path of file (path to me as text) & "Contents/Resources/ineptkey.py"
|
|
set AdobeePubTool to POSIX path of file (path to me as text) & "Contents/Resources/ineptepub.py"
|
|
set AdobePDFTool to POSIX path of file (path to me as text) & "Contents/Resources/ineptpdf.py"
|
|
set ZipFixTool to POSIX path of file (path to me as text) & "Contents/Resources/zipfix.py"
|
|
set ProgressApp to POSIX path of file (path to me as text) & "Contents/Resources/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(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(AdobeKeyGenTool) then
|
|
set dialogresult to (display dialog "The Adobe Key Generation script (ineptkey.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 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 KindleInfoPath in KindleInfoList
|
|
set shellcommand to shellcommand & " -k " & quoted form of KindleInfoPath
|
|
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 ""
|
|
try
|
|
do shell script shellcommand
|
|
on error ErrorText number errnum
|
|
set DecodingError to true
|
|
end try
|
|
set shellresult to readtemp()
|
|
writetolog("shellresult: " & shellresult & " " & ErrorText)
|
|
try
|
|
repeat
|
|
if (not DecodingError) or (totalebooks > 1) or (offset of "No key found" in ErrorText) is 0 then
|
|
exit repeat
|
|
end if
|
|
-- ask for another PID as we're only doing one ebook
|
|
set newPID to "None"
|
|
set DialogPrompt to "Couldn't decode " & fileName & ". Do you have another PID to try?"
|
|
try
|
|
set dialogresult to (display dialog DialogPrompt default answer "" buttons {"Try This One", "No Extra PID"} with title "DeDRM" default button 2)
|
|
if button returned of dialogresult is "Try This One" then
|
|
set newPID to text returned of dialogresult
|
|
end if
|
|
end try
|
|
if newPID is "None" or (length of newPID is not 10 and length of newPID is not 8) then
|
|
exit repeat
|
|
end if
|
|
set shellcommand to "python " & (quoted form of MobipocketTool) & " -p " & quoted form of newPID & " " & (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)
|
|
set DecodingError to false
|
|
set shellresult to ""
|
|
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
|
|
end repeat
|
|
if DecodingError then
|
|
set ErrorCount to ErrorCount + 1
|
|
set ErrorList to ErrorList & fileName & fileExtension & " couldn't be decoded:
|
|
" & (ErrorText as text) & "
|
|
"
|
|
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 & (character id 13)
|
|
end if
|
|
end try
|
|
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 bnKeys is 0 then
|
|
GetKeys(false, "DeDRM")
|
|
end if
|
|
set shellresult to "Error: No eReader/Barnes & Noble Name:Number 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 & (character id 13)
|
|
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 "NO"
|
|
-- 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 ""
|
|
|
|
-- first we'll try the Barnes & Noble keys
|
|
repeat with BNKey in bnKeys
|
|
|
|
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 "YES"
|
|
exit repeat
|
|
end if
|
|
if (offset of "improper key" in shellresult) is 0 then
|
|
exit repeat
|
|
end if
|
|
end if
|
|
end repeat
|
|
|
|
if decoded is "NO" then
|
|
-- now try Adobe ePub
|
|
repeat with AdeptKey in AdeptKeyList
|
|
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()
|
|
writetolog("shellresult: " & shellresult & " " & ErrorText)
|
|
--display dialog shellresult
|
|
if not DecodingError then
|
|
set decoded to "YES"
|
|
exit repeat
|
|
end if
|
|
end repeat
|
|
end if
|
|
|
|
if decoded is "YES" then
|
|
set CompletedCount to CompletedCount + 1
|
|
set CompletedList to CompletedList & fileName & fileExtension & (character id 13)
|
|
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 if (offset of "not an ADEPT EPUB" in shellresult) is not 0 then
|
|
set WarningCount to WarningCount + 1
|
|
set WarningList to (WarningList & fileName & " doesn't seem to be encrypted.
|
|
")
|
|
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 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
|
|
|
|
set unlockedFilePath to POSIX path of file (parent_folder & fileName & "_nodrm" & fileExtension)
|
|
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 & (character id 13)
|
|
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 "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 GetBNKeystring()
|
|
set BNKeystring to ""
|
|
repeat with BNKey in bnKeys
|
|
if BNKeystring is "" then
|
|
set BNKeystring to first item of BNKey & ":" & second item of BNKey
|
|
else
|
|
set BNKeystring to BNKeystring & "
|
|
" & first item of BNKey & ":" & second item of BNKey
|
|
end if
|
|
if length of third item of BNKey > 0 then
|
|
set BNKeystring to BNKeystring & "*"
|
|
end if
|
|
if length of second item of BNKey > 0 then
|
|
set BNKeystring to BNKeystring & "†"
|
|
end if
|
|
end repeat
|
|
return BNKeystring
|
|
end GetBNKeystring
|
|
|
|
|
|
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 "None"
|
|
else
|
|
set DialogPrompt to "Current UDIDs: " & UDIDstring & ".
|
|
|
|
Enter any additional iPod/iPhone/iPad UDIDs (40 characters) one at a time:"
|
|
set FinishedButton to "No More"
|
|
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 "None"
|
|
else
|
|
set DialogPrompt to "Current PIDs: " & PIDstring & ".
|
|
|
|
Enter any additional Mobipocket PIDs one at a time:"
|
|
set FinishedButton to "No More"
|
|
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, or Apple iPod/iPhone/iPad UDIDs one at a time:"
|
|
set FinishedButton to "None"
|
|
else
|
|
set DialogPrompt to "Current Kindle Serial Numbers: " & Serialstring & ".
|
|
|
|
Enter any additional Kindle Serial Numbers one at a time:"
|
|
set FinishedButton to "No More"
|
|
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 and (first character of Serial) is "B" then
|
|
set KindleSerialList to KindleSerialList & Serial
|
|
set Serial to ""
|
|
else
|
|
display dialog "Kindle Serial Numbers are 16 characters long and start with B." 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 as text) & "
|
|
|
|
"
|
|
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 'Finished', 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…", "Finished"} 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 GetKeys(running, DialogTitle)
|
|
set bnKeyText to ""
|
|
repeat
|
|
set BNKeystring to GetBNKeystring()
|
|
if BNKeystring is "" then
|
|
set DialogPrompt to "Please enter any "
|
|
set FinishedButton to "None"
|
|
else
|
|
set DialogPrompt to "Current B&N keys*, eReader keys†:
|
|
" & BNKeystring & "
|
|
|
|
|
|
Please enter any additional "
|
|
set FinishedButton to "No More"
|
|
end if
|
|
set DialogPrompt to DialogPrompt & "eReader/Barnes & Noble Name,Number key pairs one at a time. The name is usually your name as on your credit card, but might be your Barnes & Noble user name. If you're only decoding eReader files, the last 8 digits of the Number will do. The full 15 or 16 are only needed for Barnes & Noble ePubs. Only the last eight will be stored or displayed. Please separate the name and number with a comma and click \"Add\". 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 buttons {"Delete All", "Add", FinishedButton} with title DialogTitle 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 B&N .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 "Name and Number must be separated by a comma (,)." 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 bnKeyText
|
|
set keyName to (text items 1 through -2 of bnKeyText) 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 shellresult to ""
|
|
set keyfilepath to ""
|
|
if (length of keyNumber) = 16 or (length of keyNumber) = 15 then
|
|
-- get the B&N key from this pair
|
|
set shellresult to ""
|
|
set scriptError to ""
|
|
set prefsFolder to (path to preferences from user domain as string) & prefsFolderName & ":"
|
|
set keyfileName to GetUniqueName(prefsFolder, keyName & (text -8 thru -1 of keyNumber) & ".b64")
|
|
set keyfilepath to POSIX path of (prefsFolder & keyfileName)
|
|
set shellcommand to "python " & (quoted form of BNKeyGenTool) & " " & (quoted form of keyName) & " " & (quoted form of keyNumber) & " " & quoted form of keyfilepath
|
|
writetolog("shellcommand: " & "Generating bnepubkey.b64")
|
|
try
|
|
set shellresult to do shell script shellcommand
|
|
on error errmsg
|
|
set shellresult to ""
|
|
set scriptError to "BN Key Gen Script failed" & " " & errmsg
|
|
end try
|
|
writetolog("shellresult: " & scriptError & " " & shellresult)
|
|
--display dialog shellresult
|
|
end if
|
|
if shellresult is not "" then
|
|
set bnKeys to bnKeys & {{keyName, (text -8 thru -1 of keyNumber), 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 "Delete All" then
|
|
if BNKeystring 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
|
|
set bnKeys to {}
|
|
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 GetKeys
|
|
|
|
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 FinishedButton to "None"
|
|
else
|
|
set DialogPrompt to "Current Adobe Digital Editions (Adept) key files:
|
|
" & Adeptstring & "
|
|
|
|
To add extra key files (.der), click the Add… button."
|
|
set FinishedButton to "No More"
|
|
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 an Adept 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
|
|
if Adeptstring is not "" 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 {}
|
|
GetAdeptKey(false)
|
|
end if
|
|
end if
|
|
else
|
|
exit repeat
|
|
end if
|
|
end repeat
|
|
end GetAdeptKeyFiles
|
|
|
|
on GetAdeptKey(always)
|
|
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 userAdeptKeyPath to POSIX path of (preferencesFolderPath & "Local Adept Key.der")
|
|
if ((count of AdeptKeyList) is 0) or always then
|
|
set scriptError to ""
|
|
set shellresult to ""
|
|
set success to true
|
|
set shellcommand to "python " & (quoted form of AdobeKeyGenTool) & " " & quoted form of userAdeptKeyPath
|
|
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
|
|
if not (AdeptKeyList contains userAdeptKeyPath) then
|
|
set AdeptKeyList to AdeptKeyList & userAdeptKeyPath
|
|
end if
|
|
else
|
|
if (always) then
|
|
display dialog "Error generating key for Adobe Editions: " & scriptError & "
|
|
|
|
You must have Adobe Digital Editions installed for this script to work with Adobe ePubs, or add a key file manually. " buttons {"OK"} default button 1 with title "DeDRM" with icon caution
|
|
end if
|
|
end if
|
|
end if
|
|
end GetAdeptKey
|
|
|
|
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 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 generated by ignoblekeygen.py 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 KindleInfoList 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 KindleInfoList to value of property list item "KindleInfoFiles" 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 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 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 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 WritePrefs()
|
|
-- write keys to the preferences
|
|
set preferencesFilePath to (path to preferences from user domain as string) & prefsFileName
|
|
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:"KindleSerials", value:KindleSerialList}
|
|
make new property list item at end of property list items of contents of myPrefs with properties {kind:list, name:"KindleInfoFiles", value:KindleInfoList}
|
|
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 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 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
|
|
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
|
|
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
|
|
end if
|
|
return CompletedCount + WarningCount + ErrorCount
|
|
end ProcessItems
|
|
|
|
on ProgressActive()
|
|
return application ((path to resource "DeDRM Progress.app") as string) is running
|
|
--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
|
|
set dialogresult to display dialog "To remove DRM from an ebook, click 'Select Ebook…'
|
|
|
|
To configure this software, click 'Configure…'
|
|
|
|
When this application is not running, you can also remove DRM from ebooks by dropping files and folders onto its icon in the Finder.
|
|
|
|
For details of the ebook formats which this application can handle, please see 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 uses python scripts produced by Apprentice Alf, CMBDTC, DarkReverser, DiapDealer, I ♥ Cabbages, some_updates, and others.
|
|
|
|
The AppleScript part of this application is free software released into the public domain.
|
|
For full information about the licence, please 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 5.2 by Apprentice Alf" buttons {"Close", "Select Ebook… ", "Configure… "} default button 1 with icon note
|
|
ReadPrefs()
|
|
clearlog()
|
|
GetAdeptKey(false)
|
|
if button returned of dialogresult is not "Close" then
|
|
if button returned of dialogresult is "Select Ebook… " then
|
|
set DRMebook to ""
|
|
try
|
|
set DRMebook to {choose file with prompt "DeDRM
|
|
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
|
|
end if
|
|
else
|
|
GetSerials("DeDRM Configuration 1/6")
|
|
GetPIDs("DeDRM Configuration 2/6")
|
|
GetUDIDs("DeDRM Configuration 3/6")
|
|
GetKeys(true, "DeDRM Configuration 4/6")
|
|
GetAdeptKeyFiles("DeDRM Configuration 4/6")
|
|
GetOutputFolder("DeDRM Configuration 6/6")
|
|
end if
|
|
end if
|
|
WritePrefs()
|
|
end if
|
|
end run
|
|
|
|
on open some_items
|
|
--display dialog (some_items as text)
|
|
if GetTools() then
|
|
ReadPrefs()
|
|
clearlog()
|
|
GetAdeptKey(false)
|
|
|
|
if ProcessItems(some_items) is 0 then
|
|
display dialog "No ebooks found in the dropped items. DeDRM can handle Mobipocket, Kindle, eReader, Adobe ePub, Barnes & Noble ePub and Adobe PDF. Please try again." buttons {"OK"} with title "DeDRM" default button 1 with icon note
|
|
end if
|
|
WritePrefs()
|
|
end if
|
|
end open
|
|
|