2011-01-17 13:24:53 +06:00
#!/usr/bin/env python
2012-12-19 19:48:11 +06:00
# -*- coding: utf-8 -*-
2015-03-09 13:38:31 +06:00
# DeDRM.pyw
2016-01-11 12:44:44 +06:00
# Copyright 2010-2016 some_updates, Apprentice Alf and Apprentice Harper
2013-03-26 22:38:18 +06:00
# Revision history:
# 6.0.0 - Release along with unified plugin
# 6.0.1 - Bug Fixes for Windows App
2013-04-08 21:47:22 +06:00
# 6.0.2 - Fixed problem with spaces in paths and the bat file
# 6.0.3 - Fix for Windows non-ascii user names
2013-04-10 16:50:10 +06:00
# 6.0.4 - Fix for other potential unicode problems
2013-04-25 00:28:20 +06:00
# 6.0.5 - Fix typo
2015-03-09 13:38:31 +06:00
# 6.2.0 - Update to match plugin and AppleScript
2015-03-25 13:26:33 +06:00
# 6.2.1 - Fix for non-ascii user names
2015-06-30 22:27:33 +06:00
# 6.2.2 - Added URL method for B&N/nook books
2015-03-24 13:04:06 +06:00
# 6.3.0 - Add in Android support
2015-08-02 16:09:35 +06:00
# 6.3.1 - Version bump for clarity
2015-08-04 12:18:33 +06:00
# 6.3.2 - Version bump to match plugin
2015-08-12 23:35:21 +06:00
# 6.3.3 - Version bump to match plugin
2015-09-03 12:51:10 +06:00
# 6.3.4 - Version bump to match plugin
2016-01-11 12:44:44 +06:00
# 6.3.5 - Version bump to match plugin
2016-01-14 23:15:43 +06:00
# 6.3.6 - Version bump to match plugin
2016-03-13 18:00:57 +06:00
# 6.4.0 - Fix for Kindle for PC encryption change
2016-04-13 23:39:13 +06:00
# 6.4.1 - Fix for new tags in Topaz ebooks
2016-04-18 22:39:17 +06:00
# 6.4.2 - Fix for new tags in Topaz ebooks, and very small Topaz ebooks
2016-04-25 22:49:06 +06:00
# 6.4.3 - Version bump to match plugin & Mac app
2013-03-26 22:38:18 +06:00
2016-04-25 22:49:06 +06:00
__version__ = ' 6.4.3 '
2011-01-17 13:24:53 +06:00
import sys
import os , os . path
2012-12-19 19:48:11 +06:00
sys . path . append ( os . path . join ( sys . path [ 0 ] , " lib " ) )
2013-01-19 20:50:57 +06:00
import sys , os
import codecs
2013-02-07 16:28:25 +06:00
from argv_utils import add_cp65001_codec , set_utf8_default_encoding , unicode_argv
2013-01-19 20:50:57 +06:00
add_cp65001_codec ( )
set_utf8_default_encoding ( )
2012-05-16 22:15:43 +06:00
2011-01-17 13:24:53 +06:00
import shutil
import Tkinter
from Tkinter import *
import Tkconstants
import tkFileDialog
from scrolltextwidget import ScrolledText
from activitybar import ActivityBar
2013-03-20 16:23:54 +06:00
if sys . platform . startswith ( " win " ) :
from askfolder_ed import AskFolder
2011-01-17 13:24:53 +06:00
import re
import simpleprefs
2013-03-20 16:23:54 +06:00
import traceback
2011-01-17 13:24:53 +06:00
2013-01-19 20:50:57 +06:00
from Queue import Full
from Queue import Empty
from multiprocessing import Process , Queue
from scriptinterface import decryptepub , decryptpdb , decryptpdf , decryptk4mobi
# Wrap a stream so that output gets flushed immediately
# and appended to shared queue
2013-02-04 20:25:25 +06:00
class QueuedUTF8Stream :
2013-01-19 20:50:57 +06:00
def __init__ ( self , stream , q ) :
self . stream = stream
2013-02-04 20:25:25 +06:00
self . encoding = ' utf-8 '
2013-01-19 20:50:57 +06:00
self . q = q
def write ( self , data ) :
if isinstance ( data , unicode ) :
2013-02-04 20:25:25 +06:00
data = data . encode ( ' utf-8 ' , " replace " )
2013-01-19 20:50:57 +06:00
self . q . put ( data )
def __getattr__ ( self , attr ) :
return getattr ( self . stream , attr )
2011-01-17 13:24:53 +06:00
class DrmException ( Exception ) :
pass
class MainApp ( Tk ) :
2011-02-02 20:41:15 +06:00
def __init__ ( self , apphome , dnd = False , filenames = [ ] ) :
2011-01-17 13:24:53 +06:00
Tk . __init__ ( self )
self . withdraw ( )
self . dnd = dnd
2011-02-02 20:41:15 +06:00
self . apphome = apphome
2013-01-19 20:50:57 +06:00
2011-01-17 13:24:53 +06:00
# preference settings
# [dictionary key, file in preferences directory where info is stored]
2012-03-07 00:24:28 +06:00
description = [ [ ' pids ' , ' pidlist.txt ' ] ,
2011-01-17 13:24:53 +06:00
[ ' serials ' , ' seriallist.txt ' ] ,
[ ' sdrms ' , ' sdrmlist.txt ' ] ,
[ ' outdir ' , ' outdir.txt ' ] ]
2012-09-09 06:45:24 +06:00
self . po = simpleprefs . SimplePrefs ( " DeDRM " , description )
2011-01-17 13:24:53 +06:00
if self . dnd :
self . cd = ConvDialog ( self )
prefs = self . getPreferences ( )
self . cd . doit ( prefs , filenames )
else :
prefs = self . getPreferences ( )
self . pd = PrefsDialog ( self , prefs )
self . cd = ConvDialog ( self )
self . pd . show ( )
def getPreferences ( self ) :
prefs = self . po . getPreferences ( )
prefdir = prefs [ ' dir ' ]
2013-03-20 16:23:54 +06:00
adeptkeyfile = os . path . join ( prefdir , ' adeptkey.der ' )
if not os . path . exists ( adeptkeyfile ) :
import adobekey
try :
adobekey . getkey ( adeptkeyfile )
except :
pass
kindlekeyfile = os . path . join ( prefdir , ' kindlekey.k4i ' )
if not os . path . exists ( kindlekeyfile ) :
import kindlekey
2011-01-17 13:24:53 +06:00
try :
2013-03-20 16:23:54 +06:00
kindlekey . getkey ( kindlekeyfile )
2011-01-17 13:24:53 +06:00
except :
2013-03-20 16:23:54 +06:00
traceback . print_exc ( )
2011-01-17 13:24:53 +06:00
pass
2015-03-09 13:38:31 +06:00
bnepubkeyfile = os . path . join ( prefdir , ' bnepubkey.b64 ' )
if not os . path . exists ( bnepubkeyfile ) :
import ignoblekey
try :
ignoblekey . getkey ( bnepubkeyfile )
except :
traceback . print_exc ( )
pass
2011-01-17 13:24:53 +06:00
return prefs
def setPreferences ( self , newprefs ) :
prefdir = self . po . prefdir
if ' adkfile ' in newprefs :
dfile = newprefs [ ' adkfile ' ]
fname = os . path . basename ( dfile )
nfile = os . path . join ( prefdir , fname )
if os . path . isfile ( dfile ) :
shutil . copyfile ( dfile , nfile )
if ' bnkfile ' in newprefs :
dfile = newprefs [ ' bnkfile ' ]
fname = os . path . basename ( dfile )
nfile = os . path . join ( prefdir , fname )
if os . path . isfile ( dfile ) :
shutil . copyfile ( dfile , nfile )
2015-07-29 23:11:19 +06:00
if ' kindlefile ' in newprefs :
dfile = newprefs [ ' kindlefile ' ]
fname = os . path . basename ( dfile )
nfile = os . path . join ( prefdir , fname )
if os . path . isfile ( dfile ) :
shutil . copyfile ( dfile , nfile )
if ' androidfile ' in newprefs :
dfile = newprefs [ ' androidfile ' ]
2011-01-17 13:24:53 +06:00
fname = os . path . basename ( dfile )
nfile = os . path . join ( prefdir , fname )
if os . path . isfile ( dfile ) :
shutil . copyfile ( dfile , nfile )
self . po . setPreferences ( newprefs )
return
def alldone ( self ) :
if not self . dnd :
self . pd . enablebuttons ( )
else :
self . destroy ( )
class PrefsDialog ( Toplevel ) :
def __init__ ( self , mainapp , prefs_array ) :
Toplevel . __init__ ( self , mainapp )
self . withdraw ( )
self . protocol ( " WM_DELETE_WINDOW " , self . withdraw )
2012-09-09 06:45:24 +06:00
self . title ( " DeDRM " + __version__ )
2011-01-17 13:24:53 +06:00
self . prefs_array = prefs_array
self . status = Tkinter . Label ( self , text = ' Setting Preferences ' )
self . status . pack ( fill = Tkconstants . X , expand = 1 )
body = Tkinter . Frame ( self )
self . body = body
body . pack ( fill = Tkconstants . X , expand = 1 )
sticky = Tkconstants . E + Tkconstants . W
body . grid_columnconfigure ( 1 , weight = 2 )
2015-08-02 16:09:35 +06:00
2015-03-24 13:04:06 +06:00
cur_row = 0
Tkinter . Label ( body , text = ' Adobe Key file (adeptkey.der) ' ) . grid ( row = cur_row , sticky = Tkconstants . E )
2011-01-17 13:24:53 +06:00
self . adkpath = Tkinter . Entry ( body , width = 50 )
2015-03-24 13:04:06 +06:00
self . adkpath . grid ( row = cur_row , column = 1 , sticky = sticky )
2011-01-17 13:24:53 +06:00
prefdir = self . prefs_array [ ' dir ' ]
keyfile = os . path . join ( prefdir , ' adeptkey.der ' )
if os . path . isfile ( keyfile ) :
path = keyfile
2015-03-24 13:04:06 +06:00
self . adkpath . insert ( cur_row , path )
2011-01-17 13:24:53 +06:00
button = Tkinter . Button ( body , text = " ... " , command = self . get_adkpath )
2015-03-24 13:04:06 +06:00
button . grid ( row = cur_row , column = 2 )
2011-01-17 13:24:53 +06:00
2015-03-24 13:04:06 +06:00
cur_row = cur_row + 1
Tkinter . Label ( body , text = ' Kindle Key file (kindlekey.k4i) ' ) . grid ( row = cur_row , sticky = Tkconstants . E )
2013-03-20 16:23:54 +06:00
self . kkpath = Tkinter . Entry ( body , width = 50 )
2015-03-24 13:04:06 +06:00
self . kkpath . grid ( row = cur_row , column = 1 , sticky = sticky )
2011-01-17 13:24:53 +06:00
prefdir = self . prefs_array [ ' dir ' ]
2013-03-20 16:23:54 +06:00
keyfile = os . path . join ( prefdir , ' kindlekey.k4i ' )
2011-01-17 13:24:53 +06:00
if os . path . isfile ( keyfile ) :
path = keyfile
2015-03-24 13:04:06 +06:00
self . kkpath . insert ( 0 , path )
2013-03-20 16:23:54 +06:00
button = Tkinter . Button ( body , text = " ... " , command = self . get_kkpath )
2015-03-24 13:04:06 +06:00
button . grid ( row = cur_row , column = 2 )
cur_row = cur_row + 1
2015-07-29 23:11:19 +06:00
Tkinter . Label ( body , text = ' Android Kindle backup file (backup.ab) ' ) . grid ( row = cur_row , sticky = Tkconstants . E )
2015-03-24 13:04:06 +06:00
self . akkpath = Tkinter . Entry ( body , width = 50 )
self . akkpath . grid ( row = cur_row , column = 1 , sticky = sticky )
prefdir = self . prefs_array [ ' dir ' ]
2015-07-29 23:11:19 +06:00
keyfile = os . path . join ( prefdir , ' backup.ab ' )
2015-03-24 13:04:06 +06:00
if os . path . isfile ( keyfile ) :
path = keyfile
self . akkpath . insert ( 0 , path )
button = Tkinter . Button ( body , text = " ... " , command = self . get_akkpath )
button . grid ( row = cur_row , column = 2 )
2012-03-07 00:24:28 +06:00
2015-03-24 13:04:06 +06:00
cur_row = cur_row + 1
Tkinter . Label ( body , text = ' Barnes and Noble Key file (bnepubkey.b64) ' ) . grid ( row = cur_row , sticky = Tkconstants . E )
2013-03-20 16:23:54 +06:00
self . bnkpath = Tkinter . Entry ( body , width = 50 )
2015-03-24 13:04:06 +06:00
self . bnkpath . grid ( row = cur_row , column = 1 , sticky = sticky )
2011-01-17 13:24:53 +06:00
prefdir = self . prefs_array [ ' dir ' ]
2013-03-20 16:23:54 +06:00
keyfile = os . path . join ( prefdir , ' bnepubkey.b64 ' )
if os . path . isfile ( keyfile ) :
path = keyfile
2015-03-24 13:04:06 +06:00
self . bnkpath . insert ( 0 , path )
2013-03-20 16:23:54 +06:00
button = Tkinter . Button ( body , text = " ... " , command = self . get_bnkpath )
2015-03-24 13:04:06 +06:00
button . grid ( row = cur_row , column = 2 )
2011-01-17 13:24:53 +06:00
2015-03-24 13:04:06 +06:00
cur_row = cur_row + 1
Tkinter . Label ( body , text = ' Mobipocket PID list \n (8 or 10 characters, comma separated) ' ) . grid ( row = cur_row , sticky = Tkconstants . E )
2011-01-17 13:24:53 +06:00
self . pidnums = Tkinter . StringVar ( )
self . pidinfo = Tkinter . Entry ( body , width = 50 , textvariable = self . pidnums )
if ' pids ' in self . prefs_array :
self . pidnums . set ( self . prefs_array [ ' pids ' ] )
2015-03-24 13:04:06 +06:00
self . pidinfo . grid ( row = cur_row , column = 1 , sticky = sticky )
2011-01-17 13:24:53 +06:00
2015-03-24 13:04:06 +06:00
cur_row = cur_row + 1
Tkinter . Label ( body , text = ' eInk Kindle Serial Number list \n (16 characters, comma separated) ' ) . grid ( row = cur_row , sticky = Tkconstants . E )
2011-01-17 13:24:53 +06:00
self . sernums = Tkinter . StringVar ( )
self . serinfo = Tkinter . Entry ( body , width = 50 , textvariable = self . sernums )
if ' serials ' in self . prefs_array :
self . sernums . set ( self . prefs_array [ ' serials ' ] )
2015-03-24 13:04:06 +06:00
self . serinfo . grid ( row = cur_row , column = 1 , sticky = sticky )
2011-01-17 13:24:53 +06:00
2015-03-24 13:04:06 +06:00
cur_row = cur_row + 1
Tkinter . Label ( body , text = ' eReader data list \n (name:last 8 digits on credit card, comma separated) ' ) . grid ( row = cur_row , sticky = Tkconstants . E )
2011-01-17 13:24:53 +06:00
self . sdrmnums = Tkinter . StringVar ( )
self . sdrminfo = Tkinter . Entry ( body , width = 50 , textvariable = self . sdrmnums )
if ' sdrms ' in self . prefs_array :
self . sdrmnums . set ( self . prefs_array [ ' sdrms ' ] )
2015-03-24 13:04:06 +06:00
self . sdrminfo . grid ( row = cur_row , column = 1 , sticky = sticky )
2011-01-17 13:24:53 +06:00
2015-03-24 13:04:06 +06:00
cur_row = cur_row + 1
Tkinter . Label ( body , text = " Output Folder (if blank, use input ebook ' s folder) " ) . grid ( row = cur_row , sticky = Tkconstants . E )
2011-01-17 13:24:53 +06:00
self . outpath = Tkinter . Entry ( body , width = 50 )
2015-03-24 13:04:06 +06:00
self . outpath . grid ( row = cur_row , column = 1 , sticky = sticky )
2011-01-17 13:24:53 +06:00
if ' outdir ' in self . prefs_array :
dpath = self . prefs_array [ ' outdir ' ]
self . outpath . insert ( 0 , dpath )
button = Tkinter . Button ( body , text = " ... " , command = self . get_outpath )
2015-03-24 13:04:06 +06:00
button . grid ( row = cur_row , column = 2 )
2011-01-17 13:24:53 +06:00
2015-03-24 13:04:06 +06:00
cur_row = cur_row + 1
Tkinter . Label ( body , text = ' ' ) . grid ( row = cur_row , column = 0 , columnspan = 2 , sticky = Tkconstants . N )
2011-01-17 13:24:53 +06:00
2015-03-24 13:04:06 +06:00
cur_row = cur_row + 1
Tkinter . Label ( body , text = ' Alternatively Process an eBook ' ) . grid ( row = cur_row , column = 0 , columnspan = 2 , sticky = Tkconstants . N )
2011-01-17 13:24:53 +06:00
2015-03-24 13:04:06 +06:00
cur_row = cur_row + 1
Tkinter . Label ( body , text = ' Select an eBook to Process* ' ) . grid ( row = cur_row , sticky = Tkconstants . E )
2011-01-17 13:24:53 +06:00
self . bookpath = Tkinter . Entry ( body , width = 50 )
2015-03-24 13:04:06 +06:00
self . bookpath . grid ( row = cur_row , column = 1 , sticky = sticky )
2011-01-17 13:24:53 +06:00
button = Tkinter . Button ( body , text = " ... " , command = self . get_bookpath )
2015-03-24 13:04:06 +06:00
button . grid ( row = cur_row , column = 2 )
2012-03-07 00:24:28 +06:00
2015-03-24 13:04:06 +06:00
cur_row = cur_row + 1
Tkinter . Label ( body , font = ( " Helvetica " , " 10 " , " italic " ) , text = ' *To DeDRM multiple ebooks simultaneously, set your preferences and quit. \n Then drag and drop ebooks or folders onto the DeDRM_Drop_Target ' ) . grid ( row = cur_row , column = 1 , sticky = Tkconstants . E )
2011-01-17 13:24:53 +06:00
2015-03-24 13:04:06 +06:00
cur_row = cur_row + 1
Tkinter . Label ( body , text = ' ' ) . grid ( row = cur_row , column = 0 , columnspan = 2 , sticky = Tkconstants . E )
2011-01-17 13:24:53 +06:00
buttons = Tkinter . Frame ( self )
buttons . pack ( )
self . sbotton = Tkinter . Button ( buttons , text = " Set Prefs " , width = 14 , command = self . setprefs )
self . sbotton . pack ( side = Tkconstants . LEFT )
buttons . pack ( )
self . pbotton = Tkinter . Button ( buttons , text = " Process eBook " , width = 14 , command = self . doit )
self . pbotton . pack ( side = Tkconstants . LEFT )
buttons . pack ( )
self . qbotton = Tkinter . Button ( buttons , text = " Quit " , width = 14 , command = self . quitting )
self . qbotton . pack ( side = Tkconstants . RIGHT )
buttons . pack ( )
def disablebuttons ( self ) :
self . sbotton . configure ( state = ' disabled ' )
self . pbotton . configure ( state = ' disabled ' )
self . qbotton . configure ( state = ' disabled ' )
def enablebuttons ( self ) :
self . sbotton . configure ( state = ' normal ' )
self . pbotton . configure ( state = ' normal ' )
self . qbotton . configure ( state = ' normal ' )
def show ( self ) :
self . deiconify ( )
self . tkraise ( )
def hide ( self ) :
self . withdraw ( )
def get_outpath ( self ) :
cpath = self . outpath . get ( )
2013-03-20 16:23:54 +06:00
if sys . platform . startswith ( " win " ) :
# tk_chooseDirectory is horribly broken for unicode paths
# on windows - bug has been reported but not fixed for years
# workaround by using our own unicode aware version
outpath = AskFolder ( message = " Choose the folder for DRM-free ebooks " ,
defaultLocation = cpath )
else :
outpath = tkFileDialog . askdirectory (
parent = None , title = ' Choose the folder for DRM-free ebooks ' ,
initialdir = cpath , initialfile = None )
2011-01-17 13:24:53 +06:00
if outpath :
outpath = os . path . normpath ( outpath )
self . outpath . delete ( 0 , Tkconstants . END )
self . outpath . insert ( 0 , outpath )
return
def get_adkpath ( self ) :
cpath = self . adkpath . get ( )
adkpath = tkFileDialog . askopenfilename ( initialdir = cpath , parent = None , title = ' Select Adept Key file ' ,
defaultextension = ' .der ' , filetypes = [ ( ' Adept Key file ' , ' .der ' ) , ( ' All Files ' , ' .* ' ) ] )
if adkpath :
adkpath = os . path . normpath ( adkpath )
self . adkpath . delete ( 0 , Tkconstants . END )
self . adkpath . insert ( 0 , adkpath )
return
2013-03-20 16:23:54 +06:00
def get_kkpath ( self ) :
cpath = self . kkpath . get ( )
kkpath = tkFileDialog . askopenfilename ( initialdir = cpath , parent = None , title = ' Select Kindle Key file ' ,
defaultextension = ' .k4i ' , filetypes = [ ( ' Kindle Key file ' , ' .k4i ' ) , ( ' All Files ' , ' .* ' ) ] )
if kkpath :
kkpath = os . path . normpath ( kkpath )
self . kkpath . delete ( 0 , Tkconstants . END )
self . kkpath . insert ( 0 , kkpath )
return
2015-03-24 13:04:06 +06:00
def get_akkpath ( self ) :
2015-07-29 23:11:19 +06:00
cpath = self . akkpath . get ( )
akkpath = tkFileDialog . askopenfilename ( initialdir = cpath , parent = None , title = ' Select Android for Kindle backup file ' ,
2015-03-24 13:04:06 +06:00
defaultextension = ' .ab ' , filetypes = [ ( ' Kindle for Android backup file ' , ' .ab ' ) , ( ' All Files ' , ' .* ' ) ] )
2015-07-29 23:11:19 +06:00
if akkpath :
akkpath = os . path . normpath ( akkpath )
self . akkpath . delete ( 0 , Tkconstants . END )
self . akkpath . insert ( 0 , akkpath )
2015-03-24 13:04:06 +06:00
return
2011-01-17 13:24:53 +06:00
def get_bnkpath ( self ) :
cpath = self . bnkpath . get ( )
bnkpath = tkFileDialog . askopenfilename ( initialdir = cpath , parent = None , title = ' Select Barnes and Noble Key file ' ,
defaultextension = ' .b64 ' , filetypes = [ ( ' Barnes and Noble Key file ' , ' .b64 ' ) , ( ' All Files ' , ' .* ' ) ] )
if bnkpath :
bnkpath = os . path . normpath ( bnkpath )
self . bnkpath . delete ( 0 , Tkconstants . END )
self . bnkpath . insert ( 0 , bnkpath )
return
def get_bookpath ( self ) :
cpath = self . bookpath . get ( )
bookpath = tkFileDialog . askopenfilename ( parent = None , title = ' Select eBook for DRM Removal ' ,
2013-02-04 20:25:25 +06:00
filetypes = [ ( ' All Files ' , ' .* ' ) ,
( ' ePub Files ' , ' .epub ' ) ,
( ' Kindle ' , ' .azw ' ) ,
( ' Kindle ' , ' .azw1 ' ) ,
( ' Kindle ' , ' .azw3 ' ) ,
( ' Kindle ' , ' .azw4 ' ) ,
( ' Kindle ' , ' .tpz ' ) ,
( ' Kindle ' , ' .mobi ' ) ,
( ' Kindle ' , ' .prc ' ) ,
( ' eReader ' , ' .pdb ' ) ,
( ' PDF ' , ' .pdf ' ) ] ,
2011-01-17 13:24:53 +06:00
initialdir = cpath )
if bookpath :
bookpath = os . path . normpath ( bookpath )
self . bookpath . delete ( 0 , Tkconstants . END )
self . bookpath . insert ( 0 , bookpath )
return
def quitting ( self ) :
self . master . destroy ( )
def setprefs ( self ) :
# setting new prefereces
new_prefs = { }
prefdir = self . prefs_array [ ' dir ' ]
new_prefs [ ' dir ' ] = prefdir
2012-11-07 19:14:25 +06:00
new_prefs [ ' pids ' ] = self . pidinfo . get ( ) . replace ( " " , " " )
new_prefs [ ' serials ' ] = self . serinfo . get ( ) . replace ( " " , " " )
new_prefs [ ' sdrms ' ] = self . sdrminfo . get ( ) . strip ( ) . replace ( " , " , " , " )
2011-01-17 13:24:53 +06:00
new_prefs [ ' outdir ' ] = self . outpath . get ( ) . strip ( )
adkpath = self . adkpath . get ( )
if os . path . dirname ( adkpath ) != prefdir :
new_prefs [ ' adkfile ' ] = adkpath
bnkpath = self . bnkpath . get ( )
if os . path . dirname ( bnkpath ) != prefdir :
new_prefs [ ' bnkfile ' ] = bnkpath
2013-03-20 16:23:54 +06:00
kkpath = self . kkpath . get ( )
if os . path . dirname ( kkpath ) != prefdir :
new_prefs [ ' kindlefile ' ] = kkpath
2015-07-29 23:11:19 +06:00
akkpath = self . akkpath . get ( )
if os . path . dirname ( akkpath ) != prefdir :
new_prefs [ ' androidfile ' ] = akkpath
2011-01-17 13:24:53 +06:00
self . master . setPreferences ( new_prefs )
2013-03-20 16:23:54 +06:00
# and update internal copies
self . prefs_array [ ' pids ' ] = new_prefs [ ' pids ' ]
self . prefs_array [ ' serials ' ] = new_prefs [ ' serials ' ]
self . prefs_array [ ' sdrms ' ] = new_prefs [ ' sdrms ' ]
self . prefs_array [ ' outdir ' ] = new_prefs [ ' outdir ' ]
2011-01-17 13:24:53 +06:00
def doit ( self ) :
self . disablebuttons ( )
filenames = [ ]
bookpath = self . bookpath . get ( )
bookpath = os . path . abspath ( bookpath )
filenames . append ( bookpath )
self . master . cd . doit ( self . prefs_array , filenames )
class ConvDialog ( Toplevel ) :
def __init__ ( self , master , prefs_array = { } , filenames = [ ] ) :
Toplevel . __init__ ( self , master )
self . withdraw ( )
self . protocol ( " WM_DELETE_WINDOW " , self . withdraw )
self . title ( " DeDRM Processing " )
self . master = master
2011-02-02 20:41:15 +06:00
self . apphome = self . master . apphome
2011-01-17 13:24:53 +06:00
self . prefs_array = prefs_array
self . filenames = filenames
self . interval = 50
self . p2 = None
2013-01-19 20:50:57 +06:00
self . q = Queue ( )
2011-01-17 13:24:53 +06:00
self . running = ' inactive '
self . numgood = 0
self . numbad = 0
self . status = Tkinter . Label ( self , text = ' DeDRM processing... ' )
self . status . pack ( fill = Tkconstants . X , expand = 1 )
body = Tkinter . Frame ( self )
body . pack ( fill = Tkconstants . X , expand = 1 )
sticky = Tkconstants . E + Tkconstants . W
body . grid_columnconfigure ( 1 , weight = 2 )
Tkinter . Label ( body , text = ' Activity Bar ' ) . grid ( row = 0 , sticky = Tkconstants . E )
2011-02-02 20:41:15 +06:00
self . bar = ActivityBar ( body , length = 80 , height = 15 , barwidth = 5 )
2011-01-17 13:24:53 +06:00
self . bar . grid ( row = 0 , column = 1 , sticky = sticky )
msg1 = ' '
2011-02-02 20:41:15 +06:00
self . stext = ScrolledText ( body , bd = 5 , relief = Tkconstants . RIDGE , height = 4 , width = 80 , wrap = Tkconstants . WORD )
2011-01-17 13:24:53 +06:00
self . stext . grid ( row = 2 , column = 0 , columnspan = 2 , sticky = sticky )
self . stext . insert ( Tkconstants . END , msg1 )
buttons = Tkinter . Frame ( self )
buttons . pack ( )
self . qbutton = Tkinter . Button ( buttons , text = " Quit " , width = 14 , command = self . quitting )
self . qbutton . pack ( side = Tkconstants . BOTTOM )
self . status [ ' text ' ] = ' '
2013-03-26 22:38:18 +06:00
self . logfile = open ( os . path . join ( os . path . expanduser ( ' ~ ' ) , ' DeDRM.log ' ) , ' w ' )
2011-01-17 13:24:53 +06:00
def show ( self ) :
self . deiconify ( )
self . tkraise ( )
def hide ( self ) :
self . withdraw ( )
def doit ( self , prefs , filenames ) :
self . running = ' inactive '
self . prefs_array = prefs
self . filenames = filenames
self . show ( )
self . processBooks ( )
def conversion_done ( self ) :
self . hide ( )
self . master . alldone ( )
2012-03-07 00:24:28 +06:00
2011-01-17 13:24:53 +06:00
def processBooks ( self ) :
while self . running == ' inactive ' :
rscpath = self . prefs_array [ ' dir ' ]
filename = None
if len ( self . filenames ) > 0 :
filename = self . filenames . pop ( 0 )
if filename == None :
2013-03-26 22:38:18 +06:00
msg = ' Complete: '
2013-01-19 20:50:57 +06:00
msg + = ' Successes: %d , ' % self . numgood
msg + = ' Failures: %d \n ' % self . numbad
2011-01-17 13:24:53 +06:00
self . showCmdOutput ( msg )
if self . numbad == 0 :
self . after ( 2000 , self . conversion_done ( ) )
2013-03-26 22:38:18 +06:00
self . logfile . write ( " DeDRM v {0} : {1} " . format ( __version__ , msg ) )
self . logfile . close ( )
2011-01-17 13:24:53 +06:00
return
infile = filename
bname = os . path . basename ( infile )
2013-03-26 22:38:18 +06:00
msg = ' Processing: ' + bname + ' ... '
self . logfile . write ( " DeDRM v {0} : {1} \n " . format ( __version__ , msg ) )
2011-01-17 13:24:53 +06:00
self . showCmdOutput ( msg )
outdir = os . path . dirname ( filename )
if ' outdir ' in self . prefs_array :
dpath = self . prefs_array [ ' outdir ' ]
if dpath . strip ( ) != ' ' :
outdir = dpath
rv = self . decrypt_ebook ( infile , outdir , rscpath )
if rv == 0 :
self . bar . start ( )
self . running = ' active '
2013-01-19 20:50:57 +06:00
self . processQueue ( )
2011-01-17 13:24:53 +06:00
else :
2013-01-19 20:50:57 +06:00
msg = ' Unknown File: ' + bname + ' \n '
2013-03-26 22:38:18 +06:00
self . logfile . write ( " DeDRM v {0} : {1} " . format ( __version__ , msg ) )
2011-01-17 13:24:53 +06:00
self . showCmdOutput ( msg )
self . numbad + = 1
def quitting ( self ) :
# kill any still running subprocess
self . running = ' stopped '
if self . p2 != None :
2013-01-19 20:50:57 +06:00
if ( self . p2 . exitcode == None ) :
2011-01-17 13:24:53 +06:00
self . p2 . terminate ( )
self . conversion_done ( )
# post output from subprocess in scrolled text widget
def showCmdOutput ( self , msg ) :
if msg and msg != ' ' :
if sys . platform . startswith ( ' win ' ) :
msg = msg . replace ( ' \r \n ' , ' \n ' )
self . stext . insert ( Tkconstants . END , msg )
self . stext . yview_pickplace ( Tkconstants . END )
return
# read from subprocess pipe without blocking
# invoked every interval via the widget "after"
# option being used, so need to reset it for the next time
2013-01-19 20:50:57 +06:00
def processQueue ( self ) :
2011-01-17 13:24:53 +06:00
if self . p2 == None :
# nothing to wait for so just return
return
2013-01-19 20:50:57 +06:00
poll = self . p2 . exitcode
2013-03-26 22:38:18 +06:00
#print "processing", poll
done = False
text = ' '
while not done :
try :
data = self . q . get_nowait ( )
text + = data
except Empty :
done = True
if text != ' ' :
self . logfile . write ( text )
2012-03-07 00:24:28 +06:00
if poll != None :
2011-01-17 13:24:53 +06:00
self . bar . stop ( )
if poll == 0 :
2013-01-19 20:50:57 +06:00
msg = ' Success \n '
2011-01-17 13:24:53 +06:00
self . numgood + = 1
2013-03-20 16:23:54 +06:00
else :
2013-01-19 20:50:57 +06:00
msg = ' Failed \n '
self . numbad + = 1
self . p2 . join ( )
2013-03-26 22:38:18 +06:00
self . logfile . write ( " DeDRM v {0} : {1} \n " . format ( __version__ , msg ) )
2011-01-17 13:24:53 +06:00
self . showCmdOutput ( msg )
self . p2 = None
self . running = ' inactive '
self . after ( 50 , self . processBooks )
return
2012-03-07 00:24:28 +06:00
# make sure we get invoked again by event loop after interval
2013-01-19 20:50:57 +06:00
self . stext . after ( self . interval , self . processQueue )
2011-01-17 13:24:53 +06:00
return
def decrypt_ebook ( self , infile , outdir , rscpath ) :
2013-01-19 20:50:57 +06:00
q = self . q
2011-01-17 13:24:53 +06:00
rv = 1
name , ext = os . path . splitext ( os . path . basename ( infile ) )
ext = ext . lower ( )
if ext == ' .epub ' :
2013-01-19 20:50:57 +06:00
self . p2 = Process ( target = processEPUB , args = ( q , infile , outdir , rscpath ) )
self . p2 . start ( )
2011-01-17 13:24:53 +06:00
return 0
if ext == ' .pdb ' :
2013-01-19 20:50:57 +06:00
self . p2 = Process ( target = processPDB , args = ( q , infile , outdir , rscpath ) )
self . p2 . start ( )
2011-01-17 13:24:53 +06:00
return 0
2015-03-25 13:26:33 +06:00
if ext in [ ' .azw ' , ' .azw1 ' , ' .azw3 ' , ' .azw4 ' , ' .prc ' , ' .mobi ' , ' .pobi ' , ' .tpz ' ] :
2013-01-19 20:50:57 +06:00
self . p2 = Process ( target = processK4MOBI , args = ( q , infile , outdir , rscpath ) )
self . p2 . start ( )
2011-01-17 13:24:53 +06:00
return 0
if ext == ' .pdf ' :
2013-01-19 20:50:57 +06:00
self . p2 = Process ( target = processPDF , args = ( q , infile , outdir , rscpath ) )
self . p2 . start ( )
2011-01-17 13:24:53 +06:00
return 0
return rv
2013-01-19 20:50:57 +06:00
# child process starts here
def processK4MOBI ( q , infile , outdir , rscpath ) :
add_cp65001_codec ( )
set_utf8_default_encoding ( )
2013-02-04 20:25:25 +06:00
sys . stdout = QueuedUTF8Stream ( sys . stdout , q )
sys . stderr = QueuedUTF8Stream ( sys . stderr , q )
2013-01-19 20:50:57 +06:00
rv = decryptk4mobi ( infile , outdir , rscpath )
sys . exit ( rv )
# child process starts here
def processPDF ( q , infile , outdir , rscpath ) :
add_cp65001_codec ( )
set_utf8_default_encoding ( )
2013-02-04 20:25:25 +06:00
sys . stdout = QueuedUTF8Stream ( sys . stdout , q )
sys . stderr = QueuedUTF8Stream ( sys . stderr , q )
2013-01-19 20:50:57 +06:00
rv = decryptpdf ( infile , outdir , rscpath )
sys . exit ( rv )
# child process starts here
def processEPUB ( q , infile , outdir , rscpath ) :
add_cp65001_codec ( )
set_utf8_default_encoding ( )
2013-02-04 20:25:25 +06:00
sys . stdout = QueuedUTF8Stream ( sys . stdout , q )
sys . stderr = QueuedUTF8Stream ( sys . stderr , q )
2013-01-19 20:50:57 +06:00
rv = decryptepub ( infile , outdir , rscpath )
sys . exit ( rv )
# child process starts here
def processPDB ( q , infile , outdir , rscpath ) :
add_cp65001_codec ( )
set_utf8_default_encoding ( )
2013-02-04 20:25:25 +06:00
sys . stdout = QueuedUTF8Stream ( sys . stdout , q )
sys . stderr = QueuedUTF8Stream ( sys . stderr , q )
2013-01-19 20:50:57 +06:00
rv = decryptpdb ( infile , outdir , rscpath )
sys . exit ( rv )
2013-03-26 22:38:18 +06:00
def main ( ) :
argv = unicode_argv ( )
2013-01-19 20:50:57 +06:00
apphome = os . path . dirname ( argv [ 0 ] )
2011-02-02 20:41:15 +06:00
apphome = os . path . abspath ( apphome )
2011-01-17 13:24:53 +06:00
# windows may pass a spurious quoted null string as argv[1] from bat file
# simply work around this until we can figure out a better way to handle things
2013-01-19 20:50:57 +06:00
if sys . platform . startswith ( ' win ' ) and len ( argv ) == 2 :
2011-01-17 13:24:53 +06:00
temp = argv [ 1 ]
temp = temp . strip ( ' " ' )
temp = temp . strip ( )
if temp == ' ' :
argv . pop ( )
if len ( argv ) == 1 :
filenames = [ ]
dnd = False
else : # processing books via drag and drop
dnd = True
# build a list of the files to be processed
2013-01-19 20:50:57 +06:00
# note all filenames and paths have been utf-8 encoded
2011-01-17 13:24:53 +06:00
infilelst = argv [ 1 : ]
filenames = [ ]
for infile in infilelst :
infile = infile . replace ( ' " ' , ' ' )
infile = os . path . abspath ( infile )
if os . path . isdir ( infile ) :
bpath = infile
filelst = os . listdir ( infile )
for afile in filelst :
if not afile . startswith ( ' . ' ) :
filepath = os . path . join ( bpath , afile )
if os . path . isfile ( filepath ) :
filenames . append ( filepath )
else :
afile = os . path . basename ( infile )
if not afile . startswith ( ' . ' ) :
if os . path . isfile ( infile ) :
filenames . append ( infile )
# start up gui app
2011-02-02 20:41:15 +06:00
app = MainApp ( apphome , dnd , filenames )
2011-01-17 13:24:53 +06:00
app . mainloop ( )
return 0
if __name__ == " __main__ " :
sys . exit ( main ( ) )