Created
May 21, 2021 15:02
-
-
Save Terrance/0e21ef32801c846f07b28fc6fc3310e9 to your computer and use it in GitHub Desktop.
Script to convert from TickTick's backup CSV file to CalDAV-compatible VTODO files.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
from csv import DictReader | |
from datetime import datetime | |
from dateutil.rrule import rrulestr | |
from icalendar import Alarm, Calendar, Todo, vRecur | |
PRIORITY = {"0": "0", "1": "6", "3": "5", "5": "4"} | |
STATUS = {"0": "NEEDS-ACTION", "1": "COMPLETED", "2": "COMPLETED"} | |
def date(value): | |
value = value.replace("-", "").replace(":", "").replace("+0000", "Z") | |
assert value.endswith("Z") | |
return value | |
def main(): | |
with open("backup.csv") as backup: | |
for _ in range(6): | |
next(backup) | |
reader = DictReader(backup) | |
for item in reader: | |
print(item["taskId"]) | |
uid = "{}@ticktick.com.ics".format(item["taskId"]) | |
todo = Todo() | |
todo["uid"] = uid | |
todo["created"] = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ") | |
todo["summary"] = item["Title"] | |
if item["Content"]: | |
todo["description"] = item["Content"].replace("\r", "\n") | |
if item["Is Check list"]: | |
todo["description"] = todo["description"].replace("▫", "- [ ] ").replace("▪", "- [x] ") | |
if item["Start Date"]: | |
todo["dtstart"] = date(item["Start Date"]) | |
if item["Due Date"]: | |
todo["due"] = date(item["Due Date"]) | |
for repeat in item["Repeat"].rstrip().splitlines(): | |
todo.add("rrule", vRecur.from_ical(repeat)) | |
todo["priority"] = PRIORITY[item["Priority"]] | |
todo["status"] = STATUS[item["Status"]] | |
todo["dtstamp"] = date(item["Created Time"]) | |
if item["Completed Time"]: | |
todo["completed"] = date(item["Completed Time"]) | |
cal = Calendar() | |
cal.add_component(todo) | |
with open("{}@ticktick.com.ics".format(item["taskId"]), "wb") as out: | |
out.write(cal.to_ical()) | |
if __name__ == "__main__": | |
main() |
Wow, yeah, this code works now perfectly :)
This script creates one .ics file per list, each .ics file can be imported into Nextcloud, which in turns add the todos to the tasks app, which in turn is synced via webdav. With this, I can completely move away from ticktick without losing any current and historical todo. Thank you, this is awesome.
Here's the working version:
#!/usr/bin/env python3 from csv import DictReader from datetime import datetime from dateutil.rrule import rrulestr from icalendar import Alarm, Calendar, Todo, vRecur import os.path from collections import defaultdict PRIORITY = {"0": "0", "1": "6", "3": "5", "5": "4"} STATUS = {"0": "NEEDS-ACTION", "1": "COMPLETED", "2": "COMPLETED"} def date(value): value = value.replace("-", "").replace(":", "").replace("+0000", "Z") assert value.endswith("Z") return value def main(): cals = defaultdict(Calendar) with open("backup.csv") as backup: for _ in range(6): next(backup) reader = DictReader(backup) for item in reader: uid = format(item["taskId"]) todo = Todo() todo["uid"] = uid todo["created"] = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ") todo["summary"] = item["Title"] if item["Content"]: todo["description"] = item["Content"].replace("\r", "\n") if item["Is Check list"]: todo["description"] = todo["description"].replace("▫", "- [ ] ").replace("▪", "- [x] ") if item["Start Date"]: todo["dtstart"] = date(item["Start Date"]) if item["Due Date"]: todo["due"] = date(item["Due Date"]) for repeat in item["Repeat"].rstrip().splitlines(): todo.add("rrule", vRecur.from_ical(repeat)) todo["priority"] = PRIORITY[item["Priority"]] todo["status"] = STATUS[item["Status"]] todo["dtstamp"] = date(item["Created Time"]) if item["Completed Time"]: todo["completed"] = date(item["Completed Time"]) cal = cals[item["List Name"]] # get or create a calendar for the current list cal.add_component(todo) for name, cal in cals.items(): # write calendars out at the end listname = name + ".ics" print(listname) with open(listname, "wb") as out: out.write(cal.to_ical()) if __name__ == "__main__": main()
how do you use it? I just copied it into a py script
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Wow, yeah, this code works now perfectly :)
This script creates one .ics file per list, each .ics file can be imported into Nextcloud, which in turns add the todos to the tasks app, which in turn is synced via webdav. With this, I can completely move away from ticktick without losing any current and historical todo.
Thank you, this is awesome.
Here's the working version: