refactor(scraper): rename /ui/audio*, /ui/chapter-text routes to /api/ namespace

This commit is contained in:
Admin
2026-03-02 22:01:52 +05:00
parent 59b1cfab1d
commit cb90771248
2 changed files with 11 additions and 11 deletions

View File

@@ -130,8 +130,8 @@ func (s *Server) ListenAndServe(ctx context.Context) error {
mux.HandleFunc("POST /ui/scrape/book", s.handleUIScrapeBook)
mux.HandleFunc("GET /ui/scrape/status", s.handleUIScrapeStatus)
mux.HandleFunc("GET /ui/ranking/status", s.handleRankingStatus)
// Plain-text chapter content for browser-side TTS
mux.HandleFunc("GET /ui/chapter-text/{slug}/{n}", s.handleChapterText)
// Plain-text chapter content (used server-side for audio generation)
mux.HandleFunc("GET /api/chapter-text/{slug}/{n}", s.handleChapterText)
// Server-side audio generation via Kokoro /v1/audio/speech.
// Generation can take several minutes, so wrap in its own timeout handler.
audioGenHandler := http.TimeoutHandler(
@@ -139,9 +139,9 @@ func (s *Server) ListenAndServe(ctx context.Context) error {
10*time.Minute,
`{"error":"audio generation timed out"}`,
)
mux.Handle("POST /ui/audio/{slug}/{n}", audioGenHandler)
mux.Handle("POST /api/audio/{slug}/{n}", audioGenHandler)
// Proxy route: fetches the generated file from Kokoro /v1/download/{filename}.
mux.HandleFunc("GET /ui/audio-proxy/{slug}/{n}", s.handleAudioProxy)
mux.HandleFunc("GET /api/audio-proxy/{slug}/{n}", s.handleAudioProxy)
srv := &http.Server{
Addr: s.addr,
@@ -289,7 +289,7 @@ func (s *Server) handleDeleteProgress(w http.ResponseWriter, r *http.Request) {
}
// handleChapterText returns the plain text of a chapter (markdown stripped)
// for browser-side TTS. The browser POSTs this directly to Kokoro-FastAPI.
// for server-side audio generation. Called by handleAudioGenerate internally.
func (s *Server) handleChapterText(w http.ResponseWriter, r *http.Request) {
slug := r.PathValue("slug")
n, err := strconv.Atoi(r.PathValue("n"))
@@ -309,7 +309,7 @@ func (s *Server) handleChapterText(w http.ResponseWriter, r *http.Request) {
// ─── Audio generation via Kokoro /v1/audio/speech ────────────────────────────
//
// handleAudioGenerate handles POST /ui/audio/{slug}/{n}.
// handleAudioGenerate handles POST /api/audio/{slug}/{n}.
//
// It calls Kokoro's POST /v1/audio/speech with return_download_link=true.
// Kokoro generates the audio, saves it to its own temp storage, and returns
@@ -463,9 +463,9 @@ func (s *Server) generateSpeech(ctx context.Context, text, voice string, speed f
}
// writeAudioResponse writes the JSON response for a generated audio chapter.
// The URL points to our proxy handler which fetches from Kokoro on demand.
// The URL points to our proxy handler GET /api/audio-proxy/{slug}/{n}.
func (s *Server) writeAudioResponse(w http.ResponseWriter, slug string, n int, voice string, speed float64, filename string) {
proxyURL := fmt.Sprintf("/ui/audio-proxy/%s/%d?voice=%s&speed=%.1f", slug, n, voice, speed)
proxyURL := fmt.Sprintf("/api/audio-proxy/%s/%d?voice=%s&speed=%.1f", slug, n, voice, speed)
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]interface{}{
"url": proxyURL,
@@ -473,7 +473,7 @@ func (s *Server) writeAudioResponse(w http.ResponseWriter, slug string, n int, v
})
}
// handleAudioProxy handles GET /ui/audio-proxy/{slug}/{n}.
// handleAudioProxy handles GET /api/audio-proxy/{slug}/{n}.
// It looks up the Kokoro download filename for this chapter (voice/speed) and
// proxies GET /v1/download/{filename} from the Kokoro server back to the browser.
func (s *Server) handleAudioProxy(w http.ResponseWriter, r *http.Request) {

View File

@@ -40,8 +40,8 @@ export const POST: RequestHandler = async ({ params, request }) => {
const data = (await scraperRes.json()) as { url: string; filename: string };
// Rewrite the proxy URL from the scraper's /ui/audio-proxy/... to our own
// /api/audio/[slug]/[n]?voice=...&speed=... so the browser never calls the scraper directly.
// The scraper returns a proxy URL pointing to /api/audio-proxy/... — we rewrite
// it to our own /api/audio/[slug]/[n]?... so the browser never calls the scraper directly.
const voice = body.voice ?? '';
const speed = body.speed ?? 1.0;
const qs = new URLSearchParams();