Closes the transcoder's read-side gap for Phase 2. HLS transcoding now
works for tracks uploaded under TRACK_STORAGE_BACKEND=s3 without
requiring the stream server pod to share a local volume.
Changes:
- internal/services/hls_transcode_service.go
- New SignedURLProvider interface (minimal: GetSignedURL).
- HLSTranscodeService gains optional s3Resolver + SetS3Resolver.
- TranscodeTrack routed through new resolveSource helper — returns
local FilePath for local tracks, a 1h-TTL signed URL for s3-backed
rows. Missing resolver for an s3 track returns a clear error.
- os.Stat check skipped for HTTP(S) sources (ffmpeg validates them).
- transcodeBitrate takes `source` explicitly so URL propagation is
obvious and ValidateExecPath is bypassed only for the known
signed-URL shape.
- isHTTPSource helper (http://, https:// prefix check).
- internal/workers/job_worker.go
- JobWorker gains optional s3Resolver + SetS3Resolver.
- processTranscodingJob skips the local-file stat when
track.StorageBackend='s3', reads via signed URL instead.
- Passes w.s3Resolver to NewHLSTranscodeService when non-nil.
- internal/config/config.go: DI wires S3StorageService into JobWorker
after instantiation (nil-safe).
- internal/core/track/service.go (copyFileAsyncS3)
- Re-enabled stream server trigger: generates a 1h-TTL signed URL
for the fresh s3 key and passes it to streamService.StartProcessing.
Rust-side ffmpeg consumes HTTPS URLs natively. Failure is logged
but does not fail the upload (track will sit in Processing until
a retry / reconcile).
- internal/core/track/track_upload_handler.go (CompleteChunkedUpload)
- Reload track after S3 migration to pick up the new storage_key.
- Compute transcodeSource = signed URL (s3 path) or finalPath (local).
- Pass transcodeSource to both streamService.StartProcessing and
jobEnqueuer.EnqueueTranscodingJob — dual-trigger preserved per
plan D2 (consolidation deferred v1.0.9).
- internal/services/hls_transcode_service_test.go
- TestHLSTranscodeService_TranscodeTrack_EmptyFilePath updated for
the expanded error message ("empty FilePath" vs "file path is empty").
Known limitation (v1.0.9): HLS segment OUTPUT still writes to the
local outputDir; only the INPUT side is S3-aware. Multi-pod HLS serving
needs the worker to upload segments to MinIO post-transcode. Acceptable
for v1.0.8 target — single-pod staging supports both local + s3 tracks.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>