49 lines
1.6 KiB
Python
49 lines
1.6 KiB
Python
"""TickTick (滴答清单) sink — create a task from parsed Markdown.
|
|
|
|
TickTick's Open API exposes a task object whose ``content`` field holds the body
|
|
text. The official native ingestion path for arbitrary Markdown is therefore a
|
|
task: the document title becomes the task title and the Markdown becomes the
|
|
task content. Tasks have no attachment/inline-image surface, so local images are
|
|
not delivered.
|
|
|
|
Docs: https://developer.ticktick.com/docs (POST /open/v1/task).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from . import _http
|
|
from .base import ParsedDoc, Sink, SinkError, SinkResult, register
|
|
|
|
API_URL = "https://api.ticktick.com/open/v1/task"
|
|
|
|
|
|
@register
|
|
class TickTickSink(Sink):
|
|
name = "ticktick"
|
|
aliases = ("dida", "滴答清单")
|
|
requires = ("TICKTICK_TOKEN",)
|
|
label = "TickTick task (滴答清单)"
|
|
|
|
def deliver(self, doc: ParsedDoc) -> SinkResult:
|
|
token = self.env("TICKTICK_TOKEN")
|
|
project_id = self.env("TICKTICK_PROJECT_ID")
|
|
|
|
payload = {"title": doc.title, "content": doc.markdown}
|
|
if project_id:
|
|
payload["projectId"] = project_id
|
|
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
status, parsed = _http.request_json("POST", API_URL, headers=headers, payload=payload)
|
|
|
|
if status >= 400:
|
|
raise SinkError(f"TickTick HTTP {status}: {parsed}")
|
|
if not parsed.get("id"):
|
|
raise SinkError(f"TickTick returned no task id: {parsed}")
|
|
|
|
return SinkResult(
|
|
sink=self.name,
|
|
ok=True,
|
|
url=None,
|
|
detail="task content (no inline images supported by TickTick)",
|
|
)
|