Files
Frog-Lover-Antony 6f9ca3864f v0.1
2026-07-18 17:40:47 +03:00

8.0 KiB

Copyparty Content Tag — Project Plan

Phase 0: Infrastructure & Discovery (IN PROGRESS)

Copyparty API Capability Tests (2026-07-16)

Test server: localhost:8086, user user:12345, config copyparty-test-config.yaml

Authentication

Test Endpoint Result Notes
Anonymous listing GET /?ls PASS Returns acct: "*", read-only /public/ only
PW header auth GET /?ls + PW: 12345 header PASS Returns acct: "user", both routes visible
URL param auth GET /?ls&pw=12345 PASS Identical to header auth
Wrong password GET /private/?ls + wrong PW PASS → 403 Forbidden on write volumes

Permission model (confirmed)

  • /public/perms: ["read","get"] — serves app files, read-only
  • /private/user/perms: ["read","write","move","delete","dot","get","admin"] — full workspace

Directory operations

Test Endpoint Result Notes
Mkdir (auto-parent) mPOST /content/?replace + act=mkdir&name=unmanaged PASS Creates intermediate /content/ automatically
JSON listing GET /path/?ls PASS Full metadata: size, timestamp, w-hash, permissions
Dotfile listing GET /path/?ls&dots PASS Includes hidden files/dirs
Plaintext listing GET /path/?ls=t PASS Human-readable terminal format
Tree listing GET /path/?tree=. PASS Returns nested dir structure as JSON

File CRUD

Test Endpoint Result Notes
PUT upload (new file) PUT /path/file.txt?j + body PASS Returns {filesz, fileurl, sha512}
PUT overwrite PUT /path/file.txt?j + Replace: 1 header PASS Must use header, NOT ?replace param
PUT dedup (no replace) PUT /path/file.txt?j without Replace header PASS Creates timestamped copy — auto-dedup behavior
Append to file PUT /path/file.tsv?apnd&j + body bytes PASS Appends raw bytes, returns new sha512
Multipart upload mPOST /dir/?replace&j + -F f=@file.txt PASS Returns {files: [{fn, path, sha512, sz}]}
Read as plaintext GET /path/file.tsv?txt PASS Full file content in response body
Move file POST /src?move=/dst PASS Source gone, dest appears at new path
Copy file POST /src?copy=/dst PASS Both source and copy exist
Delete single POST /path/file?delete&j PASS Returns textual confirm: "deleted 1 files"
Batch delete jPOST /?delete&j + JSON array of abs paths PASS Deletes multiple paths at root level
Test Endpoint Result Notes
Server search jPOST /?ls + {"q":"name=latest.tsv"} ⚠⚠ PARTIAL Returns raw text lines, not filtered JSON listing. Useful for verification but NOT for app data fetching — use full ?ls + client-side filter instead.

File metadata (copyparty-provided)

Every file in ?ls response includes:

  • href — relative filename/path
  • sz — size in bytes
  • ts — unix timestamp
  • ext — file extension
  • tags.wW-hash (base32 sha512-derived, server-computed file ID) ← our primary key
  • tags.up_by, tags.up_ip, tags._up_at — upload provenance

Upload tracking

  • GET /?ups — lists recent uploads by IP with human-readable format
  • GET /?ru&j — server-wide recent uploads (JSON) when authed

Key findings for implementation

  1. W-hash is our stable file ID — no need to generate external identifiers. Survives moves within same volume.
  2. PUT overwrite requires Replace: 1 HTTP header, not URL parameter. Without it, copyparty auto-deduplicates (creates timestamped copy).
  3. TSV DB strategy: Read with ?txt, write with PUT + Replace: 1 for full rewrite, or ?apnd for append-only rows.
  4. Server search is unusable for structured data retrieval — returns raw text lines. App must list dirs then filter client-side.
  5. Batch delete at root—requires absolute paths and root-level jPOST call.

Test cleanup completed

All test artifacts removed from /private/user/. Workspace clean except pre-existing tag-data/ directory (27 files, 127MB — left untouched).


Phase 1: Core app scaffold (COMPLETE)

  • HTML scaffold — src/index.html complete (Login, Tagging, Gallery views + context menu)
  • CSS — src/style.css complete (dark theme, all views styled)
  • Copyparty API wrapper — .part1_config_auth.js complete (Config, CP_CP, Auth)
  • TSV DB operations — .part2_tsv_db.js complete (parse, serialize, CRUD, UUID)
  • Scan + import pipeline — .part3_scan_import.js complete (content detect, dir init, import)
  • Bug fixes (2026-07-17):
    • Fixed TAB.join(f)f.join(TAB) in part2 (was producing literal "Symbol" string)
    • Fixed dbMap[fileId]dbMap.has(fileId) / dbMap.set() (part2 uses Map, part3 accessed as plain object)
    • Fixed missing cwd arg in TsvDb.appendRow() call in part3
    • Fixed CP.createDir / CP.moveFileCP_CP.createDir / CP_CP.moveFile in part3
  • Smoke-test bug fixes (2026-07-17):
    • Fixed _url() double-slash when cwd starts with / — now normalizes base and path before joining
    • Fixed createDir() 405 crash on existing directory — now idempotent, accepts 405 as success
    • Fixed checkPerms() calling CP.ls() before CP assigned — changed to this.ls()
    • Fixed deleteFile() missing &j in query params — now matches verified endpoint
    • Fixed writeFile() ignoring replace param — now actually sets Replace: 1 header when true
  • app.js assembled — Login view (Check/Enter), view switching, Tagging view (grid, viewer+nav, album/tag editors, delete), Gallery integration

Phase 2: Content processing (COMPLETE)

  • Perceptual hash (phash) via canvas — 16x16 grayscale, median threshold → 64-char hex
  • Median-cut color extraction — up to 4 dominant colors with percentages

Phase 3: Tagging UI (COMPLETE)

  • Image viewer + prev/next navigation (keyboard arrows too)
  • Album assigner with UUID generation
  • Tag input with autocomplete from existing tags
  • Delete button wired to copyparty delete API
  • Debounced save (800ms) on tag/album changes
  • Gallery grid grouped by album (ungrouped section for no-album images)
  • Tag filter picker (real-time, debounced 250ms)
  • Similarity/color-based sorting
  • Context menu (find similar by hash/color, trash file)
  • Sidebar tag editor

Phase 5: Test infrastructure (COMPLETE)

  • Curl sanity test suite (tests/api-tests.sh) — 12 tests covering auth, CRUD, mkdir
  • Node.js TSV unit tests (tests/tsv-test.js) — 37 tests, all passing
  • Gitea Actions CI workflow (.gitea-ci.yaml)

Remaining / Next Steps

  • Deploy to copyparty and smoke-test in browser (requires running copyparty instance)
  • Automated browser tests in Docker (Playwright/Puppeteer container)
  • Album naming: currently uses raw UUIDs in album selector — consider a human-readable album name → UUID mapping
  • .part5_gallery.js added to index.html script list (currently loaded dynamically via fetch in app.js; both approaches work)

File Inventory

File Purpose Lines
src/index.html All 3 views markup + context menu ~186
src/style.css Dark theme, layout for all views ~170
src/.part1_config_auth.js Config, CP_CP API wrapper, Auth ~220
src/.part2_tsv_db.js TSV parser/serializer, DB CRUD ~240
src/.part3_scan_import.js Content detect, dir init, import ~150
src/.part4_image_processing.js Phash + median-cut color extraction ~295
src/.part5_gallery.js Gallery view logic ~new
src/app.js Main app: Login, Tagging, view switching ~500
tests/api-tests.sh Curl-based API tests ~new
tests/tsv-test.js Node.js TSV unit tests (37 passing) ~new
.gitea-ci.yaml CI workflow ~new