Distinguishes plain URLs from BitTorrent sources at task creation:
src_file must name a .torrent, magnet links auto-pick a BT-capable
provider (qBittorrent preferred, aria2 fallback), and ytdlp is rejected
for torrent sources. validateFiles now caps selected files at 10k to
block crafted-torrent entity floods.
Generated with Devin
@ -225,6 +225,7 @@ Order = user-visible value first; each ships with backend + UI + tests.
- [x] Tencent Captcha (upstream #2178) — `captcha_type=tcaptcha` now performs real verification: `pkg/tcaptcha` calls Tencent Cloud `DescribeCaptchaResult` with full TC3-HMAC-SHA256 request signing (CaptchaAppId/AppSecretKey + SecretId/SecretKey, CaptchaType 9, client IP propagated); login/register/forgot-password flows emit `{ticket, randstr}` from the TCaptcha.js popup widget via a new `TCaptcha` verify-button component; admin Captcha section gains the provider option + four credential fields; en+zh locales
- [x] Tencent Captcha (upstream #2178) — `captcha_type=tcaptcha` now performs real verification: `pkg/tcaptcha` calls Tencent Cloud `DescribeCaptchaResult` with full TC3-HMAC-SHA256 request signing (CaptchaAppId/AppSecretKey + SecretId/SecretKey, CaptchaType 9, client IP propagated); login/register/forgot-password flows emit `{ticket, randstr}` from the TCaptcha.js popup widget via a new `TCaptcha` verify-button component; admin Captcha section gains the provider option + four credential fields; en+zh locales
- [x] Localized admin strings (#25/#2691) — `setting.Provider.Localized` resolves any `<key>_i18n` JSON map by language tag (exact → bare primary subtag → wildcard `*` → base value); `SiteBasicLocalized` covers site name/title/description; consumed by site config, announcement endpoint, share-preview OG tags, index.html placeholders, WOPI breadcrumb, and email templates (recipient language); SKU gains `name_i18n`/`des_i18n` columns resolved per buyer language in the shop; admin gets a reusable `LocalizedFields` accordion (per-language inputs) wired into site name/description/announcement and SKU name/description; en+zh locales
- [x] Localized admin strings (#25/#2691) — `setting.Provider.Localized` resolves any `<key>_i18n` JSON map by language tag (exact → bare primary subtag → wildcard `*` → base value); `SiteBasicLocalized` covers site name/title/description; consumed by site config, announcement endpoint, share-preview OG tags, index.html placeholders, WOPI breadcrumb, and email templates (recipient language); SKU gains `name_i18n`/`des_i18n` columns resolved per buyer language in the shop; admin gets a reusable `LocalizedFields` accordion (per-language inputs) wired into site name/description/announcement and SKU name/description; en+zh locales
- [x] Weighted policy selection (upstream #2178 item 2) — `GroupSetting.WeightedPolicies` spreads uploads across the group's allowed policies by free capacity: `pickByFreeCapacity` picks the member with the most remaining `MaxTotalSize` headroom that fits the file (uncapped/suspended members not weighed); explicit directory/user preferences still win; size-aware `getPreferredPolicyForSize` wired into both upload paths; admin group editor gains a switch, en+zh locales
- [x] Weighted policy selection (upstream #2178 item 2) — `GroupSetting.WeightedPolicies` spreads uploads across the group's allowed policies by free capacity: `pickByFreeCapacity` picks the member with the most remaining `MaxTotalSize` headroom that fits the file (uncapped/suspended members not weighed); explicit directory/user preferences still win; size-aware `getPreferredPolicyForSize` wired into both upload paths; admin group editor gains a switch, en+zh locales
- [x] Download source typing + torrent bomb guard (upstream #2178 离线下载) — `CreateDownloadTask` distinguishes plain URLs from BitTorrent sources: `src_file` must name a `.torrent`, `magnet:` links auto-pick a BT-capable provider (qBittorrent preferred, aria2 fallback) and fail fast when only non-BT nodes exist; explicit `provider=ytdlp` with a torrent source is rejected; `validateFiles` caps selected files per task at `maxDownloadFiles` (10k) with `queue.CriticalErr` so crafted torrents cannot flood the entity table