release: v1.4.3
GitHub Release / release (push) Canceled after 0s
ci / ci (22, ubuntu-latest) (push) Canceled after 0s
Publish Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Canceled after 0s
Publish Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Canceled after 0s
Publish Docker image / merge (push) Canceled after 0s

Add a Telegram channel or group storage backend, with proxied image URLs and an optional API proxy.
This commit is contained in:
O96u committed 2026-10-09 15:39:24 +08:00
1 parent 4ed4692f5e
commit cc19dc6435
32 files changed
+1527 -143

No files matched your search

+34 -2
View File
@@ -9,6 +9,11 @@ import {
type StorageBackendPatch
} from '../../../utils/storage-backends'
import { parseS3Config, validateS3Config } from '../../../utils/storage/s3'
import {
parseTelegramConfig,
validateTelegramConfig,
validateApiProxyUrl
} from '../../../utils/storage/telegram'
import { parseQuotaBytes } from '../../../utils/storage-capacity'
import type { ServingMode } from '../../../utils/storage/types'
@@ -20,10 +25,13 @@ interface StoragePatchBody {
bucket?: string
prefix?: string
forcePathStyle?: boolean
chatId?: string
apiProxyUrl?: string
}
secrets?: {
accessKeyId?: string
secretAccessKey?: string
botToken?: string
}
servingMode?: ServingMode
publicUrl?: string
@@ -63,6 +71,26 @@ export default defineEventHandler(async (event) => {
patch.name = body.name.trim() || row.name
}
if (body.config !== undefined && row.type === 'telegram') {
const current = parseTelegramConfig(row.config_json) ?? { chatId: '' }
const apiProxyUrl = body.config.apiProxyUrl?.trim() ?? current.apiProxyUrl ?? ''
const next = {
chatId: body.config.chatId?.trim() ?? current.chatId,
apiProxyUrl: apiProxyUrl || undefined
}
const error = validateTelegramConfig(next)
if (error) {
createApiError(event, 'INVALID_REQUEST', error, 400)
}
if (apiProxyUrl) {
const proxyError = validateApiProxyUrl(apiProxyUrl)
if (proxyError) {
createApiError(event, 'INVALID_REQUEST', proxyError, 400)
}
}
patch.config = next
}
if (body.config !== undefined && row.type === 's3') {
const current = parseS3Config(row.config_json) ?? {
endpoint: '',
@@ -87,7 +115,11 @@ export default defineEventHandler(async (event) => {
patch.secrets = body.secrets
}
if (body.servingMode !== undefined) {
if (body.secrets !== undefined && row.type === 'telegram') {
patch.secrets = body.secrets
}
if (body.servingMode !== undefined && row.type !== 'telegram') {
if (body.servingMode !== 'proxy' && body.servingMode !== 'public') {
createApiError(event, 'INVALID_REQUEST', '访问方式无效', 400)
}
@@ -99,7 +131,7 @@ export default defineEventHandler(async (event) => {
}
if (body.quotaBytes !== undefined) {
if (row.type === 's3') {
if (row.type === 's3' || row.type === 'telegram') {
const quotaBytes = parseQuotaBytes(body.quotaBytes)
if (!quotaBytes) {
createApiError(event, 'INVALID_REQUEST', '请填写有效的存储套餐总量', 400)
+53
View File
@@ -2,13 +2,19 @@ import { requireAdminAuth } from '../../../utils/access'
import { createApiError } from '../../../utils/api-error'
import {
insertStorageBackend,
insertTelegramBackend,
isStorageEnvConfigured
} from '../../../utils/storage-backends'
import { validateS3Config } from '../../../utils/storage/s3'
import {
validateTelegramConfig,
validateApiProxyUrl
} from '../../../utils/storage/telegram'
import { parseQuotaBytes } from '../../../utils/storage-capacity'
import type { ServingMode } from '../../../utils/storage/types'
interface StorageCreateBody {
type?: 's3' | 'telegram'
name?: string
provider?: string
config?: {
@@ -17,10 +23,13 @@ interface StorageCreateBody {
bucket?: string
prefix?: string
forcePathStyle?: boolean
chatId?: string
apiProxyUrl?: string
}
secrets?: {
accessKeyId?: string
secretAccessKey?: string
botToken?: string
}
servingMode?: ServingMode
publicUrl?: string
@@ -40,6 +49,50 @@ export default defineEventHandler(async (event) => {
(): StorageCreateBody => ({})
)
const backendType = body.type === 'telegram' ? 'telegram' : 's3'
if (backendType === 'telegram') {
const name = body.name?.trim() || 'Telegram 频道'
const chatId = body.config?.chatId?.trim() ?? ''
const apiProxyUrl = body.config?.apiProxyUrl?.trim() ?? ''
const botToken = body.secrets?.botToken?.trim() ?? ''
if (!chatId || !botToken) {
createApiError(event, 'INVALID_REQUEST', 'Bot Token 与 Chat ID 不能为空', 400)
}
const config = {
chatId,
apiProxyUrl: apiProxyUrl || undefined
}
const configError = validateTelegramConfig(config)
if (configError) {
createApiError(event, 'INVALID_REQUEST', configError, 400)
}
if (apiProxyUrl) {
const proxyError = validateApiProxyUrl(apiProxyUrl)
if (proxyError) {
createApiError(event, 'INVALID_REQUEST', proxyError, 400)
}
}
const quotaBytes = parseQuotaBytes(body.quotaBytes)
if (!quotaBytes) {
createApiError(event, 'INVALID_REQUEST', '请填写有效的存储套餐总量', 400)
}
const id = insertTelegramBackend({
name,
config,
secrets: { botToken },
quotaBytes,
enabled: body.enabled,
isDefault: body.isDefault
})
return { success: true, id }
}
const name = body.name?.trim() || 'S3 兼容存储'
const config = {
endpoint: body.config?.endpoint?.trim() ?? '',