#!/usr/bin/env python import sys, pygame, string, datetime, os, MythTV from subprocess import * from pygame.locals import * pygame.init() pygame.key.set_repeat(300, 50) # map myth keys to pygame keys MYTHKEYS = { "0": K_0, "1": K_1, "2": K_2, "3": K_3, "4": K_4, "5": K_5, "6": K_6, "7": K_7, "8": K_8, "9": K_9, "Esc": K_ESCAPE, "Backspace": K_BACKSPACE, "Return": K_RETURN, "Enter": K_RETURN, "Space": K_SPACE } class MythTVKey(MythTV.MythDB): def getAllKeybindings(self, hostname=None): """ Returns values for all settings. Returns None if there are no settings. If multiple rows are found (multiple hostnames), returns the value of the first one. """ c = self.db.cursor() if hostname is None: c.execute(""" SELECT action, keylist FROM keybindings WHERE hostname IS NULL and context='Global'""") else: c.execute(""" SELECT action, keylist FROM keybindings WHERE hostname LIKE('%s%%') and context='Global'""" % (hostname)) # fixme U R DOIN IT WRONG rows = c.fetchall() c.close() if rows: return rows else: return None class Widget(object): def __init__(self): pass def keypress(self, key): pass class LetterSurface(Widget): def __init__(self, text, colour=(255,0,0), highlight=(0,0,255), fontsize=16, ttf=None): super(LetterSurface,self).__init__() self.text = text self.colour = colour self.font = pygame.font.Font(ttf, fontsize) self.highlight = highlight self.is_selectable = False def render(self, highlighted=False): if highlighted: surface = self.font.render(self.text, True, self.colour, self.highlight) else: surface = self.font.render(self.text, True, self.colour) return surface def get_size(self): return self.font.size(self.text) class SelectableLetterSurface(LetterSurface): def __init__(self, text, colour=(255,0,0), highlight=(0,0,255), fontsize=16, ttf=None, action=None): super(SelectableLetterSurface,self).__init__(text, colour, highlight, fontsize, ttf) self.is_selectable = True if action: self.action = action else: self.action = self.dummy def dummy(self): pass def keypress(self, key): if key == K_RETURN: self.action() class ChangeableLetterSurface(LetterSurface): def __init__(self, values, colour=(255,0,0), highlight=(0,0,255), fontsize=16, ttf=None): super(ChangeableLetterSurface,self).__init__(None, colour, highlight, fontsize, ttf) self.values = values self.colour = colour if len(self.values) == 0: self.values = ["----"] self.idx = 0 self.text = self.values[self.idx] self.font = pygame.font.Font(ttf, fontsize) self.is_selectable = True def keypress(self, key): if key == K_UP: self.idx += 1 if self.idx == len(self.values): self.idx = 0 elif key == K_DOWN: self.idx -= 1 if self.idx == -1: self.idx = len(self.values) - 1 self.text = self.values[self.idx] class MainWindow: def __init__(self): WIDTH, HEIGHT = 320, 200 self.screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption('MythTV alarm clock') # register standard keys so this works on the desktop self.register_key_event(K_UP, self.send_key, K_UP) self.register_key_event(K_DOWN, self.send_key, K_DOWN) self.register_key_event(K_RETURN, self.send_key, K_RETURN) self.register_key_event(K_LEFT, self.left) self.register_key_event(K_RIGHT, self.right) self.register_key_event(K_ESCAPE, sys.exit) self.register_nonkey_event(pygame.QUIT, sys.exit) self.bindMythKeys() self.hours = ChangeableLetterSurface( [("0%s" % x)[-2:] for x in range(24)], fontsize=60, colour=(255,255,255), highlight=(255,0,0)) self.min = ChangeableLetterSurface( [("0%s" % x)[-2:] for x in range(60)], fontsize=60, colour=(255,255,255), highlight=(255,0,0)) self.repeat = ChangeableLetterSurface( ["Next only", "Every day", "Mon - Fri"], fontsize=60, colour=(255,255,255), highlight=(255,0,0)) button_save = SelectableLetterSurface("Save", fontsize=60, colour=(255,255,255), highlight=(255,0,0), action=self.save) button_cancel = SelectableLetterSurface("Cancel", fontsize=60, colour=(255,255,255), highlight=(255,0,0), action=sys.exit) colon = LetterSurface(":", fontsize=60, colour=(255,255,255), highlight=(255,0,0)) hw, hh = self.hours.get_size() cw, ch = colon.get_size() mw, mh = self.min.get_size() toplinewidth = hw + cw + mw toplineleft = (WIDTH / 2) - (toplinewidth / 2) rw, rh = self.repeat.get_size() midlineleft = (WIDTH / 2) - (rw / 2) bsw, bsh = button_save.get_size() bcw, bch = button_cancel.get_size() self.add_widget(self.hours, (toplineleft,10)) self.add_widget(colon, (toplineleft + hw,10)) self.add_widget(self.min, (toplineleft + hw + cw,10)) self.add_widget(self.repeat, (midlineleft, hh + 20)) self.add_widget(button_save, (WIDTH - bsw - 10, HEIGHT - bsh - 10)) self.add_widget(button_cancel, (10, HEIGHT - bch - 10)) self.clock = pygame.time.Clock() self.current_widget = 0 self.render() self.mainloop() def bindMythKeys(self): myth = MythTVKey() mkeys = dict(myth.getAllKeybindings(hostname="joyce")) self.bindMythKey(mkeys, "UP", self.send_key, K_UP) self.bindMythKey(mkeys, "DOWN", self.send_key, K_DOWN) self.bindMythKey(mkeys, "SELECT", self.send_key, K_RETURN) self.bindMythKey(mkeys, "LEFT", self.left) self.bindMythKey(mkeys, "RIGHT", self.right) self.bindMythKey(mkeys, "ESCAPE", sys.exit) def bindMythKey(self, keydict, mythaction, handler, extra_data=None): for mythkeyname in keydict[mythaction].split(","): pygamekeyname = MYTHKEYS.get(mythkeyname, None) if pygamekeyname: self.register_key_event(pygamekeyname, handler, extra_data) def add_widget(self, widget, position): if not hasattr(self, "widgets"): self.widgets = [] self.widgets.append((widget, position)) def register_key_event(self, key, handler, extra_data=None): if not hasattr(self, "key_events"): self.key_events = {} self.key_events[key] = (handler, extra_data) def register_nonkey_event(self, key, handler, extra_data=None): if not hasattr(self, "nonkey_events"): self.nonkey_events = {} self.nonkey_events[key] = (handler, extra_data) def render(self): self.screen.fill((0,0,0)) count = 0 for widget, position in self.widgets: highlighted = count == self.current_widget self.screen.blit(widget.render(highlighted), position) count += 1 pygame.display.flip() def mainloop(self): while 1: self.clock.tick(60) # run at 60fps rather than busywaiting for event in pygame.event.get(KEYDOWN): handler, extra_data = self.key_events.get(event.key, (None, None)) if handler: if extra_data: handler(extra_data) else: handler() for event in pygame.event.get(): handler, extra_data = self.nonkey_events.get(event.type, (None, None)) if handler: if extra_data: handler(extra_data) else: handler() def send_key(self, key): self.widgets[self.current_widget][0].keypress(key) self.render() def save(self): m = int(self.min.text) h = int(self.hours.text) crontab = { "mi": m, "h": h } if self.repeat.text == "Next only": now = datetime.datetime.now() nowd = now.date() thisdayattime = datetime.datetime(nowd.year, nowd.month, nowd.day, h, m) delta = now - thisdayattime if delta.days < 0: # specified time is later on today crontab.update({ "d": thisdayattime.day, "mo": thisdayattime.month, "wd": "*" }) else: # specified time has already happened today, so it's tomorrow newdayattime = thisdayattime + datetime.timedelta(1) crontab.update({ "d": newdayattime.day, "mo": newdayattime.month, "wd": "*" }) elif self.repeat.text == "Every day": crontab.update({ "d": "*", "mo": "*", "wd": "*" }) elif self.repeat.text == "Mon - Fri": crontab.update({ "d": "*", "mo": "*", "wd": "1-5" }) cmd = os.path.join(os.path.split(__file__)[0], "play-alarm") cmd = os.path.realpath(cmd) line = ("%(mi)s %(h)s %(d)s %(mo)s %(wd)s " % crontab) + \ cmd + \ " # myth-alarm-clock" existing_crontab = Popen(["crontab", "-l"], stdout=PIPE).communicate()[0] new_crontab = existing_crontab + "\n" + line + "\n" Popen(["crontab", "-"], stdout=PIPE, stdin=PIPE, stderr=STDOUT).communicate(new_crontab) # show save message self.widgets = [] self.add_widget(LetterSurface("alarm set", fontsize=30, colour=(0,255, 0), highlight=(255,0,0)), (10,10)) self.render() # and die pygame.time.wait(500) sys.exit() def left(self): while 1: self.current_widget -= 1 if self.current_widget == -1: self.current_widget = len(self.widgets) - 1 if self.widgets[self.current_widget][0].is_selectable: break self.render() def right(self): while 1: self.current_widget += 1 if self.current_widget == len(self.widgets): self.current_widget = 0 if self.widgets[self.current_widget][0].is_selectable: break self.render() if __name__ == "__main__": main = MainWindow()