Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save amazingmarvin/91d82dda85908e88e122712e036c1c57 to your computer and use it in GitHub Desktop.
Save amazingmarvin/91d82dda85908e88e122712e036c1c57 to your computer and use it in GitHub Desktop.
A shell script to start tracking an Amazing Marvin task in Toggl Track.
#!/bin/bash
# -------------------------------------------------
# Before running the script, make sure that you understand it. Running code you find on the Internet may damage your system.
# -------------------------------------------------
# In Amazing marvin, set the path to this script as "Start time tracking task" in the "System Triggers strategy" like this:
# /Path/to/this/script $TASK_TITLE
# Replace "YourSecretToken" with your Toggl API token below.
# -------------------------------------------------
curl -v -u YourSecretToken:api_token \
-H "Content-Type: application/json" \
-d '{"time_entry":{"description":'"\"$1\""',"created_with":"curl"}}' \
-X POST https://api.track.toggl.com/api/v8/time_entries/start
@otisdog8
Copy link

otisdog8 commented May 29, 2024

As an update, I wrote a bit of python to add some more data (Project and Task in toggl) modeled by the secondary category and project respectively, though this code is fairly brittle and relies on exact names matching between marvin and toggl (you may also have to specify the path to marvin; I think there's some PATH weirdness sometimes).

import subprocess
import json
import requests
from base64 import b64encode
from datetime import datetime, timezone

workspace_id = "ID"

api_token = b"TOKEN"

base_url = f'https://api.track.toggl.com/api/v9/workspaces/{workspace_id}'
auth_value = 'Basic %s' %  b64encode(api_token + b":api_token").decode("ascii")

def run_command(command):
    result = subprocess.run(command, shell=True, capture_output=True, text=True)
    return result.stdout

def get_item(parent_id):
    command = f"marvin get {parent_id} --json"
    return json.loads(run_command(command))

def current_utc_time():
    return datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')

def main():
    tracking_command = "marvin tracking --json"
    root_id = "root"
    
    # Capture the tracking command output
    tracking_output_raw = run_command(tracking_command)
    try:
        tracking_output = json.loads(tracking_output_raw)
    except json.JSONDecodeError:
        print("Failed to decode JSON:", tracking_output_raw)
        return
    
    if tracking_output.get('parentId') is None:
        print("Invalid tracking output:", tracking_output)
        return
    
    parent_id = tracking_output['parentId']
    
    result_array = [tracking_output]

    # Walk the Parent ID chain
    while parent_id != root_id:
        item = get_item(parent_id)
        result_array.append(item)
        parent_id = item['parentId']

    print(result_array)

    # Get workspace projects
    
    projects = requests.get(base_url + '/projects?active=true', headers={'content-type': 'application/json', 'Authorization' : auth_value})
    projects = projects.json()
    
    # Identify matching projects
    for project in projects:
        if project["name"] == result_array[-2]["title"]:
            project_id = project["id"]
    
    # Identify matching tasks
    tasks = requests.get(base_url + f'/projects/{project_id}/tasks', headers={'content-type': 'application/json', 'Authorization' : auth_value})
    tasks = tasks.json()
    # Identify matching projects
    for task in tasks:
        if task["name"] == result_array[1]["title"]:
            task_id = task["id"]
    note = result_array[0].get("title", "")
    # Start time entry
    data = requests.post(base_url + '/time_entries', json={"created_with":"MarvinTrackIntegration","description":note,"duration":-1,"project_id":project_id,"start":current_utc_time(),"tags":["productive"],"task_id":task_id, "workspace_id":int(workspace_id)}, headers={'content-type': 'application/json', 'Authorization' :  auth_value})
    print(data.json())
    

if __name__ == "__main__":
    main()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment