mirror of https://github.com/Hoffelhas/autodoist
Tested new section logic. In addition 'delay' has been optimised by taking computation time into account. General clean-up of code
parent
c50f62d946
commit
41c3cc3b5c
76
autodoist.py
76
autodoist.py
|
@ -7,10 +7,11 @@ import requests
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import time
|
||||||
global overview_item_ids
|
global overview_item_ids
|
||||||
global overview_item_labels
|
global overview_item_labels
|
||||||
|
|
||||||
|
# Makes --help text wider
|
||||||
def make_wide(formatter, w=120, h=36):
|
def make_wide(formatter, w=120, h=36):
|
||||||
"""Return a wider HelpFormatter, if possible."""
|
"""Return a wider HelpFormatter, if possible."""
|
||||||
try:
|
try:
|
||||||
|
@ -23,7 +24,6 @@ def make_wide(formatter, w=120, h=36):
|
||||||
logging.error("Argparse help formatter failed, falling back.")
|
logging.error("Argparse help formatter failed, falling back.")
|
||||||
return formatter
|
return formatter
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# Version
|
# Version
|
||||||
|
@ -78,7 +78,7 @@ def main():
|
||||||
'debug.log', 'w+', 'utf-8'),
|
'debug.log', 'w+', 'utf-8'),
|
||||||
logging.StreamHandler()]
|
logging.StreamHandler()]
|
||||||
)
|
)
|
||||||
|
# Sync with Todoist API
|
||||||
def sync(api):
|
def sync(api):
|
||||||
try:
|
try:
|
||||||
logging.debug('Syncing the current state from the API')
|
logging.debug('Syncing the current state from the API')
|
||||||
|
@ -88,6 +88,7 @@ def main():
|
||||||
'Error trying to sync with Todoist API: %s' % str(e))
|
'Error trying to sync with Todoist API: %s' % str(e))
|
||||||
quit()
|
quit()
|
||||||
|
|
||||||
|
# Simple query for yes/no answer
|
||||||
def query_yes_no(question, default="yes"):
|
def query_yes_no(question, default="yes"):
|
||||||
# """Ask a yes/no question via raw_input() and return their answer.
|
# """Ask a yes/no question via raw_input() and return their answer.
|
||||||
|
|
||||||
|
@ -120,6 +121,7 @@ def main():
|
||||||
sys.stdout.write("Please respond with 'yes' or 'no' "
|
sys.stdout.write("Please respond with 'yes' or 'no' "
|
||||||
"(or 'y' or 'n').\n")
|
"(or 'y' or 'n').\n")
|
||||||
|
|
||||||
|
# Initialisation of Autodoist
|
||||||
def initialise(args):
|
def initialise(args):
|
||||||
|
|
||||||
# Check we have a API key
|
# Check we have a API key
|
||||||
|
@ -198,6 +200,7 @@ def main():
|
||||||
|
|
||||||
return api, label_id
|
return api, label_id
|
||||||
|
|
||||||
|
# Check for Autodoist update
|
||||||
def check_for_update(current_version):
|
def check_for_update(current_version):
|
||||||
updateurl = 'https://api.github.com/repos/Hoffelhas/autodoist/releases'
|
updateurl = 'https://api.github.com/repos/Hoffelhas/autodoist/releases'
|
||||||
|
|
||||||
|
@ -207,7 +210,7 @@ def main():
|
||||||
release_info_json = r.json()
|
release_info_json = r.json()
|
||||||
|
|
||||||
if not current_version == release_info_json[0]['tag_name']:
|
if not current_version == release_info_json[0]['tag_name']:
|
||||||
logging.warning("\n\nYour version is not up-to-date! \nYour version: {}. Latest version: {}\nSee latest version at: {}\n".format(
|
logging.warning("\n\nYour version is not up-to-date! \nYour version: {}. Latest version: {}\nFind the latest version at: {}\n".format(
|
||||||
current_version, release_info_json[0]['tag_name'], release_info_json[0]['html_url']))
|
current_version, release_info_json[0]['tag_name'], release_info_json[0]['html_url']))
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
|
@ -224,6 +227,7 @@ def main():
|
||||||
logging.error("Error while checking for updates: {}".format(e))
|
logging.error("Error while checking for updates: {}".format(e))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
# Assign current type based on settings
|
||||||
def check_name(name):
|
def check_name(name):
|
||||||
len_suffix = [len(args.pp_suffix), len(args.ss_suffix), len(args.ps_suffix), len(args.sp_suffix)]
|
len_suffix = [len(args.pp_suffix), len(args.ss_suffix), len(args.ps_suffix), len(args.sp_suffix)]
|
||||||
|
|
||||||
|
@ -231,6 +235,8 @@ def main():
|
||||||
current_type = args.inbox
|
current_type = args.inbox
|
||||||
elif name[-len_suffix[0]:] == args.pp_suffix:
|
elif name[-len_suffix[0]:] == args.pp_suffix:
|
||||||
current_type = 'parallel'
|
current_type = 'parallel'
|
||||||
|
elif args.pp_suffix == '//' and name[-1:] == '_': # Workaround for section names, which don't allow / symbol.
|
||||||
|
current_type = 'parallel'
|
||||||
elif name[-len_suffix[1]:] == args.ss_suffix:
|
elif name[-len_suffix[1]:] == args.ss_suffix:
|
||||||
current_type = 'sequential'
|
current_type = 'sequential'
|
||||||
elif name[-len_suffix[1]:] == args.ps_suffix:
|
elif name[-len_suffix[1]:] == args.ps_suffix:
|
||||||
|
@ -242,6 +248,7 @@ def main():
|
||||||
|
|
||||||
return current_type
|
return current_type
|
||||||
|
|
||||||
|
# Scan the end of a name to find what type it is
|
||||||
def get_type(object, key):
|
def get_type(object, key):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -266,6 +273,7 @@ def main():
|
||||||
|
|
||||||
return current_type, type_changed
|
return current_type, type_changed
|
||||||
|
|
||||||
|
# Determine a project type
|
||||||
def get_project_type(project_object):
|
def get_project_type(project_object):
|
||||||
"""Identifies how a project should be handled."""
|
"""Identifies how a project should be handled."""
|
||||||
project_type, project_type_changed = get_type(
|
project_type, project_type_changed = get_type(
|
||||||
|
@ -273,6 +281,7 @@ def main():
|
||||||
|
|
||||||
return project_type, project_type_changed
|
return project_type, project_type_changed
|
||||||
|
|
||||||
|
# Determine a section type
|
||||||
def get_section_type(section_object):
|
def get_section_type(section_object):
|
||||||
"""Identifies how a section should be handled."""
|
"""Identifies how a section should be handled."""
|
||||||
if section_object is not None:
|
if section_object is not None:
|
||||||
|
@ -284,6 +293,7 @@ def main():
|
||||||
|
|
||||||
return section_type, section_type_changed
|
return section_type, section_type_changed
|
||||||
|
|
||||||
|
# Determine an item type
|
||||||
def get_item_type(item, project_type):
|
def get_item_type(item, project_type):
|
||||||
"""Identifies how an item with sub items should be handled."""
|
"""Identifies how an item with sub items should be handled."""
|
||||||
|
|
||||||
|
@ -299,6 +309,7 @@ def main():
|
||||||
|
|
||||||
return item_type, item_type_changed
|
return item_type, item_type_changed
|
||||||
|
|
||||||
|
# Logic to add a label to an item
|
||||||
def add_label(item, label):
|
def add_label(item, label):
|
||||||
if label not in item['labels']:
|
if label not in item['labels']:
|
||||||
labels = item['labels']
|
labels = item['labels']
|
||||||
|
@ -311,6 +322,7 @@ def main():
|
||||||
overview_item_ids[str(item['id'])] = 1
|
overview_item_ids[str(item['id'])] = 1
|
||||||
overview_item_labels[str(item['id'])] = labels
|
overview_item_labels[str(item['id'])] = labels
|
||||||
|
|
||||||
|
# Logic to remove a label from an item
|
||||||
def remove_label(item, label):
|
def remove_label(item, label):
|
||||||
if label in item['labels']:
|
if label in item['labels']:
|
||||||
labels = item['labels']
|
labels = item['labels']
|
||||||
|
@ -323,6 +335,7 @@ def main():
|
||||||
overview_item_ids[str(item['id'])] = -1
|
overview_item_ids[str(item['id'])] = -1
|
||||||
overview_item_labels[str(item['id'])] = labels
|
overview_item_labels[str(item['id'])] = labels
|
||||||
|
|
||||||
|
# Ensure labels are only issued once
|
||||||
def update_labels(label_id):
|
def update_labels(label_id):
|
||||||
filtered_overview_ids = [
|
filtered_overview_ids = [
|
||||||
k for k, v in overview_item_ids.items() if v != 0]
|
k for k, v in overview_item_ids.items() if v != 0]
|
||||||
|
@ -330,7 +343,8 @@ def main():
|
||||||
labels = overview_item_labels[item_id]
|
labels = overview_item_labels[item_id]
|
||||||
api.items.update(item_id, labels=labels)
|
api.items.update(item_id, labels=labels)
|
||||||
|
|
||||||
def create_none_section(): # TODO: actually only needs to be created once?
|
# To handle items which have no sections
|
||||||
|
def create_none_section():
|
||||||
none_sec = {
|
none_sec = {
|
||||||
'id': None,
|
'id': None,
|
||||||
'name': 'None',
|
'name': 'None',
|
||||||
|
@ -344,16 +358,17 @@ def main():
|
||||||
# Initialise api
|
# Initialise api
|
||||||
api, label_id = initialise(args)
|
api, label_id = initialise(args)
|
||||||
|
|
||||||
# Main loop
|
# Start main loop
|
||||||
while True:
|
while True:
|
||||||
|
start_time = time.time()
|
||||||
overview_item_ids = {}
|
overview_item_ids = {}
|
||||||
overview_item_labels = {}
|
overview_item_labels = {}
|
||||||
sync(api)
|
sync(api)
|
||||||
|
|
||||||
for project in api.projects.all():
|
for project in api.projects.all():
|
||||||
|
|
||||||
if project['name'] == 'Test //':
|
# To determine if a sequential task was found
|
||||||
print('here')
|
first_found_project = False
|
||||||
|
|
||||||
if label_id is not None:
|
if label_id is not None:
|
||||||
# Get project type
|
# Get project type
|
||||||
|
@ -362,15 +377,6 @@ def main():
|
||||||
project['name'], project_type)
|
project['name'], project_type)
|
||||||
|
|
||||||
# Get all items for the project
|
# Get all items for the project
|
||||||
# items = api.items.all(
|
|
||||||
# lambda x: x['project_id'] == project['id'])
|
|
||||||
|
|
||||||
|
|
||||||
# section_ids = [x['id'] for x in sections]
|
|
||||||
# section_ids.insert(0,None)
|
|
||||||
|
|
||||||
# sections.append(create_none_section()) # Add a None-section to handle items in a project that have no section, append is faster than insert(0,ind)
|
|
||||||
|
|
||||||
project_items = api.items.all(lambda x: x['project_id'] == project['id'])
|
project_items = api.items.all(lambda x: x['project_id'] == project['id'])
|
||||||
|
|
||||||
# Run for both none-sectioned and sectioned items
|
# Run for both none-sectioned and sectioned items
|
||||||
|
@ -382,6 +388,9 @@ def main():
|
||||||
|
|
||||||
for section in sections:
|
for section in sections:
|
||||||
|
|
||||||
|
# To determine if a sequential task was found
|
||||||
|
first_found_section = False
|
||||||
|
|
||||||
# Get section type
|
# Get section type
|
||||||
section_type, section_type_changed = get_section_type(
|
section_type, section_type_changed = get_section_type(
|
||||||
section)
|
section)
|
||||||
|
@ -414,11 +423,6 @@ def main():
|
||||||
for item in items:
|
for item in items:
|
||||||
item['parent_type'] = None
|
item['parent_type'] = None
|
||||||
|
|
||||||
# To determine if a sequential task was found
|
|
||||||
first_found_project = False
|
|
||||||
first_found_section = False
|
|
||||||
first_found_item = True
|
|
||||||
|
|
||||||
# For all items in this section
|
# For all items in this section
|
||||||
for item in items:
|
for item in items:
|
||||||
active_type = None # Reset
|
active_type = None # Reset
|
||||||
|
@ -533,7 +537,6 @@ def main():
|
||||||
if label_id is not None:
|
if label_id is not None:
|
||||||
# Skip processing an item if it has already been checked
|
# Skip processing an item if it has already been checked
|
||||||
if item['checked'] == 1:
|
if item['checked'] == 1:
|
||||||
#TODO: remove label if it has it?
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Check item type
|
# Check item type
|
||||||
|
@ -542,13 +545,6 @@ def main():
|
||||||
logging.debug('Identified \'%s\' as %s type',
|
logging.debug('Identified \'%s\' as %s type',
|
||||||
item['content'], item_type)
|
item['content'], item_type)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# If there is no item
|
|
||||||
if item_type is not None:
|
|
||||||
# Reset in case that parentless task is tagged, overrules project
|
|
||||||
first_found_item = False
|
|
||||||
|
|
||||||
# Determine hierarchy types for logic
|
# Determine hierarchy types for logic
|
||||||
hierarchy_types = [item_type, section_type, project_type]
|
hierarchy_types = [item_type, section_type, project_type]
|
||||||
active_types = [type(x) != type(None) for x in hierarchy_types]
|
active_types = [type(x) != type(None) for x in hierarchy_types]
|
||||||
|
@ -560,7 +556,6 @@ def main():
|
||||||
active_type = item_type
|
active_type = item_type
|
||||||
add_label(item, label_id)
|
add_label(item, label_id)
|
||||||
|
|
||||||
|
|
||||||
elif active_types[1]:
|
elif active_types[1]:
|
||||||
# Do section types
|
# Do section types
|
||||||
active_type = section_type
|
active_type = section_type
|
||||||
|
@ -580,13 +575,16 @@ def main():
|
||||||
if not first_found_project:
|
if not first_found_project:
|
||||||
add_label(item, label_id)
|
add_label(item, label_id)
|
||||||
first_found_project = True
|
first_found_project = True
|
||||||
# elif not first_found_item and not project_type == 's-p':
|
|
||||||
# add_label(item, label_id)
|
|
||||||
# first_found_item = True
|
|
||||||
|
|
||||||
elif project_type == 'parallel' or project_type == 'p-s':
|
elif project_type == 'parallel' or project_type == 'p-s':
|
||||||
add_label(item, label_id)
|
add_label(item, label_id)
|
||||||
|
|
||||||
|
# Mark other conditions too
|
||||||
|
if first_found_section == False and active_types[1]:
|
||||||
|
first_found_section = True
|
||||||
|
if first_found_project is False and active_types[2]:
|
||||||
|
first_found_project = True
|
||||||
|
|
||||||
# If there are children
|
# If there are children
|
||||||
if len(child_items) > 0:
|
if len(child_items) > 0:
|
||||||
# Check if item state has changed, if so clean children for good measure
|
# Check if item state has changed, if so clean children for good measure
|
||||||
|
@ -668,9 +666,15 @@ def main():
|
||||||
if args.onetime:
|
if args.onetime:
|
||||||
break
|
break
|
||||||
|
|
||||||
logging.debug('Sleeping for %d seconds', args.delay)
|
end_time = time.time()
|
||||||
time.sleep(args.delay)
|
delta_time = end_time - start_time
|
||||||
|
|
||||||
|
if args.delay - delta_time < 0:
|
||||||
|
logging.debug('Computation time %d is larger than the specified delay %d. Sleeping skipped.', delta_time, args.delay)
|
||||||
|
elif args.delay >= 0:
|
||||||
|
sleep_time = args.delay - delta_time
|
||||||
|
logging.debug('Sleeping for %d seconds', sleep_time)
|
||||||
|
time.sleep(sleep_time)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
Loading…
Reference in New Issue