1
0

feat: move old scripts from my gist to here

This commit is contained in:
2026-06-01 23:27:41 +08:00
parent d7df194a12
commit c4b68400b3
2 changed files with 257 additions and 0 deletions

101
assets/ics2csv.py Normal file
View File

@@ -0,0 +1,101 @@
import icalendar
def DumpComponentHeader(file, component):
fields = []
inclusiveUnitCounter = 0
fields += map(lambda x: x + ' - required', component.required)
fields += map(lambda x: x + ' - singletons', component.singletons)
for units in component.inclusive:
fields += map(lambda x: x + ' - inclusive{}'.format(inclusiveUnitCounter), units)
inclusiveUnitCounter += 1
fields += ('exclusive - name', 'exclusive - data')
fields += ('multiple', )
file.write(','.join(fields))
file.write('\n')
def DumpComponentData(file, component):
data = []
gotten_instance = None
for item in component.required:
gotten_instance = component.get(item)
if gotten_instance is not None:
data.append(AdvancedFormater(gotten_instance))
else:
data.append('')
for item in component.singletons:
gotten_instance = component.get(item)
if gotten_instance is not None:
data.append(AdvancedFormater(gotten_instance))
else:
data.append('')
for units in component.inclusive:
for item in units:
gotten_instance = component.get(item)
if gotten_instance is not None:
data.append(AdvancedFormater(gotten_instance))
else:
data.append('')
gotten_name = ""
gotten_data = ""
for item in component.exclusive:
gotten_instance = component.get(item)
if gotten_instance is not None:
gotten_name = item
gotten_data = AdvancedFormater(gotten_instance)
break
data.append(gotten_name)
data.append(gotten_data)
for item in component.multiple:
gotten_instance = component.get(item)
if gotten_instance is not None:
data.append('- {} -'.format(item))
data.append(AdvancedFormater(gotten_instance))
else:
data.append('')
file.write(','.join(data))
file.write('\n')
def AdvancedFormater(data):
if isinstance(data, icalendar.prop.vDDDTypes):
return str(data.dt)
else:
return str(data)
# read file
icsFile = open('test.ics', 'rb')
cal = icalendar.Calendar.from_ical(icsFile.read())
icsFile.close()
# analyse file
csvEvent = open('event.csv', 'w')
csvEventHeader = False
csvAlarm = open('alarm.csv', 'w')
csvAlarmHeader = False
eventCount = 0
alarmCount = 0
miscCount = 0
for component in cal.walk():
if component.name == 'VEVENT':
eventCount += 1
if not csvEventHeader:
DumpComponentHeader(csvEvent, component)
csvEventHeader = True
DumpComponentData(csvEvent, component)
elif component.name == 'VALARM':
alarmCount += 1
if not csvAlarmHeader:
DumpComponentHeader(csvAlarm, component)
csvAlarmHeader = True
DumpComponentData(csvAlarm, component)
else:
miscCount += 1
csvEvent.close()
csvAlarm.close()
print('Event count: {}\nAlarm count: {}\nMisc count: {}'.format(eventCount, alarmCount, miscCount))

156
assets/ics_converter.py Normal file
View File

@@ -0,0 +1,156 @@
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))