Last active 1489047421

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

unread.py Raw
1#!/usr/bin/env python3
2c = {
3 "client_id": "",
4 "client_secret": "",
5 "refresh_token": "" # obtained after running script for first time
6}
7
8import os
9import sys
10import time
11try:
12 import requests
13except ImportError:
14 print("pip install requests")
15 sys.exit(1)
16if 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)
24elif sys.platform == "linux": # Untested
25 try:
26 import notify2
27 except ImportError:
28 print("pip install notify2, uses dbus notifications")
29 sys.exit(1)
30elif sys.platform == "darwin": # Untested
31 try:
32 from pync import Notifier
33 except ImportError:
34 print("pip install pync")
35 sys.exit(1)
36
37if 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
41if 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
52if sys.platform == "win32":
53 class Notifier:
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
57 message_map = {win32con.WM_DESTROY: self.OnDestroy, }
58 wc = win32gui.WNDCLASS()
59 self.destroyed = False
60 hinst = wc.hInstance = GetModuleHandle(None)
61 wc.lpszClassName = "PythonTaskbar"
62 wc.lpfnWndProc = message_map
63 class_atom = win32gui.RegisterClass(wc)
64 style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
65 self.hwnd = win32gui.CreateWindow(class_atom, "Taskbar", style,
66 0, 0, win32con.CW_USEDEFAULT,
67 win32con.CW_USEDEFAULT, 0, 0,
68 hinst, None)
69 win32gui.UpdateWindow(self.hwnd)
70 icon_path_name = os.path.abspath(os.path.join(sys.path[0],
71 "balloontip.ico"))
72 icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
73 try:
74 hicon = win32gui.LoadImage(hinst, icon_path_name,
75 win32con.IMAGE_ICON, 0, 0, icon_flags)
76 except:
77 hicon = win32gui.LoadIcon(0, win32con.IDI_APPLICATION)
78 flags = win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP
79 nid = (self.hwnd, 0, flags, win32con.WM_USER+20, hicon, "tooltip")
80 win32gui.Shell_NotifyIcon(win32gui.NIM_ADD, nid)
81 win32gui.Shell_NotifyIcon(win32gui.NIM_MODIFY,
82 (self.hwnd, 0, win32gui.NIF_INFO,
83 win32con.WM_USER+20, hicon,
84 "Balloon tooltip", msg, 200, title))
85 time.sleep(10)
86 win32gui.DestroyWindow(self.hwnd)
87 win32gui.UnregisterClass(class_atom, hinst)
88 self.destroyed = True
89
90 def OnDestroy(self, hwnd, msg, wparam, lparam):
91 nid = (self.hwnd, 0)
92 win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, nid)
93 win32gui.PostQuitMessage(0) # Terminate the app.
94
95 def isDestroyed(self):
96 return self.destroyed
97elif sys.platform == "linux": # Untested
98 class Notifier:
99 def __init__(self, msg, title="Unread"):
100 n = notify2.Notification(title, msg, "notification-message-im")
101 n.show()
102 return n
103elif sys.platform == "darwin": # Untested
104 pass # Notifier class already imported with pync
105
106def truncate(text):
107 if len(text) > 150:
108 return text[:147] + "..."
109 return text
110
111def main():
112 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"]
113 h = {"User-Agent": "Unread by /u/suudo", "Authorization": "Bearer " + token}
114 messages = requests.get("https://oauth.reddit.com/message/unread", headers=h).json()["data"]["children"]
115 if len(messages) > 1:
116 n = Notifier("\n".join(
117 "/u/{}: {}".format(m["data"]["author"], truncate(m["data"]["body"])) for m in messages
118 ), "Unread: New messages from")
119 elif messages:
120 message = messages[0]["data"]
121 text = message["body"]
122 n = Notifier(truncate(message["body"]),
123 "Unread: New {} from /u/{}".format("comment" if message["was_comment"] else "message", message["author"]) )
124# requests.post("https://oauth.reddit.com/api/read_all_messages", headers=h)
125
126if __name__ == "__main__":
127 main()