feat: GeoIP-based geo detection + configurable rename template

- Add MaxMind GeoLite2-City mmdb auto-download and IP-based geo lookup
  (covers all 249 countries globally, replacing limited 8-country regex)
- Add RenameOptions with 5 toggleable fields (flag/alias/country/city/index)
  stored as rename_options_json on collections
- Collection rename pipeline uses DetectGeoWithServer(name, server) which
  tries GeoIP lookup first, falls back to name-based regex matching
- Chinese country/city names + emoji flag prefix
- Country-city dedup: skip city when it equals country (e.g. 香港/香港)
- URI fragment encoding: url.QueryEscape -> url.PathEscape (%20 not +)
- Egress cache key excludes name field so renamed nodes still match cache
- Frontend: 5 toggle buttons in collection edit form, default all on
- Migrations: 0004 (source alias + collection rename_enabled),
  0005 (collection rename_options_json)
This commit is contained in:
2026-07-28 14:44:54 +08:00
parent 389c0d172a
commit de9ac92ede
29 changed files with 1256 additions and 225 deletions
+20
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"os"
"os/signal"
"path/filepath"
"syscall"
"time"
@@ -16,6 +17,7 @@ import (
"github.com/peterqiu0516/sub-store/internal/config"
"github.com/peterqiu0516/sub-store/internal/database"
"github.com/peterqiu0516/sub-store/internal/geoip"
"github.com/peterqiu0516/sub-store/internal/handler"
"github.com/peterqiu0516/sub-store/internal/middleware"
)
@@ -54,6 +56,24 @@ func RunServer(cfg *config.Config) error {
return err
}
// Ensure GeoIP database exists (download in background if missing)
mmdbPath := filepath.Join(filepath.Dir(cfg.Database.Path), "GeoLite2-City.mmdb")
geoip.SetMmdbPath(mmdbPath)
if _, err := os.Stat(mmdbPath); err != nil {
logrus.Info("GeoIP database not found, downloading in background...")
go func() {
if err := geoip.DownloadMmdb(mmdbPath); err != nil {
logrus.WithError(err).Warn("GeoIP download failed, name-based detection will be used as fallback")
} else {
logrus.Info("GeoIP database downloaded successfully")
// Reload the reader
geoip.SetMmdbPath(mmdbPath)
}
}()
} else {
logrus.Info("GeoIP database found")
}
return startFiber(cfg, db)
}