drag and drop urls from your browser's navigation window to a tkinter widget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | #!/usr/bin/torify /usr/bin/python
import Tkinter
import tkFont
import requests
import html2text
import urllib2
class TkDND(object):
def __init__(self, master):
master.tk.eval('package require tkdnd')
self.master = master
self.tk = master.tk
self._subst_format = ('%A', '%a', '%b', '%D', '%d', '%m', '%T',
'%W', '%X', '%Y', '%x', '%y')
self._subst_format_str = " ".join(self._subst_format)
def bindtarget(self, window, callback, dndtype, event='<Drop>', priority=50):
cmd = self._prepare_tkdnd_func(callback)
return self.tk.call('dnd', 'bindtarget', window, dndtype, event,
cmd, priority)
def _prepare_tkdnd_func(self, callback):
funcid = self.master.register(callback, self._dndsubstitute)
cmd = ('%s %s' % (funcid, self._subst_format_str))
return cmd
def _dndsubstitute(self, *args):
if len(args) != len(self._subst_format):
return args
def try_int(x):
x = str(x)
try:
return int(x)
except ValueError:
return x
A, a, b, D, d, m, T, W, X, Y, x, y = args
event = Tkinter.Event()
event.action = A # Current action of the drag and drop operation.
event.action_list = a # Action list supported by the drag source.
event.mouse_button = b # Mouse button pressed during the drag and drop.
event.data = D # The data that has been dropped.
event.descr = d # The list of descriptions.
event.modifier = m # The list of modifier keyboard keys pressed.
event.dndtype = T
event.widget = self.master.nametowidget(W)
event.x_root = X # Mouse pointer x coord, relative to the root win.
event.y_root = Y
event.x = x # Mouse pointer x coord, relative to the widget.
event.y = y
event.action_list = str(event.action_list).split()
for name in ('mouse_button', 'x', 'y', 'x_root', 'y_root'):
setattr(event, name, try_int(getattr(event, name)))
return (event, )
class TextPlus(Tkinter.Text):
def __init__(self, *args, **kwargs):
Tkinter.Text.__init__(self, *args, **kwargs)
_rc_menu_install(self)
# overwrite default class binding so we don't need to return "break"
self.bind_class("Text", "<Control-a>", self.event_select_all)
self.bind("<Button-3><ButtonRelease-3>", self.show_menu)
def event_select_all(self, *args):
self.focus_force()
self.tag_add("sel","1.0","end")
def show_menu(self, e):
self.tk.call("tk_popup", self.menu, e.x_root, e.y_root)
class EntryPlus(Tkinter.Entry):
def __init__(self, *args, **kwargs):
Tkinter.Entry.__init__(self, *args, **kwargs)
_rc_menu_install(self, go=True)
# overwrite default class binding so we don't need to return "break"
self.bind_class("Entry", "<Control-a>", self.event_select_all)
self.bind("<Button-3><ButtonRelease-3>", self.show_menu)
def event_select_all(self, *args):
self.focus_force()
self.selection_range(0, Tkinter.END)
def event_paste_and_go(self, *args):
self.delete(0,Tkinter.END)
self.focus_force()
self.event_generate("<<Paste>>")
handlereturn(self)
def show_menu(self, e):
self.tk.call("tk_popup", self.menu, e.x_root, e.y_root)
def _rc_menu_install(w, go = False):
w.menu = Tkinter.Menu(w, tearoff=0)
w.menu.add_command(label="Cut")
w.menu.add_command(label="Copy")
w.menu.add_command(label="Paste")
if go:
w.menu.add_command(label="Paste & Go")
w.menu.add_separator()
w.menu.add_command(label="Select all")
w.menu.entryconfigure("Cut", command=lambda: w.focus_force() or w.event_generate("<<Cut>>"))
w.menu.entryconfigure("Copy", command=lambda: w.focus_force() or w.event_generate("<<Copy>>"))
w.menu.entryconfigure("Paste", command=lambda: w.focus_force() or w.event_generate("<<Paste>>"))
if go:
w.menu.entryconfigure("Paste & Go", command=w.event_paste_and_go)
w.menu.entryconfigure("Select all", command=w.event_select_all)
def handle(event):
event.widget.delete(0,Tkinter.END)
url = event.data.strip()
event.widget.insert(0,url)
textwindow(url)
def handlereturn(entry):
p = entry.get().splitlines()[0]
if not p.startswith('http'):
p = 'file://'+ p
textwindow(p)
def convert65536(s):
#convert out-of-range characters
res = []
for c in s:
k = ord(c)
if k < 65536:
res.append(c)
else:
res.append("{"+str(k)+"?}")
return "".join(res)
def gethtml(link):
user_agent = "Mozilla/5.0 (Windows NT 6.1; rv:38.0) Gecko/20100101 Firefox/38.0"
headers={'user-agent':user_agent}
s = requests.Session()
try:
res = s.get(link,headers=headers).text
except requests.exceptions.InvalidSchema:
req=urllib2.Request(link,None,headers)
r = urllib2.urlopen(req)
res = r.read().decode('utf8')
return res
def textwindow(url):
title = url
h = html2text.HTML2Text()
h.ignore_links = True
h.ignore_images = True
s = gethtml(url)
s = h.handle(s)
s = h.unescape(s)
text = convert65536(s)
top = Tkinter.Toplevel()
top.geometry("+200+100")
top.title(title)
top.bind("<Escape>", lambda _ : top.destroy())
S = Tkinter.Scrollbar(top)
customFont = tkFont.Font(family="Arial", size=16)
T = TextPlus(top,height=20,width=78,font=customFont,bg="lightgrey")
S.pack(side=Tkinter.RIGHT,fill=Tkinter.Y)
T.pack(side=Tkinter.LEFT,fill=Tkinter.Y)
S.config(command=T.yview)
T.config(yscrollcommand=S.set)
T.insert(Tkinter.END,text)
def main():
root = Tkinter.Tk()
root.geometry("950x32+200+32")
root.title('markdown')
dnd = TkDND(root)
customFont = tkFont.Font(family="Arial", size=14)
entry = EntryPlus(font=customFont,bg="lightgrey")
entry.pack(expand=1,fill='both')
dnd.bindtarget(entry,handle,'text/plain')
entry.bind("<Return>", lambda _ : handlereturn(entry))
root.mainloop()
if __name__=="__main__":
main()
|
I try to block ads but firefox now has built in ads. Tor uses an older version of firefox that is a bit better so I switched to tor, which also has other benefits. But still sometimes a webpage is too difficult to navigate because of all the pics, the cramped layout to make room for the useless ads, the sidebars, the sticky tags that move with you when you scroll the page, etcetera. So I go to menu item "view - page style" and select "no style", which 9 out of 10 times is enough. But some webpages are very very stubborn.
To get those pages to display nicely too, I bypass the browser altogether, using it only for the links in the navigation bar or the bookmarks browser. This script is a kind of text-only, independent browser companion.
Make this script executable (after first installing tor, or after adapting the bang line, it can also work without tor) run it and drag and drop urls (or saved local files) into the small longish rectangle that appears.
Windows displaying the text of the files or webpages will appear below it. Take some time to change my choices for the right fonts and colors for background and text and for the initial positon and size of the windows. Maybe you also want more or less lines or longer lines.
Some day I would want to make this all configurable via the GUI but for now one has to edit the code or just accept my choices for the time being.
The TkDND class is part of a recipe I found on (I think) stackexchange, I never got Tkinter functioning as a drag and drop source to work, but it works fine as a drop target. The routine converting chars that Tkinter can't display is also adapted from something I found on the web.
It is also possible to put a link in the navigation bar using cut and paste, or by just typing it in, in that case press "return" to load the page. The text window has cut and paste functions too.