summaryrefslogtreecommitdiff
path: root/internal/repository
AgeCommit message (Collapse)Author
2026-05-17Restructure repo: move Go server into player-server/Paul Buetow
2026-05-17Fix in-progress media thresholdPaul Buetow
2026-05-17Add progress service completion methodsPaul Buetow
2026-05-17Add playback repository cleanup queriesPaul Buetow
2026-05-17Add finished flag to playback progressPaul Buetow
2026-05-16Configure SQLite for NFS-backed deploymentsPaul Buetow
2026-05-16Migrate stale sets schema for podcastsPaul Buetow
2026-05-10internal/service: fix ListEpisodes global pagination by using cross-feed SQL ↵Paul Buetow
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
2026-05-10Add circuit breaker / backoff for failing podcast feeds in CheckFeedsPaul Buetow
- 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
2026-05-10internal/repository: use placeholders for LIMIT and OFFSET in ListMediaPaul Buetow
2026-05-10Decouple podcast browse logic from BrowseSet via PodcastBrowser interfacePaul Buetow
Extract PodcastBrowser interface and podcastBrowseService implementation to move podcast-specific grid augmentation out of browseService.BrowseSet. - Remove PodcastRepo from BrowseServiceStore and MediaServiceStore. - browseService now delegates podcast set augmentation to an injected PodcastBrowser strategy (kept optional/nil-safe). - Add NewMediaServiceWithPodcastBrowser to wire a real PodcastBrowser (backed by PodcastRepo) in production while keeping the plain NewMediaService for existing callers/tests. - Update main.go to instantiate NewPodcastBrowseService and inject it. - Update browse_test.go to test PodcastBrowser-augmented paths through the new constructor signature. This keeps BrowseSet focused on files and folders only and removes the podcast dependency from the browse contract.
2026-05-09style: gofmt and goimports formatting fixesPaul Buetow
2026-05-09t1: remove repository migration shimPaul Buetow
2026-05-09Refine media browsing and set coversPaul Buetow
2026-05-06remove debug fmt.Printf leak from ListMedia query builder\n\nFixes: u0Paul Buetow
2026-05-05Fix podcast migration backward compatibility and login logo widthPaul Buetow
2026-05-05Fix podcast support critical bugs from code reviewPaul Buetow
- Fix boolean scanning from SQLite INTEGER columns (intToBool helper) - Fix BrowseSet LIMIT 0 returning zero episodes (use 1000 instead) - Fix checkFeed double-fetch by parsing from resp.Body directly + Add ParseFeedReader for body reuse - Fix file handle leak in DownloadEpisode (explicit Close before ImportMediaFile) - Fix incomplete rollback in DownloadEpisode (remove file + delete media row) - Fix 204 No Content handler writing 'null' body - Fix DownloadCoverImage to accept *http.Client with timeout - Deduplicate uniqueFilename into shared internal/service/filename.go - Wire frontend renderPodcastEpisodes into renderBrowse from API data - Refactor podcasts.js: remove extra API call, fix toggle toast, remove duplicate toast - Add Config.PodcastCheckMinutes + PODCAST_CHECK_INTERVAL_MINUTES env var - Start background CheckFeeds goroutine in main.go with ticker - Update NewPodcastService to accept checkInterval parameter - Log errors from CheckFeeds and episode creation instead of silently discarding
2026-05-05Add podcast support backend: RSS/Atom feeds, episode management, cover scrapingPaul Buetow
2026-05-04task 7: refactor oversized functions into helpersPaul Buetow
Refactored the following functions per CLAUDE.md (50+ line limit): - internal/scanner/scanner.go: scanSet (192 → 56 lines) Extracted: ensureSet, loadExistingMedia, gatherCoverImages, thumbnailForVideo, thumbnailForImage, buildThumbnailPath, processNewFile, updateAudioThumbnails - internal/repository/migrate.go: Migrate (134 → 23 lines) Extracted: enableForeignKeys, execSchema; split schema into tablesSchema and indexesSchema constants - internal/config.go: LoadConfig (85 → 28 lines) Extracted: defaultConfig, loadNumericSettings, loadStringSettings, loadLogLevel, loadSecureCookies; added validLogLevels variable - cmd/mediaplayer/main.go: run / runWithSignal (114 → 26 / 26 lines) Extracted: parseVersionFlag, buildLogger, wireDeps, runServer, ensureSignalChannel, shutdownGracefully; introduced appDeps struct - internal/api/server.go: routes (96 → 8 lines) Extracted per route group: routesPublic, routesSharePublic, routesStatic, routesHTML, routesAuth, routesSets, routesMedia, routesNotes, routesProgress, routesShares, routesAdmin Added helpers: requireSession, requireAdmin, publicMethod - internal/service/browse.go: BrowseSet (85 → 26 lines) Extracted: prefixForParent, classifyMediaPath, buildFolderMap, folderHasCover, buildFolders All public interfaces remain unchanged. Tests pass: go test ./... -race -cover
2026-05-04task c: run gofmt and fix unwrapped error literals across the codebasePaul Buetow
2026-05-03task 2 review fixes: narrow BrowseService and accessHelper store interfacesPaul Buetow
2026-05-03task 2: decompose mediaService and adminService into role-focused structsPaul Buetow
Extract accessHelper and split mediaService into: - browseService (read-only browsing, streaming, thumbnails) - writeService (upload, soft-delete, restore) - shareService (share links) - tagService (tagging) - favService (favorites) - noteService (notes) Split adminService into: - trashService (list deleted media) - scanService (trigger rescan, scan progress) - userAdminService (create/list/delete users) - permissionAdminService (grant/revoke/list permissions) Add repository sub-interfaces for each service. Add negative tests for share sub-service.
2026-05-03Backfill godoc for task 1Paul Buetow
2026-05-03fix(admin): fix rescan goroutine lifecycle and race on shared ScanProgressPaul Buetow
- Protect adminService scan state (cancel func + progress pointer) with sync.Mutex. - Allocate fresh ScanProgress per trigger and pass it to the scanner, eliminating races on the previously shared progress struct. - Cancel previous scan context before starting a new one. - Add tests for cancellation, fresh progress per scan, concurrent triggers, and empty progress when never started. - Fix race-prone tests by polling Running==true before waiting for completion.
2026-05-03feat: hybrid cache-busting for thumbnails and coversPaul Buetow
- Add Cache-Control: no-cache headers to thumbnail and cover endpoints (GET /api/media/{id}/thumbnail, GET /api/sets/{id}/cover, GET /s/{token}/thumbnail) so browsers revalidate instead of serving stale cached images after regeneration. - Add frontend cache-busting via ?t=Date.now() after folder cover regeneration so the browser fetches the newly overwritten image. - Replace toolbar filters with inline search syntax (min:, max:, tag:, like:, type:, sort:, minsize:, maxsize:) for faster filtering. - Remove dedicated toolbar and advanced filter panel; consolidate all filtering into the search bar. - Expand filter state to support filesize_min/filesize_max.
2026-05-02feat: secure shares with keyboard-first My Shares modal (hotkeys S/L)Paul Buetow
2026-05-01Task 1: Create AuthService and route handleBootstrap/handleLogin through itPaul Buetow
Introduce service.AuthService interface with Bootstrap and Login methods, a concrete authService implementation, and a MockAuthService for testing. Wire AuthService into api.Server and update cmd/mediaplayer/main.go to use it. This removes direct store access from handleBootstrap and handleLogin, fixing the DIP violation. Sentinel errors (ErrAlreadyBootstrapped, ErrInvalidCredentials) are added to the service package so the API layer can map them to the correct HTTP status codes without leaking DB details. Files created: - internal/service/auth.go Files modified: - internal/service/service.go - internal/service/media.go - internal/service/mock.go - internal/repository/repository.go - internal/repository/mock.go - internal/api/server.go - internal/api/handlers_auth.go - internal/api/handlers_test.go - internal/api/handlers_more_test.go - cmd/mediaplayer/main.go
2026-05-01add readme and so onPaul Buetow
2026-05-01Add support for audiobook/cover images with ancestor lookup and fix keyboard ↵Paul Buetow
navigation Backend: - Add UpdateMediaThumbnail to MediaRepo for efficient thumbnail-only updates - Update ScannerStore interface to include thumbnail update capability - Update mock implementations across repository and API layers for interface changes - Enhance scanner to detect image files in ancestor directories for audio covers - Add background goroutine for async rescan to avoid HTTP timeout Frontend: - Fix hjkl cursor keys to navigate grid properly - Implement ancestor directory cover image lookup for audiobooks Infrastructure: - Add start.sh helper script for quick server startup during development
2026-05-01Rename Go module from codeberg.org/snonux/play to codeberg.org/snonux/playerPaul Buetow
2026-04-30pa: raise aggregate test coverage to 81.5%Paul Buetow
2026-04-30task ia: fix media listing/filtering semantics (favorites bool, filesize ↵Paul Buetow
filters, permission scoping)
2026-04-30task da: enforce media access and owner/admin role permissionsPaul Buetow
Changes: - MediaService.ListMedia now accepts userID and filters by allowed sets for non-admins via AllowedSetIDs in repository.MediaFilter. - Handlers pass userID into ListMedia; API returns 403 for forbidden. - Added verifyModifyAccess and verifySetModifyAccess helpers so only owners/admins can upload, soft-delete, restore, and regenerate thumbnails/covers; viewers are blocked. - GetMediaDetail, ToggleFavorite, AssignTag, RemoveTag, notes, and shares now consistently verifyAccess before proceeding. - Handlers handle ErrForbidden with 403 for soft-delete and restore. - Added negative tests proving viewers cannot mutate and unauthorized users cannot access/detail/tag/note/favorite/share inaccessible media.
2026-04-30Rename module to codeberg.org/snonux/play (task aa)Paul Buetow
- Update go.mod module path - Replace all internal imports from github.com/paul/kiss-media-player to codeberg.org/snonux/play - Run go mod tidy and gofmt -w .
2026-04-30fix(ca): translate sql.ErrNoRows to nil,nil for optional lookupsPaul Buetow
Repository methods that perform single-row queries now return (nil,nil) instead of leaking sql.ErrNoRows when a row is missing. This aligns with service-layer expectations (e.g. GetMediaDetail, ValidateSession, UpdateProgress, AssignTag, access checks) so normal missing data does not break app flows. Files changed: - internal/repository/media.go, user.go, set.go, set_permission.go, tag.go, note.go, playback_progress.go, playback_accumulator.go, session.go, share.go - internal/repository/sqlite_test.go (updated assertions) - internal/repository/sqlite_no_rows_test.go (new focused repository tests) - internal/service/no_rows_test.go (new focused service tests)
2026-04-30refactor: split repository.Store into focused interfacesPaul Buetow
2026-04-30fix: exclude soft-deleted media from GetMediaByIDPaul Buetow
2026-04-29fix: correct LIKE escape in ListMediaPaul Buetow
2026-04-29feat(n9): Implement MediaService, AdminService, ProgressService, GCWorkerPaul Buetow
2026-04-29feat: implement bcrypt password hashing, session management, login/logout ↵Paul Buetow
handlers, and bootstrap flow (m9)
2026-04-29feat: SQLite schema migrations, repository interfaces, and concrete SQLite ↵Paul Buetow
implementations with :memory: table-driven tests (task l9)
2026-04-28h9: scaffold go project structurePaul Buetow
- Initialize go.mod (github.com/paul/kiss-media-player) - Add internal/version.go with const Version - Add internal/config.go with env-based Config struct and validation (PORT, MEDIA_ROOT, DB_PATH, MAX_UPLOAD_SIZE_MB, SESSION_TIMEOUT_HOURS, GC_INTERVAL_MINUTES, SHARE_DEFAULT_EXPIRY_DAYS, LOG_LEVEL) - Add table-driven config validation tests (defaults, overrides, invalid values) - Add cmd/mediaplayer/main.go with -version flag - Create directory scaffold: internal/{model,repository,scanner,probe,thumb, clock,auth,service,api,setassign}, web/{css,js}, k8s - Add .gitignore for binaries and data.db - Refactor env parsing into envInt/envString helpers per go-best-practices