feat(scrape-range): add chapter range scraping for admin users

Adds FromChapter/ToChapter fields to orchestrator.Config and skips out-of-range
chapters in processBook. Exposes POST /scrape/book/range Go endpoint and a
matching UI proxy at /api/scrape/range. The book detail page now shows admins
a range input (from/to chapter) and a per-chapter 'scrape from here up' button.
This commit is contained in:
Admin
2026-03-05 14:00:50 +05:00
parent 97e7a8dc02
commit a54d8d43aa
4 changed files with 251 additions and 30 deletions

View File

@@ -33,6 +33,29 @@ func (s *Server) handleScrapeBook(w http.ResponseWriter, r *http.Request) {
s.runAsync(w, cfg)
}
// handleScrapeBookRange handles POST /api/scrape/book/range.
// Body: {"url": "...", "from": N, "to": M}
// Scrapes only chapters in the range [from, to] (inclusive).
// from=0 means "start from chapter 1"; to=0 means "no upper limit".
func (s *Server) handleScrapeBookRange(w http.ResponseWriter, r *http.Request) {
var body struct {
URL string `json:"url"`
From int `json:"from"`
To int `json:"to"`
}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil || body.URL == "" {
http.Error(w, `{"error":"request body must be JSON with \"url\" field"}`, http.StatusBadRequest)
return
}
cfg := s.oCfg
cfg.SingleBookURL = body.URL
cfg.FromChapter = body.From
cfg.ToChapter = body.To
s.runAsync(w, cfg)
}
// runAsync launches an orchestrator in the background and returns 202 Accepted.
// Only one scrape job runs at a time; concurrent requests receive 409 Conflict.
func (s *Server) runAsync(w http.ResponseWriter, cfg orchestrator.Config) {