feat(e2e): use direct HTTP for chapter scraping, cap TTS at 200 chars

- e2e fixture: replace single contentClient with directClient (plain HTTP)
  for chapter/metadata/ranking + contentClient (Browserless) for urlClient
  only — matches production wiring and is significantly faster
- server: add max_chars field to audio request body; truncates stripped text
  to N runes before sending to Kokoro (used by e2e for quick TTS tests)
- fix: move RankingItem to scraper package to break novelfire→storage import
  cycle; storage.RankingItem is now a type alias for backward compat
- fix: update stale New() call in novelfire integration test (missing args)
- fix: replace removed blob-ranking methods in storage integration test with
  current per-item API (UpsertRankingItem/ListRankingItems/RankingLastUpdated)
- justfile: add test-e2e and e2e tasks
This commit is contained in:
Admin
2026-03-03 20:02:15 +05:00
parent b8d4d94b18
commit af3c487afb
8 changed files with 105 additions and 83 deletions

View File

@@ -348,8 +348,9 @@ func (s *Server) handleAudioGenerate(w http.ResponseWriter, r *http.Request) {
voice := s.kokoroVoice
speed := 1.0
var body struct {
Voice string `json:"voice"`
Speed float64 `json:"speed"`
Voice string `json:"voice"`
Speed float64 `json:"speed"`
MaxChars int `json:"max_chars"`
}
if r.Body != nil {
_ = json.NewDecoder(r.Body).Decode(&body)
@@ -409,6 +410,9 @@ func (s *Server) handleAudioGenerate(w http.ResponseWriter, r *http.Request) {
http.Error(w, `{"error":"chapter text is empty"}`, http.StatusUnprocessableEntity)
return
}
if body.MaxChars > 0 && len([]rune(text)) > body.MaxChars {
text = string([]rune(text)[:body.MaxChars])
}
if s.kokoroURL == "" {
http.Error(w, `{"error":"kokoro not configured"}`, http.StatusServiceUnavailable)
return