| Age | Commit message (Collapse) | Author |
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
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
|
|
Prevents nil dereference panics in handlers that unconditionally
access s.cfg (share, media, auth). Fail-fast at wiring time matches
project convention.
|
|
- Introduce auth.SessionManager interface in internal/auth/interfaces.go
- Rename concrete struct to sessionManager (unexported) and have it satisfy interface
- Update api/service layers to depend on interface, not concrete type
- Add MockSessionManager for testing
- Update all call sites and tests to use interface
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- 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
|
|
|
|
- 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
|
|
- 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
|
|
|
|
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
|
|
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.
|
|
|
|
AuthService abstraction
|
|
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.
|
|
|
|
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
|
|
- 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.
|
|
- 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.
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
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.
|
|
content-type fixes, thumbnail refresh, and verbose logging
|
|
|
|
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
|