#! /usr/bin/env python """Tkinter-based GUI for websucker. Easy use: type or paste source URL and destination directory in their respective text boxes,click GO or hit return,and presto. """ from Tkinter import * import Tkinter import websucker import sys import os import threading import Queue import time VERBOSE=2 try: class Canceled(Exception): "Exception used to cancel run()." except (NameError,TypeError): Canceled=__name__ + ".Canceled" class SuckerThread(websucker.Sucker): stopit=0 savedir=None rootdir=None def __init__(self,msgq): self.msgq=msgq websucker.Sucker.__init__(self) self.setflags(verbose=VERBOSE) self.urlopener.addheaders=[ ('User-agent','websucker/%s' % websucker.__version__), ] def message(self,format,*args): if args: format=format%args ##print format self.msgq.put(format) def run1(self,url): try: try: self.reset() self.addroot(url) self.run() except Canceled: self.message("[canceled]") else: self.message("[done]") finally: self.msgq.put(None) def savefile(self,text,path): if self.stopit: raise Canceled websucker.Sucker.savefile(self,text,path) def getpage(self,url): if self.stopit: raise Canceled return websucker.Sucker.getpage(self,url) def savefilename(self,url): path=websucker.Sucker.savefilename(self,url) if self.savedir: n=len(self.rootdir) if path[:n] == self.rootdir: path=path[n:] while path[:1] == os.sep: path=path[1:] path=os.path.join(self.savedir,path) return path def XXXaddrobot(self,*args): pass def XXXisallowed(self,*args): return 1 class App: sucker=None msgq=None def __init__(self,top): self.top=top top.columnconfigure(99,weight=1) self.url_label=Label(top,text="URL:") self.url_label.grid(row=0,column=0,sticky='e') self.url_entry=Entry(top,width=60,exportselection=0) self.url_entry.grid(row=0,column=1,sticky='we', columnspan=99) self.url_entry.focus_set() self.url_entry.bind("",self.go) self.dir_label=Label(top,text="Directory:") self.dir_label.grid(row=1,column=0,sticky='e') self.dir_entry=Entry(top) self.dir_entry.grid(row=1,column=1,sticky='we', columnspan=99) self.go_button=Button(top,text="Go",command=self.go) self.go_button.grid(row=2,column=1,sticky='w') self.cancel_button=Button(top,text="Cancel", command=self.cancel, state=DISABLED) self.cancel_button.grid(row=2,column=2,sticky='w') self.auto_button=Button(top,text="Paste+Go", command=self.auto) self.auto_button.grid(row=2,column=3,sticky='w') self.status_label=Label(top,text="[idle]") self.status_label.grid(row=2,column=4,sticky='w') self.top.update_idletasks() self.top.grid_propagate(0) def message(self,text,*args): if args: text=text % args self.status_label.config(text=text) def check_msgq(self): while not self.msgq.empty(): msg=self.msgq.get() if msg is None: self.go_button.configure(state=NORMAL) self.auto_button.configure(state=NORMAL) self.cancel_button.configure(state=DISABLED) if self.sucker: self.sucker.stopit=0 self.top.bell() else: self.message(msg) self.top.after(100,self.check_msgq) def go(self,event=None): if not self.msgq: self.msgq=Queue.Queue(0) self.check_msgq() if not self.sucker: self.sucker=SuckerThread(self.msgq) if self.sucker.stopit: return self.url_entry.selection_range(0,END) url=self.url_entry.get() url=url.strip() if not url: self.top.bell() self.message("[Error: No URL entered]") return self.rooturl=url dir=self.dir_entry.get().strip() if not dir: self.sucker.savedir=None else: self.sucker.savedir=dir self.sucker.rootdir=os.path.dirname( websucker.Sucker.savefilename(self.sucker,url)) self.go_button.configure(state=DISABLED) self.auto_button.configure(state=DISABLED) self.cancel_button.configure(state=NORMAL) self.message( '[running...]') self.sucker.stopit=0 t=threading.Thread(target=self.sucker.run1,args=(url,)) t.start() def cancel(self): if self.sucker: self.sucker.stopit=1 self.message("[canceling...]") def auto(self): tries=['PRIMARY','CLIPBOARD'] text="" for t in tries: try: text=self.top.selection_get(selection=t) except TclError: continue text=text.strip() if text: break if not text: self.top.bell() self.message("[Error: clipboard is empty]") return self.url_entry.delete(0,END) self.url_entry.insert(0,text) self.go() class AppArray: def __init__(self,top=None): if not top: top=Tk() top.title("websucker GUI") top.iconname("wsgui") top.wm_protocol('WM_DELETE_WINDOW',self.exit) self.top=top self.appframe=Frame(self.top) self.appframe.pack(fill='both') self.applist=[] self.exit_button=Button(top,text="Exit",command=self.exit) self.exit_button.pack(side=RIGHT) self.new_button=Button(top,text="New",command=self.addsucker) self.new_button.pack(side=LEFT) self.addsucker() ##self.applist[0].url_entry.insert(END,"http://www.python.org/doc/essays/") def addsucker(self): self.top.geometry("") frame=Frame(self.appframe,borderwidth=2,relief=GROOVE) frame.pack(fill='x') app=App(frame) self.applist.append(app) done=0 def mainloop(self): while not self.done: time.sleep(0.1) self.top.update() def exit(self): for app in self.applist: app.cancel() app.message("[exiting...]") self.done=1 def main(): AppArray().mainloop() if __name__ == '__main__': main()