mirror of
				https://github.com/noDRM/DeDRM_tools.git
				synced 2025-10-23 23:07:47 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			702 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			702 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python
 | |
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| # DeDRM.pyw
 | |
| # Copyright 2010-2016 some_updates, Apprentice Alf and Apprentice Harper
 | |
| 
 | |
| # Revision history:
 | |
| #   6.0.0 - Release along with unified plugin
 | |
| #   6.0.1 - Bug Fixes for Windows App
 | |
| #   6.0.2 - Fixed problem with spaces in paths and the bat file
 | |
| #   6.0.3 - Fix for Windows non-ascii user names
 | |
| #   6.0.4 - Fix for other potential unicode problems
 | |
| #   6.0.5 - Fix typo
 | |
| #   6.2.0 - Update to match plugin and AppleScript
 | |
| #   6.2.1 - Fix for non-ascii user names
 | |
| #   6.2.2 - Added URL method for B&N/nook books
 | |
| #   6.3.0 - Add in Android support
 | |
| #   6.3.1 - Version bump for clarity
 | |
| #   6.3.2 - Version bump to match plugin
 | |
| #   6.3.3 - Version bump to match plugin
 | |
| #   6.3.4 - Version bump to match plugin
 | |
| #   6.3.5 - Version bump to match plugin
 | |
| #   6.3.6 - Version bump to match plugin
 | |
| #   6.4.0 - Fix for Kindle for PC encryption change
 | |
| #   6.4.1 - Fix for new tags in Topaz ebooks
 | |
| #   6.4.2 - Fix for new tags in Topaz ebooks, and very small Topaz ebooks
 | |
| #   6.4.3 - Version bump to match plugin & Mac app
 | |
| #   6.5.0 - Fix for some new tags in Topaz ebooks
 | |
| #   6.5.1 - Version bump to match plugin & Mac app
 | |
| #   6.5.2 - Fix for a new tag in Topaz ebooks
 | |
| #   6.5.3 - Explicitly warn about KFX files
 | |
| #   6.5.4 - PDF float fix.
 | |
| #   6.5.5 - Kindle for PC/Accented characters in username fix.
 | |
| #   6.6.0 - Initial KFX support from TomThumb
 | |
| #   6.6.1 - Standalong app fix from wzyboy
 | |
| 
 | |
| __version__ = '6.6.1'
 | |
| 
 | |
| import sys
 | |
| import os, os.path
 | |
| sys.path.append(os.path.join(sys.path[0],"lib"))
 | |
| import sys, os
 | |
| import codecs
 | |
| 
 | |
| from argv_utils import add_cp65001_codec, set_utf8_default_encoding, unicode_argv
 | |
| add_cp65001_codec()
 | |
| set_utf8_default_encoding()
 | |
| 
 | |
| 
 | |
| import shutil
 | |
| import Tkinter
 | |
| from Tkinter import *
 | |
| import Tkconstants
 | |
| import tkFileDialog
 | |
| from scrolltextwidget import ScrolledText
 | |
| from activitybar import ActivityBar
 | |
| if sys.platform.startswith("win"):
 | |
|     from askfolder_ed import AskFolder
 | |
| import re
 | |
| import simpleprefs
 | |
| import traceback
 | |
| 
 | |
| 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
 | |
| class QueuedUTF8Stream:
 | |
|     def __init__(self, stream, q):
 | |
|         self.stream = stream
 | |
|         self.encoding = 'utf-8'
 | |
|         self.q = q
 | |
|     def write(self, data):
 | |
|         if isinstance(data,unicode):
 | |
|             data = data.encode('utf-8',"replace")
 | |
|         self.q.put(data)
 | |
|     def __getattr__(self, attr):
 | |
|         return getattr(self.stream, attr)
 | |
| 
 | |
| class DrmException(Exception):
 | |
|     pass
 | |
| 
 | |
| class MainApp(Tk):
 | |
|     def __init__(self, apphome, dnd=False, filenames=[]):
 | |
|         Tk.__init__(self)
 | |
|         self.withdraw()
 | |
|         self.dnd = dnd
 | |
|         self.apphome = apphome
 | |
| 
 | |
|         # preference settings
 | |
|         # [dictionary key, file in preferences directory where info is stored]
 | |
|         description = [ ['pids'   , 'pidlist.txt'   ],
 | |
|                         ['serials', 'seriallist.txt'],
 | |
|                         ['sdrms'  , 'sdrmlist.txt'  ],
 | |
|                         ['outdir' , 'outdir.txt'    ]]
 | |
|         self.po = simpleprefs.SimplePrefs("DeDRM",description)
 | |
|         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']
 | |
|         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
 | |
|             try:
 | |
|                 kindlekey.getkey(kindlekeyfile)
 | |
|             except:
 | |
|                 traceback.print_exc()
 | |
|                 pass
 | |
|         bnepubkeyfile = os.path.join(prefdir,'bnepubkey.b64')
 | |
|         if not os.path.exists(bnepubkeyfile):
 | |
|             import ignoblekey
 | |
|             try:
 | |
|                 ignoblekey.getkey(bnepubkeyfile)
 | |
|             except:
 | |
|                 traceback.print_exc()
 | |
|                 pass
 | |
|         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)
 | |
|         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']
 | |
|             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)
 | |
|         self.title("DeDRM " + __version__)
 | |
|         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)
 | |
| 
 | |
|         cur_row = 0
 | |
|         Tkinter.Label(body, text='Adobe Key file (adeptkey.der)').grid(row=cur_row, sticky=Tkconstants.E)
 | |
|         self.adkpath = Tkinter.Entry(body, width=50)
 | |
|         self.adkpath.grid(row=cur_row, column=1, sticky=sticky)
 | |
|         prefdir = self.prefs_array['dir']
 | |
|         keyfile = os.path.join(prefdir,'adeptkey.der')
 | |
|         if os.path.isfile(keyfile):
 | |
|             path = keyfile
 | |
|             self.adkpath.insert(cur_row, path)
 | |
|         button = Tkinter.Button(body, text="...", command=self.get_adkpath)
 | |
|         button.grid(row=cur_row, column=2)
 | |
| 
 | |
|         cur_row = cur_row + 1
 | |
|         Tkinter.Label(body, text='Kindle Key file (kindlekey.k4i)').grid(row=cur_row, sticky=Tkconstants.E)
 | |
|         self.kkpath = Tkinter.Entry(body, width=50)
 | |
|         self.kkpath.grid(row=cur_row, column=1, sticky=sticky)
 | |
|         prefdir = self.prefs_array['dir']
 | |
|         keyfile = os.path.join(prefdir,'kindlekey.k4i')
 | |
|         if os.path.isfile(keyfile):
 | |
|             path = keyfile
 | |
|             self.kkpath.insert(0, path)
 | |
|         button = Tkinter.Button(body, text="...", command=self.get_kkpath)
 | |
|         button.grid(row=cur_row, column=2)
 | |
| 
 | |
|         cur_row = cur_row + 1
 | |
|         Tkinter.Label(body, text='Android Kindle backup file (backup.ab)').grid(row=cur_row, sticky=Tkconstants.E)
 | |
|         self.akkpath = Tkinter.Entry(body, width=50)
 | |
|         self.akkpath.grid(row=cur_row, column=1, sticky=sticky)
 | |
|         prefdir = self.prefs_array['dir']
 | |
|         keyfile = os.path.join(prefdir,'backup.ab')
 | |
|         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)
 | |
| 
 | |
|         cur_row = cur_row + 1
 | |
|         Tkinter.Label(body, text='Barnes and Noble Key file (bnepubkey.b64)').grid(row=cur_row, sticky=Tkconstants.E)
 | |
|         self.bnkpath = Tkinter.Entry(body, width=50)
 | |
|         self.bnkpath.grid(row=cur_row, column=1, sticky=sticky)
 | |
|         prefdir = self.prefs_array['dir']
 | |
|         keyfile = os.path.join(prefdir,'bnepubkey.b64')
 | |
|         if os.path.isfile(keyfile):
 | |
|             path = keyfile
 | |
|             self.bnkpath.insert(0, path)
 | |
|         button = Tkinter.Button(body, text="...", command=self.get_bnkpath)
 | |
|         button.grid(row=cur_row, column=2)
 | |
| 
 | |
|         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)
 | |
|         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'])
 | |
|         self.pidinfo.grid(row=cur_row, column=1, sticky=sticky)
 | |
| 
 | |
|         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)
 | |
|         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'])
 | |
|         self.serinfo.grid(row=cur_row, column=1, sticky=sticky)
 | |
| 
 | |
|         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)
 | |
|         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'])
 | |
|         self.sdrminfo.grid(row=cur_row, column=1, sticky=sticky)
 | |
| 
 | |
|         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)
 | |
|         self.outpath = Tkinter.Entry(body, width=50)
 | |
|         self.outpath.grid(row=cur_row, column=1, sticky=sticky)
 | |
|         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)
 | |
|         button.grid(row=cur_row, column=2)
 | |
| 
 | |
|         cur_row = cur_row + 1
 | |
|         Tkinter.Label(body, text='').grid(row=cur_row, column=0, columnspan=2, sticky=Tkconstants.N)
 | |
| 
 | |
|         cur_row = cur_row + 1
 | |
|         Tkinter.Label(body, text='Alternatively Process an eBook').grid(row=cur_row, column=0, columnspan=2, sticky=Tkconstants.N)
 | |
| 
 | |
|         cur_row = cur_row + 1
 | |
|         Tkinter.Label(body, text='Select an eBook to Process*').grid(row=cur_row, sticky=Tkconstants.E)
 | |
|         self.bookpath = Tkinter.Entry(body, width=50)
 | |
|         self.bookpath.grid(row=cur_row, column=1, sticky=sticky)
 | |
|         button = Tkinter.Button(body, text="...", command=self.get_bookpath)
 | |
|         button.grid(row=cur_row, column=2)
 | |
| 
 | |
|         cur_row = cur_row + 1
 | |
|         Tkinter.Label(body, font=("Helvetica", "10", "italic"), text='*To DeDRM multiple ebooks simultaneously, set your preferences and quit.\nThen drag and drop ebooks or folders onto the DeDRM_Drop_Target').grid(row=cur_row, column=1, sticky=Tkconstants.E)
 | |
| 
 | |
|         cur_row = cur_row + 1
 | |
|         Tkinter.Label(body, text='').grid(row=cur_row, column=0, columnspan=2, sticky=Tkconstants.E)
 | |
| 
 | |
|         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()
 | |
|         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)
 | |
|         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
 | |
| 
 | |
|     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
 | |
| 
 | |
|     def get_akkpath(self):
 | |
|         cpath = self.akkpath.get()
 | |
|         akkpath = tkFileDialog.askopenfilename(initialdir = cpath, parent=None, title='Select Android for Kindle backup file',
 | |
|             defaultextension='.ab', filetypes=[('Kindle for Android backup file', '.ab'), ('All Files', '.*')])
 | |
|         if akkpath:
 | |
|             akkpath = os.path.normpath(akkpath)
 | |
|             self.akkpath.delete(0, Tkconstants.END)
 | |
|             self.akkpath.insert(0, akkpath)
 | |
|         return
 | |
| 
 | |
|     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',
 | |
|             filetypes=[('All Files', '.*'),
 | |
|                     ('ePub Files','.epub'),
 | |
|                     ('Kindle','.azw'),
 | |
|                     ('Kindle','.azw1'),
 | |
|                     ('Kindle','.azw3'),
 | |
|                     ('Kindle','.azw4'),
 | |
|                     ('Kindle','.tpz'),
 | |
|                     ('Kindle','.azw8'),
 | |
|                     ('Kindle','.kfx'),
 | |
|                     ('Kindle','.kfx-zip'),
 | |
|                     ('Kindle','.mobi'),
 | |
|                     ('Kindle','.prc'),
 | |
|                     ('eReader','.pdb'),
 | |
|                     ('PDF','.pdf')],
 | |
|             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
 | |
|         new_prefs['pids'] = self.pidinfo.get().replace(" ","")
 | |
|         new_prefs['serials'] = self.serinfo.get().replace(" ","")
 | |
|         new_prefs['sdrms'] = self.sdrminfo.get().strip().replace(", ",",")
 | |
|         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
 | |
|         kkpath = self.kkpath.get()
 | |
|         if os.path.dirname(kkpath) != prefdir:
 | |
|             new_prefs['kindlefile'] = kkpath
 | |
|         akkpath = self.akkpath.get()
 | |
|         if os.path.dirname(akkpath) != prefdir:
 | |
|             new_prefs['androidfile'] = akkpath
 | |
|         self.master.setPreferences(new_prefs)
 | |
|         # 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']
 | |
| 
 | |
|     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
 | |
|         self.apphome = self.master.apphome
 | |
|         self.prefs_array = prefs_array
 | |
|         self.filenames = filenames
 | |
|         self.interval = 50
 | |
|         self.p2 = None
 | |
|         self.q = Queue()
 | |
|         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)
 | |
|         self.bar = ActivityBar(body, length=80, height=15, barwidth=5)
 | |
|         self.bar.grid(row=0, column=1, sticky=sticky)
 | |
| 
 | |
|         msg1 = ''
 | |
|         self.stext = ScrolledText(body, bd=5, relief=Tkconstants.RIDGE, height=4, width=80, 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.qbutton = Tkinter.Button(buttons, text="Quit", width=14, command=self.quitting)
 | |
|         self.qbutton.pack(side=Tkconstants.BOTTOM)
 | |
|         self.status['text'] = ''
 | |
| 
 | |
|         self.logfile = open(os.path.join(os.path.expanduser('~'),'DeDRM.log'),'w')
 | |
| 
 | |
|     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()
 | |
| 
 | |
|     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:
 | |
|                 msg = 'Complete:  '
 | |
|                 msg += 'Successes: %d, ' % self.numgood
 | |
|                 msg += 'Failures: %d\n' % self.numbad
 | |
|                 self.showCmdOutput(msg)
 | |
|                 if self.numbad == 0:
 | |
|                     self.after(2000,self.conversion_done())
 | |
|                 self.logfile.write("DeDRM v{0}: {1}".format(__version__,msg))
 | |
|                 self.logfile.close()
 | |
|                 return
 | |
|             infile = filename
 | |
|             bname = os.path.basename(infile)
 | |
|             msg = 'Processing: ' + bname + '...'
 | |
|             self.logfile.write("DeDRM v{0}: {1}\n".format(__version__,msg))
 | |
|             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'
 | |
|                 self.processQueue()
 | |
|             else:
 | |
|                 msg = 'Unknown File: ' + bname + '\n'
 | |
|                 self.logfile.write("DeDRM v{0}: {1}".format(__version__,msg))
 | |
|                 self.showCmdOutput(msg)
 | |
|                 self.numbad += 1
 | |
| 
 | |
|     def quitting(self):
 | |
|         # kill any still running subprocess
 | |
|         self.running = 'stopped'
 | |
|         if self.p2 != None:
 | |
|             if (self.p2.exitcode == None):
 | |
|                 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
 | |
|     def processQueue(self):
 | |
|         if self.p2 == None:
 | |
|             # nothing to wait for so just return
 | |
|             return
 | |
|         poll = self.p2.exitcode
 | |
|         #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)
 | |
|         if poll != None:
 | |
|             self.bar.stop()
 | |
|             if poll == 0:
 | |
|                 msg = 'Success\n'
 | |
|                 self.numgood += 1
 | |
|             else:
 | |
|                 msg = 'Failed\n'
 | |
|                 self.numbad += 1
 | |
|             self.p2.join()
 | |
|             self.logfile.write("DeDRM v{0}: {1}\n".format(__version__,msg))
 | |
|             self.showCmdOutput(msg)
 | |
|             self.p2 = None
 | |
|             self.running = 'inactive'
 | |
|             self.after(50,self.processBooks)
 | |
|             return
 | |
|         # make sure we get invoked again by event loop after interval
 | |
|         self.stext.after(self.interval,self.processQueue)
 | |
|         return
 | |
| 
 | |
|     def decrypt_ebook(self, infile, outdir, rscpath):
 | |
|         q = self.q
 | |
|         rv = 1
 | |
|         name, ext = os.path.splitext(os.path.basename(infile))
 | |
|         ext = ext.lower()
 | |
|         if ext == '.epub':
 | |
|             self.p2 = Process(target=processEPUB, args=(q, infile, outdir, rscpath))
 | |
|             self.p2.start()
 | |
|             return 0
 | |
|         if ext == '.pdb':
 | |
|             self.p2 = Process(target=processPDB, args=(q, infile, outdir, rscpath))
 | |
|             self.p2.start()
 | |
|             return 0
 | |
|         if ext in ['.azw', '.azw1', '.azw3', '.azw4', '.prc', '.mobi', '.pobi', '.tpz', '.azw8', '.kfx', '.kfx-zip']:
 | |
|             self.p2 = Process(target=processK4MOBI,args=(q, infile, outdir, rscpath))
 | |
|             self.p2.start()
 | |
|             return 0
 | |
|         if ext == '.pdf':
 | |
|             self.p2 = Process(target=processPDF, args=(q, infile, outdir, rscpath))
 | |
|             self.p2.start()
 | |
|             return 0
 | |
|         return rv
 | |
| 
 | |
| 
 | |
| # child process starts here
 | |
| def processK4MOBI(q, infile, outdir, rscpath):
 | |
|     add_cp65001_codec()
 | |
|     set_utf8_default_encoding()
 | |
|     sys.stdout = QueuedUTF8Stream(sys.stdout, q)
 | |
|     sys.stderr = QueuedUTF8Stream(sys.stderr, q)
 | |
|     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()
 | |
|     sys.stdout = QueuedUTF8Stream(sys.stdout, q)
 | |
|     sys.stderr = QueuedUTF8Stream(sys.stderr, q)
 | |
|     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()
 | |
|     sys.stdout = QueuedUTF8Stream(sys.stdout, q)
 | |
|     sys.stderr = QueuedUTF8Stream(sys.stderr, q)
 | |
|     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()
 | |
|     sys.stdout = QueuedUTF8Stream(sys.stdout, q)
 | |
|     sys.stderr = QueuedUTF8Stream(sys.stderr, q)
 | |
|     rv = decryptpdb(infile, outdir, rscpath)
 | |
|     sys.exit(rv)
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     argv=unicode_argv()
 | |
|     apphome = os.path.dirname(argv[0])
 | |
|     apphome = os.path.abspath(apphome)
 | |
| 
 | |
|     # 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
 | |
|     if sys.platform.startswith('win') and len(argv) == 2:
 | |
|         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
 | |
|         # note all filenames and paths have been utf-8 encoded
 | |
|         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
 | |
|     app = MainApp(apphome, dnd, filenames)
 | |
|     app.mainloop()
 | |
|     return 0
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     sys.exit(main())
 | 
