#!/usr/bin/python3 import argparse import os import threading from time import sleep import notify2 import pystray from PIL import Image from playsound import playsound from pystray import MenuItem as item NAME = 'Eye Strain Reminder' MESSAGE = 'Friendly reminder to observe the 20-20-20 rule' MESSAGE_MISSED = 'Missed notification(s), resuming countdown' TIMEOUT = 20 MILLISECOND = 1000 MINUTE = 60 DIR = os.path.dirname(os.path.abspath(__file__)) icon = mute = disable_notifs = invert_icons = notify_thread = sound = None def init(): print("Initializing EyeStrainReminder...") notify2.init(NAME) def create_tray_icon(): global icon image = get_image() icon = pystray.Icon(NAME, image, NAME, generate_menu_items()) icon.run() def update_icon(): global icon image = get_image() icon.icon = image def get_image(): theme = [[DIR + "/files/eye_light.png", DIR + "/files/eye_dark.png"], [DIR + "/files/eye_dark.png", DIR + "/files/eye_light.png"]] return Image.open(theme[invert_icons][disable_notifs]) def generate_menu_items(): menu_items = [] menu_items.append(item('Mute' if not mute else 'Unmute', toggle_mute)) menu_items.append(item('Do Not Disturb' if not disable_notifs else 'Enable Notifications', toggle_notifications)) return menu_items def toggle_mute(): global mute mute = not mute update_menu() def toggle_notifications(): global disable_notifs disable_notifs = not disable_notifs update_menu() update_icon() def update_menu(): global icon icon.menu = generate_menu_items() icon.update_menu() def uninit(): notify2.uninit() def wait(): sleep(TIMEOUT*MINUTE) def send_notification(): if not disable_notifs: notify(MESSAGE) else: print("Notifications are disabled, waiting for an enable...") while disable_notifs: sleep(10) notify(MESSAGE_MISSED) def notify(message): print(message) notification = notify2.Notification(NAME, message, "notification-device-eject") notification.set_timeout(TIMEOUT * MILLISECOND) notification.set_urgency(notify2.URGENCY_LOW) notification.show() play_sound() sleep(TIMEOUT) notification.close() play_sound() def play_sound(): if not mute: playsound(sound) def parse_args(): parser = argparse.ArgumentParser() parser.add_argument("-i", "--invert_icons", action="store_true", default=False, help="Default to the dark icon for light themes") parser.add_argument("-m", "--mute", action="store_true", default=False, help="Mute notification sounds by default") parser.add_argument("-n", "--disable_notifs", action="store_true", default=False, help="Disable notifications by default") parser.add_argument("-s", "--sound", action="store", default=DIR + "/files/default.wav", help="Custom notification sound") args = parser.parse_args() globals().update(args.__dict__) def notification_loop(): init() while 1: wait() send_notification() uninit() def main(): parse_args() notify_thread = threading.Thread(target=notification_loop, name="Notify Thread") notify_thread.start() create_tray_icon() notify_thread.join() if __name__ == '__main__': main()