156 lines
4.9 KiB
Python
156 lines
4.9 KiB
Python
import icalendar
|
|
import sys
|
|
import os
|
|
import database
|
|
import json
|
|
import datetime
|
|
import dt as localdt
|
|
|
|
def AdvancedDatetTimeGet(dt, isStartDateTime):
|
|
if isinstance(dt, datetime.datetime):
|
|
gottenDatetime = int(dt.timestamp() / 60)
|
|
elif isinstance(dt, datetime.date):
|
|
gottenDatetime = int(datetime.datetime(
|
|
dt.year,
|
|
dt.month,
|
|
dt.day,
|
|
0 if isStartDateTime else 23,
|
|
0 if isStartDateTime else 59,
|
|
0 if isStartDateTime else 59,
|
|
0, tzinfo=LOCAL_TZ
|
|
).timestamp() / 60)
|
|
else:
|
|
raise Exception('Unexpected data')
|
|
|
|
timezoneOffset = LOCAL_UTC_OFFSET
|
|
return (gottenDatetime, timezoneOffset)
|
|
|
|
def AdvancedDateTimeAnalyser(component):
|
|
startDatetimeRef = component.get('DTSTART').dt
|
|
(startDatetime, timezoneOffset) = AdvancedDatetTimeGet(startDatetimeRef, True)
|
|
|
|
if component.get('DTEND') is not None:
|
|
(endDatetime, _) = AdvancedDatetTimeGet(startDatetimeRef, False)
|
|
elif component.get('DURATION') is not None:
|
|
endDurationRef = component.get('DURATION').dt
|
|
if isinstance(endDurationRef, datetime.timedelta):
|
|
endDatetime = startDatetime + int(endDurationRef.total_seconds() / 60)
|
|
else:
|
|
raise Exception('Unexpected data')
|
|
else:
|
|
raise Exception('Unexpected data')
|
|
|
|
return (startDatetime, endDatetime, timezoneOffset)
|
|
|
|
def LoopRulesConverter(component):
|
|
jsonData = component.get('RRULE')
|
|
if jsonData is None:
|
|
return ""
|
|
|
|
loopRules = ""
|
|
loopStopRules = ""
|
|
freq = jsonData.get('FREQ')[0]
|
|
if freq == 'MONTHLY':
|
|
loopRules = 'MSA{}'.format(str(jsonData.get('INTERVAL')[0]))
|
|
elif freq == 'WEEKLY':
|
|
occupiedWeek = [False, ] * 7
|
|
for item in jsonData.get('BYDAY'):
|
|
occupiedWeek[WEEK_DICT[item]] = True
|
|
loopRules = 'W{}{}'.format(
|
|
''.join(map(lambda x: 'T' if x else 'F', occupiedWeek)),
|
|
str(jsonData.get('INTERVAL')[0])
|
|
)
|
|
elif freq == 'YEARLY':
|
|
loopRules = 'YS{}'.format(str(jsonData.get('INTERVAL')[0]))
|
|
else:
|
|
raise Exception('Unexpected data')
|
|
|
|
if jsonData.get('COUNT') is not None:
|
|
loopStopRules = 'T{}'.format(str(jsonData.get('COUNT')[0]))
|
|
else:
|
|
loopStopRules = 'F'
|
|
|
|
return loopRules + '-' + loopStopRules
|
|
|
|
# ============================ read args
|
|
icsFilePath = sys.argv[1]
|
|
if not os.path.isfile(icsFilePath):
|
|
print('Fail to load ics file')
|
|
sys.exit(1)
|
|
|
|
# read file
|
|
icsFile = open(icsFilePath, 'rb')
|
|
cal = icalendar.Calendar.from_ical(icsFile.read())
|
|
icsFile.close()
|
|
|
|
# ============================ init const
|
|
utfOffset = float(input('Input this ics file\'s utc offset (time unit: hour)>'))
|
|
LOCAL_UTC_OFFSET = int(utfOffset * 60)
|
|
LOCAL_TZ = localdt.UTCTimezone(LOCAL_UTC_OFFSET)
|
|
WEEK_DICT = {
|
|
"SU": 6, "MO": 0, "TU": 1, "WE": 2, "TH": 3, "FR": 4, "SA": 5,
|
|
}
|
|
|
|
# ============================ pick database
|
|
|
|
db = database.CalendarDatabase()
|
|
db.open()
|
|
username = input('Input username >')
|
|
password = input('Input password >')
|
|
(status, error, token) = db.common_webLogin(username, password, 'Python backend', '127.0.0.1')
|
|
if not status:
|
|
print('Fail to login.')
|
|
sys.exit(1)
|
|
(status, error, collectionList) = db.collection_getFullOwn(token)
|
|
if not status:
|
|
print('Database return an error')
|
|
sys.exit(1)
|
|
print('Pick a collection to insert imported events')
|
|
counter = 0
|
|
for i in collectionList:
|
|
print('{}\t{}'.format(counter, i[1]))
|
|
counter += 1
|
|
pickedIndex = int(input())
|
|
collectionUuid = collectionList[pickedIndex][0]
|
|
|
|
# ============================ analyse file
|
|
eventCount = 0
|
|
allCount = 0
|
|
for component in cal.walk():
|
|
allCount += 1
|
|
# only import event chunk
|
|
if component.name == 'VEVENT':
|
|
eventCount += 1
|
|
title = str(component.get('SUMMARY'))
|
|
descriptionPrototype = {
|
|
'color': '#1e90ff',
|
|
'description': None
|
|
}
|
|
descriptionList = []
|
|
if component.get('DESCRIPTION') is not None and str(component.get('DESCRIPTION')) != '':
|
|
descriptionList.append(component.get('DESCRIPTION'))
|
|
if component.get('LOCATION') is not None and str(component.get('LOCATION')) != '':
|
|
descriptionList.append(component.get('LOCATION'))
|
|
descriptionPrototype['description'] = '\n'.join(descriptionList)
|
|
description = json.dumps(descriptionPrototype)
|
|
|
|
(eventDateTimeStart, eventDateTimeEnd, timezoneOffset) = AdvancedDateTimeAnalyser(component)
|
|
loopRules = LoopRulesConverter(component)
|
|
|
|
(status, _, _) = db.calendar_add(
|
|
token,
|
|
collectionUuid,
|
|
title,
|
|
description,
|
|
eventDateTimeStart,
|
|
eventDateTimeEnd,
|
|
loopRules,
|
|
timezoneOffset
|
|
)
|
|
if not status:
|
|
print('Database return an error')
|
|
sys.exit(1)
|
|
|
|
db.common_logout(token)
|
|
db.close()
|
|
print('All chunk: {}\nEvent count: {}'.format(allCount, eventCount)) |