mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-03 18:22:57 +00:00
182 lines
4.7 KiB
Go
182 lines
4.7 KiB
Go
package services
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"fotbal-club/internal/config"
|
|
)
|
|
|
|
// EnsureFACRLogosProcessed triggers post-processing of FACR logos referenced
|
|
// in cached prefetch JSON files (facr_club_info.json, facr_tables.json).
|
|
// It is idempotent and safe to call multiple times.
|
|
func EnsureFACRLogosProcessed(cacheDir string) error {
|
|
if config.AppConfig != nil && !config.AppConfig.RembgEnabled {
|
|
return nil
|
|
}
|
|
var firstErr error
|
|
clubInfo := filepath.Join(cacheDir, "facr_club_info.json")
|
|
if _, err := os.Stat(clubInfo); err == nil {
|
|
if err := postProcessFACRClubInfoLogos(cacheDir); err != nil && firstErr == nil {
|
|
firstErr = fmt.Errorf("club_info: %w", err)
|
|
}
|
|
}
|
|
tables := filepath.Join(cacheDir, "facr_tables.json")
|
|
if _, err := os.Stat(tables); err == nil {
|
|
if err := postProcessFACRTablesLogos(cacheDir); err != nil && firstErr == nil {
|
|
firstErr = fmt.Errorf("tables: %w", err)
|
|
}
|
|
}
|
|
return firstErr
|
|
}
|
|
|
|
// progress state for rembg batch
|
|
var rembgMu sync.RWMutex
|
|
var rembgRunning bool
|
|
var rembgTotal int
|
|
var rembgDone int
|
|
var rembgStarted time.Time
|
|
var rembgFinished *time.Time
|
|
|
|
// RembgStatus represents current background removal progress
|
|
type RembgStatus struct {
|
|
Running bool `json:"running"`
|
|
Total int `json:"total"`
|
|
Done int `json:"done"`
|
|
StartedAt time.Time `json:"started_at"`
|
|
FinishedAt *time.Time `json:"finished_at,omitempty"`
|
|
}
|
|
|
|
// GetRembgStatus returns a snapshot of current rembg batch progress
|
|
func GetRembgStatus() RembgStatus {
|
|
rembgMu.RLock()
|
|
defer rembgMu.RUnlock()
|
|
return RembgStatus{
|
|
Running: rembgRunning,
|
|
Total: rembgTotal,
|
|
Done: rembgDone,
|
|
StartedAt: rembgStarted,
|
|
FinishedAt: rembgFinished,
|
|
}
|
|
}
|
|
|
|
// StartFACRLogosBatch scans cached FACR JSONs and processes all referenced FACR logos
|
|
// using ProcessFACRLogo. Progress is tracked via GetRembgStatus. If a batch is already
|
|
// running, this call is a no-op and returns false. Otherwise returns true and starts
|
|
// a background goroutine.
|
|
func StartFACRLogosBatch(cacheDir string) bool {
|
|
if config.AppConfig != nil && !config.AppConfig.RembgEnabled {
|
|
return false
|
|
}
|
|
rembgMu.Lock()
|
|
if rembgRunning {
|
|
rembgMu.Unlock()
|
|
return false
|
|
}
|
|
// Collect unique FACR logo URLs to determine total
|
|
urls := collectFACRLogos(cacheDir)
|
|
rembgRunning = true
|
|
rembgTotal = len(urls)
|
|
rembgDone = 0
|
|
rembgStarted = time.Now()
|
|
rembgFinished = nil
|
|
rembgMu.Unlock()
|
|
|
|
if len(urls) == 0 {
|
|
// nothing to do; mark finished quickly
|
|
rembgMu.Lock()
|
|
rembgRunning = false
|
|
now := time.Now()
|
|
rembgFinished = &now
|
|
rembgMu.Unlock()
|
|
return true
|
|
}
|
|
|
|
go func(urlList []string) {
|
|
defer func() {
|
|
// Best-effort: after processing, ensure JSONs are rewritten to point to processed URLs
|
|
_ = EnsureFACRLogosProcessed(cacheDir)
|
|
rembgMu.Lock()
|
|
rembgRunning = false
|
|
now := time.Now()
|
|
rembgFinished = &now
|
|
rembgMu.Unlock()
|
|
}()
|
|
for _, u := range urlList {
|
|
_, _ = ProcessFACRLogo(u) // best effort; skip errors
|
|
rembgMu.Lock()
|
|
rembgDone++
|
|
rembgMu.Unlock()
|
|
}
|
|
}(urls)
|
|
return true
|
|
}
|
|
|
|
// collectFACRLogos returns unique FACR-hosted logo URLs from cached prefetch JSONs.
|
|
func collectFACRLogos(cacheDir string) []string {
|
|
uniq := map[string]struct{}{}
|
|
add := func(s string) {
|
|
s = strings.TrimSpace(s)
|
|
if s == "" {
|
|
return
|
|
}
|
|
// Only FACR sources; skip already-processed local /uploads and other hosts
|
|
ls := strings.ToLower(s)
|
|
if strings.HasPrefix(ls, "/uploads/") || strings.HasPrefix(ls, "/dist/") {
|
|
return
|
|
}
|
|
if !strings.Contains(ls, "fotbal.cz") {
|
|
return
|
|
}
|
|
uniq[s] = struct{}{}
|
|
}
|
|
// facr_club_info.json
|
|
if b, err := os.ReadFile(filepath.Join(cacheDir, "facr_club_info.json")); err == nil {
|
|
var payload struct {
|
|
Competitions []struct {
|
|
Matches []struct {
|
|
HomeLogoURL string `json:"home_logo_url"`
|
|
AwayLogoURL string `json:"away_logo_url"`
|
|
} `json:"matches"`
|
|
} `json:"competitions"`
|
|
}
|
|
if json.Unmarshal(b, &payload) == nil {
|
|
for _, c := range payload.Competitions {
|
|
for _, m := range c.Matches {
|
|
add(m.HomeLogoURL)
|
|
add(m.AwayLogoURL)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// facr_tables.json
|
|
if b, err := os.ReadFile(filepath.Join(cacheDir, "facr_tables.json")); err == nil {
|
|
var payload struct {
|
|
Competitions []struct {
|
|
Table struct {
|
|
Overall []struct {
|
|
TeamLogoURL string `json:"team_logo_url"`
|
|
} `json:"overall"`
|
|
} `json:"table"`
|
|
} `json:"competitions"`
|
|
}
|
|
if json.Unmarshal(b, &payload) == nil {
|
|
for _, c := range payload.Competitions {
|
|
for _, r := range c.Table.Overall {
|
|
add(r.TeamLogoURL)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
out := make([]string, 0, len(uniq))
|
|
for k := range uniq {
|
|
out = append(out, k)
|
|
}
|
|
return out
|
|
}
|