Some frontends stuff multi-line subscription content into a single
string with literal backslash-n sequences. The whole blob parsed as
one URI whose fragment swallowed the remaining links (1 node with a
garbage name instead of N nodes).
Normalize literal \r\n / \n to real newlines at the ParseProxyLines
entry, after format detection and before splitting. Real newline
input and single links are unaffected.
HH-766
RenameCollectionNodes now reads geo info from cached egress-probe fields (country, countryCode, city, flag) on each node instead of doing per-node DNS lookups via DetectGeoWithServer.
When no cached egress data is available (probe not yet run), it falls back to name-based regex only (DetectGeo, no DNS) so the UI is never blocked. The background egress probe (triggered on source create/update) populates the cache asynchronously.
Also: runEgressProbe now stores countryCode and flag emoji from ipwho.is response. egressCacheKey and addCachedEgressInfo updated to include the new fields.
Reverted previous name-first hack on DetectGeoWithServer and DNS cache on geoip.LookupHost — no longer needed since rename doesn't call them.
Collection preview with rename: 30s -> 52ms (with cache miss, name-based fallback).
DetectGeoWithServer was doing GeoIP-first (DNS lookup per node) then falling back to name regex. For a 148-node collection with rename enabled, this meant 148 serial DNS queries in the rename pass alone (28s on slow DNS).
Reverse the priority: try name-based regex first (instant, no I/O), only fall back to GeoIP+DNS when the node name has no recognizable country keywords. Most proxy names already contain country/city info.
Also add in-memory DNS cache in geoip.LookupHost so repeated lookups for the same hostname don't re-resolve.
Collection preview with rename: 30s -> 3s.
Egress probe results (IP/country/region/city/isp) were cached using the
fetcher's cache_ttl (300s / 5min). After 5 minutes the cache expired and
the node list showed empty Egress IP/Country/Region fields again.
Add a dedicated egress_cache_ttl config (default 24h) so egress data
persists long enough to be useful when re-expanding the node list.
Add _sourceAlias and _previewId to the skip list in egressCacheKey so
that nodes from source preview (with _sourceAlias) and collection
preview (without _sourceAlias, after rename) produce the same cache
key. This ensures egress info cached during source-level probe is
visible when expanding collection cards.
Nodes whose country cannot be detected are now filtered out instead of
kept with their original name. This prevents unlabelled/unrenamed nodes
from appearing in collection output.
Nodes with port=0 or empty server cause client-side errors (e.g.
sing-box decode config failures). Filter them at the render dispatch
layer so all targets (sing-box, mihomo, surge, etc.) are protected.
vless outbound was passing Clash's network field (ws/grpc/h2) directly
to sing-box's network field (which only accepts tcp/udp). Extract
clashToSingBoxTransport() to convert ws/grpc/h2/quic/httpupgrade into
sing-box transport objects. Apply to both vless and vmess outbounds.
- Backend: preview handlers accept forceRefresh in request body
- Frontend: Sources & Collections cards get a refresh button that
bypasses cache and re-fetches from remote
mihomo (Clash Meta) natively supports xhttp and all Clash transports.
Build minimal mihomo YAML config directly from the proxy node instead
of converting to sing-box JSON format.
1. sslinks 403: Cloudflare blocks server IP. Add fetcher.proxy_url config
so subscription/flow requests can route through an HTTP proxy.
2. Egress probe: Docker image lacked sing-box. Install sing-box v1.11.4
in the Alpine runtime stage.
3. Collection rename: group by display baseName instead of internal
groupKey, format index as -N instead of %02d. Fixes double-suffix
issue where EnsureUniqueProxyNames appended -2/-3 onto existing 02.
- Dockerfile: 3-stage build (frontend npm build → backend go build → alpine runtime)
- Frontend dist files served from disk at /app/frontend/dist
- server.go: catch-all GET handler serves static files with SPA fallback to index.html
- config.go: new server.frontend_dir option (env: SUB_STORE_SERVER_FRONTEND_DIR)
- API routes (/api/*), download routes, and /health take priority over static serving
- 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)