diff --git a/etetasks.py b/etetasks.py new file mode 100644 index 0000000..f2c0363 --- /dev/null +++ b/etetasks.py @@ -0,0 +1,116 @@ +''' +I wrote this to make tasks for the tasks.org app with an etebase sync server. + +It's not feature comprehensive but it's helpful for bulk task making. + +The CLI is not great, it's easier to do python -i pytasks.py and code up +whatever you want. + +https://github.com/tasks/tasks +https://github.com/etesync +''' +import argparse +import datetime +import etebase +import sys +import tasks_credentials +import time + +from voussoirkit import betterhelp +from voussoirkit import passwordy +from voussoirkit import pipeable +from voussoirkit import timetools +from voussoirkit import vlogging + +log = vlogging.getLogger(__name__, '') + +PRODID = 'voussoir/pytasks' + +client = etebase.Client(tasks_credentials.CLIENT_NAME, tasks_credentials.SERVER) +account = etebase.Account.login(client, tasks_credentials.USERNAME, tasks_credentials.PASSWORD) +collection_manager = account.get_collection_manager() +collections = collection_manager.list('etebase.vtodo', etebase.FetchOptions().limit(500000)) +collections = [c for c in collections.data if not c.deleted] + +todo = collections[0] +item_manager = collection_manager.get_item_manager(todo) + +def make_vcal(text, *, categories=[], due=None): + now = timetools.now().strftime('%Y%m%dT%H%M%SZ') + + if due is None: + due = '' + elif isinstance(due, datetime.date): + due = 'DUE;VALUE=DATE:' + due.strftime('%Y%m%d') + elif isinstance(due, datetime.datetime): + due = 'DUE:' + due.strftime('%Y%m%dT%H%M%S') + else: + raise TypeError(due) + + lines = [ + 'BEGIN:VCALENDAR', + 'VERSION:2.0', + 'PRODID:' + PRODID, + 'BEGIN:VTODO', + 'DTSTAMP:' + now, + 'UID:' + passwordy.random_digits(32), + due, + 'CREATED:' + now, + 'LAST-MODIFIED:' + now, + 'SUMMARY:' + text, + ('CATEGORIES:' + ','.join(categories)) if len(categories) > 0 else '', + 'END:VTODO', + 'END:VCALENDAR', + ] + lines = [l for l in lines if l] + vcal = '\r\n'.join(lines) + '\r\n' + return vcal.encode('utf-8') + +def make_item(*args, **kwargs): + item = item_manager.create({}, make_vcal(*args, **kwargs)) + return item + +def publish_items(items): + if isinstance(items, etebase.Item): + item_manager.batch([items]) + else: + item_manager.batch(list(items)) + +def export_argparse(args): + items = item_manager.list(etebase.FetchOptions().limit(50000000)) + items = list(items.data) + for item in items: + pipeable.stdout(item.content.decode('utf-8')) + pipeable.stdout() + return 0 + +def make_tasks_argparse(args): + titles = pipeable.input_many(args.titles, strip=True, skip_blank=True) + items = [] + for title in titles: + log.info('Creating task %s.', title) + item = make_item(title) + items.append(item) + publish_items(items) + return 0 + +@vlogging.main_decorator +def main(argv): + parser = argparse.ArgumentParser() + subparsers = parser.add_subparsers() + + ################################################################################################ + + p_make_tasks = subparsers.add_parser('make_tasks', aliases=['make-tasks', 'maketasks', 'maketask']) + p_make_tasks.add_argument('titles', nargs='+') + p_make_tasks.set_defaults(func=make_tasks_argparse) + + ################################################################################################ + + p_export = subparsers.add_parser('export') + p_export.set_defaults(func=export_argparse) + + return betterhelp.go(parser, argv) + +if __name__ == '__main__': + raise SystemExit(main(sys.argv[1:]))