feat(backend): add FutsalLiga scraper as secondary data source

Implement web scraping fallback for the official FutsalLiga website as a secondary data source between the primary API and the FlashScore fallback. This provides more reliable data retrieval with correct competition information when the primary API fails.

Add scrapeFutsalLiga function to extract club details, matches, and standings directly from the league website. Update refresh logic to attempt FutsalLiga scraping before falling back to FlashScore API
This commit is contained in:
Your Name committed 2026-10-04 21:24:28 +02:00
1 parent 85666d290c
commit 225da9253c
6 files changed
+914 -1331

No files matched your search

+14 -1
View File
@@ -1660,7 +1660,20 @@ func refresh(ctx context.Context) error {
// Try primary API first
if err := getJSON(ctx, client, urlDetail, &detail); err != nil {
log.Printf("primary api detail failed (%v), trying fallback", err)
log.Printf("primary api detail failed (%v), trying futsalliga scrape", err)
// Second source: scrape the official league site (current data, correct competition)
if comb, serr := scrapeFutsalLiga(ctx, client); serr == nil {
c.mu.Lock()
c.data = comb
c.mu.Unlock()
if werr := writeDiskJSON(c.data); werr != nil {
log.Printf("warn: write disk json: %v", werr)
}
log.Printf("refreshed data: comps=%d source=%s", len(comb.ClubDetail.Competitions), "futsalliga")
return nil
} else {
log.Printf("futsalliga scrape failed (%v), trying flashscore fallback", serr)
}
urlDetail = fmt.Sprintf("%s/club/%s/%s?slug=%s", fallbackBaseURL, clubType, fallbackClubID, fallbackSlug)
urlTable = fmt.Sprintf("%s/club/%s/%s/table?slug=%s", fallbackBaseURL, clubType, fallbackClubID, fallbackSlug)
if err := getJSON(ctx, client, urlDetail, &detail); err != nil {