Files
djk/internal/app/config_defaults.go
T

159 lines
4.9 KiB
Go

package app
import (
"crypto/aes"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"os"
)
const (
defaultAPIBase = "https://dr6skssi3nxbk.cloudfront.net"
defaultCDNURL = "https://sjljsla.lkkwip.cn"
userAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Mobile/15E148 Safari/604.1"
xUserAgent = "BuildID=com.abc.Butterfly;SysType=ios;DevID=00000000000000000000000000000;Ver=1.0.0;DevType=iPhone;DeviceBrand=APPLE;DeviceModel=iPhone;SystemName=iOS;SystemVersion=18.7;Terminal=1;IsH5=1;Sid=00000000000000000000000000000000"
)
type Config struct {
adminUsername string
adminPassword string
adminUserExplicit bool
adminPasswordExplicit bool
settingsLoaded bool
dataDir string
outputDirSetting string
APIBase string `json:"apiBase"`
CDNURL string `json:"cdnURL"`
Token string `json:"token"`
AESKeyHex string `json:"aesKeyHex"`
InterfaceKey string `json:"interfaceKey"`
ParamKey string `json:"paramKey"`
ParamIV string `json:"paramIV"`
OutputDir string `json:"outputDir"`
FFmpeg string `json:"ffmpeg"`
Concurrency int `json:"concurrency"`
RequestConcurrency int `json:"requestConcurrency"`
RequestIntervalMS int `json:"requestIntervalMs"`
MaxPagesPerSort int `json:"maxPagesPerSort"`
PageSize int `json:"pageSize"`
Retries int `json:"retries"`
SkipBytes int64 `json:"skipBytes"`
InsecureTLS bool `json:"insecureTLS"`
ProxyURL string `json:"proxyURL,omitempty"`
HuangguoAIURL string `json:"huangguoAIURL,omitempty"`
HuangguoVideoURL string `json:"huangguoVideoURL,omitempty"`
HuangdouURL string `json:"huangdouURL,omitempty"`
HongguoURL string `json:"hongguoURL,omitempty"`
}
func defaultConfig() Config {
return Config{
APIBase: defaultAPIBase,
CDNURL: defaultCDNURL,
OutputDir: defaultOutputDir(),
FFmpeg: "ffmpeg",
Concurrency: 2,
RequestConcurrency: 2,
RequestIntervalMS: 500,
MaxPagesPerSort: 20,
PageSize: 50,
Retries: 3,
SkipBytes: 512 * 1024,
InsecureTLS: false,
}
}
func defaultOutputDir() string {
return "短剧下载"
}
func loadConfig(path string) Config {
cfg := defaultConfig()
if path != "" {
b, err := os.ReadFile(path)
if err != nil {
fmt.Printf(" 读取配置失败,使用默认配置: %v\n", err)
} else if err := json.Unmarshal(b, &cfg); err != nil {
fmt.Printf(" 解析配置失败,使用默认配置: %v\n", err)
cfg = defaultConfig()
}
}
applyConfigEnvironment(&cfg)
if cfg.APIBase == "" {
cfg.APIBase = defaultAPIBase
}
if cfg.CDNURL == "" {
cfg.CDNURL = defaultCDNURL
}
if cfg.OutputDir == "" {
cfg.OutputDir = defaultOutputDir()
}
if cfg.FFmpeg == "" {
cfg.FFmpeg = "ffmpeg"
}
if cfg.Concurrency <= 0 {
cfg.Concurrency = 2
}
if cfg.RequestConcurrency <= 0 {
cfg.RequestConcurrency = 2
}
if cfg.RequestIntervalMS <= 0 {
cfg.RequestIntervalMS = 500
}
if cfg.MaxPagesPerSort <= 0 {
cfg.MaxPagesPerSort = 20
}
if cfg.PageSize <= 0 || cfg.PageSize > 100 {
cfg.PageSize = 50
}
if cfg.Retries <= 0 {
cfg.Retries = 3
}
if cfg.SkipBytes <= 0 {
cfg.SkipBytes = 512 * 1024
}
return cfg
}
func applyConfigEnvironment(cfg *Config) {
setIf := func(dst *string, key string) {
if v := os.Getenv(key); v != "" {
*dst = v
}
}
setIf(&cfg.APIBase, "JUKU_API_BASE")
setIf(&cfg.CDNURL, "JUKU_CDN_URL")
setIf(&cfg.Token, "JUKU_TOKEN")
setIf(&cfg.AESKeyHex, "JUKU_AES_KEY_HEX")
setIf(&cfg.InterfaceKey, "JUKU_INTERFACE_KEY")
setIf(&cfg.ParamKey, "JUKU_PARAM_KEY")
setIf(&cfg.ParamIV, "JUKU_PARAM_IV")
setIf(&cfg.HuangguoAIURL, "JUKU_HUANGGUO_AI_URL")
setIf(&cfg.HuangguoVideoURL, "JUKU_HUANGGUO_VIDEO_URL")
setIf(&cfg.HuangdouURL, "JUKU_HUANGDOU_URL")
setIf(&cfg.HongguoURL, "JUKU_HONGGUO_URL")
setIf(&cfg.ProxyURL, "JUKU_PROXY_URL")
setIf(&cfg.OutputDir, "JUKU_OUTPUT_DIR")
setIf(&cfg.FFmpeg, "JUKU_FFMPEG")
}
func (c Config) validate() error {
if _, err := configuredProxy(c.ProxyURL); err != nil {
return err
}
if c.ParamKey != "" && len(c.ParamKey) != aes.BlockSize || c.ParamIV != "" && len(c.ParamIV) != aes.BlockSize {
return fmt.Errorf("paramKey/paramIV 必须是 %d 字节", aes.BlockSize)
}
if key, err := hex.DecodeString(c.AESKeyHex); c.AESKeyHex != "" && (err != nil || len(key) != aes.BlockSize) {
return errors.New("aesKeyHex 必须是 16 字节 AES 密钥的 hex 编码")
}
for _, endpoint := range []string{c.APIBase, c.HuangguoAIURL, c.HuangguoVideoURL, c.HuangdouURL, c.HongguoURL} {
if endpoint != "" && !isProviderHTTPMediaURL(endpoint) {
return errors.New("站点地址必须是有效的 HTTP/HTTPS URL")
}
}
return nil
}