Last active 1489047421

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

Revision e50d84bafcb8ab4471639e0fa0232fa5ab8807ae

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 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
95elif 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
101elif sys.platform == "darwin": # Untested
102 pass # Notifier class already imported with pync
103
104def truncate(text):
105 if len(text) > 150:
106 return text[:147] + "..."
107 return text
108
109def 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
124if __name__ == "__main__":
125 main()