Initial commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
__pycache__
|
||||
CLAUDE.md
|
||||
23
.pre-commit-config.yaml
Normal file
23
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.12.1
|
||||
hooks:
|
||||
- id: black
|
||||
language_version: python3
|
||||
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.13.2
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.1.9
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.8.0
|
||||
hooks:
|
||||
- id: mypy
|
||||
additional_dependencies: [types-requests]
|
||||
5
README.md
Normal file
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# ActivityWatch Watcher Amazing Marvin
|
||||
|
||||
An Activity Watch Watcher that logs the task that is currently being tracked in
|
||||
Amazing Marvin.
|
||||
|
||||
1404
poetry.lock
generated
Normal file
1404
poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
pyproject.toml
Normal file
24
pyproject.toml
Normal file
@@ -0,0 +1,24 @@
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry]
|
||||
name = "awam"
|
||||
version = "0.1.0"
|
||||
description = "An ActivityWatch watcher that logs the tracked Amazing Marvin task."
|
||||
authors = ["Felix Martin"]
|
||||
readme = "README.md"
|
||||
packages = [{include = "awam", from = "src"}]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
aw-client = "*"
|
||||
aw-core = "*"
|
||||
requests = "*"
|
||||
keyring = "*"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
pre-commit = "*"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
awam = "awam.__main__:main"
|
||||
119
src/awam/__main__.py
Normal file
119
src/awam/__main__.py
Normal file
@@ -0,0 +1,119 @@
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from time import sleep
|
||||
from typing import Any, Dict, Optional, Tuple
|
||||
|
||||
import keyring
|
||||
import requests
|
||||
from aw_client import ActivityWatchClient
|
||||
from aw_core.models import Event
|
||||
|
||||
|
||||
def get_tracked_task(api_token: str) -> Optional[Dict[str, Any]]:
|
||||
"""Get the currently tracked task from Amazing Marvin API."""
|
||||
url = "https://serv.amazingmarvin.com/api/trackedItem"
|
||||
headers = {"X-API-Token": api_token, "Content-Type": "application/json"}
|
||||
|
||||
try:
|
||||
response = requests.get(url, headers=headers)
|
||||
response.raise_for_status()
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"No tracked task found (status: {response.status_code})")
|
||||
return None
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"Error fetching tracked task: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def setup_activitywatch_client() -> Tuple[ActivityWatchClient, str]:
|
||||
"""Initialize ActivityWatch client and create bucket."""
|
||||
client = ActivityWatchClient("amazing-marvin-watcher", testing=False)
|
||||
bucket_id = f"amazing-marvin-task_{client.client_hostname}"
|
||||
event_type = "amazing-marvin-task"
|
||||
|
||||
try:
|
||||
client.create_bucket(bucket_id, event_type=event_type)
|
||||
print(f"ActivityWatch bucket '{bucket_id}' ready")
|
||||
return client, bucket_id
|
||||
except Exception as e:
|
||||
print(f"Error setting up ActivityWatch: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def create_task_event(tracked_task: Optional[Dict[str, Any]]) -> Optional[Event]:
|
||||
"""Create an ActivityWatch event from a tracked Amazing Marvin task."""
|
||||
if not tracked_task:
|
||||
return None
|
||||
|
||||
event_data = {
|
||||
"task_title": tracked_task.get("title", "Unknown Task"),
|
||||
"task_id": tracked_task.get("_id", ""),
|
||||
"database": tracked_task.get("db", "Tasks"),
|
||||
"app": "Amazing Marvin",
|
||||
}
|
||||
|
||||
return Event(timestamp=datetime.now(timezone.utc), data=event_data)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
username = os.getlogin()
|
||||
token = keyring.get_password("amazing-marvin-api-token", username)
|
||||
|
||||
if not token:
|
||||
print(
|
||||
"No API token found in keyring. Please store your Amazing Marvin API token:"
|
||||
)
|
||||
print(
|
||||
f"Run: python -c \"import keyring; keyring.set_password('amazing-marvin-api-token', '{username}', 'YOUR_TOKEN_HERE')\""
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
client, bucket_id = setup_activitywatch_client()
|
||||
|
||||
print("Starting Amazing Marvin task tracking...")
|
||||
print("Press Ctrl+C to stop")
|
||||
|
||||
current_task_id = None
|
||||
heartbeat_interval = 10 # seconds
|
||||
|
||||
try:
|
||||
with client:
|
||||
while True:
|
||||
tracked_task = get_tracked_task(token)
|
||||
|
||||
if tracked_task:
|
||||
task_id = tracked_task.get("_id")
|
||||
task_title = tracked_task.get("title", "Unknown Task")
|
||||
|
||||
if task_id != current_task_id:
|
||||
current_task_id = task_id
|
||||
print(f"Now tracking: {task_title}")
|
||||
|
||||
event = create_task_event(tracked_task)
|
||||
if event:
|
||||
client.heartbeat(
|
||||
bucket_id,
|
||||
event,
|
||||
pulsetime=heartbeat_interval + 5,
|
||||
queued=True,
|
||||
commit_interval=30.0,
|
||||
)
|
||||
else:
|
||||
if current_task_id is not None:
|
||||
current_task_id = None
|
||||
print("No task currently being tracked")
|
||||
|
||||
sleep(heartbeat_interval)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\nStopping Amazing Marvin task tracking...")
|
||||
sleep(1) # Give time for queued events to be sent
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user