You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DeDRM_tools/Kindle_Mobi_Tools/K4_Mobi_DeDRM_Combined_Tool/K4MobiDeDRM.pyw

242 lines
9.7 KiB
Python

#!/usr/bin/env python
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
import sys
sys.path.append('lib')
import os, os.path, urllib
import Tkinter
import Tkconstants
import tkFileDialog
import tkMessageBox
from scrolltextwidget import ScrolledText
import subprocess
from subprocess import Popen, PIPE, STDOUT
import subasyncio
from subasyncio import Process
class MainDialog(Tkinter.Frame):
def __init__(self, root):
Tkinter.Frame.__init__(self, root, border=5)
self.root = root
self.interval = 2000
self.p2 = None
self.status = Tkinter.Label(self, text='Remove Encryption from a K4PC, K4M, or Mobi eBook')
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='K4 or Mobi eBook input file').grid(row=0, sticky=Tkconstants.E)
self.mobipath = Tkinter.Entry(body, width=50)
self.mobipath.grid(row=0, column=1, sticky=sticky)
cwd = os.getcwdu()
cwd = cwd.encode('utf-8')
self.mobipath.insert(0, cwd)
button = Tkinter.Button(body, text="...", command=self.get_mobipath)
button.grid(row=0, column=2)
Tkinter.Label(body, text='Directory for the Unencrypted Output File').grid(row=1, sticky=Tkconstants.E)
self.outpath = Tkinter.Entry(body, width=50)
self.outpath.grid(row=1, column=1, sticky=sticky)
cwd = os.getcwdu()
cwd = cwd.encode('utf-8')
outname = cwd
self.outpath.insert(0, outname)
button = Tkinter.Button(body, text="...", command=self.get_outpath)
button.grid(row=1, column=2)
Tkinter.Label(body, text='Kindle.info file (optional)').grid(row=2, sticky=Tkconstants.E)
self.altinfopath = Tkinter.Entry(body, width=50)
self.altinfopath.grid(row=2, column=1, sticky=sticky)
#cwd = os.getcwdu()
#cwd = cwd.encode('utf-8')
#self.altinfopath.insert(0, cwd)
button = Tkinter.Button(body, text="...", command=self.get_altinfopath)
button.grid(row=2, column=2)
Tkinter.Label(body, text='Comma Separated List of 10 Character PIDs (no spaces)').grid(row=3, sticky=Tkconstants.E)
self.pidnums = Tkinter.StringVar()
self.pidinfo = Tkinter.Entry(body, width=50, textvariable=self.pidnums)
self.pidinfo.grid(row=3, column=1, sticky=sticky)
msg1 = 'Conversion Log \n\n'
self.stext = ScrolledText(body, bd=5, relief=Tkconstants.RIDGE, height=15, width=60, wrap=Tkconstants.WORD)
self.stext.grid(row=4, column=0, columnspan=2,sticky=sticky)
self.stext.insert(Tkconstants.END,msg1)
buttons = Tkinter.Frame(self)
buttons.pack()
self.sbotton = Tkinter.Button(
buttons, text="Start", width=10, command=self.convertit)
self.sbotton.pack(side=Tkconstants.LEFT)
Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT)
self.qbutton = Tkinter.Button(
buttons, text="Quit", width=10, command=self.quitting)
self.qbutton.pack(side=Tkconstants.RIGHT)
# 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
def processPipe(self):
poll = self.p2.wait('nowait')
if poll != None:
text = self.p2.readerr()
text += self.p2.read()
msg = text + '\n\n' + 'Encryption successfully removed\n'
if poll == 1:
msg = text + '\n\n' + 'Error: Encryption Removal Failed\n'
if poll == 2:
msg = text + '\n\n' + 'Input File was Not Encrypted - No Output File Needed\n'
self.showCmdOutput(msg)
self.p2 = None
self.sbotton.configure(state='normal')
return
text = self.p2.readerr()
text += self.p2.read()
self.showCmdOutput(text)
# make sure we get invoked again by event loop after interval
self.stext.after(self.interval,self.processPipe)
return
# post output from subprocess in scrolled text widget
def showCmdOutput(self, msg):
if msg and msg !='':
msg = msg.encode('utf-8')
self.stext.insert(Tkconstants.END,msg)
self.stext.yview_pickplace(Tkconstants.END)
return
# run as a subprocess via pipes and collect stdout
def mobirdr(self, infile, outfile, altinfopath, pidnums):
# os.putenv('PYTHONUNBUFFERED', '1')
pidoption = ''
if pidnums and pidnums != '':
pidoption = ' -p "' + pidnums + '" '
infooption = ''
if altinfopath and altinfopath != '':
infooption = ' -k "' + altinfopath + '" '
cmdline = 'python ./lib/k4mobidedrm.py ' + pidoption + infooption + '"' + infile + '" "' + outfile + '"'
print cmdline
if sys.platform.startswith('win'):
search_path = os.environ['PATH']
search_path = search_path.lower()
if search_path.find('python') >= 0:
cmdline = 'python lib\k4mobidedrm.py ' + pidoption + infooption + '"' + infile + '" "' + outfile + '"'
else :
cmdline = 'lib\k4mobidedrm.py ' + pidoption + infooption + '"' + infile + '" "' + outfile + '"'
cmdline = cmdline.encode(sys.getfilesystemencoding())
p2 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=PIPE, stderr=PIPE, close_fds=False)
return p2
def get_mobipath(self):
cpath = self.mobipath.get()
mobipath = tkFileDialog.askopenfilename(
initialdir = cpath,
parent=None, title='Select K4PC, K4M or Mobi eBook File',
defaultextension='.prc', filetypes=[('Mobi eBook File', '.prc'), ('Mobi eBook File', '.azw'),('Mobi eBook File', '.mobi'),
('All Files', '.*')])
if mobipath:
mobipath = os.path.normpath(mobipath)
self.mobipath.delete(0, Tkconstants.END)
self.mobipath.insert(0, mobipath)
return
def get_outpath(self):
cwd = os.getcwdu()
cwd = cwd.encode('utf-8')
outpath = tkFileDialog.askdirectory(
parent=None, title='Directory to Store Unencrypted file into',
initialdir=cwd, initialfile=None)
if outpath:
outpath = os.path.normpath(outpath)
self.outpath.delete(0, Tkconstants.END)
self.outpath.insert(0, outpath)
return
def get_altinfopath(self):
cwd = os.getcwdu()
cwd = cwd.encode('utf-8')
altinfopath = tkFileDialog.askopenfilename(
parent=None, title='Select kindle.info File',
defaultextension='.prc', filetypes=[('Kindle Info', '.info'),
('All Files', '.*')],
initialdir=cwd)
if altinfopath:
altinfopath = os.path.normpath(altinfopath)
self.altinfopath.delete(0, Tkconstants.END)
self.altinfopath.insert(0, altinfopath)
return
def quitting(self):
# kill any still running subprocess
if self.p2 != None:
if (self.p2.wait('nowait') == None):
self.p2.terminate()
self.root.destroy()
# actually ready to run the subprocess and get its output
def convertit(self):
# now disable the button to prevent multiple launches
self.sbotton.configure(state='disabled')
mobipath = self.mobipath.get()
outpath = self.outpath.get()
altinfopath = self.altinfopath.get()
pidnums = self.pidinfo.get()
if not mobipath or not os.path.exists(mobipath):
self.status['text'] = 'Specified K4PC, K4M or Mobi eBook file does not exist'
self.sbotton.configure(state='normal')
return
if not outpath:
self.status['text'] = 'No output directory specified'
self.sbotton.configure(state='normal')
return
if not os.path.isdir(outpath):
self.status['text'] = 'Error specified output directory does not exist'
self.sbotton.configure(state='normal')
return
if altinfopath and not os.path.exists(altinfopath):
self.status['text'] = 'Specified kindle.info file does not exist'
self.sbotton.configure(state='normal')
return
# default output file name to be input file name + '_nodrm.mobi'
initname = os.path.splitext(os.path.basename(mobipath))[0]
initname += '_nodrm.mobi'
outpath += os.sep + initname
log = 'Command = "python k4mobidedrm.py"\n'
log += 'K4PC, K4M or Mobi Path = "'+ mobipath + '"\n'
log += 'Output File = "' + outpath + '"\n'
log += 'Kindle.info file = "' + altinfopath + '"\n'
log += 'PID list = "' + pidnums + '"\n'
log += '\n\n'
log += 'Please Wait ...\n\n'
log = log.encode('utf-8')
self.stext.insert(Tkconstants.END,log)
self.p2 = self.mobirdr(mobipath, outpath, altinfopath, pidnums)
# python does not seem to allow you to create
# your own eventloop which every other gui does - strange
# so need to use the widget "after" command to force
# event loop to run non-gui events every interval
self.stext.after(self.interval,self.processPipe)
return
def main(argv=None):
root = Tkinter.Tk()
root.title('K4PC/K4M/Mobi eBook Encryption Removal')
root.resizable(True, False)
root.minsize(300, 0)
MainDialog(root).pack(fill=Tkconstants.X, expand=1)
root.mainloop()
return 0
if __name__ == "__main__":
sys.exit(main())