X-Git-Url: https://adrianiainlam.tk/git/?p=indicator-lunar-calendar.git;a=blobdiff_plain;f=indicator-lunar-calendar.py;fp=indicator-lunar-calendar.py;h=9f3ef0114c799f8e1b5ed15b452f47c300e76bd2;hp=0000000000000000000000000000000000000000;hb=95f1a19535e4a5336ff325a48199ada1998efd2f;hpb=9ee9956267315fa231fd54727e2e92a585a43bb3 diff --git a/indicator-lunar-calendar.py b/indicator-lunar-calendar.py new file mode 100755 index 0000000..9f3ef01 --- /dev/null +++ b/indicator-lunar-calendar.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# indicator-lunar-calendar - shows lunar calendar information +# Copyright (c) 2019 Adrian I Lam s/spam/me/ +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHOR OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# I would like to thank Tobias Schlitt , who wrote +# indicator-chars which I used +# as a reference when writing this software. + +import signal +import datetime +import os +import gi +gi.require_version('Gdk', '3.0') +gi.require_version('Gtk', '3.0') +gi.require_version('AppIndicator3', '0.1') +from gi.repository import Gdk, Gtk, AppIndicator3 +from LunarCalendarPy.LunarCalendar import LunarCalendar +import schedule +import threading +import time +import dbus +from dbus.mainloop.glib import DBusGMainLoop + +APP_NAME = 'indicator-lunar-calendar-py' +APP_VERSION = '1.2+py' + +SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) + + +class IndicatorLunarCalendar: + def __init__(self): + self.indicator = AppIndicator3.Indicator.new( + 'lunar-indicator', + os.path.join(SCRIPT_DIR, 'icons', '鼠.svg'), + AppIndicator3.IndicatorCategory.APPLICATION_STATUS) + self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE) + + self.menu = Gtk.Menu() + self.item = Gtk.MenuItem() + self.item.connect("activate", self.do_nothing) + self.menu.append(self.item) + self.indicator.set_menu(self.menu) + self.menu.show_all() + + self.lc = LunarCalendar() + self.update_indicator() + + def update_indicator(self): + # get current time at UTC+8, add 1 to date if after 23:00 (子時) + now = datetime.datetime.utcnow() + datetime.timedelta(hours=8) + hour = now.hour + if hour >= 23: + now = now.date() + datetime.timedelta(days=1) + + lunar = self.lc.solarToLunar(now.year, now.month, now.day) + lunar['hour'] = '子丑寅卯辰巳午未申酉戌亥'[(hour + 1) % 24 // 2] + + compact_date = lunar['lunarMonthName'] + lunar['lunarDayName'] + long_date = ( + lunar['GanZhiYear'] + '年(' + lunar['zodiac'] + '年)\n' + + lunar['lunarMonthName'] + lunar['lunarDayName'] + ) + if lunar['term']: + compact_date += ' ' + lunar['term'] + long_date += ' ' + lunar['term'] + long_date += '\n' + lunar['hour'] + '時' + + self.indicator.set_icon( + os.path.join(SCRIPT_DIR, 'icons', lunar['zodiac'] + '.svg') + ) + self.indicator.set_label(compact_date, '') + self.item.set_label(long_date) + + def do_nothing(self, arg): + pass + + +def run_schedule_one_iteration(): + prev_idle_sec = 60 * 60 + idle_sec = schedule.idle_seconds() + while idle_sec < prev_idle_sec: + prev_idle_sec = idle_sec + + if idle_sec > 2: + time.sleep(idle_sec - 2) + elif idle_sec > 0.199: + time.sleep(idle_sec - 0.199) + else: + schedule.run_pending() + + idle_sec = schedule.idle_seconds() + + +def cronThreadBody(): + while True: + run_schedule_one_iteration() + + +def updateJob(i): + i.update_indicator() + + +if __name__ == '__main__': + signal.signal(signal.SIGINT, lambda signum, frame: Gtk.main_quit()) + + i = IndicatorLunarCalendar() + + schedule.every().hour.at(":00").do(updateJob, i=i) + cronThread = threading.Thread(target=cronThreadBody) + cronThread.start() + + dbusloop = DBusGMainLoop() + bus = dbus.SystemBus(mainloop=dbusloop) + obj = bus.get_object('org.freedesktop.login1', '/org/freedesktop/login1') + iface = dbus.Interface(obj, + dbus_interface='org.freedesktop.login1.Manager') + + def sleepHandler(arg): + if arg == 0: + i.update_indicator() + schedule.clear() + schedule.every().minute.at(":00").do(updateJob, i=i) + newThread = threading.Thread(target=run_schedule_one_iteration) + newThread.start() + + iface.connect_to_signal('PrepareForSleep', sleepHandler) + + Gtk.main()