EyeStrainReminder/eyestrainreminder/EyeStrainReminder.py

154 lines
3.7 KiB
Python
Executable File

#!/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 Menu as menu, 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 = start_sound = end_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))
menu_items.append(menu.SEPARATOR)
menu_items.append(item('Exit', exit))
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 exit():
global icon
icon.stop()
os._exit(0)
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(start_sound)
sleep(TIMEOUT)
notification.close()
play_sound(end_sound)
def play_sound(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("-ss", "--start_sound", action="store", default=DIR +
"/files/ptt-s.wav", help="Custom start notification sound")
parser.add_argument("-es", "--end_sound", action="store", default=DIR +
"/files/ptt-e.wav", help="Custom end 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()