Skip to content

Extract video creation_time from container metadata#75

Open
magent-cryptograss wants to merge 15 commits into
cryptograss:mainfrom
magent-cryptograss:video-creation-time
Open

Extract video creation_time from container metadata#75
magent-cryptograss wants to merge 15 commits into
cryptograss:mainfrom
magent-cryptograss:video-creation-time

Conversation

@magent-cryptograss

Copy link
Copy Markdown
Contributor

Summary

Pass video creation timestamp from ffprobe through to the draft response so the wiki can auto-fill the date picker.

  • MediaAnalysis gets a creation_time field, populated from format.tags.creation_time
  • ContentFile model gets the same field
  • content.py route maps it through

Companion to pickipedia #64 which reads this field to pre-fill the date.

Test plan

  • Upload a video recorded on a phone → response includes creation_time in the file object
  • Upload a video without metadata → creation_time is null, no errors

jMyles added 15 commits March 15, 2026 02:21
BT clients construct webseed URLs as base_url + torrent_name + file_path,
but IPFS gateway serves files without the torrent name directory level.

New /webseed/{cid}/ Caddy route rewrites:
  /webseed/{cid}/{torrent_name}/{file} → /ipfs/{cid}/{file}

Also updates enrich endpoint to use the new webseed URL.
Use $1/$2 (uri replacement syntax) instead of {re.1}/{re.2}
(matcher syntax).
BEP 19 webseed behavior differs by torrent type:
- Single-file: client fetches the URL directly
- Multi-file: client appends name/path to the URL

Most releases (23/26) are single video files. Using single-file
format means the webseed URL can point directly to the IPFS gateway
without any path rewriting needed.

Multi-file torrents (albums) still use the /webseed/ rewrite route.
The endpoint now returns the actual webseed URLs used in the torrent,
so Blue Railroad can store them in Release YAML and the PHP renderer
can use them directly in magnet links. This is needed because
single-file and multi-file torrents use different webseed URL formats.
Instead of relying solely on webseeds (which require torrent metadata
that magnet-link-only clients can't bootstrap without peers), this adds
a proper libtorrent seeder that participates in the BitTorrent swarm.

- New seeder service: manages libtorrent session, seeds all enriched
  content from /staging/seeding/{cid}/ directories
- Torrent file serving: GET /torrent/{infohash}.torrent endpoint
- Seeder status: GET /torrent/status for monitoring
- Enrich endpoint now adds torrents to seeder and returns torrent_url
- Dockerfile exposes port 6881 for BitTorrent traffic
- Playbook forwards BT ports (6881 TCP+UDP) and adds /torrent* route
- Added libtorrent dependency to requirements.txt
Restores the AV1+Opus HLS transcoding integration that was in the
original Node.js pinning service but was lost in the Python rewrite.

- POST /transcode-coconut: pins source to IPFS, submits to Coconut API
- POST /webhook/coconut: receives completion, downloads HLS, pins to IPFS
- GET /job/{id}: poll for job status (camelCase to match arthel frontend)
- GET /jobs: list recent jobs
- COCONUT_API_KEY added to config and docker-compose env
- Local ffmpeg transcoding remains as fallback
- Video finalization now tries Coconut.co first (AV1+Opus HLS),
  falls back to local ffmpeg if Coconut unavailable or fails
- New transcoding_strategy field on ContentFinalizeRequest:
  auto (default), coconut, local, none
- New transcoding-submitted SSE event for async Coconut path
- All draft responses include commit hash (GIT_COMMIT env var)
  for staleness detection
- config.get_commit() helper exposes build identity

Depends on Dockerfile baking GIT_COMMIT at build time:
  docker build --build-arg GIT_COMMIT=$(git rev-parse --short HEAD) ...
- Add transcoding_qualities field to ContentFinalizeRequest — lets
  callers specify output heights (e.g. [1080, 720, 480]). Defaults
  to [720, 480] when not provided. Threaded through to Coconut API.
- Document available quality values and bitrate tiers in coconut.py
- Add test suite: 13 tests covering job config building (default and
  custom qualities, bitrate tiers, AV1+Opus codec enforcement),
  job persistence (save/load/list), model defaults
The regex \w+\d*\.hunter only matched single-level subdomains like
magent1.hunter.cryptograss.live but not pickipedia.justin.hunter.
Changed to [\w.-]+ to match any depth of subdomain.
Add action parameter to HMAC token creation/verification to support
separate "upload:" and "finalize:" token prefixes. Upload tokens allow
any logged-in wiki user to push bytes to staging. Finalize tokens
(issued only to users with finalize-release permission) are required
to pin to IPFS.

New require_finalize_auth dependency used on /finalize endpoints.
Backwards-compatible: old upload tokens still accepted for finalize
with a deprecation warning.
Deploy pickipedia and delivery-kid together — no need to accept
upload-prefixed tokens at finalize endpoints.
New GET /staging/drafts/{draft_id}/{filename} endpoint serves uploaded
files from staging for preview (video embed, audio playback) on wiki
ReleaseDraft pages.

Supports both header auth (HMAC/API key/wallet) and query param auth
(?token=&user=&timestamp=) so <video src="..."> tags work without
JS fetch workarounds. Path traversal protection via component
sanitization and resolved-path validation. FileResponse handles
HTTP range requests natively for video seeking.
…llback

- Use a dict for MIME type registration instead of repeated add_type calls
- Move require_auth import to module top level (no circular import issue)
- Add comment clarifying why HTTPException is caught and passed
The staging endpoint was deployed but Caddy's explicit path allowlist
didn't include it, so requests fell through to the default fallback.
ffprobe already reads format tags — now we pass creation_time (ISO 8601)
through MediaAnalysis → ContentFile → draft response, so the wiki can
auto-fill the date picker from the camera/phone recording timestamp.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants