cal.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #!/usr/bin/env python3
  2. '''
  3. This file is part of FIXME Screen Calendar.
  4. FIXME Events is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. FIXME Events is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with FIXME Events. If not, see <http://www.gnu.org/licenses/>.
  14. '''
  15. import requests
  16. import icalendar
  17. import arrow
  18. import types
  19. import json
  20. FILE = 'events.json'
  21. user_agent = 'fixme-calendar/0.1'
  22. calendars = [
  23. 'https://calendar.google.com/calendar/ical/sruulkb8vh28dim9bcth8emdm4%40group.calendar.google.com/public/basic.ics',
  24. 'https://calendar.google.com/calendar/ical/fablab.renens%40gmail.com/public/basic.ics',
  25. ]
  26. #
  27. # Functions
  28. #
  29. def get_recurrences(cal_name, dt_start, dt_end, evt):
  30. #print('get_recurrences')
  31. rrule = evt.get('rrule')
  32. byday = rrule.get('byday')
  33. freq = rrule.get('freq')[0]
  34. until = rrule.get('until')
  35. if until is not None:
  36. rec_end = arrow.get(until[0])
  37. else:
  38. rec_end = arrow.get().replace(months=+1)
  39. events = []
  40. while dt_start < rec_end:
  41. events.append(get_event(cal_name, dt_start, dt_end, evt))
  42. # Increment date
  43. if freq == 'WEEKLY':
  44. dt_start = dt_start.replace(days=+7)
  45. dt_end = dt_end.replace(days=+7)
  46. elif freq == 'MONTHLY':
  47. dt_start = dt_start.replace(months=+1)
  48. dt_end = dt_end.replace(months=+1)
  49. elif freq == 'YEARLY':
  50. dt_start = dt_start.replace(years=+1)
  51. dt_end = dt_end.replace(years=+1)
  52. else:
  53. dt_start = dt_start.replace(days=+1)
  54. dt_end = dt_end.replace(days=+1)
  55. return events
  56. def get_event(cal_name, dt_start, dt_end, evt):
  57. summary = evt.get('summary')
  58. #print('get_event=' + summary)
  59. location = evt.get('location')
  60. description = evt.get('description')
  61. dt_start = dt_start.to('Europe/Zurich')
  62. dt_end = dt_end.to('Europe/Zurich')
  63. return {
  64. 'cal': cal_name,
  65. 'name': summary,
  66. 'dow': dt_start.datetime.strftime('%A'),
  67. 's_day': dt_start.format('DD'),
  68. 's_month': dt_start.format('MMM'),
  69. 's_month_num': dt_start.format('MM'),
  70. 's_year': dt_start.format('YYYY'),
  71. 's_time': dt_start.format('HH:mm'),
  72. 'e_day': dt_end.format('DD'),
  73. 'e_month': dt_end.format('MMM'),
  74. 'e_year': dt_end.format('YYYY'),
  75. 'e_time': dt_end.format('HH:mm'),
  76. 'timestamp': dt_start.timestamp,
  77. 'location': location,
  78. 'description': description,
  79. }
  80. def get_calendar(url):
  81. name = ''
  82. events = []
  83. cal_data = requests.get(url, headers={'User-Agent': user_agent}).content
  84. try:
  85. cal_obj = icalendar.Calendar.from_ical(cal_data)
  86. cal_name = cal_obj.get('x-wr-calname')
  87. #print('get_calendar=' + cal_name)
  88. recent = arrow.now().floor('day').replace(days=-30) # FIXME: must be yesterday ?
  89. for e in cal_obj.walk():
  90. if e.name != 'VEVENT':
  91. continue
  92. # Get dates
  93. try:
  94. dt_start = arrow.get(e.get('dtstart').dt)
  95. dt_end = arrow.get(e.get('dtend').dt)
  96. except TypeError as f:
  97. dt_start = arrow.Arrow.fromdate(e.get('dtstart').dt)
  98. dt_end = arrow.Arrow.fromdate(e.get('dtend').dt)
  99. # Only future or recent events
  100. if dt_start < recent:
  101. continue
  102. # Create and add event
  103. if not e.has_key('rrule') or (e.has_key('rrule') and isinstance(e.get('rrule'), types.NoneType)):
  104. evt = get_event(cal_name, dt_start, dt_end, e)
  105. if evt not in events:
  106. events.append(evt)
  107. else:
  108. for f in get_recurrences(cal_name, dt_start, dt_end, e):
  109. if f not in events:
  110. events.append(f)
  111. except IOError as e:
  112. events.append({'name': e, 'cal': cal_name})
  113. return events
  114. def get_data():
  115. #print('get_data')
  116. # Get all events
  117. events = []
  118. for cal in calendars:
  119. events += get_calendar(cal)
  120. events = sorted(events, key=lambda i: i['timestamp'])
  121. # Split according to date range
  122. today_start = arrow.get().replace(hour=0, minute=0, second=0)
  123. today_end = today_start.replace(days=+1)
  124. week_end = today_start.replace(days=+7)
  125. past_events = [x for x in events if x['timestamp'] <= today_start.timestamp]
  126. today_events = [x for x in events if x['timestamp'] > today_start.timestamp and x['timestamp'] <= today_end.timestamp]
  127. week_events = [x for x in events if x['timestamp'] > today_end.timestamp and x['timestamp'] <= week_end.timestamp]
  128. future_events = [x for x in events if x['timestamp'] > week_end.timestamp]
  129. data = {
  130. 'past_events': past_events,
  131. 'today_events': today_events,
  132. 'week_events': week_events,
  133. 'future_events': future_events,
  134. }
  135. return data
  136. #
  137. # MAIN
  138. #
  139. if __name__ == '__main__':
  140. events = get_data()
  141. f = open(FILE, 'w+')
  142. f.write(json.dumps(events))
  143. f.close()