

Для людей, которые работают в офисе с персональным компьютером — бухгалтеров, инженеров, секретарей, менеджеров, специалистов, экспертов, начальников структурных подразделений и тем более директоров — сегодня обычным делом является сопровождать решение нескольких вопросов одновременно.
К примеру, звонит клиент и просит внести изменения в договор. Ты кладешь трубку — и тут звонит твой коллега и просит тебя направить ему давно забытый материал, который нужно еще постараться отыскать. Не успеваешь ты договорить с коллегой, как звонит на сотовый директор и просит составить ему небольшой отчет. А ведь до этого ты занимался своим вопросом! Нужно всё запомнить, ничего не упустить! Типичная ситуация, не правда ли?
Для того, чтобы все успевать в таких ситуациях, поможет простая напоминалка. Но что такое простая напоминалка? Каковы критерии ее простоты?
Для меня «простой напоминалкой» является та, которая действует по следующему принципу:
- Открываешь диалоговое окно напоминалки горячей клавишей (ну, или сочетанием клавиш, например Ctrl+Shift+X)
- Вводишь время и текст напоминания простыми понятными словами (например, «через 15 минут скинуть Алексею материал», «в 11 отчет директору», «в 13-15 обед», «завтра в 15:10 проследить за письмом», «в среду в 10 в налоговую»)
- Нажимаешь Enter.
- В заданное время выскакивает напоминалка, которую можно закрыть или отложить.
Лучшим, как мне кажется, решением такой задачи является программа XMinder. Наверное, если бы я писал техническое задание на разработку простой напоминалки, она бы выглядела именно как XMinder.
Этой программой я пользовался долгое время, пока однажды не решил установить на рабоче�� компьютере операционную систему Linux (к сожалению, программа XMinder написана только под Windows).
Потеря такой замечательной напоминалки была существенной, необходимо было находить выход и… я решил написать программу сам.
Ранее я имел небольшой опыт написания программ в html, php, actionscript (flash). Однако для такой задачи решил выбрать связку Python+Bash+Zenity+At.
Почему Python? — Потому что по нему нашлась хорошая документация, потому что по умолчанию он установлен в моем дистрибутиве Linux Mint 17. Уже после первых шагов осваивания нового языка я понимал, что решение задачи мне будет посильно.
Почему Bash? — Это отдельная история и связана она с функцией «Отложить» в моей напоминалке.
Почему Zenity? — Потому что просто, лаконично и опять же — встроено по умолчанию в большинство дистрибутивов LInux.
Почему At? — Так ведь именно эта программа всю задачу и решает! И умеет хранить данные даже после перезагрузки компьютера!
Таким образом, я только собрал в единое целое пару программ и добавил нужный синтаксис.
В итоге у меня получилось 2 файлика:
remind.py:
#!/usr/bin/env python # -*- coding: utf-8 -*- # RemindMe v1.5 created by Dennis Smal' in 2014 godgrace@mail.ru from __future__ import print_function import subprocess import re import sys def replace_all(t, d): """Общая функция для подмены переменных""" for i, j in d.iteritems(): t = t.replace(i, j, 1) return t def get_datex(text): """Извлекает из текста дату и подстроку с датой, которую нужно удалить""" whatdate = '' delwhatdate = '' datex = re.findall(r'\d{2}[.,-]\d{2}[.,-]\d{4}|\d{1}[.,-]\d{2}[.,-]\d{4}',text) # ищем дату в формате 19.08.2014 или 19-08-2014 или 19,08,2014 if datex: date = datex[0].replace('-','.').replace(',','.') # преобразуем дату в формат 19.08.2014 whatdate = date delwhatdate = datex[0]+' ' return whatdate, delwhatdate def get_day(text): """Извлекает из текста день недели и подстроку, которую нужно удалить""" when = '' delday = '' day = re.findall('завтра|Завтра|в понедельник|во вторник|в среду|в четверг|в пятницу|в субботу|в воскресенье',text) daywithoutin = re.findall('понедельник|вторник|среда|четверг|пятница|суббота|воскресенье',text) if day: ind = {'завтра':'tomorrow', 'Завтра':'tomorrow', 'в понедельник':'mon', 'во вторник':'tue', 'в среду':'wed', 'в четверг':'thu', 'в пятницу':'fri', 'в субботу':'sat', 'в воскресенье':'sun'} when = replace_all(day[0], ind) delday = day[0]+' ' elif daywithoutin: ind = {'понедельник':'mon', 'вторник':'tue', 'среда':'wed', 'четверг':'thu', 'пятница':'fri', 'суббота':'sat', 'воскресенье':'sun'} when = replace_all(daywithoutin[0], ind) delday = daywithoutin[0]+' ' return (when, delday) def get_clock(text): """Извлекает из текста время и подстроку, которую нужно удалить""" how = '' delclock = '' clock = re.findall('минуты |часа |дня |минуту |часов |день |минут |час |дней ',text) if clock: # смотрим, есть ли указание на часы, минуты, дни clockbank = {'минут ':'min', 'час ':'hour', 'дней ':'days', 'минуту ':'min', 'часа ':'hours', 'дня ':'days', 'минуты ':'min', 'часов ':'hours', 'день ':'days'} how = replace_all(clock[0], clockbank) delclock = clock[0] return (how, delclock) def add_task(out, x): """Добавляет напоминание в очередь at""" #для отладки, чтобы долго не ждать #x = 'at now' #print (x) cmd = 'echo "DISPLAY=:0 ~/remindme/task %s" | %s' % (out, x) subprocess.Popen(cmd, shell=True) def main(when="Через 15 минут", reminder=""): warn_cmd = [ 'zenity', '--warning', '--text="Попробуйте ещё раз.."' ] cmd = [ 'zenity', '--entry', '--title=Напоминалка', '--text=Введите напоминание', '--entry-text={} {}'.format(when, reminder), '--width=400' ] loop = True while loop: get = subprocess.check_output(cmd) # получаем текст text = get+' ' # добавляем в конец пробел, чтобы отрабатывать уведомления типа "напомнить мне через 10 минут". Если бы пробела не было, параметр clock был бы пуст. В параметре clock после слова "час" тоже стоит пробел, чтобы различать поиск "час" и "часов". find = re.findall('ерез [0-9]+|В [0-9:-]+|в [0-9:-]+|ерез час',text) if get: # убеждаемся, заполнено ли поле ввода if find: # убеждаемся, указано ли время напоминания what = find[0].split() timex = what[1].replace('-',':').replace('час','1') if len(timex) > 2: # заменяет выражения типа "в 10" на "в 10:00" time = timex else: time = timex+':00' whatdate, delwhatdate = get_datex(text) when, delday = get_day(text) how, delclock = get_clock(text) reps = {'ерез':'at now + %s %s' % (timex,how),'В':'at %s %s %s' % (time,when,whatdate),'в':'at %s %s %s' % (time,when,whatdate)} wors = {'Через %s %s' % (what[1],delclock):'','через %s %s' % (what[1],delclock):'','В %s ' % what[1]:'','в %s ' % what[1]:'', '%s' % delday:'', 'Через час':'', 'через час':'', '%s' % delwhatdate:'',} # какие слова мы будем удалять x = replace_all(what[0], reps) # это время, на которое запланировано появление напоминания out = replace_all(text, wors) # это текст напоминания add_task(out, x) loop = False else: error = subprocess.check_output(warn_cmd) else: loop = False def usage(): s = "Использование: {} [Время напоминания [Напоминание]]".format(__file__) print(s) if __name__ == "__main__": if len(sys.argv) <= 3: main(*sys.argv[1:]) else: usage()
и task:
#!/bin/bash zenity --question --title=Напоминание --ok-label=Отложить --cancel-label=Ok --text="$*" case $? in 0) ~/remindme/remind.py "Через 15 минут" "$*" ;; 1) ;; esac
Файлы нужно положить в одну директорию (у меня это ~/remindme) и сделать исполняемыми (например командой «chmod +x»).
На файл remind.py необходимо назначать горячие клавиши (в разных дистрибутивах это делается по-разному), например, сочетание клавиш Ctrl+Shift+X.
Файлы для скачивания доступны по ссылке.
Проект выложен на GitHub.
