summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2026-05-04task b: inject app context into AdminService and propagate cancellation to ↵Paul Buetow
background scans
2026-05-04task 6: narrow service interfaces in Server and MiddlewarePaul Buetow
Split Server struct to accept narrow service interfaces instead of fat composites (MediaService, AdminService). Each handler now depends only on its specific slice (MediaBrowseService, MediaWriteService, etc.). Split Middleware to depend on a narrow UserStore interface instead of full repository.Store. Updated all constructors, call sites, and tests. Added negative tests for nil AdminService and ProgressService returning 501 Not Implemented. References task 6.
2026-05-03task 2: add unit tests for decomposed sub-servicesPaul 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-03Task 8: standardize scanner and handler loggingPaul Buetow
2026-05-03Fix GC hard-delete ordering for task dPaul Buetow
2026-05-03Fix GC worker test synchronization for task aPaul Buetow
2026-05-03Backfill godoc for task 1Paul Buetow
2026-05-03Use Go 1.25 for Docker buildsPaul Buetow
2026-05-03refactor(api): extract Remuxer interface and move ffmpeg/MPEG-TS/mime logic ↵Paul Buetow
to internal/probe Move LooksLikeMPEGTS, MimeTypeForFilename and the ffmpeg remux path out of the api transport layer into a new internal/probe/remux.go package. This removes os/exec and mime tables from the api layer, satisfying the DIP principle. - New probe.Remuxer interface with FFRemuxer implementation - Server depends on probe.Remuxer, injected via NewServer - Updated cmd/mediaplayer wiring and all test helpers - All tests pass: go test ./... -race -cover
2026-05-03test: raise coverage above 60% in cmd/mediaplayer, model, and probePaul Buetow
- cmd/mediaplayer: add runWithSignal injection point for testing; cover version flag, invalid flags, invalid config, normal shutdown, all log levels, invalid DB, and privileged-port bind failure. Refactor run() to delegate to runWithSignal with optional signal channel. - internal/config: allow PORT=0 (ephemeral) to support test server startup. Update AGENTS.md validation docs accordingly. - internal/model: add comprehensive ScanProgress tests (Start, Done, IncrementFile/Set, SetCurrentSet/FilesTotal, Copy isolation, and concurrent access). - internal/probe: add image tests for isImagePath (all extensions and case insensitivity), real EXIF extraction via ImageMagick + exiv2, Probe against real JPEG, MP4, empty file, and nonexistent paths. - internal/config_test: replace PORT=0 invalid-value test with PORT=-1.
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-03Fix media info and detached playback statePaul Buetow
2026-05-03Fix: Sidebar visibility on page loadPaul Buetow
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-02refine playback navigation and player modesPaul Buetow
2026-05-02add playback navigation shortcutsPaul Buetow
2026-05-02add player minimize togglePaul Buetow
2026-05-02show audiobook covers as cardsPaul Buetow
2026-05-02show buffered media progressPaul Buetow
2026-05-02fix detached playback and scan progressPaul Buetow
2026-05-02feat: secure shares with keyboard-first My Shares modal (hotkeys S/L)Paul Buetow
2026-05-02more on thisPaul Buetow
2026-05-02switch sidebar hotkey to s, always rebuild/rescan in start.sh, bump sw.js cachePaul Buetow
2026-05-02fix:xPaul Buetow
2026-05-01api: remux MPEG-TS files to MP4 on the flyPaul Buetow
2026-05-01fix(gc): pass cancellable context to GCWorker.run() to avoid goroutine leak (#5)Paul Buetow
Replace context.Background() inside GCWorker.run() with a cancellable context created in Start() and cancelled in Stop(). This fixes the goroutine leak risk identified in 100-go-mistakes #62. Files changed: - internal/service/gc.go
2026-05-01task 4: DRY permission checking by extracting checkSetPermission helperPaul Buetow
Consolidates the duplicated user-admin, explicit permission, and set.Permissions loop logic from verifyAccess, verifyModifyAccess, and verifySetModifyAccess into a single checkSetPermission helper. - checkSetPermission accepts a requiredRole; empty string means any role. - verifyAccess delegates set-level permission check to helper. - verifyModifyAccess delegates owner-only check to helper. - verifySetModifyAccess delegates directly to helper. All tests pass with -race -cover.
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-01refactor(api): split monolithic handlers.go into domain-specific files (task 3)Paul Buetow
Split internal/api/handlers.go (1045 lines) to improve KISS/SRP: - handlers_auth.go – bootstrap, login, logout, health, session cookies - handlers_media.go – sets, media CRUD, tags, favorites, notes, progress - handlers_share.go – create/list/revoke shares, share page, share stream - handlers_admin.go – trash, rescan, users, permissions - handlers_file.go – stream, download, thumbnail, regenerate thumbnail Shared helpers (writeJSON, readJSON, pathID, serveFileResult, mimeTypeForFilename, etc.) remain in handlers.go. All tests pass: go test ./... -race -cover.
2026-05-01service: split media.go (745 lines) into 5 focused filesPaul Buetow
Split the monolithic media.go into cohesive files to fix KISS/SRP violation: - media_access.go: permission verification helpers (verifyAccess, verifyModifyAccess, verifySetModifyAccess) - media_browse.go: browsing, listing, streaming, thumbnails, set cover, tags and favorites - media_write.go: upload, create, soft-delete, restore - media_share.go: share token creation, validation, revocation, streaming via token - media_notes.go: note get/upsert/delete The shared mediaService struct, NewMediaService constructor, and common helpers (supported extensions, type guessing, thumbnail generation) remain in media.go. No functional changes — all tests pass.
2026-05-01Split MediaService interface into role-specific interfaces to fix ISP/OCP ↵Paul Buetow
violation
2026-05-01Add player stage collapse, multi-set selection, grid nav, m4b support, ↵Paul Buetow
content-type fixes, thumbnail refresh, and verbose logging
2026-05-01add readme and so onPaul Buetow
2026-05-01Improve start.sh with auto-bootstrap, rescan, and URL printingPaul Buetow
- Add stop/restart/status commands - Auto-bootstrap admin user on first run - Auto-trigger rescan if library is empty - Print connection URL and login credentials on startup - Print quick keyboard shortcut tips
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-01Make rescan asynchronous in background goroutinePaul Buetow
TriggerRescan now returns immediately and runs the actual scan in a 30-minute timeout background goroutine. This prevents long scans from tying up or timing out the HTTP request. Update related tests to wait on a channel for the async scan to complete.
2026-05-01Add cover image detection for audio files in scannerPaul Buetow
During scanning, when an audio file is found in a directory that also contains an image file (jpg/png/gif), the scanner now assigns that image as the audio file's thumbnail_path. This is common for audiobooks which have cover.jpg alongside the audio files. Changes: - scanner: two-pass walk to collect sibling images, then pair with audio - CSS: add .row-cover style for audio items with covers - JS: render audio rows with cover images when thumbnail_path is set
2026-05-01Rename Go module from codeberg.org/snonux/play to codeberg.org/snonux/playerPaul Buetow
2026-05-01Minimalist UI: hide all elements until activated; add help modal and ↵Paul Buetow
keyboard shortcuts - Redesign UI to be invisible by default: only header + '?' button shown - Press m to show sidebar, t for toolbar, / for search, ? for help - Add help modal with all keyboard shortcuts - Fix scanner to skip corrupt/unprobeable files instead of aborting - Fix scanner to skip thumbnail errors instead of aborting - Fix rescan to use background context so it completes after HTTP response - Rename project from KISS Media Player to Player
2026-04-30fix: permissions matrix UI now returns proper shape from backendPaul Buetow
The frontend admin.js expects {sets, users, permissions} but ListPermissions returned a flat []SetPermission slice. - Add PermissionsMatrix struct with JSON tags - Update AdminService.ListPermissions to return *PermissionsMatrix - Update mocks and all call sites to match new signature - Update tests to assert the new matrix shape
2026-04-30mobile: responsive layout, touch-friendly progress bar, collapsible filtersPaul Buetow
- Add mobile breakpoints (860px/520px) with compact header, full-width sidebar overlay, flexible search bar, and adaptive toolbar. - Player now spans full width on mobile and has reduced stage height. - Progress bar gains touch-drag support (touchstart/move/end) for mobile seeking. - Collapse advanced filters (tags/duration/filesize) behind a 'Filters' toggle to keep the default toolbar KISS. Only type and favorites remain always visible.
2026-04-30pa: raise aggregate test coverage to 81.5%Paul Buetow
2026-04-30task la: finish admin SPA workflows (permissions matrix UI, trash restore, ↵Paul Buetow
self-delete UX)
2026-04-30[ma] Add missing SPA controls: download, tags, thumbnail/cover regen, ↵Paul Buetow
upload, filesize display, duration/filesize/tag filters, favorites
2026-04-30na: Remove inline styles and non-theme color literals from frontendPaul Buetow
2026-04-30Wire playback resume end to end (task ka)Paul Buetow
- Add JSON tags to model structs so API responses use camelCase keys (e.g., id, file_name, position_seconds). - MediaDetail now includes progress; add ResumeFrom() helper on MediaDetail. - Frontend playSelected() fetches /api/media/:id and reads progress.position_seconds before starting playback, then passes resume position to selectAndPlay(). - player.js selectAndPlay/loadMedia accept resumeFrom parameter instead of reading media.resume_from from list items. - Backend test coverage: handlers_test verifies detail endpoint returns progress position in JSON; media_test verifies GetMediaDetail includes progress and ResumeFrom() value. - Frontend test coverage: added web/js/tests/playback-resume.test.js validating detail JSON shape, resume position computation, and list item contract.
2026-04-30ba: align go.mod toolchain version with Dockerfile and PLAN.md (Go 1.23)Paul Buetow
2026-04-30task oa: Add SECURE_COOKIES config to control session cookie Secure flagPaul Buetow
- Add SecureCookies bool to internal.Config (default true) - Update LoadConfig in internal/config.go to parse SECURE_COOKIES env var - Update setSessionCookie and clearSessionCookie in internal/api/handlers.go to read cfg.SecureCookies - Add tests verifying Secure=true/false and logout clears cookie accordingly - Update AGENTS.md and PLAN.md with new option documentation