Last active 1489047421

Unread, a python script that can be set up in a scheduler to show desktop notifications for Reddit messages. Cross platform!

Steven Smith revised this gist 1489083420. Go to revision

1 file changed, 2 insertions, 2 deletions

unread.py

@@ -58,8 +58,8 @@ if sys.platform == "win32":
58 58 wc = win32gui.WNDCLASS()
59 59 self.destroyed = False
60 60 hinst = wc.hInstance = GetModuleHandle(None)
61 - wc.lpszClassName = "PythonTaskbar{}".format(str(time.time()))
62 - wc.lpfnWndProc = message_map # could also specify a wndproc.
61 + wc.lpszClassName = "PythonTaskbar"
62 + wc.lpfnWndProc = message_map
63 63 class_atom = win32gui.RegisterClass(wc)
64 64 style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
65 65 self.hwnd = win32gui.CreateWindow(class_atom, "Taskbar", style,

Steven Smith revised this gist 1489083367. Go to revision

1 file changed, 2 insertions

unread.py

@@ -52,6 +52,8 @@ if not c["refresh_token"]:
52 52 if sys.platform == "win32":
53 53 class Notifier:
54 54 def __init__(self, msg, title="Unread"):
55 + # This obscure block of code brought to you by the letters "not pythonic"
56 + # From https://github.com/K-DawG007/Stack-Watch/blob/master/windows_popup.py, adapted from dead url https://gist.github.com/brousch/6523559
55 57 message_map = {win32con.WM_DESTROY: self.OnDestroy, }
56 58 wc = win32gui.WNDCLASS()
57 59 self.destroyed = False

Steven Smith revised this gist 1489083091. Go to revision

1 file changed, 125 insertions

unread.py(file created)

@@ -0,0 +1,125 @@
1 + #!/usr/bin/env python3
2 + c = {
3 + "client_id": "",
4 + "client_secret": "",
5 + "refresh_token": "" # obtained after running script for first time
6 + }
7 +
8 + import os
9 + import sys
10 + import time
11 + try:
12 + import requests
13 + except ImportError:
14 + print("pip install requests")
15 + sys.exit(1)
16 + if sys.platform == "win32":
17 + try:
18 + import win32con
19 + import win32gui
20 + from win32api import GetModuleHandle
21 + except ImportError:
22 + print("Install pywin32 from https://sourceforge.net/projects/pywin32/files/pywin32/")
23 + sys.exit(1)
24 + elif sys.platform == "linux": # Untested
25 + try:
26 + import notify2
27 + except ImportError:
28 + print("pip install notify2, uses dbus notifications")
29 + sys.exit(1)
30 + elif sys.platform == "darwin": # Untested
31 + try:
32 + from pync import Notifier
33 + except ImportError:
34 + print("pip install pync")
35 + sys.exit(1)
36 +
37 + if not c["client_id"] or not c["client_secret"]:
38 + print("Set client_id and client_secret (create a script app)")
39 + sys.exit(1)
40 +
41 + if not c["refresh_token"]:
42 + import webbrowser
43 + webbrowser.open("https://www.reddit.com/api/v1/authorize?client_id=" + c["client_id"] + "&response_type=code&state=a&redirect_uri=http://localhost&scope=identity,privatemessages&duration=permanent")
44 + code = input("Code: ").strip()
45 + if code:
46 + print(requests.post("https://www.reddit.com/api/v1/access_token", auth=(c["client_id"], c["client_secret"]), headers={"User-Agent": "Unread by /u/suudo"}, data={"grant_type": "authorization_code", "code": code, "redirect_uri": "http://localhost"}).json()["refresh_token"])
47 + sys.exit(1)
48 + else:
49 + print("No code entered")
50 + sys.exit(1)
51 +
52 + if sys.platform == "win32":
53 + class Notifier:
54 + def __init__(self, msg, title="Unread"):
55 + message_map = {win32con.WM_DESTROY: self.OnDestroy, }
56 + wc = win32gui.WNDCLASS()
57 + self.destroyed = False
58 + hinst = wc.hInstance = GetModuleHandle(None)
59 + wc.lpszClassName = "PythonTaskbar{}".format(str(time.time()))
60 + wc.lpfnWndProc = message_map # could also specify a wndproc.
61 + class_atom = win32gui.RegisterClass(wc)
62 + style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
63 + self.hwnd = win32gui.CreateWindow(class_atom, "Taskbar", style,
64 + 0, 0, win32con.CW_USEDEFAULT,
65 + win32con.CW_USEDEFAULT, 0, 0,
66 + hinst, None)
67 + win32gui.UpdateWindow(self.hwnd)
68 + icon_path_name = os.path.abspath(os.path.join(sys.path[0],
69 + "balloontip.ico"))
70 + icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
71 + try:
72 + hicon = win32gui.LoadImage(hinst, icon_path_name,
73 + win32con.IMAGE_ICON, 0, 0, icon_flags)
74 + except:
75 + hicon = win32gui.LoadIcon(0, win32con.IDI_APPLICATION)
76 + flags = win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP
77 + nid = (self.hwnd, 0, flags, win32con.WM_USER+20, hicon, "tooltip")
78 + win32gui.Shell_NotifyIcon(win32gui.NIM_ADD, nid)
79 + win32gui.Shell_NotifyIcon(win32gui.NIM_MODIFY,
80 + (self.hwnd, 0, win32gui.NIF_INFO,
81 + win32con.WM_USER+20, hicon,
82 + "Balloon tooltip", msg, 200, title))
83 + time.sleep(10)
84 + win32gui.DestroyWindow(self.hwnd)
85 + win32gui.UnregisterClass(class_atom, hinst)
86 + self.destroyed = True
87 +
88 + def OnDestroy(self, hwnd, msg, wparam, lparam):
89 + nid = (self.hwnd, 0)
90 + win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, nid)
91 + win32gui.PostQuitMessage(0) # Terminate the app.
92 +
93 + def isDestroyed(self):
94 + return self.destroyed
95 + elif sys.platform == "linux": # Untested
96 + class Notifier:
97 + def __init__(self, msg, title="Unread"):
98 + n = notify2.Notification(title, msg, "notification-message-im")
99 + n.show()
100 + return n
101 + elif sys.platform == "darwin": # Untested
102 + pass # Notifier class already imported with pync
103 +
104 + def truncate(text):
105 + if len(text) > 150:
106 + return text[:147] + "..."
107 + return text
108 +
109 + def main():
110 + token = requests.post("https://www.reddit.com/api/v1/access_token", auth=(c["client_id"], c["client_secret"]), headers={"User-Agent": "Unread by /u/suudo"}, data={"grant_type": "refresh_token", "refresh_token": c["refresh_token"]}).json()["access_token"]
111 + h = {"User-Agent": "Unread by /u/suudo", "Authorization": "Bearer " + token}
112 + messages = requests.get("https://oauth.reddit.com/message/unread", headers=h).json()["data"]["children"]
113 + if len(messages) > 1:
114 + n = Notifier("\n".join(
115 + "/u/{}: {}".format(m["data"]["author"], truncate(m["data"]["body"])) for m in messages
116 + ), "Unread: New messages from")
117 + elif messages:
118 + message = messages[0]["data"]
119 + text = message["body"]
120 + n = Notifier(truncate(message["body"]),
121 + "Unread: New {} from /u/{}".format("comment" if message["was_comment"] else "message", message["author"]) )
122 + # requests.post("https://oauth.reddit.com/api/read_all_messages", headers=h)
123 +
124 + if __name__ == "__main__":
125 + main()
Newer Older