B
This commit is contained in:
@@ -15,6 +15,9 @@ PUBLIC_BASE_URL=
|
||||
# 1. Clash/Mihomo YAML proxies 文件
|
||||
# 2. base64 编码 URI 订阅
|
||||
# 3. 直接明文 URI 订阅
|
||||
# 也支持本地文件,例如:
|
||||
# AIRPORT_B_URL=/app/data/sources/airport-b.txt
|
||||
# AIRPORT_B_URL=file:///app/data/sources/airport-b.txt
|
||||
AIRPORT_A_URL=
|
||||
# 允许留空;留空时该机场会自动跳过,不参与默认查询
|
||||
AIRPORT_B_URL=
|
||||
|
||||
@@ -48,6 +48,7 @@ sub-provider/
|
||||
cn-ip.yaml
|
||||
data/
|
||||
cache/
|
||||
sources/
|
||||
.env.example
|
||||
Dockerfile
|
||||
docker-compose.yaml
|
||||
@@ -69,6 +70,7 @@ cp .env.example .env
|
||||
- `PUBLIC_PATH` 改成足够长的随机字符串
|
||||
- `PUBLIC_BASE_URL` 建议填写你反代后的最终访问地址,例如 `https://sub.example.com`
|
||||
- `AIRPORT_A_URL` / `AIRPORT_B_URL` 都可以直接填订阅地址,项目会自动判断是 YAML 还是 URI 订阅
|
||||
- 也可以直接填本地文件路径,例如 `/app/data/sources/airport-b.txt` 或 `file:///app/data/sources/airport-b.txt`
|
||||
- 允许把其中一个留空;留空时这个机场会自动跳过
|
||||
|
||||
3. 启动:
|
||||
@@ -148,6 +150,7 @@ HEAD /<PUBLIC_PATH>/bundle/stash.yaml?sources=airport-a,airport-b
|
||||
- 生成后的完整 YAML 会缓存到 `output/bundle-cache/`,默认 600 秒内直接返回缓存
|
||||
- 可用 `force_refresh=true` 强制跳过缓存并覆盖旧缓存文件
|
||||
- 上游订阅原始内容也会按 TTL 落盘缓存到 `data/fetch-cache/`,默认 900 秒
|
||||
- 如果你想固定使用本地文件订阅,可以把文件放到 `data/sources/`,再把 `AIRPORT_*_URL` 指向 `/app/data/sources/xxx.txt`
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@ import base64
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any, Iterable
|
||||
from urllib.parse import parse_qs, unquote, urlparse
|
||||
|
||||
import httpx
|
||||
import yaml
|
||||
|
||||
from app.config import get_settings
|
||||
from app.config import ROOT_DIR, get_settings
|
||||
from app.models import FetchResult, ProviderDocument, SourceConfig, SourceSnapshot
|
||||
from app.services.cache import TTLCache
|
||||
from app.services.fetch_cache import build_fetch_cache_key, load_fetch_cache, save_fetch_cache
|
||||
@@ -31,6 +32,17 @@ async def fetch_source(name: str, source: SourceConfig) -> FetchResult:
|
||||
logger.info("fetch_source memory cache hit: source=%s ttl=%s", name, ttl)
|
||||
return cached
|
||||
|
||||
local_path = resolve_local_source_path(source.url)
|
||||
if local_path is not None:
|
||||
logger.info("fetch_source local file: source=%s path=%s", name, local_path)
|
||||
try:
|
||||
result = FetchResult(text=local_path.read_text(encoding="utf-8"), headers={})
|
||||
except Exception:
|
||||
logger.exception("fetch_source local file read failed: source=%s path=%s", name, local_path)
|
||||
raise
|
||||
_fetch_cache.set(name, result, ttl)
|
||||
return result
|
||||
|
||||
cache_key = build_fetch_cache_key(name=name, url=source.url)
|
||||
disk_cached = load_fetch_cache(
|
||||
cache_dir=settings.fetch_cache_dir,
|
||||
@@ -66,6 +78,34 @@ async def fetch_source(name: str, source: SourceConfig) -> FetchResult:
|
||||
return result
|
||||
|
||||
|
||||
def resolve_local_source_path(raw: str) -> Path | None:
|
||||
candidate = raw.strip()
|
||||
if not candidate:
|
||||
return None
|
||||
|
||||
parsed = urlparse(candidate)
|
||||
if parsed.scheme in {"http", "https"}:
|
||||
return None
|
||||
|
||||
if parsed.scheme == "file":
|
||||
path_text = unquote(parsed.path or "")
|
||||
if parsed.netloc:
|
||||
path_text = f"//{parsed.netloc}{path_text}"
|
||||
if re.match(r"^/[A-Za-z]:", path_text):
|
||||
path_text = path_text[1:]
|
||||
path = Path(path_text)
|
||||
else:
|
||||
path = Path(candidate)
|
||||
|
||||
if not path.is_absolute():
|
||||
path = ROOT_DIR / path
|
||||
|
||||
resolved = path.resolve()
|
||||
if not resolved.is_file():
|
||||
raise FileNotFoundError(f"Local source file not found: {resolved}")
|
||||
return resolved
|
||||
|
||||
|
||||
async def build_provider_document(name: str, source: SourceConfig) -> ProviderDocument:
|
||||
settings = get_settings()
|
||||
ttl = source.cache_ttl_seconds or settings.cache_ttl_seconds
|
||||
|
||||
@@ -15,6 +15,8 @@ sources:
|
||||
display_name: B
|
||||
kind: auto
|
||||
url: ${AIRPORT_B_URL}
|
||||
headers:
|
||||
User-Agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"
|
||||
prefix: "[B] "
|
||||
include_regex: ""
|
||||
exclude_regex: "流量|重置|到期|续费|官网|离线|套餐"
|
||||
|
||||
Reference in New Issue
Block a user