ya3

ya3 -- yet another appointment application
Log | Files | Refs

commit 9325442532283a59d47fc768b8ea7a1331e1c88e
parent 49ebb3884d0ce41e0d4c7151c2dcbece6ce64558
Author: Matthias Balk <mbalk@mbalk.de>
Date:   Sun, 16 Sep 2018 19:40:08 +0200

Using "vobject" instead of "ical2vcal"

Further improvements:
- configuration file
- `create-appointment.py` for creation of events

Diffstat:
MREADME.rst | 32+++++++++++---------------------
Aconfig.py | 12++++++++++++
Acreate-appointment.py | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mya3 | 68++++++++++++++++++++++++++++++++++----------------------------------
4 files changed, 123 insertions(+), 55 deletions(-)

diff --git a/README.rst b/README.rst @@ -4,48 +4,38 @@ ya3 -- yet another appointment application ya3 wants to be a simple tool helping you to organise your appointments. It is far away from being finished. -ya3 uses Charl Botha's ical2vcal to read and write calendar files (vCal). See -http://cpbotha.net/2007/04/26/google-calendar-to-palm-desktop-conversion/ and -http://code.google.com/p/ical2vcal/ for more information. - For licensing information see LICENSE.txt . Features ~~~~~~~~ - Reading all vCal files from a directory and spit out appointments of the next few days on stdout. +- Creation of new appointments Features to be implemented ~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Create new appointments. -- Change existing appointments. -- Delete appointments. - Support for recurrence (like birthdays). - ... +Requirements +~~~~~~~~~~~~ +- Python3 (and Python2!!! :-o) +- Python dateutil +- Python vobject + Installation and setup ~~~~~~~~~~~~~~~~~~~~~~ -First of all, python is needed. - -Second, get ya3 via git: +Get ya3 and place it where you like: $ cd /path/where/ya3/shall/be/put $ git pull .... ya3 -Third, get ical2vcal via svn: -$ cd ya3/ical2vcal -$ svn checkout http://ical2vcal.googlecode.com/svn/trunk/ . -ACHTUNG: URL veraltet. Siehe https://code.google.com/archive/p/ical2vcal/ - -Fourth, copy and edit configuration (not yet implemented): -$ mkdir -p -m 0700 $HOME/.ya3/calendars -$ cp /path/where/ya3/shall/be/put/ya3/config.template $HOME/.ya3/ +Edit configuration in config.py to fit your needs. Usage ~~~~~ -$ ya3 <vcal file> +$ create-appointment.py -Future plans: -$ ya3 -g [date from[-date to]] +$ ya3 <vcal file> Example ~~~~~~~ diff --git a/config.py b/config.py @@ -0,0 +1,12 @@ +from datetime import timedelta +from os import path + +CAL_DIR = path.expanduser('~/.ya3/calendars/') + +DEFAULTS = { + 'LOCATION': 'Besprechungsraum', + 'SUMMARY': 'Meeting' +} + +MAX_AGE = timedelta(days=1) +MAX_AHEAD = timedelta(days=14) diff --git a/create-appointment.py b/create-appointment.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +import os +import re +import time +import uuid +from collections import OrderedDict +from datetime import datetime + +from dateutil.parser import parse + +import config + + +def localtime2utc(datetimestr): + local = parse('%s %s' % (datetimestr, time.tzname[0])) + return local - local.utcoffset() + + +def get_input(key): + if key in config.DEFAULTS: + i = input('%s: [%s] ' % (key, config.DEFAULTS[key])) + return i if i.strip() is not '' else config.DEFAULTS[key] + return input('%s: ' % key) + + +def create_event(): + event = OrderedDict([ + ('BEGIN', 'VEVENT'), + ('DTSTART', None), + ('DTEND', None), + ('LOCATION', None), + ('SUMMARY', None), + ('UID', str(uuid.uuid4())), + ('END', 'VEVENT'), + ]) + + for key in ['DTSTART', 'DTEND', 'LOCATION', 'SUMMARY']: + event[key] = get_input(key) + if re.match('DT', key): + event[key] = localtime2utc(event[key]) + + return event + + +def event2file(event): + filename = '%s-%s.ics' % (event['DTSTART'].strftime('%Y-%m-%d'), + re.sub(r'\s+', '-', event['SUMMARY'].lower())) + f = open(os.path.join(config.CAL_DIR, filename), 'w') + f.write('BEGIN:VCALENDAR\nVERSION:2.0\n') + f.write('PRODID://ya3//yet another appointment application//\n') + + def item2str(key, value): + if isinstance(value, datetime): + return '%s:%s\n' % (key, value.strftime('%Y%m%dT%H%M%SZ')) + return '%s:%s\n' % (key, value) + + for key in event: + f.write(item2str(key, event[key])) + + f.write('END:VCALENDAR\n') + f.close() + + +event = create_event() +event2file(event) diff --git a/ya3 b/ya3 @@ -1,42 +1,42 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ya3 -- yet another appointment application""" import sys -import time -from ical2vcal import vcal +from datetime import datetime + +import config +import vobject +from dateutil.tz import gettz + + +def conv2local(dt): + if dt.tzinfo is None: + return datetime(dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second, + tzinfo=gettz()) + return dt.astimezone(gettz()) + def print_events(icsfilename): """foo""" - try: - cal = vcal.parse(icsfilename) - for event in cal.events: - try: - start = time.strptime(event.dtstart, '%Y%m%dT%H%M%S') - except ValueError: - start = time.strptime(event.dtstart, '%Y%m%d') - - try: - end = time.strptime(event.dtend, '%Y%m%dT%H%M%S') - except ValueError: - end = time.strptime(event.dtend, '%Y%m%d') - - try: - location = " (" + event.location + ")" - except AttributeError: - location = "" - - if start >= time.localtime(time.time() - 86400) and \ - start < time.localtime(time.time() + 14 * 86400): - print time.strftime('%Y-%m-%d %H:%M', start) + " - " + \ - time.strftime('%H:%M', end) + " " + event.summary + \ - location - #start = vcal.parsetime(event.dtstart) - #print start - return True - - except vcal.ParseError: - return False - -for filename in sys.argv: + + f = open(icsfilename) + for event in vobject.readComponents(f): + start = conv2local(event.vevent.dtstart.value) + end = conv2local(event.vevent.dtend.value) + + try: + location = " (" + event.vevent.location.value + ")" + except AttributeError: + location = "" + + if start >= datetime.now(gettz()) - config.MAX_AGE and \ + start < datetime.now(gettz()) + config.MAX_AHEAD: + print('%s - %s %s%s' % (start.strftime('%Y-%m-%d %H:%M'), + end.strftime('%H:%M'), + event.vevent.summary.value, + location)) + + +for filename in sys.argv[1:]: print_events(filename)