refactor(scraper): rename /ui/audio*, /ui/chapter-text routes to /api/ namespace
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user