summaryrefslogtreecommitdiff
path: root/internal/api
AgeCommit message (Collapse)Author
2026-05-07Task 51: add API error helpersPaul Buetow
2026-05-07task 31: introduce media streamer servicePaul Buetow
2026-05-07Task 21: move thumbnail regeneration to write servicePaul Buetow
2026-05-07Refactor API server dependencies for task 11Paul Buetow
2026-05-07Handle share page marshal errors (a1)Paul Buetow
2026-05-06internal/service: inject http.Client into podcastService constructor (task 41)Paul Buetow
2026-05-06Fix music video duration display in progress barPaul Buetow
2026-05-06Add podcast E2E integration testsPaul 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-04Use white-background PNG logo for README, favicon, and loginPaul Buetow
- Generate logo.png (white bg) from SVG for README and login screen - Regenerate favicon.ico from white-background logo - Keep original logo.svg available for future edits - Update server routes and middleware to serve new logo.png
2026-05-04Add project logo, favicon, and display logo on login screenPaul Buetow
- Add logo.svg at project root and reference it in README.md - Generate favicon.ico from logo and place in web/ - Serve logo.svg and favicon.ico as static assets - Display logo on the login page with responsive sizing
2026-05-04task f: validate media_id and sessionID in progress handler and servicePaul 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 9: Centralize file extension and media type mappings in internal/mediatypePaul Buetow
Create a new internal/mediatype package with a single source of truth for: - Extension-to-media-type mappings (TypeForExt) - Extension-to-MIME mappings (MIMETypeForExt) - Supported extension checks (IsSupportedExt, IsImageExt, IsCoverImageExt) Replace duplicated logic across: - internal/service/service.go (supportedExtensions, guessMediaType) - internal/scanner/scanner.go (mediaExtensions, imageExtensions, mediaTypeFromExt) - internal/api/handlers.go (probe.MimeTypeForFilename) - internal/probe/probe.go (imageExtensions, isImagePath) - internal/probe/remux.go (MimeTypeForFilename) Divergent defaults unified: both scanner and service now default unknown extensions to video (model.MediaTypeVideo) via mediatype.TypeForExt. Update tests to use mediatype package and remove obsolete scanner tests. Update AGENTS.md to reflect the new package.
2026-05-04task c: run gofmt and fix unwrapped error literals across the codebasePaul Buetow
2026-05-04task 3: decouple API layer from repository with MediaQueryFilter and ↵Paul Buetow
AuthService abstraction
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 8: standardize scanner and handler loggingPaul 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-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-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-02fix:xPaul Buetow
2026-05-01api: remux MPEG-TS files to MP4 on the flyPaul 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-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-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-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-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-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-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
2026-04-30task ia: fix media listing/filtering semantics (favorites bool, filesize ↵Paul Buetow
filters, permission scoping)
2026-04-30task ha: enforce upload limits, role checks, probing, thumbnails, cleanupPaul Buetow
- handlers.go: enforce MAX_UPLOAD_SIZE_MB via http.MaxBytesReader and http.MaxBytesError mapping to 413. - service/media.go: UploadMedia now verifies owner/admin, rejects unsupported extensions, probes metadata with ffprobe, generates video thumbnails, enforces unique filenames, and cleans up temp files + hard-deletes DB row on any failure. - Reconcile PLAN.md 500MB -> 100MB default to match AGENTS.md/config. - Add service and API tests for max-size rejection, unsupported extension, missing role, probe failure, thumbnail failure, cleanup, and success paths.
2026-04-30ga — implement thumbnail and set cover regeneration end to endPaul Buetow
- mediaService: implement RegenerateThumbnail and RegenerateSetCover - Inject thumb.Generator and probe.Prober into MediaService - Update NewMediaService constructor and all call sites - Add service tests for success, failure, permission denied, and not-found - Add API tests for cover regeneration and thumbnail error mapping - All tests pass
2026-04-30ja: implement public share landing page and improve error mappingPaul Buetow
- Add web/share.html with a minimal HTML5 video player, theme variables, centered layout, play overlay, and Back to Home link. - Update handleSharePage to return HTML for browser Accept headers (text/html or empty) and JSON for application/json. Return 410 Gone for expired shares. - Update handleShareStream to map service errors to distinct HTTP codes: ErrShareExpired -> 410, ErrShareNotFound/ErrMediaNotFound -> 404. - Improve ValidateShareToken and StreamSharedMedia to return sentinel errors (ErrShareNotFound, ErrShareExpired, ErrMediaNotFound) instead of generic string errors. - Update and add tests for share page HTML/JSON negotiation and share stream 404/410 responses.
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: allow static assets during bootstrap when no users existPaul Buetow
The BootstrapRedirect middleware was blocking /css/ and /js/ requests when no users existed, which prevented the bootstrap.html page from loading its stylesheets and scripts. This caused the form to submit as raw form data (rather than JSON via the JS API) and silently fail. - Added /css/* and /js/* to isBootstrapPublic() so static assets are served without redirect when no users exist. - Also added /images/, /favicon.svg, /manifest.json, and /sw.js for completeness.
2026-04-30refactor: extract query param parsing from handleListMediaPaul Buetow
2026-04-30refactor: extract nil service check into helperPaul Buetow
2026-04-30fix: add explicit permission checks to StreamMedia and DownloadMediaPaul Buetow
2026-04-29feat(q9): implement REST handlers, streaming, uploads, shares, notes, ↵Paul Buetow
progress, admin routes
2026-04-29q9: add table-driven httptest coverage for REST handlersPaul Buetow
Add comprehensive table-driven tests in handlers_more_test.go covering all previously un-tested handlers and middleware paths. Includes negative tests (nil service, invalid IDs, missing bodies, service errors) and real-file assertions for stream/download/thumbnail. coverage: 58.8% -> 94.9%
2026-04-29feat: implement bcrypt password hashing, session management, login/logout ↵Paul Buetow
handlers, and bootstrap flow (m9)