Front-ends for the mobi tools, and tools updated to work as libraries to the front ends
This commit is contained in:
parent
d1d2bfcb1e
commit
a23dd40ecf
|
@ -0,0 +1,138 @@
|
||||||
|
#!/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 subprocess
|
||||||
|
from subprocess import Popen, PIPE, STDOUT
|
||||||
|
import subasyncio
|
||||||
|
from subasyncio import Process
|
||||||
|
import Tkinter
|
||||||
|
import Tkconstants
|
||||||
|
import tkFileDialog
|
||||||
|
import tkMessageBox
|
||||||
|
from scrolltextwidget import ScrolledText
|
||||||
|
|
||||||
|
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='Find your Kindle PID')
|
||||||
|
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='Kindle Serial # or iPhone UDID').grid(row=1, sticky=Tkconstants.E)
|
||||||
|
self.serialnum = Tkinter.StringVar()
|
||||||
|
self.serialinfo = Tkinter.Entry(body, width=45, textvariable=self.serialnum)
|
||||||
|
self.serialinfo.grid(row=1, 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=3, 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' + 'Kindle PID Successfully Determined\n'
|
||||||
|
if poll != 0:
|
||||||
|
msg = text + '\n\n' + 'Error: Kindle PID Failed\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 !='':
|
||||||
|
self.stext.insert(Tkconstants.END,msg)
|
||||||
|
self.stext.yview_pickplace(Tkconstants.END)
|
||||||
|
return
|
||||||
|
|
||||||
|
# run as a subprocess via pipes and collect stdout
|
||||||
|
def pidrdr(self, serial):
|
||||||
|
# os.putenv('PYTHONUNBUFFERED', '1')
|
||||||
|
cmdline = 'python ./lib/kindlepid.py "' + serial + '"'
|
||||||
|
if sys.platform[0:3] == 'win':
|
||||||
|
search_path = os.environ['PATH']
|
||||||
|
search_path = search_path.lower()
|
||||||
|
if search_path.find('python') >= 0:
|
||||||
|
cmdline = 'python lib\kindlepid.py "' + serial + '"'
|
||||||
|
else :
|
||||||
|
cmdline = 'lib\kindlepid.py "' + serial + '"'
|
||||||
|
|
||||||
|
p2 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=PIPE, stderr=PIPE, close_fds=False)
|
||||||
|
return p2
|
||||||
|
|
||||||
|
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')
|
||||||
|
serial = self.serialinfo.get()
|
||||||
|
if not serial or serial == '':
|
||||||
|
self.status['text'] = 'No Kindle Serial Number or iPhone UDID specified'
|
||||||
|
self.sbotton.configure(state='normal')
|
||||||
|
return
|
||||||
|
|
||||||
|
log = 'Command = "python kindlepid.py"\n'
|
||||||
|
log += 'Serial = "' + serial + '"\n'
|
||||||
|
log += '\n\n'
|
||||||
|
log += 'Please Wait ...\n\n'
|
||||||
|
self.stext.insert(Tkconstants.END,log)
|
||||||
|
self.p2 = self.pidrdr(serial)
|
||||||
|
|
||||||
|
# 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('Kindle and iPhone PID Calculator')
|
||||||
|
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())
|
|
@ -0,0 +1,163 @@
|
||||||
|
#!/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 subprocess
|
||||||
|
from subprocess import Popen, PIPE, STDOUT
|
||||||
|
import subasyncio
|
||||||
|
from subasyncio import Process
|
||||||
|
import Tkinter
|
||||||
|
import Tkconstants
|
||||||
|
import tkFileDialog
|
||||||
|
import tkMessageBox
|
||||||
|
from scrolltextwidget import ScrolledText
|
||||||
|
|
||||||
|
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='Fix Encrypted Mobi eBooks so the Kindle can read them')
|
||||||
|
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='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)
|
||||||
|
self.mobipath.insert(0, os.getcwd())
|
||||||
|
button = Tkinter.Button(body, text="...", command=self.get_mobipath)
|
||||||
|
button.grid(row=0, column=2)
|
||||||
|
|
||||||
|
Tkinter.Label(body, text='10 Character PID').grid(row=1, sticky=Tkconstants.E)
|
||||||
|
self.pidnum = Tkinter.StringVar()
|
||||||
|
self.pidinfo = Tkinter.Entry(body, width=12, textvariable=self.pidnum)
|
||||||
|
self.pidinfo.grid(row=1, 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=2, 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' + 'Fix for Kindle successful\n'
|
||||||
|
if poll != 0:
|
||||||
|
msg = text + '\n\n' + 'Error: Fix for Kindle Failed\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 !='':
|
||||||
|
self.stext.insert(Tkconstants.END,msg)
|
||||||
|
self.stext.yview_pickplace(Tkconstants.END)
|
||||||
|
return
|
||||||
|
|
||||||
|
# run as a subprocess via pipes and collect stdout
|
||||||
|
def krdr(self, infile, pidnum):
|
||||||
|
# os.putenv('PYTHONUNBUFFERED', '1')
|
||||||
|
cmdline = 'python ./lib/kindlefix.py "' + infile + '" "' + pidnum + '"'
|
||||||
|
if sys.platform[0:3] == 'win':
|
||||||
|
search_path = os.environ['PATH']
|
||||||
|
search_path = search_path.lower()
|
||||||
|
if search_path.find('python') >= 0:
|
||||||
|
cmdline = 'python lib\kindlefix.py "' + infile + '" "' + pidnum + '"'
|
||||||
|
else :
|
||||||
|
cmdline = 'lib\kindlefix.py "' + infile + '" "' + pidnum + '"'
|
||||||
|
|
||||||
|
p2 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=PIPE, stderr=PIPE, close_fds=False)
|
||||||
|
return p2
|
||||||
|
|
||||||
|
|
||||||
|
def get_mobipath(self):
|
||||||
|
mobipath = tkFileDialog.askopenfilename(
|
||||||
|
parent=None, title='Select Mobi eBook File',
|
||||||
|
defaultextension='.prc', filetypes=[('Mobi eBook File', '.prc'), ('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 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()
|
||||||
|
pidnum = self.pidinfo.get()
|
||||||
|
if not mobipath or not os.path.exists(mobipath):
|
||||||
|
self.status['text'] = 'Specified Mobi eBook file does not exist'
|
||||||
|
self.sbotton.configure(state='normal')
|
||||||
|
return
|
||||||
|
if not pidnum or pidnum == '':
|
||||||
|
self.status['text'] = 'No PID specified'
|
||||||
|
self.sbotton.configure(state='normal')
|
||||||
|
return
|
||||||
|
|
||||||
|
log = 'Command = "python kindlefix.py"\n'
|
||||||
|
log += 'Mobi Path = "'+ mobipath + '"\n'
|
||||||
|
log += 'PID = "' + pidnum + '"\n'
|
||||||
|
log += '\n\n'
|
||||||
|
log += 'Please Wait ...\n\n'
|
||||||
|
self.stext.insert(Tkconstants.END,log)
|
||||||
|
self.p2 = self.krdr(mobipath, pidnum)
|
||||||
|
|
||||||
|
# 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('Fix Encrypted Mobi eBooks to work with the Kindle')
|
||||||
|
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())
|
|
@ -0,0 +1,192 @@
|
||||||
|
#!/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 subprocess
|
||||||
|
from subprocess import Popen, PIPE, STDOUT
|
||||||
|
import subasyncio
|
||||||
|
from subasyncio import Process
|
||||||
|
import Tkinter
|
||||||
|
import Tkconstants
|
||||||
|
import tkFileDialog
|
||||||
|
import tkMessageBox
|
||||||
|
from scrolltextwidget import ScrolledText
|
||||||
|
|
||||||
|
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 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='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)
|
||||||
|
self.mobipath.insert(0, os.getcwd())
|
||||||
|
button = Tkinter.Button(body, text="...", command=self.get_mobipath)
|
||||||
|
button.grid(row=0, column=2)
|
||||||
|
|
||||||
|
Tkinter.Label(body, text='Name for 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)
|
||||||
|
self.outpath.insert(0, '')
|
||||||
|
button = Tkinter.Button(body, text="...", command=self.get_outpath)
|
||||||
|
button.grid(row=1, column=2)
|
||||||
|
|
||||||
|
Tkinter.Label(body, text='10 Character PID').grid(row=2, sticky=Tkconstants.E)
|
||||||
|
self.pidnum = Tkinter.StringVar()
|
||||||
|
self.pidinfo = Tkinter.Entry(body, width=12, textvariable=self.pidnum)
|
||||||
|
self.pidinfo.grid(row=2, 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=3, 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 != 0:
|
||||||
|
msg = text + '\n\n' + 'Error: Encryption Removal Failed\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 !='':
|
||||||
|
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, pidnum):
|
||||||
|
# os.putenv('PYTHONUNBUFFERED', '1')
|
||||||
|
cmdline = 'python ./lib/mobidedrm.py "' + infile + '" "' + outfile + '" "' + pidnum + '"'
|
||||||
|
if sys.platform[0:3] == 'win':
|
||||||
|
search_path = os.environ['PATH']
|
||||||
|
search_path = search_path.lower()
|
||||||
|
if search_path.find('python') >= 0:
|
||||||
|
cmdline = 'python lib\mobidedrm.py "' + infile + '" "' + outfile + '" "' + pidnum + '"'
|
||||||
|
else :
|
||||||
|
cmdline = 'lib\mobidedrm.py "' + infile + '" "' + outfile + '" "' + pidnum + '"'
|
||||||
|
|
||||||
|
p2 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=PIPE, stderr=PIPE, close_fds=False)
|
||||||
|
return p2
|
||||||
|
|
||||||
|
|
||||||
|
def get_mobipath(self):
|
||||||
|
mobipath = tkFileDialog.askopenfilename(
|
||||||
|
parent=None, title='Select Mobi eBook File',
|
||||||
|
defaultextension='.prc', filetypes=[('Mobi eBook File', '.prc'), ('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):
|
||||||
|
mobipath = self.mobipath.get()
|
||||||
|
initname = os.path.basename(mobipath)
|
||||||
|
p = initname.find('.')
|
||||||
|
if p >= 0: initname = initname[0:p]
|
||||||
|
initname += '_nodrm.mobi'
|
||||||
|
outpath = tkFileDialog.asksaveasfilename(
|
||||||
|
parent=None, title='Select Unencrypted Mobi File to produce',
|
||||||
|
defaultextension='.mobi', initialfile=initname,
|
||||||
|
filetypes=[('Mobi files', '.mobi'), ('All files', '.*')])
|
||||||
|
if outpath:
|
||||||
|
outpath = os.path.normpath(outpath)
|
||||||
|
self.outpath.delete(0, Tkconstants.END)
|
||||||
|
self.outpath.insert(0, outpath)
|
||||||
|
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()
|
||||||
|
pidnum = self.pidinfo.get()
|
||||||
|
if not mobipath or not os.path.exists(mobipath):
|
||||||
|
self.status['text'] = 'Specified Mobi eBook file does not exist'
|
||||||
|
self.sbotton.configure(state='normal')
|
||||||
|
return
|
||||||
|
if not outpath:
|
||||||
|
self.status['text'] = 'No output file specified'
|
||||||
|
self.sbotton.configure(state='normal')
|
||||||
|
return
|
||||||
|
if not pidnum or pidnum == '':
|
||||||
|
self.status['text'] = 'No PID specified'
|
||||||
|
self.sbotton.configure(state='normal')
|
||||||
|
return
|
||||||
|
|
||||||
|
log = 'Command = "python mobidedrm.py"\n'
|
||||||
|
log += 'Mobi Path = "'+ mobipath + '"\n'
|
||||||
|
log += 'Output File = "' + outpath + '"\n'
|
||||||
|
log += 'PID = "' + pidnum + '"\n'
|
||||||
|
log += '\n\n'
|
||||||
|
log += 'Please Wait ...\n\n'
|
||||||
|
self.stext.insert(Tkconstants.END,log)
|
||||||
|
self.p2 = self.mobirdr(mobipath, outpath, pidnum)
|
||||||
|
|
||||||
|
# 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('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())
|
|
@ -1,16 +1,17 @@
|
||||||
#!/usr/bin/python
|
class Unbuffered:
|
||||||
# The Kindleizer v0.2. Copyright (c) 2007, 2009 Igor Skochinsky <skochinsky@mail.ru>
|
def __init__(self, stream):
|
||||||
# This script enables encrypted Mobipocket books to be readable by Kindle
|
self.stream = stream
|
||||||
# History:
|
def write(self, data):
|
||||||
# 0.1 initial release
|
self.stream.write(data)
|
||||||
# 0.2 fixed corrupted metadata issue (thanks to Mark Peek)
|
self.stream.flush()
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
return getattr(self.stream, attr)
|
||||||
|
|
||||||
import prc, sys, struct
|
import sys
|
||||||
|
sys.stdout=Unbuffered(sys.stdout)
|
||||||
|
|
||||||
if sys.hexversion >= 0x3000000:
|
|
||||||
print "This script is incompatible with Python 3.x. Please install Python 2.6.x from python.org"
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
|
import prc, struct
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
|
|
||||||
def strByte(s,off=0):
|
def strByte(s,off=0):
|
||||||
|
@ -104,7 +105,7 @@ def find_key(rec0, pid):
|
||||||
drmInfo = strPutDWord(drmInfo,4,(dw4|0x800))
|
drmInfo = strPutDWord(drmInfo,4,(dw4|0x800))
|
||||||
dw0, dw4, dw18, dw1c = struct.unpack(">II16xII", drmInfo)
|
dw0, dw4, dw18, dw1c = struct.unpack(">II16xII", drmInfo)
|
||||||
#print "Updated drmInfo:", "%08X, %08X, %s, %08X, %08X"%(dw0, dw4, hexlify(drmInfo[0x8:0x18]), dw18, dw1c)
|
#print "Updated drmInfo:", "%08X, %08X, %s, %08X, %08X"%(dw0, dw4, hexlify(drmInfo[0x8:0x18]), dw18, dw1c)
|
||||||
return rec0[:iOff+0x10] + PC1(temp_key, drmInfo, False) + rec0[iOff+0x30:]
|
return rec0[:iOff+0x10] + PC1(temp_key, drmInfo, False) + rec0[:iOff+0x30]
|
||||||
iOff += dwSize
|
iOff += dwSize
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -115,7 +116,14 @@ def replaceext(filename, newext):
|
||||||
else:
|
else:
|
||||||
return nameparts[0]+newext
|
return nameparts[0]+newext
|
||||||
|
|
||||||
def main(fname, pid):
|
def main(argv=sys.argv):
|
||||||
|
print "The Kindleizer v0.2. Copyright (c) 2007 Igor Skochinsky"
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print "Fixes encrypted Mobipocket books to be readable by Kindle"
|
||||||
|
print "Usage: kindlefix.py file.mobi PID"
|
||||||
|
return 1
|
||||||
|
fname = sys.argv[1]
|
||||||
|
pid = sys.argv[2]
|
||||||
if len(pid)==10 and pid[-3]=='*':
|
if len(pid)==10 and pid[-3]=='*':
|
||||||
pid = pid[:-2]
|
pid = pid[:-2]
|
||||||
if len(pid)!=8 or pid[-1]!='*':
|
if len(pid)!=8 or pid[-1]!='*':
|
||||||
|
@ -159,10 +167,6 @@ def main(fname, pid):
|
||||||
print "Output written to "+outfname
|
print "Output written to "+outfname
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
print "The Kindleizer v0.2. Copyright (c) 2007, 2009 Igor Skochinsky"
|
|
||||||
if len(sys.argv)<3:
|
if __name__ == "__main__":
|
||||||
print "Fixes encrypted Mobipocket books to be readable by Kindle"
|
sys.exit(main())
|
||||||
print "Usage: kindlefix.py file.mobi PID"
|
|
||||||
else:
|
|
||||||
fname = sys.argv[1]
|
|
||||||
sys.exit(main(fname, sys.argv[2]))
|
|
||||||
|
|
|
@ -4,9 +4,20 @@
|
||||||
# History:
|
# History:
|
||||||
# 0.1 Initial release
|
# 0.1 Initial release
|
||||||
# 0.2 Added support for generating PID for iPhone (thanks to mbp)
|
# 0.2 Added support for generating PID for iPhone (thanks to mbp)
|
||||||
# Unofficial: Added support for Kindle DX and Kindle 2 International
|
# 0.3 changed to autoflush stdout, fixed return code usage
|
||||||
|
class Unbuffered:
|
||||||
|
def __init__(self, stream):
|
||||||
|
self.stream = stream
|
||||||
|
def write(self, data):
|
||||||
|
self.stream.write(data)
|
||||||
|
self.stream.flush()
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
return getattr(self.stream, attr)
|
||||||
|
|
||||||
import sys, binascii
|
import sys
|
||||||
|
sys.stdout=Unbuffered(sys.stdout)
|
||||||
|
|
||||||
|
import binascii
|
||||||
|
|
||||||
if sys.hexversion >= 0x3000000:
|
if sys.hexversion >= 0x3000000:
|
||||||
print "This script is incompatible with Python 3.x. Please install Python 2.6.x from python.org"
|
print "This script is incompatible with Python 3.x. Please install Python 2.6.x from python.org"
|
||||||
|
@ -49,29 +60,38 @@ def pidFromSerial(s, l):
|
||||||
|
|
||||||
return pid
|
return pid
|
||||||
|
|
||||||
print "Mobipocket PID calculator for Amazon Kindle. Copyright (c) 2007, 2009 Igor Skochinsky"
|
def main(argv=sys.argv):
|
||||||
if len(sys.argv)>1:
|
print "Mobipocket PID calculator for Amazon Kindle. Copyright (c) 2007, 2009 Igor Skochinsky"
|
||||||
serial = sys.argv[1]
|
if len(sys.argv)==2:
|
||||||
if len(serial)==16:
|
serial = sys.argv[1]
|
||||||
if serial.startswith("B001"):
|
|
||||||
print "Kindle 1 serial number detected"
|
|
||||||
elif serial.startswith("B002"):
|
|
||||||
print "Kindle 2 serial number detected"
|
|
||||||
elif serial.startswith("B003"):
|
|
||||||
print "Kindle 2i serial number detected"
|
|
||||||
elif serial.startswith("B004"):
|
|
||||||
print "Kindle DX serial number detected"
|
|
||||||
else:
|
|
||||||
print "Warning: unrecognized serial number. Please recheck input."
|
|
||||||
sys.exit(1)
|
|
||||||
pid = pidFromSerial(serial,7)+"*"
|
|
||||||
print "Mobipocked PID for Kindle serial# "+serial+" is "+checksumPid(pid)
|
|
||||||
elif len(serial)==40:
|
|
||||||
print "iPhone serial number (UDID) detected"
|
|
||||||
pid = pidFromSerial(serial,8)
|
|
||||||
print "Mobipocked PID for iPhone serial# "+serial+" is "+checksumPid(pid)
|
|
||||||
else:
|
else:
|
||||||
print "Warning: unrecognized serial number. Please recheck input."
|
print "Usage: kindlepid.py <Kindle Serial Number>/<iPhone/iPod Touch UDID>"
|
||||||
sys.exit(1)
|
return 1
|
||||||
else:
|
if len(serial)==16:
|
||||||
print "Usage: kindlepid.py <Kindle Serial Number>/<iPhone/iPod Touch UDID>"
|
if serial.startswith("B001"):
|
||||||
|
print "Kindle 1 serial number detected"
|
||||||
|
elif serial.startswith("B002"):
|
||||||
|
print "Kindle 2 serial number detected"
|
||||||
|
elif serial.startswith("B003"):
|
||||||
|
print "Kindle 2 Global serial number detected"
|
||||||
|
elif serial.startswith("B004"):
|
||||||
|
print "Kindle DX serial number detected"
|
||||||
|
else:
|
||||||
|
print "Warning: unrecognized serial number. Please recheck input."
|
||||||
|
return 1
|
||||||
|
pid = pidFromSerial(serial,7)+"*"
|
||||||
|
print "Mobipocked PID for Kindle serial# "+serial+" is "+checksumPid(pid)
|
||||||
|
return 0
|
||||||
|
elif len(serial)==40:
|
||||||
|
print "iPhone serial number (UDID) detected"
|
||||||
|
pid = pidFromSerial(serial,8)
|
||||||
|
print "Mobipocked PID for iPhone serial# "+serial+" is "+checksumPid(pid)
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print "Warning: unrecognized serial number. Please recheck input."
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
|
|
|
@ -21,8 +21,21 @@
|
||||||
# 0.07 - The extra data flags aren't present in MOBI header < 0xE8 in size
|
# 0.07 - The extra data flags aren't present in MOBI header < 0xE8 in size
|
||||||
# 0.08 - ...and also not in Mobi header version < 6
|
# 0.08 - ...and also not in Mobi header version < 6
|
||||||
# 0.09 - ...but they are there with Mobi header version 6, header size 0xE4!
|
# 0.09 - ...but they are there with Mobi header version 6, header size 0xE4!
|
||||||
|
# 0.10 - use autoflushed stdout and proper return values
|
||||||
|
|
||||||
import sys,struct,binascii
|
class Unbuffered:
|
||||||
|
def __init__(self, stream):
|
||||||
|
self.stream = stream
|
||||||
|
def write(self, data):
|
||||||
|
self.stream.write(data)
|
||||||
|
self.stream.flush()
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
return getattr(self.stream, attr)
|
||||||
|
|
||||||
|
import sys
|
||||||
|
sys.stdout=Unbuffered(sys.stdout)
|
||||||
|
|
||||||
|
import struct,binascii
|
||||||
|
|
||||||
class DrmException(Exception):
|
class DrmException(Exception):
|
||||||
pass
|
pass
|
||||||
|
@ -206,7 +219,7 @@ if not __name__ == "__main__":
|
||||||
description = 'Removes DRM from secure Mobi files'
|
description = 'Removes DRM from secure Mobi files'
|
||||||
supported_platforms = ['linux', 'osx', 'windows'] # Platforms this plugin will run on
|
supported_platforms = ['linux', 'osx', 'windows'] # Platforms this plugin will run on
|
||||||
author = 'The Dark Reverser' # The author of this plugin
|
author = 'The Dark Reverser' # The author of this plugin
|
||||||
version = (0, 0, 9) # The version number of this plugin
|
version = (0, 0, 10) # The version number of this plugin
|
||||||
file_types = set(['prc','mobi','azw']) # The file types that this plugin will be applied to
|
file_types = set(['prc','mobi','azw']) # The file types that this plugin will be applied to
|
||||||
on_import = True # Run this plugin during the import
|
on_import = True # Run this plugin during the import
|
||||||
|
|
||||||
|
@ -232,12 +245,13 @@ if not __name__ == "__main__":
|
||||||
def customization_help(self, gui=False):
|
def customization_help(self, gui=False):
|
||||||
return 'Enter PID (separate multiple PIDs with comma)'
|
return 'Enter PID (separate multiple PIDs with comma)'
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def main(argv=sys.argv):
|
||||||
print "MobiDeDrm v0.09. Copyright (c) 2008 The Dark Reverser"
|
print "MobiDeDrm v0.10. Copyright (c) 2008 The Dark Reverser"
|
||||||
if len(sys.argv)<4:
|
if len(sys.argv)<4:
|
||||||
print "Removes protection from Mobipocket books"
|
print "Removes protection from Mobipocket books"
|
||||||
print "Usage:"
|
print "Usage:"
|
||||||
print " mobidedrm infile.mobi outfile.mobi PID"
|
print " mobidedrm infile.mobi outfile.mobi PID"
|
||||||
|
return 1
|
||||||
else:
|
else:
|
||||||
infile = sys.argv[1]
|
infile = sys.argv[1]
|
||||||
outfile = sys.argv[2]
|
outfile = sys.argv[2]
|
||||||
|
@ -247,3 +261,9 @@ if __name__ == "__main__":
|
||||||
file(outfile, 'wb').write(DrmStripper(data_file, pid).getResult())
|
file(outfile, 'wb').write(DrmStripper(data_file, pid).getResult())
|
||||||
except DrmException, e:
|
except DrmException, e:
|
||||||
print "Error: %s" % e
|
print "Error: %s" % e
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,22 @@
|
||||||
# 0.01 - Initial version
|
# 0.01 - Initial version
|
||||||
# 0.02 - Fix issue with size computing
|
# 0.02 - Fix issue with size computing
|
||||||
# 0.03 - Fix issue with some files
|
# 0.03 - Fix issue with some files
|
||||||
|
# 0.04 - make stdout self flushing and fix return values
|
||||||
|
|
||||||
|
class Unbuffered:
|
||||||
|
def __init__(self, stream):
|
||||||
|
self.stream = stream
|
||||||
|
def write(self, data):
|
||||||
|
self.stream.write(data)
|
||||||
|
self.stream.flush()
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
return getattr(self.stream, attr)
|
||||||
|
|
||||||
|
import sys
|
||||||
|
sys.stdout=Unbuffered(sys.stdout)
|
||||||
|
|
||||||
|
|
||||||
import struct, sys
|
import struct
|
||||||
|
|
||||||
class BitReader:
|
class BitReader:
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
|
@ -146,16 +159,18 @@ def unpackBook(input_file):
|
||||||
r += decompressSection(i)
|
r += decompressSection(i)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
print "MobiHuff v0.03"
|
def main(argv=sys.argv):
|
||||||
print " Copyright (c) 2008 The Dark Reverser <dark.reverser@googlemail.com>"
|
print "MobiHuff v0.03"
|
||||||
if len(sys.argv)!=3:
|
print " Copyright (c) 2008 The Dark Reverser <dark.reverser@googlemail.com>"
|
||||||
print ""
|
if len(sys.argv)!=3:
|
||||||
|
print ""
|
||||||
print "Description:"
|
print "Description:"
|
||||||
print " Unpacks the new mobipocket huffdic compression."
|
print " Unpacks the new mobipocket huffdic compression."
|
||||||
print " This program works with unencrypted files only."
|
print " This program works with unencrypted files only."
|
||||||
print "Usage:"
|
print "Usage:"
|
||||||
print " mobihuff.py infile.mobi outfile.html"
|
print " mobihuff.py infile.mobi outfile.html"
|
||||||
else:
|
return 1
|
||||||
|
else:
|
||||||
infile = sys.argv[1]
|
infile = sys.argv[1]
|
||||||
outfile = sys.argv[2]
|
outfile = sys.argv[2]
|
||||||
try:
|
try:
|
||||||
|
@ -165,4 +180,10 @@ else:
|
||||||
print "done"
|
print "done"
|
||||||
except ValueError, e:
|
except ValueError, e:
|
||||||
print
|
print
|
||||||
print "Error: %s" % e
|
print "Error: %s" % e
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
|
||||||
|
|
||||||
|
import Tkinter
|
||||||
|
import Tkconstants
|
||||||
|
|
||||||
|
# basic scrolled text widget
|
||||||
|
class ScrolledText(Tkinter.Text):
|
||||||
|
def __init__(self, master=None, **kw):
|
||||||
|
self.frame = Tkinter.Frame(master)
|
||||||
|
self.vbar = Tkinter.Scrollbar(self.frame)
|
||||||
|
self.vbar.pack(side=Tkconstants.RIGHT, fill=Tkconstants.Y)
|
||||||
|
kw.update({'yscrollcommand': self.vbar.set})
|
||||||
|
Tkinter.Text.__init__(self, self.frame, **kw)
|
||||||
|
self.pack(side=Tkconstants.LEFT, fill=Tkconstants.BOTH, expand=True)
|
||||||
|
self.vbar['command'] = self.yview
|
||||||
|
# Copy geometry methods of self.frame without overriding Text
|
||||||
|
# methods = hack!
|
||||||
|
text_meths = vars(Tkinter.Text).keys()
|
||||||
|
methods = vars(Tkinter.Pack).keys() + vars(Tkinter.Grid).keys() + vars(Tkinter.Place).keys()
|
||||||
|
methods = set(methods).difference(text_meths)
|
||||||
|
for m in methods:
|
||||||
|
if m[0] != '_' and m != 'config' and m != 'configure':
|
||||||
|
setattr(self, m, getattr(self.frame, m))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.frame)
|
|
@ -0,0 +1,149 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
|
||||||
|
|
||||||
|
import os, sys
|
||||||
|
import signal
|
||||||
|
import threading
|
||||||
|
import subprocess
|
||||||
|
from subprocess import Popen, PIPE, STDOUT
|
||||||
|
|
||||||
|
# **heavily** chopped up and modfied version of asyncproc.py
|
||||||
|
# to make it actually work on Windows as well as Mac/Linux
|
||||||
|
# For the original see:
|
||||||
|
# "http://www.lysator.liu.se/~bellman/download/"
|
||||||
|
# author is "Thomas Bellman <bellman@lysator.liu.se>"
|
||||||
|
# available under GPL version 3 or Later
|
||||||
|
|
||||||
|
# create an asynchronous subprocess whose output can be collected in
|
||||||
|
# a non-blocking manner
|
||||||
|
|
||||||
|
# What a mess! Have to use threads just to get non-blocking io
|
||||||
|
# in a cross-platform manner
|
||||||
|
|
||||||
|
# luckily all thread use is hidden within this class
|
||||||
|
|
||||||
|
class Process(object):
|
||||||
|
def __init__(self, *params, **kwparams):
|
||||||
|
if len(params) <= 3:
|
||||||
|
kwparams.setdefault('stdin', subprocess.PIPE)
|
||||||
|
if len(params) <= 4:
|
||||||
|
kwparams.setdefault('stdout', subprocess.PIPE)
|
||||||
|
if len(params) <= 5:
|
||||||
|
kwparams.setdefault('stderr', subprocess.PIPE)
|
||||||
|
self.__pending_input = []
|
||||||
|
self.__collected_outdata = []
|
||||||
|
self.__collected_errdata = []
|
||||||
|
self.__exitstatus = None
|
||||||
|
self.__lock = threading.Lock()
|
||||||
|
self.__inputsem = threading.Semaphore(0)
|
||||||
|
self.__quit = False
|
||||||
|
|
||||||
|
self.__process = subprocess.Popen(*params, **kwparams)
|
||||||
|
|
||||||
|
if self.__process.stdin:
|
||||||
|
self.__stdin_thread = threading.Thread(
|
||||||
|
name="stdin-thread",
|
||||||
|
target=self.__feeder, args=(self.__pending_input,
|
||||||
|
self.__process.stdin))
|
||||||
|
self.__stdin_thread.setDaemon(True)
|
||||||
|
self.__stdin_thread.start()
|
||||||
|
|
||||||
|
if self.__process.stdout:
|
||||||
|
self.__stdout_thread = threading.Thread(
|
||||||
|
name="stdout-thread",
|
||||||
|
target=self.__reader, args=(self.__collected_outdata,
|
||||||
|
self.__process.stdout))
|
||||||
|
self.__stdout_thread.setDaemon(True)
|
||||||
|
self.__stdout_thread.start()
|
||||||
|
|
||||||
|
if self.__process.stderr:
|
||||||
|
self.__stderr_thread = threading.Thread(
|
||||||
|
name="stderr-thread",
|
||||||
|
target=self.__reader, args=(self.__collected_errdata,
|
||||||
|
self.__process.stderr))
|
||||||
|
self.__stderr_thread.setDaemon(True)
|
||||||
|
self.__stderr_thread.start()
|
||||||
|
|
||||||
|
def pid(self):
|
||||||
|
return self.__process.pid
|
||||||
|
|
||||||
|
def kill(self, signal):
|
||||||
|
self.__process.send_signal(signal)
|
||||||
|
|
||||||
|
# check on subprocess (pass in 'nowait') to act like poll
|
||||||
|
def wait(self, flag):
|
||||||
|
if flag.lower() == 'nowait':
|
||||||
|
rc = self.__process.poll()
|
||||||
|
else:
|
||||||
|
rc = self.__process.wait()
|
||||||
|
if rc != None:
|
||||||
|
if self.__process.stdin:
|
||||||
|
self.closeinput()
|
||||||
|
if self.__process.stdout:
|
||||||
|
self.__stdout_thread.join()
|
||||||
|
if self.__process.stderr:
|
||||||
|
self.__stderr_thread.join()
|
||||||
|
return self.__process.returncode
|
||||||
|
|
||||||
|
def terminate(self):
|
||||||
|
if self.__process.stdin:
|
||||||
|
self.closeinput()
|
||||||
|
self.__process.terminate()
|
||||||
|
|
||||||
|
# thread gets data from subprocess stdout
|
||||||
|
def __reader(self, collector, source):
|
||||||
|
while True:
|
||||||
|
data = os.read(source.fileno(), 65536)
|
||||||
|
self.__lock.acquire()
|
||||||
|
collector.append(data)
|
||||||
|
self.__lock.release()
|
||||||
|
if data == "":
|
||||||
|
source.close()
|
||||||
|
break
|
||||||
|
return
|
||||||
|
|
||||||
|
# thread feeds data to subprocess stdin
|
||||||
|
def __feeder(self, pending, drain):
|
||||||
|
while True:
|
||||||
|
self.__inputsem.acquire()
|
||||||
|
self.__lock.acquire()
|
||||||
|
if not pending and self.__quit:
|
||||||
|
drain.close()
|
||||||
|
self.__lock.release()
|
||||||
|
break
|
||||||
|
data = pending.pop(0)
|
||||||
|
self.__lock.release()
|
||||||
|
drain.write(data)
|
||||||
|
|
||||||
|
# non-blocking read of data from subprocess stdout
|
||||||
|
def read(self):
|
||||||
|
self.__lock.acquire()
|
||||||
|
outdata = "".join(self.__collected_outdata)
|
||||||
|
del self.__collected_outdata[:]
|
||||||
|
self.__lock.release()
|
||||||
|
return outdata
|
||||||
|
|
||||||
|
# non-blocking read of data from subprocess stderr
|
||||||
|
def readerr(self):
|
||||||
|
self.__lock.acquire()
|
||||||
|
errdata = "".join(self.__collected_errdata)
|
||||||
|
del self.__collected_errdata[:]
|
||||||
|
self.__lock.release()
|
||||||
|
return errdata
|
||||||
|
|
||||||
|
# non-blocking write to stdin of subprocess
|
||||||
|
def write(self, data):
|
||||||
|
if self.__process.stdin is None:
|
||||||
|
raise ValueError("Writing to process with stdin not a pipe")
|
||||||
|
self.__lock.acquire()
|
||||||
|
self.__pending_input.append(data)
|
||||||
|
self.__inputsem.release()
|
||||||
|
self.__lock.release()
|
||||||
|
|
||||||
|
# close stdinput of subprocess
|
||||||
|
def closeinput(self):
|
||||||
|
self.__lock.acquire()
|
||||||
|
self.__quit = True
|
||||||
|
self.__inputsem.release()
|
||||||
|
self.__lock.release()
|
||||||
|
|
Loading…
Reference in New Issue