feat: Android download page, analysis retry and a collapsible search
ci / api / api (push) Successful in 37s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 46s
ci / db / db (push) Failing after 14s
ci / recommender / recommender (push) Successful in 51s
ci / ts / ts (packages + web) (push) Successful in 57s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m2s
ci / api / api (push) Successful in 37s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 46s
ci / db / db (push) Failing after 14s
ci / recommender / recommender (push) Successful in 51s
ci / ts / ts (packages + web) (push) Successful in 57s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m2s
- /android is a public page with the latest APK, the server address to copy and three install steps; linked from the sign-in screen and the profile menu - failed audio analysis can be retried from the library page, which also shows the most common error; the analyzer no longer burns attempts on files that are missing because the disk is not mounted - the top bar search folds into a round button and slides open on click, "/" or Ctrl+K Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2d49cb3f19
commit
fda6ed48ab
27 files changed
+757
-277
No files matched your search
@@ -565,5 +565,6 @@ func TestPublicRoutes(t *testing.T) {
|
||||
e := newEnv(t)
|
||||
assert.Equal(t, http.StatusOK, e.do(http.MethodGet, "/api/v1/server-info", nil).Code)
|
||||
assert.Equal(t, http.StatusOK, e.do(http.MethodGet, "/healthz", nil).Code)
|
||||
assert.NotEqual(t, http.StatusUnauthorized, e.do(http.MethodGet, "/api/v1/app/android/latest", nil).Code, "APK page is public")
|
||||
assert.Equal(t, http.StatusUnauthorized, e.do(http.MethodGet, "/api/v1/unknown", nil).Code)
|
||||
}
|
||||
@@ -55,6 +55,8 @@ var publicRoutes = map[string]bool{
|
||||
"GET /api/v1/server-info": true,
|
||||
"POST /api/v1/auth/login": true,
|
||||
"POST /api/v1/auth/refresh": true,
|
||||
// Android-приложение раздаётся по ссылке /android без входа: в APK нет ничего, кроме клиента.
|
||||
"GET /api/v1/app/android/latest": true,
|
||||
}
|
||||
|
||||
// Что разрешено, пока пользователь обязан сменить учётные данные / пароль.
|
||||
@@ -90,7 +92,8 @@ func Middleware(svc *Service, log *slog.Logger) func(http.Handler) http.Handler
|
||||
// Обложки открывает <img> без заголовка Authorization — ссылку защищает подпись.
|
||||
// Аудио открывает <audio> — тоже без заголовка; ссылка подписана для пользователя.
|
||||
cover := (r.Method == http.MethodGet || r.Method == http.MethodHead) &&
|
||||
(strings.HasPrefix(r.URL.Path, "/api/v1/covers/") || strings.HasPrefix(r.URL.Path, "/api/v1/stream/"))
|
||||
(strings.HasPrefix(r.URL.Path, "/api/v1/covers/") || strings.HasPrefix(r.URL.Path, "/api/v1/stream/") ||
|
||||
strings.HasPrefix(r.URL.Path, "/api/v1/app/android/download/"))
|
||||
if !strings.HasPrefix(r.URL.Path, "/api/v1/") || publicRoutes[route] || cover {
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
return
|
||||
|
||||
Reference in new issue
Block a user