-rw-r--r-- mindfulness.py
1 # Copyright (c) 2022 Matt Colligan 2 # 3 # Permission is hereby granted, free of charge, to any person obtaining a copy 4 # of this software and associated documentation files (the "Software"), to deal 5 # in the Software without restriction, including without limitation the rights 6 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 # copies of the Software, and to permit persons to whom the Software is 8 # furnished to do so, subject to the following conditions: 9 # 10 # The above copyright notice and this permission notice shall be included in 11 # all copies or substantial portions of the Software. 12 # 13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 # SOFTWARE. 20 21 import os 22 from random import randint 23 from urllib import request 24 25 import gi 26 27 gi.require_version("Gst", "1.0") 28 from gi.repository import Gst 29 from libqtile.log_utils import logger 30 from libqtile.utils import get_cache_dir 31 from libqtile.widget import base 32 33 Gst.init(None) 34 35 36 class ReMindfulness(base.ThreadPoolText): 37 """ 38 Mindfulness reminder widget (Proof of concept / work in progress) 39 40 Inspired by Kyle MacLeod's mindfulnotifier Android app 41 (https://github.com/kmac/mindfulnotifier). The widget will periodically play a 42 calming tone at semi-random intervals. 43 44 Note, if the specified audio_file does not exist (i.e. the first time the widget is 45 configured, leaving the default value for ``audio_file``), one will be downloaded. 46 It is fetched via the mindfulnotifier app's github repository. 47 """ 48 49 default_path = os.path.join(get_cache_dir(), "tibetan_bell_ding_b.mp3") 50 default_url = "https://github.com/kmac/mindfulnotifier/raw/master/media/tibetan_bell_ding_b.mp3" 51 52 defaults = [ 53 ("audio_file", default_path, "Lower bound for the interval between reminders"), 54 ("interval_minimum", 60 * 60, "Lower bound for the interval between reminders"), 55 ("interval_maximum", 90 * 60, "Upper bound for the interval between reminders"), 56 ("reminder_background", "ff0000", "Background colour when reminding"), 57 ("reminder_foreground", "ff0000", "Foreground colour when reminding"), 58 ("reminder_duration", 5, "Duration of reminders (i.e. for appearance change)"), 59 ("reminder_text", None, "Text"), 60 ] 61 62 def __init__(self, text="", **config): 63 base.ThreadPoolText.__init__(self, text, **config) 64 self.add_defaults(ReMindfulness.defaults) 65 self._just_started = True 66 self._original_foreground = self.foreground 67 self._original_background = self.background 68 69 self.add_callbacks( 70 { 71 "Button1": self._reset_colours, 72 } 73 ) 74 75 def _configure(self, qtile, bar): 76 self._just_started = not self.configured 77 base.ThreadPoolText._configure(self, qtile, bar) 78 79 def poll(self): 80 self.update_interval = randint(self.interval_minimum, self.interval_maximum) 81 82 if self._just_started: 83 return self.text 84 85 if not os.path.exists(self.audio_file): 86 logger.info("Downloading default tone for ReMindfulness widget") 87 request.urlretrieve(self.default_url, self.audio_file) 88 89 playbin = Gst.ElementFactory.make("playbin", "playbin") 90 playbin.props.uri = "file://" + self.audio_file 91 playbin.set_state(Gst.State.PLAYING) 92 93 self.foreground = self.reminder_foreground 94 self.background = self.reminder_background 95 self.timeout_add(self.reminder_duration, self._reset_colours) 96 97 return self.text 98 99 def _reset_colours(self): 100 self.foreground = self._original_foreground 101 self.background = self._original_background 102