birthdays-calendar-generator/birthdays-cal.py

127 lines
3.8 KiB
Python

import datetime
import hashlib
import sys
from bisect import bisect
import yaml
from icalendar import Calendar, Event
event_config = {'description': '', 'categories': '', 'language': ''}
zsigns = [(1, 20, ''), (2, 18, ''), (3, 20, ''), (4, 20, ''),
(5, 21, ''), (6, 21, ''), (7, 22, ''), (8, 23, ''),
(9, 23, ''), (10, 23, ''), (11, 22, ''), (12, 22, ''),
(12, 31, '')]
def load_config():
result = dict()
with open('config.yml', 'r', encoding='utf-8') as f:
result = yaml.load(f)
return result
def write_calendar(cal, filename):
with open(filename, 'wb') as f:
f.write(cal.to_ical())
def parse_dates(birthdays):
for item in birthdays:
person = item['person']
birthday_str = person['birthday']
if len(birthday_str) == 5:
person['birthday_no_year'] = True
birthday_str = birthday_str.replace(birthday_str[2], '.')
birthday_str = birthday_str + '.0001'
person['birthday'] = datetime.datetime.strptime(
birthday_str, '%d.%m.%Y').date()
def display(cal):
print(cal.to_ical().decode('utf-8'))
def sha1(string):
if isinstance(string, str):
string = string.encode('utf8')
h = hashlib.sha1()
h.update(string)
return h.hexdigest()
def age(person, year):
return abs(year - person['birthday'].year)
def zodiac_sign(person):
birthday = person['birthday']
return zsigns[bisect(zsigns, (birthday.month, birthday.day))][2]
def make_event(person, year):
event_date = person['birthday'].replace(year=year)
description = event_config['description']
lang_params = {'language': event_config['language']}
if 'birthday_no_year' in person:
description = description.replace('{age}', '')
description = description.format(
age=age(person, year), zodiac=zodiac_sign(person))
event = Event()
event.add('uid', sha1(person['name'] + ' birthday ' + str(year)))
event.add('summary', person['name'],
encode=True, parameters=lang_params)
event.add('description', description, encode=True, parameters=lang_params)
event.add('categories', event_config['categories'])
event.add('transp', 'TRANSPARENT')
event.add('dtstamp', datetime.datetime(
event_date.year, event_date.month, event_date.day))
event.add('dtstart', event_date)
event.add('dtend', event_date)
event.add('created', datetime.datetime.utcnow())
event.add('last-modified', datetime.datetime.utcnow())
return event
def add_events(cal, birthdays, year):
for item in birthdays:
event = make_event(item['person'], year)
cal.add_component(event)
def make_calendar(calname, timezone, birthdays, scale):
cal = Calendar()
cal.add('version', '2.0')
cal.add('prodid', '-//birthdays calendar generator//b4tman.ru//')
cal.add('calscale', 'GREGORIAN')
cal.add('method', 'PUBLISH')
cal.add('x-wr-timezone', timezone)
cal.add('x-wr-calname', calname)
for year in range(scale['start'], scale['start'] + scale['length']):
add_events(cal, birthdays, year)
return cal
config = load_config()
birthdays = config['birthdays']
event_config['language'] = config['language']
event_config['description'] = config['events']['description']
event_config['categories'] = config['events']['categories']
parse_dates(birthdays)
birthdays.sort(key=lambda x: x['person']['birthday'].strftime('%m.%d'))
cal = make_calendar(config['calname'],
config['timezone'], birthdays, config['scale'])
if len(sys.argv) > 1:
filename = sys.argv[1]
write_calendar(cal, filename)
else:
display(cal)