| Age | Commit message (Collapse) | Author |
|
Move all dependency wiring, background worker startup, server lifecycle
(Wire, StartBackgroundWorkers, RunServer, RunWithSignal, BuildLogger) into
internal/app so cmd/player/main.go becomes thin: parse flags, load config,
delegate to app.RunWithSignal. Updated main_test.go to call app.Wire and
app.StartBackgroundWorkers directly.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
l9: Add mediaRoot field to mediaStreamer. NewMediaStreamer now takes a
mediaRoot string parameter; when non-empty, Open() rejects any path that
does not reside under that directory (filepath.Clean prefix check), returning
ErrForbidden to prevent filepath-traversal via a compromised AbsPath in the
DB. Production wiring passes cfg.MediaRoot; tests that don't exercise path
traversal pass "". Added TestMediaStreamerOpenRejectsPathOutsideRoot to
cover the rejection path.
k9: Add a defer-based cleanup guard in DownloadEpisode. After the enclosure
file is written, a succeeded flag gates a deferred closure that calls
dbCleanup() (undoes DB row + removes file) when persistDownloadedEpisode
succeeded, or removeAndLog(path) when it did not. This ensures that any
failure after the file is written — including UpdateEpisodeMedia — leaves no
orphaned files on disk. The guard is disarmed by setting succeeded=true on
the happy path.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
handleError previously hard-coded a switch mapping every service sentinel to
its HTTP status. Adding a new sentinel required editing handleError (OCP
violation). Move the status onto the sentinel itself: introduce
api.HTTPStatuser { HTTPStatus() int }, convert the 10 dispatched service
sentinels to a typed *apiError that implements it, and turn handleError into
a thin errors.As-based dispatcher. ErrShareExpired stays a plain sentinel
because it is handled inline by share handlers and never reaches
handleError.
Sentinel messages are aligned with what handleError used to emit (e.g.
ErrForbidden is now "forbidden" instead of "access denied",
ErrAlreadyBootstrapped is "bootstrap already complete") so the dispatcher
can use err.Error() uniformly. Wrapped errors (fmt.Errorf("%w: ...",
ErrNotFound, ...)) keep their context in the response body, which is a
minor improvement over the previous behaviour that collapsed everything to
the bare sentinel message. errors.Is keeps working via pointer equality on
the *apiError sentinels.
|
|
handlers_share.go (handleCreateShare share-expiry) and handlers_auth.go
(setSessionCookie and apiTokenExpiresAt) previously called time.Now() directly,
which made time-dependent semantics impossible to assert deterministically in
tests. They now use s.clk.Now(), where s.clk is a clock.Clock injected through
ServerDeps.Clock (nil-default to clock.RealClock{} so existing callers keep
working unchanged). apiTokenExpiresAt is promoted to a method on *Server so it
can reach the injected clock. Production wiring in cmd/player/main.go passes
deps.clk so handlers share the same time source as the rest of the services.
Two new unit tests (handlers_share_test.go) use clock.MockClock to assert
handleCreateShare and setSessionCookie compute their expiry timestamps from
the injected clock rather than the wall clock.
While propagating, this commit also includes a mechanical fix-up for the
pathID(...) signature change (now returns int64 + error) across the API
handler files so the package still builds; the additional err-check makes
malformed path variables produce 400 instead of silently parsing as zero.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
browseService.GetThumbnail previously called os.Stat directly, coupling
the service layer to the filesystem and forcing tests to write temporary
files. Introduce a thumb.Resolver interface plus an FSResolver default,
inject it into browseService, and wire NewMediaServiceWithDeps so
production constructs the resolver explicitly. Tests can now swap in a
fake Resolver without touching disk.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
extracted
Two related refactors that converged on internal/api/server.go.
s9 — NewServerWithLogger no longer panics on nil deps.Config. Returns
(*Server, error) so cmd/player/main.go can log a clear message and exit
cleanly when wiring is misconfigured. All callers updated, including
api unit tests that construct a Server directly.
aa — Share-page HTML rendering moved out of handlers_share.go into a
new internal/web package. internal/web/sharepage.go owns
SharePageRenderer and the private injectShareMedia helper; the api
handler now calls s.shareRenderer.Render(...) and routes errors via
http.Error. injectShareMedia coverage was moved alongside it in
internal/web/sharepage_test.go; the duplicate tests in
handlers_more_test.go were removed (placeholder comment left so the
reference is greppable). Server gained one new field (shareRenderer
*web.SharePageRenderer) and one new constructor line; production
wiring uses deps.StaticFS.
Background: both tasks were initially worked by separate sub-agents
that stopped mid-edit when usage limits hit; their WIP was preserved
in a stash and finalized in this commit. Tests rerun from a clean
state: full Go unit suite green, 25/25 LLM e2e, 22/22 Playwright.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
cmd/player/main.go had recoverBackgroundWorkerPanic and
internal/service/recover.go had handleWorkerPanic implementing the same
log-and-stack panic recovery. Export the service variant as RecoverWorker
(unchanged signature), use it from main.go, and drop the duplicate
helper plus the now-unused runtime/debug import.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
|
|
|