66 lines
2.1 KiB
Python
66 lines
2.1 KiB
Python
"""Yuque (语雀) sink: create a Markdown doc in a repository via the open API.
|
|
|
|
Yuque's open API (``https://www.yuque.com/api/v2``) authenticates with an
|
|
``X-Auth-Token`` header and creates docs under a repository namespace. The body
|
|
is posted as raw Markdown.
|
|
|
|
Yuque's open API has no asset-upload endpoint, so local image refs are left
|
|
untouched — host images at a public URL for them to render.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from . import _http, _md
|
|
from .base import ParsedDoc, Sink, SinkError, SinkResult, register
|
|
|
|
API = "https://www.yuque.com/api/v2"
|
|
|
|
|
|
@register
|
|
class YuqueSink(Sink):
|
|
name = "yuque"
|
|
aliases = ("语雀",)
|
|
requires = ("YUQUE_TOKEN", "YUQUE_NAMESPACE")
|
|
label = "Yuque doc (open API)"
|
|
|
|
def deliver(self, doc: ParsedDoc) -> SinkResult:
|
|
token = self.env("YUQUE_TOKEN")
|
|
namespace = self.env("YUQUE_NAMESPACE")
|
|
headers = {
|
|
"X-Auth-Token": token,
|
|
"User-Agent": "MinerU-Skill/3.0",
|
|
"Content-Type": "application/json",
|
|
}
|
|
|
|
base_dir = Path(doc.markdown_path).parent if doc.markdown_path else None
|
|
n_images = len(_md.find_local_images(doc.markdown, base_dir))
|
|
|
|
status, parsed = _http.request_json(
|
|
"POST", f"{API}/repos/{namespace}/docs", headers=headers, payload={
|
|
"title": doc.title,
|
|
"slug": _md.slugify(doc.title),
|
|
"public": 0,
|
|
"format": "markdown",
|
|
"body": doc.markdown,
|
|
},
|
|
)
|
|
|
|
data = parsed.get("data")
|
|
if not data:
|
|
if status >= 400 or parsed.get("message"):
|
|
raise SinkError(parsed.get("message") or f"HTTP {status}")
|
|
raise SinkError(f"Yuque returned no doc data (HTTP {status})")
|
|
|
|
slug = data.get("slug")
|
|
if n_images:
|
|
detail = f"text only ({n_images} local image(s); host images publicly to embed)"
|
|
else:
|
|
detail = "text only"
|
|
return SinkResult(
|
|
sink=self.name, ok=True,
|
|
url=f"https://www.yuque.com/{namespace}/{slug}",
|
|
detail=detail,
|
|
)
|