8c01fd6e1a
- EmailsImport: jnj_mailbox_sync_v1.0 (sync JNJ schranky) - Covance: create_lab_results_report_v1.0 + zpracovane CSV (samples/kits/equeries/test-results), browser profily - Feasibility UCO2001: store_cda_*, store_sipiq_links, classify_krok, mark_sipiq_sent, report v1.1 (stary report do TRASH) - IWRS/Drugs: pregenerovane onsite inventory / shipment reporty - TrilliumMCP server + trilium upload/diacritics skripty - .mcp.json Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
81 lines
2.9 KiB
Python
81 lines
2.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
trilium_upload_file_v1.0.py
|
|
Verze: 1.0 | Datum: 2026-06-09
|
|
Popis: Nahraje libovolný soubor do Trilia (ETAPI) jako samostatnou poznámku
|
|
typu "file" pod zadaný rodič (default složka Claude). Ověří shodu
|
|
přes SHA-256 (lokál vs. uložený obsah).
|
|
Použití: python trilium_upload_file_v1.0.py "<cesta_k_souboru>" [parentNoteId]
|
|
"""
|
|
import sys, os, json, hashlib, mimetypes, urllib.request, io
|
|
|
|
# konzole na Windows (cp1250) neumi nektere znaky -> vynutime UTF-8 vystup
|
|
try:
|
|
sys.stdout.reconfigure(encoding="utf-8")
|
|
except Exception:
|
|
pass
|
|
|
|
BASE = "https://trilium.buzalka.cz/etapi"
|
|
TOKEN = "WoPH9O8hn2y6_r6pQSjpOVSmuL0os2hIQsLBHDOawebOx8l+MUc8v+GE="
|
|
DEFAULT_PARENT = "NeoXOIw0uBK2" # slozka Claude
|
|
|
|
|
|
def req(method, path, data=None, ctype="application/json; charset=utf-8", raw=False):
|
|
body = None
|
|
if data is not None:
|
|
body = data if isinstance(data, (bytes, bytearray)) else json.dumps(data, ensure_ascii=False).encode("utf-8")
|
|
r = urllib.request.Request(BASE + path, data=body, method=method)
|
|
r.add_header("Authorization", TOKEN)
|
|
if body is not None:
|
|
r.add_header("Content-Type", ctype)
|
|
try:
|
|
with urllib.request.urlopen(r) as resp:
|
|
out = resp.read()
|
|
if raw:
|
|
return out
|
|
txt = out.decode("utf-8")
|
|
return json.loads(txt) if txt.strip().startswith(("{", "[")) else txt
|
|
except urllib.error.HTTPError as e:
|
|
print(f" HTTP {e.code} {method} {path}: {e.read().decode('utf-8','replace')}")
|
|
raise
|
|
|
|
|
|
def main():
|
|
path = sys.argv[1]
|
|
parent = sys.argv[2] if len(sys.argv) > 2 else DEFAULT_PARENT
|
|
fname = os.path.basename(path)
|
|
blob = open(path, "rb").read()
|
|
mime = mimetypes.guess_type(fname)[0] or "application/octet-stream"
|
|
sha_local = hashlib.sha256(blob).hexdigest()
|
|
|
|
# 1) vytvor poznamku typu file (prazdny obsah)
|
|
note = req("POST", "/create-note", {
|
|
"parentNoteId": parent, "title": fname, "type": "file",
|
|
"mime": mime, "content": "",
|
|
})["note"]
|
|
nid = note["noteId"]
|
|
|
|
# 2) nahraj binarni obsah
|
|
req("PUT", f"/notes/{nid}/content", bytes(blob), ctype="application/octet-stream")
|
|
|
|
# 3) originalFileName label (spravne stahovani pod nazvem)
|
|
req("POST", "/attributes", {
|
|
"noteId": nid, "type": "label", "name": "originalFileName",
|
|
"value": fname, "isInheritable": False,
|
|
})
|
|
|
|
# 4) overeni
|
|
back = req("GET", f"/notes/{nid}/content", raw=True)
|
|
sha_remote = hashlib.sha256(back).hexdigest()
|
|
ok = (sha_local == sha_remote)
|
|
print(f"noteId: {nid}")
|
|
print(f"název: {fname}")
|
|
print(f"mime: {mime}")
|
|
print(f"lokál: {len(blob)} B sha256={sha_local[:16]}…")
|
|
print(f"server: {len(back)} B sha256={sha_remote[:16]}…")
|
|
print("OVĚŘENÍ: SHODA OK" if ok else "OVĚŘENÍ: NESHODA!")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|