| Age | Commit message (Collapse) | Author |
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
android.yml: Flutter Android pipeline running flutter analyze + flutter test
on every push or PR touching player-android/**. Uses ghcr.io/cirruslabs/flutter:stable
with a flutter-pub-cache named volume. Path-scoped so Go-only changes do not
trigger the Flutter runner.
nightly.yml: Nightly LLM e2e stub pipeline on cron 0 2 * * * (main only).
Injects ANTHROPIC_API_KEY from a protected Woodpecker project secret, includes
a belt-and-suspenders branch guard, a placeholder llm-e2e step (exits 0), and a
cost-log step that emits a parseable cost summary line for future monitoring.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Stage 1 (server-unit) runs go test -race -count=1 ./... on every push
for a fast ~10-15 s feedback gate. Stage 2 (server-integration +
web-smoke) runs only on pushes to main or PRs targeting main, after
Stage 1 passes. web-smoke builds the server binary, waits for /healthz
readiness via curl --retry, then runs the Playwright Chromium suite
against testmedia. Go module, build, and Playwright Chromium caches use
named Woodpecker host volumes to avoid redundant downloads.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Produces player-android/docs/testing-strategy.md as a decision gate
covering test scope, CI emulator options, integration_test vs Patrol,
and LLM access mode. Reviewed by sub-agent; all issues addressed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Add fromJson/toJson round-trip tests for all 9 Dart models (Media,
MediaSet, User, Tag, Note, Share, PodcastFeed, PodcastEpisode,
PlaybackHint) and 3 PlayerApiClient constructor tests. Each model
group covers a fully-populated round-trip (including int-to-double
cast verification and ISO-8601 DateTime value comparison) and an
exhaustive defaults-from-empty-map test. All 21 tests run via
'flutter test' with no emulator.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Expanded docs/api.md from 83 lines to full coverage: all 58 registered
routes documented with method, both /api/ and /api/v1/ path aliases,
request/response JSON schemas, status codes, and curl examples
- Added Authentication section: Bearer token vs session cookie, auth
precedence in RequireSession middleware, first-time bootstrap flow
- Added API Versioning section: /api/ (legacy/web) vs /api/v1/ (stable
contract), handleBoth convention, recommendation for mobile clients
- Added Error Envelope section: {error: ...} documented once with full
status code table
- Added Token Lifecycle subsection: minting (one-time plaintext), expiry
enforcement, last_used_at semantics, and revocation behaviour
- Added Range header support documentation for streaming endpoints
- Added Quick Reference table mapping every route to its auth level
- Updated AGENTS.md with two new sections: Bearer-or-cookie unified
middleware pattern in RequireSession, and handleBoth route registration
convention to prevent multi-client contract drift
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Documents per-package coverage (73.6% overall), identifies untested
functions (progress_transaction.go at 0%, several podcast sub-service
methods, API share handlers), and catalogues reusable test helpers
found in *_test.go files for use by later test-addition tasks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
feed-checker into sub-services
Extract three role-focused sub-services from the monolithic podcastService:
- podcast_sub.go: podcastSubscriptionService handles SubscribeFeed, ListFeeds,
EditFeed, UnsubscribeFeed and podcast set lifecycle.
- podcast_episode.go: podcastEpisodeService handles ListEpisodes,
DownloadEpisode, ToggleEpisodeComplete and enclosure downloading.
- podcast_checker.go: podcastFeedChecker handles CheckFeeds, conditional GET,
backoff and episode upserting.
- podcast_helpers.go: shared helpers (podcastFolderName, sanitizeSetName,
sanitizeFilename).
podcast.go becomes a thin composite that embeds the three sub-services and
exposes a PodcastEpisodeService-compatible interface, preserving existing
API-layer wiring and tests.
|
|
SoC violation
- Add ErrCannotDeleteSelf sentinel error in service layer.
- Change DeleteUser signature to (ctx, callerID, id) across all layers.
- Move self-deletion guard from handleDeleteUser handler into userAdminService.DeleteUser.
- Update handleError to map ErrCannotDeleteSelf to 400 BadRequest.
- Adjust all affected tests to use the new signature.
|
|
Apply the Go best-practice convention 'accept interfaces, return concrete
types' across the service and scanner packages:
- NewBrowseService -> *browseService
- NewWriteService -> *writeService
- NewMediaStreamer -> *mediaStreamer
- NewFSScanner -> *FSScanner
- NewFSScannerWithLogger -> *FSScanner
- NewPodcastBrowseService -> *podcastBrowseService
- NewTagService -> *tagService
- NewShareService -> *shareService
- NewProgressService -> *progressService
- NewAdminService -> *adminService
- NewAdminServiceWithLogger -> *adminService
- NewAuthService -> *authService
- NewNoteService -> *noteService
- NewFavService -> *favService
- NewMediaService -> *mediaService
- NewMediaServiceWithPodcastBrowser -> *mediaService
Callers continue to work unchanged because Go allows assigning a concrete
type to an interface variable. All tests pass with -race -cover.
|
|
GetSetCover was returning a stale os.Stat wrapped error when no thumbnail
candidate was found (line 465), and was not translating os.IsNotExist
to ErrNotFound when the candidate thumbnail was missing (line 468).
Both cases now return service.ErrNotFound so the caller/handler can
respond with 404 instead of 500.
|
|
|
|
insertPodcastEpisodes and upsertFeedEpisodes
- insertPodcastEpisodes now returns an error when CreateEpisode fails so
callers (e.g. SubscribeFeed) can log it instead of silently dropping episodes.
- upsertFeedEpisodes now logs per-episode lookup/insert failures, collects
the failed GUIDs, and returns a summary error so the background CheckFeeds
caller can log a warning while continuing to process the rest of the feed.
All tests pass with -race -cover.
|
|
Previously checkFeed silently discarded the DB update error when a feed
returned 304 Not Modified. If the update failed, LastCheckedAt was not
persisted, causing the next background check to re-fetch the same
unchanged feed unnecessarily.
Now the error is propagated back to CheckFeeds so it is logged like any
other feed-check failure.
|
|
|
|
|
|
|
|
|
|
query
Previously ListEpisodes requested per-feed episodes with the full limit
from every feed, concatenated them, and then sliced the resulting slice
in memory. This silently skipped episodes from deeper pages because the
per-feed DB limit never returned them.
Fix: Add a new repository method ListEpisodesByFeedIDsWithStatus that
takes a slice of feed IDs and applies LIMIT/OFFSET globally in a single
SQL query (IN (...)). The service builds the feed ID list and delegates
pagination to the database instead of emulating it in memory.
Files changed:
- internal/repository/podcast.go: add ListEpisodesByFeedIDsWithStatus
- internal/repository/podcast_repo.go: extend PodcastRepo interface
- internal/repository/mock.go: add mock implementation
- internal/service/podcast.go: replace per-feed loop with new method
- internal/service/podcast_test.go: add tests for ListEpisodes
- internal/repository/podcast_test.go: add integration tests for new repo method
- internal/api/handlers_test.go: add mockPingStore method
|
|
- DB: add consecutive_failures and next_check_at to podcast_feeds
- model: add ConsecutiveFailures and NextCheckAt to PodcastFeed struct
- repository: update CRUD queries to handle new columns and
ListFeedsNeedingCheck to skip feeds with future next_check_at
- service: update CheckFeeds to use new query, update checkFeed to
reset counters on success and increment exponential backoff on failure
- tests: adapt mock signatures, add backoff integration test
|
|
- Add defer out.Close() after os.Create in copyFile to prevent fd leak.
- Remove redundant explicit out.Close() calls in error and success paths.
- Best-effort remove partially written destination file on io.Copy error.
|