Front-ends for the mobi tools, and tools updated to work as libraries to the front ends

This commit is contained in:
some_updates
2015-02-04 11:18:20 +00:00
committed by Apprentice Alf
parent d1d2bfcb1e
commit a23dd40ecf
9 changed files with 791 additions and 57 deletions

View File

@@ -1,16 +1,17 @@
#!/usr/bin/python
# The Kindleizer v0.2. Copyright (c) 2007, 2009 Igor Skochinsky <skochinsky@mail.ru>
# This script enables encrypted Mobipocket books to be readable by Kindle
# History:
# 0.1 initial release
# 0.2 fixed corrupted metadata issue (thanks to Mark Peek)
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 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
def strByte(s,off=0):
@@ -104,7 +105,7 @@ def find_key(rec0, pid):
drmInfo = strPutDWord(drmInfo,4,(dw4|0x800))
dw0, dw4, dw18, dw1c = struct.unpack(">II16xII", drmInfo)
#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
return None
@@ -115,7 +116,14 @@ def replaceext(filename, newext):
else:
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]=='*':
pid = pid[:-2]
if len(pid)!=8 or pid[-1]!='*':
@@ -159,10 +167,6 @@ def main(fname, pid):
print "Output written to "+outfname
return 0
print "The Kindleizer v0.2. Copyright (c) 2007, 2009 Igor Skochinsky"
if len(sys.argv)<3:
print "Fixes encrypted Mobipocket books to be readable by Kindle"
print "Usage: kindlefix.py file.mobi PID"
else:
fname = sys.argv[1]
sys.exit(main(fname, sys.argv[2]))
if __name__ == "__main__":
sys.exit(main())

View File

@@ -4,9 +4,20 @@
# History:
# 0.1 Initial release
# 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:
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
print "Mobipocket PID calculator for Amazon Kindle. Copyright (c) 2007, 2009 Igor Skochinsky"
if len(sys.argv)>1:
serial = sys.argv[1]
if len(serial)==16:
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)
def main(argv=sys.argv):
print "Mobipocket PID calculator for Amazon Kindle. Copyright (c) 2007, 2009 Igor Skochinsky"
if len(sys.argv)==2:
serial = sys.argv[1]
else:
print "Warning: unrecognized serial number. Please recheck input."
sys.exit(1)
else:
print "Usage: kindlepid.py <Kindle Serial Number>/<iPhone/iPod Touch UDID>"
print "Usage: kindlepid.py <Kindle Serial Number>/<iPhone/iPod Touch UDID>"
return 1
if len(serial)==16:
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())

View File

@@ -21,8 +21,21 @@
# 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.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):
pass
@@ -206,7 +219,7 @@ if not __name__ == "__main__":
description = 'Removes DRM from secure Mobi files'
supported_platforms = ['linux', 'osx', 'windows'] # Platforms this plugin will run on
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
on_import = True # Run this plugin during the import
@@ -232,12 +245,13 @@ if not __name__ == "__main__":
def customization_help(self, gui=False):
return 'Enter PID (separate multiple PIDs with comma)'
if __name__ == "__main__":
print "MobiDeDrm v0.09. Copyright (c) 2008 The Dark Reverser"
def main(argv=sys.argv):
print "MobiDeDrm v0.10. Copyright (c) 2008 The Dark Reverser"
if len(sys.argv)<4:
print "Removes protection from Mobipocket books"
print "Usage:"
print " mobidedrm infile.mobi outfile.mobi PID"
return 1
else:
infile = sys.argv[1]
outfile = sys.argv[2]
@@ -247,3 +261,9 @@ if __name__ == "__main__":
file(outfile, 'wb').write(DrmStripper(data_file, pid).getResult())
except DrmException, e:
print "Error: %s" % e
return 1
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -9,9 +9,22 @@
# 0.01 - Initial version
# 0.02 - Fix issue with size computing
# 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:
def __init__(self, data):
@@ -146,16 +159,18 @@ def unpackBook(input_file):
r += decompressSection(i)
return r
print "MobiHuff v0.03"
print " Copyright (c) 2008 The Dark Reverser <dark.reverser@googlemail.com>"
if len(sys.argv)!=3:
print ""
def main(argv=sys.argv):
print "MobiHuff v0.03"
print " Copyright (c) 2008 The Dark Reverser <dark.reverser@googlemail.com>"
if len(sys.argv)!=3:
print ""
print "Description:"
print " Unpacks the new mobipocket huffdic compression."
print " This program works with unencrypted files only."
print "Usage:"
print " mobihuff.py infile.mobi outfile.html"
else:
return 1
else:
infile = sys.argv[1]
outfile = sys.argv[2]
try:
@@ -165,4 +180,10 @@ else:
print "done"
except ValueError, e:
print
print "Error: %s" % e
print "Error: %s" % e
return 1
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -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)

View File

@@ -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()