Skip to content

Instantly share code, notes, and snippets.

@error9900
Last active January 31, 2024 00:46
Show Gist options
  • Save error9900/b3e18c803a39bb4a9147be37faf595f7 to your computer and use it in GitHub Desktop.
Save error9900/b3e18c803a39bb4a9147be37faf595f7 to your computer and use it in GitHub Desktop.
Change one Label to another Label on all tasks with the first Label...
"""
This will find all Tasks with a specific Label, remove that Label, and add another specified Label.
Make sure you add your API token to `data/token.txt`!
You'll need the Python SDK for this to work:
https://developer.todoist.com/rest/v2/#python-sdk
"""
import uuid
import requests
import todoist_api_python.api
SESSION = requests.Session()
def load_token():
with open("data/token.txt", "r", encoding="utf-8") as file:
line = file.readline()
token = line.strip()
return token
todoist_api = todoist_api_python.api.TodoistAPI(load_token())
def check_response(response):
if not response.ok:
raise ValueError(f"Error: {response.content}")
def sync_post(body):
response = SESSION.post(
"https://api.todoist.com/sync/v9/sync",
headers={"Authorization": f"Bearer {load_token()}"},
json=body,
timeout=60,
)
check_response(response)
return response
def check_task_for_label(task, label: str):
return label in task.labels
def remove_label(task, label_to_remove) -> bool:
if check_task_for_label(task, label_to_remove):
task.labels.remove(label_to_remove)
return True
return False
def add_label(task, new_label) -> bool:
if check_task_for_label(task, new_label):
return False
task.labels.append(new_label)
return True
def build_command_update_labels(task):
command = {
"type": "item_update",
"args": {"id": task.id, "labels": task.labels},
"uuid": uuid.uuid4().hex,
}
return command
def bulk_update_labels(tasks) -> None:
max_batch_size = 99
for i in range(0, len(tasks), max_batch_size):
commands = []
batch = tasks[i : i + max_batch_size]
for task in batch:
command = build_command_update_labels(task)
commands.append(command)
body = {"commands": commands}
print(f"Attempting to update labels for a batch of {len(batch)} tasks...")
sync_post(body)
def bulk_update_labels_new(tasks, labels_to_add=None, labels_to_remove=None) -> None:
tasks_to_update = []
for task in tasks:
labels_before = list(task.labels)
if labels_to_remove:
for label in labels_to_remove:
remove_label(task, label)
if labels_to_add:
for label in labels_to_add:
add_label(task, label)
if set(labels_before) != set(task.labels):
tasks_to_update.append(task)
if tasks_to_update:
print(
f"Attempting to update labels for {len(tasks_to_update)} tasks in total..."
)
bulk_update_labels(tasks=tasks_to_update)
def swap_labels() -> None:
label_to_remove = input("Enter the label to remove: ")
label_to_add = input("Enter the label to add: ")
tasks = todoist_api.get_tasks(filter=f"@{label_to_remove}")
if tasks:
bulk_update_labels_new(
tasks,
labels_to_remove=[label_to_remove],
labels_to_add=[label_to_add],
)
else:
raise ValueError(f"No tasks with @{label_to_remove} found!")
if __name__ == "__main__":
swap_labels()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment