mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-29 03:26:37 +08:00
fix cloud library scale and playback compatibility
Root cause: display-only cloud library filtering was reused by scan jobs, merged cloud mounts could be skipped, and OpenList listing relied on WebDAV/first-page behavior that could cap huge directories around 100 items. Cloud scans also let new items consume probe budget before existing rows with missing track/artwork metadata.\n\nChanges:\n- split display filtering from scannable cloud filtering so merged cloud mounts still scan\n- add OpenList API pagination with WebDAV fallback\n- prioritize existing cloud media missing metadata before new imports\n- restrict automatic cloud sync to one successful 19:00-21:00 daily window and keep manual scan immediate\n- disable startup cloud full-scan by default, with an explicit opt-in setting\n- improve Emby/cloud playback compatibility and cache/search/test coverage from the continued work
This commit is contained in:
+30
-18
@@ -78,7 +78,6 @@ func main() {
|
||||
if err := services.Auth.SeedAdmin(context.Background()); err != nil {
|
||||
logger.Warn("seed admin failed", zap.Error(err))
|
||||
}
|
||||
services.Boot()
|
||||
|
||||
router := buildRouter(cfg, logger, services)
|
||||
|
||||
@@ -88,27 +87,29 @@ func main() {
|
||||
ReadHeaderTimeout: 15 * time.Second,
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", srv.Addr)
|
||||
if err != nil {
|
||||
logger.Fatal("listen failed", zap.String("addr", srv.Addr), zap.Error(err))
|
||||
}
|
||||
localIP := getLocalIP()
|
||||
logger.Info("server is ready",
|
||||
zap.String("local", fmt.Sprintf("http://%s:%d", localIP, cfg.App.Port)),
|
||||
zap.String("listen", srv.Addr),
|
||||
)
|
||||
go func() {
|
||||
localIP := getLocalIP()
|
||||
publicIP := getPublicIP(3 * time.Second)
|
||||
if publicIP != "" {
|
||||
logger.Info("server is ready",
|
||||
zap.String("local", fmt.Sprintf("http://%s:%d", localIP, cfg.App.Port)),
|
||||
zap.String("public", fmt.Sprintf("http://%s:%d", publicIP, cfg.App.Port)),
|
||||
zap.String("listen", srv.Addr),
|
||||
)
|
||||
} else {
|
||||
logger.Info("server is ready",
|
||||
zap.String("local", fmt.Sprintf("http://%s:%d", localIP, cfg.App.Port)),
|
||||
zap.String("listen", srv.Addr),
|
||||
)
|
||||
}
|
||||
// 自动启动 Telegram 长轮询(无需公网 Webhook)
|
||||
services.TelegramBot.StartPolling(context.Background())
|
||||
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
if err := srv.Serve(ln); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
logger.Fatal("listen failed", zap.Error(err))
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
if publicIP := getPublicIP(3 * time.Second); publicIP != "" {
|
||||
logger.Info("server public endpoint",
|
||||
zap.String("public", fmt.Sprintf("http://%s:%d", publicIP, cfg.App.Port)),
|
||||
)
|
||||
}
|
||||
}()
|
||||
go services.Boot()
|
||||
go services.TelegramBot.StartPolling(context.Background())
|
||||
|
||||
// Graceful shutdown.
|
||||
stop := make(chan os.Signal, 1)
|
||||
@@ -200,6 +201,13 @@ func setNoCacheHeaders(c *gin.Context) {
|
||||
|
||||
func shouldBypassSPAFallback(path string) bool {
|
||||
lower := strings.ToLower(path)
|
||||
for _, exact := range []string{
|
||||
"/emby",
|
||||
} {
|
||||
if lower == exact {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, prefix := range []string{
|
||||
"/api/",
|
||||
"/emby/",
|
||||
@@ -213,6 +221,10 @@ func shouldBypassSPAFallback(path string) bool {
|
||||
"/displaypreferences/",
|
||||
"/branding/",
|
||||
"/localization/",
|
||||
"/startup/",
|
||||
"/quickconnect/",
|
||||
"/socket",
|
||||
"/embywebsocket",
|
||||
} {
|
||||
if strings.HasPrefix(lower, prefix) {
|
||||
return true
|
||||
|
||||
+17
-8
@@ -72,14 +72,23 @@ func TestServeSPAServesAssetsImmutableAndBypassesAPIRoutes(t *testing.T) {
|
||||
t.Fatalf("asset Cache-Control = %q, want immutable", got)
|
||||
}
|
||||
|
||||
apiReq := httptest.NewRequest(http.MethodGet, "/api/missing", nil)
|
||||
apiResp := httptest.NewRecorder()
|
||||
router.ServeHTTP(apiResp, apiReq)
|
||||
if apiResp.Code != http.StatusNotFound {
|
||||
t.Fatalf("api fallback status = %d, want 404", apiResp.Code)
|
||||
}
|
||||
if strings.Contains(apiResp.Body.String(), "index") {
|
||||
t.Fatalf("api route should not serve SPA index: %q", apiResp.Body.String())
|
||||
for _, path := range []string{
|
||||
"/api/missing",
|
||||
"/emby",
|
||||
"/emby/missing",
|
||||
"/Startup/Configuration",
|
||||
"/QuickConnect/Enabled",
|
||||
"/embywebsocket",
|
||||
} {
|
||||
req := httptest.NewRequest(http.MethodGet, path, nil)
|
||||
resp := httptest.NewRecorder()
|
||||
router.ServeHTTP(resp, req)
|
||||
if resp.Code != http.StatusNotFound {
|
||||
t.Fatalf("%s fallback status = %d, want 404", path, resp.Code)
|
||||
}
|
||||
if strings.Contains(resp.Body.String(), "index") {
|
||||
t.Fatalf("%s should not serve SPA index: %q", path, resp.Body.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user