summaryrefslogtreecommitdiff
path: root/internal/api
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-02 22:08:46 +0300
committerPaul Buetow <paul@buetow.org>2026-05-02 22:10:28 +0300
commite391bea837f9740aa8b303dedb6f87c09abd4201 (patch)
tree737ddbf8c58cd2b7acd0fb160494d9184e2c1983 /internal/api
parente898357da954acb561a0a88b4443da52f774ce36 (diff)
fix detached playback and scan progress
Diffstat (limited to 'internal/api')
-rw-r--r--internal/api/handlers.go4
-rw-r--r--internal/api/handlers_admin.go7
-rw-r--r--internal/api/handlers_test.go27
-rw-r--r--internal/api/server.go2
4 files changed, 27 insertions, 13 deletions
diff --git a/internal/api/handlers.go b/internal/api/handlers.go
index 41c4197..0436247 100644
--- a/internal/api/handlers.go
+++ b/internal/api/handlers.go
@@ -103,6 +103,10 @@ func (s *Server) serveBootstrap(w http.ResponseWriter, r *http.Request) {
s.serveFile(w, r, "bootstrap.html")
}
+func (s *Server) serveDetach(w http.ResponseWriter, r *http.Request) {
+ s.serveFile(w, r, "detach.html")
+}
+
// ------------------------------------------------------------------
// File serving helpers
// ------------------------------------------------------------------
diff --git a/internal/api/handlers_admin.go b/internal/api/handlers_admin.go
index 246a466..e9935d4 100644
--- a/internal/api/handlers_admin.go
+++ b/internal/api/handlers_admin.go
@@ -33,6 +33,13 @@ func (s *Server) handleRescan(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
}
+func (s *Server) handleScanProgress(w http.ResponseWriter, r *http.Request) {
+ if !requireService(w, s.adminSvc) {
+ return
+ }
+ writeJSON(w, http.StatusOK, s.adminSvc.ScanProgress(r.Context()))
+}
+
func (s *Server) handleListUsers(w http.ResponseWriter, r *http.Request) {
if !requireService(w, s.adminSvc) {
return
diff --git a/internal/api/handlers_test.go b/internal/api/handlers_test.go
index 2201897..0003b88 100644
--- a/internal/api/handlers_test.go
+++ b/internal/api/handlers_test.go
@@ -679,8 +679,8 @@ func TestServer_MediaList(t *testing.T) {
},
{
name: "with query params",
- query: "?set_id=1&type=video&search=foo&tags=bar,baz&favorites=true&min_duration=10&max_duration=100&sort=name&limit=5&offset=10",
- filter: repository.MediaFilter{SetID: intPtr(1), Type: (*model.MediaType)(func() *string { s := "video"; return &s }()), Search: "foo", Tags: []string{"bar", "baz"}, Favorites: true, MinDuration: floatPtr(10), MaxDuration: floatPtr(100), Sort: "name", Limit: 5, Offset: 10},
+ query: "?set_id=1&type=video&search=foo&tags=bar,baz&favorites=true&min_duration=10&max_duration=100&sort=name&limit=5&offset=10",
+ filter: repository.MediaFilter{SetID: intPtr(1), Type: (*model.MediaType)(func() *string { s := "video"; return &s }()), Search: "foo", Tags: []string{"bar", "baz"}, Favorites: true, MinDuration: floatPtr(10), MaxDuration: floatPtr(100), Sort: "name", Limit: 5, Offset: 10},
listResult: []model.Media{},
wantCode: http.StatusOK,
},
@@ -716,14 +716,14 @@ func TestServer_MediaList(t *testing.T) {
func TestServer_MediaDetail(t *testing.T) {
tests := []struct {
- name string
- id string
- result *service.MediaDetail
- err error
- wantCode int
- wantMedia bool
- wantResumeFrom float64
- wantProgressNil bool
+ name string
+ id string
+ result *service.MediaDetail
+ err error
+ wantCode int
+ wantMedia bool
+ wantResumeFrom float64
+ wantProgressNil bool
}{
{
name: "ok with progress",
@@ -762,8 +762,8 @@ func TestServer_MediaDetail(t *testing.T) {
return
}
var resp struct {
- Media *model.Media `json:"media"`
- Progress *model.PlaybackProgress `json:"progress"`
+ Media *model.Media `json:"media"`
+ Progress *model.PlaybackProgress `json:"progress"`
}
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
t.Fatalf("unmarshal detail: %v", err)
@@ -1083,7 +1083,7 @@ func TestServer_Shares(t *testing.T) {
},
GetSharedMediaFunc: func(ctx context.Context, token string) (*service.GetSharedMediaResult, error) {
return &service.GetSharedMediaResult{
- Media: &service.SharedMediaView{ID: 1, FileName: "x.mp4", Type: model.MediaTypeVideo, Duration: 120},
+ Media: &service.SharedMediaView{ID: 1, FileName: "x.mp4", Type: model.MediaTypeVideo, Duration: 120},
StreamURL: "/s/abc/stream",
ThumbURL: "/s/abc/thumbnail",
}, nil
@@ -1190,6 +1190,7 @@ func TestServer_AdminRoutes(t *testing.T) {
}{
{"list trash", "GET", "/api/admin/trash", "", http.StatusOK},
{"rescan", "POST", "/api/admin/rescan", "", http.StatusOK},
+ {"scan progress", "GET", "/api/admin/scan-progress", "", http.StatusOK},
{"list users", "GET", "/api/admin/users", "", http.StatusOK},
{"create user", "POST", "/api/admin/users", `{"username":"bob","password":"pass","is_admin":false}`, http.StatusOK},
{"delete user", "DELETE", "/api/admin/users/2", "", http.StatusOK},
diff --git a/internal/api/server.go b/internal/api/server.go
index 4d18d76..11518df 100644
--- a/internal/api/server.go
+++ b/internal/api/server.go
@@ -107,6 +107,7 @@ func (s *Server) routes() {
s.mux.Handle("/bootstrap.html", http.HandlerFunc(s.serveBootstrap))
s.mux.Handle("/", s.mw.RequireSession(http.HandlerFunc(s.serveIndex)))
s.mux.Handle("GET /index.html", s.mw.RequireSession(http.HandlerFunc(s.serveIndex)))
+ s.mux.Handle("GET /detach.html", s.mw.RequireSession(http.HandlerFunc(s.serveDetach)))
// Session-required routes
s.mux.Handle("POST /api/logout", s.mw.RequireSession(http.HandlerFunc(s.handleLogout)))
@@ -148,6 +149,7 @@ func (s *Server) routes() {
// Admin routes
s.mux.Handle("GET /api/admin/trash", s.mw.RequireSession(s.mw.RequireAdmin(http.HandlerFunc(s.handleListTrash))))
s.mux.Handle("POST /api/admin/rescan", s.mw.RequireSession(s.mw.RequireAdmin(http.HandlerFunc(s.handleRescan))))
+ s.mux.Handle("GET /api/admin/scan-progress", s.mw.RequireSession(s.mw.RequireAdmin(http.HandlerFunc(s.handleScanProgress))))
s.mux.Handle("GET /api/admin/users", s.mw.RequireSession(s.mw.RequireAdmin(http.HandlerFunc(s.handleListUsers))))
s.mux.Handle("POST /api/admin/users", s.mw.RequireSession(s.mw.RequireAdmin(http.HandlerFunc(s.handleCreateUser))))
s.mux.Handle("DELETE /api/admin/users/{id}", s.mw.RequireSession(s.mw.RequireAdmin(http.HandlerFunc(s.handleDeleteUser))))