mirror of
https://github.com/MarSeventh/CloudFlare-ImgBed.git
synced 2026-01-31 09:03:19 +08:00
Feat:telegram渠道支持设置代理;优化上传设置页面使用体验
This commit is contained in:
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
css/239.d71f401a.css.gz
Normal file
BIN
css/239.d71f401a.css.gz
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
css/417.8b7df435.css.gz
Normal file
BIN
css/417.8b7df435.css.gz
Normal file
Binary file not shown.
Binary file not shown.
1
css/855.0de4ad0d.css
Normal file
1
css/855.0de4ad0d.css
Normal file
File diff suppressed because one or more lines are too long
BIN
css/855.0de4ad0d.css.gz
Normal file
BIN
css/855.0de4ad0d.css.gz
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
1
css/app.be4a11ae.css
Normal file
1
css/app.be4a11ae.css
Normal file
File diff suppressed because one or more lines are too long
BIN
css/app.be4a11ae.css.gz
Normal file
BIN
css/app.be4a11ae.css.gz
Normal file
Binary file not shown.
@@ -3,12 +3,12 @@ import { getDatabase } from '../../../utils/databaseAdapter.js';
|
||||
export async function onRequest(context) {
|
||||
// 上传设置相关,GET方法读取设置,POST方法保存设置
|
||||
const {
|
||||
request, // same as existing Worker API
|
||||
env, // same as existing Worker API
|
||||
params, // if filename includes [id] or [[path]]
|
||||
waitUntil, // same as ctx.waitUntil in existing Worker API
|
||||
next, // used for middleware or to fetch assets
|
||||
data, // arbitrary space for passing data between middlewares
|
||||
request, // same as existing Worker API
|
||||
env, // same as existing Worker API
|
||||
params, // if filename includes [id] or [[path]]
|
||||
waitUntil, // same as ctx.waitUntil in existing Worker API
|
||||
next, // used for middleware or to fetch assets
|
||||
data, // arbitrary space for passing data between middlewares
|
||||
} = context;
|
||||
|
||||
const db = getDatabase(env);
|
||||
@@ -60,6 +60,7 @@ export async function getUploadConfig(db, env) {
|
||||
savePath: 'environment variable',
|
||||
botToken: env.TG_BOT_TOKEN,
|
||||
chatId: env.TG_CHAT_ID,
|
||||
proxyUrl: env.TG_PROXY_URL || '', // 可选的代理 URL
|
||||
enabled: true,
|
||||
fixed: true,
|
||||
})
|
||||
@@ -70,6 +71,7 @@ export async function getUploadConfig(db, env) {
|
||||
// 如果环境变量未删除,进行覆盖操作
|
||||
if (telegramChannels[0]) {
|
||||
telegramChannels[0].enabled = tg.enabled
|
||||
telegramChannels[0].proxyUrl = tg.proxyUrl
|
||||
}
|
||||
|
||||
continue
|
||||
@@ -85,7 +87,7 @@ export async function getUploadConfig(db, env) {
|
||||
channels: [],
|
||||
}
|
||||
telegram.loadBalance = tgLoadBalance
|
||||
|
||||
|
||||
|
||||
|
||||
// =====================读取r2渠道配置=====================
|
||||
@@ -156,7 +158,7 @@ export async function getUploadConfig(db, env) {
|
||||
s3Channels[0].enabled = s.enabled
|
||||
s3Channels[0].quota = s.quota // 保留容量限制配置
|
||||
}
|
||||
|
||||
|
||||
continue
|
||||
}
|
||||
// id自增
|
||||
@@ -176,7 +178,7 @@ export async function getUploadConfig(db, env) {
|
||||
const discord = {}
|
||||
const discordChannels = []
|
||||
discord.channels = discordChannels
|
||||
|
||||
|
||||
// 从环境变量读取 Discord 配置
|
||||
if (env.DISCORD_BOT_TOKEN) {
|
||||
discordChannels.push({
|
||||
@@ -192,7 +194,7 @@ export async function getUploadConfig(db, env) {
|
||||
fixed: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
for (const dc of settingsKV.discord?.channels || []) {
|
||||
// 如果 savePath 是 environment variable,修改可变参数
|
||||
if (dc.savePath === 'environment variable') {
|
||||
@@ -221,7 +223,7 @@ export async function getUploadConfig(db, env) {
|
||||
const huggingface = {}
|
||||
const huggingfaceChannels = []
|
||||
huggingface.channels = huggingfaceChannels
|
||||
|
||||
|
||||
// 从环境变量读取 HuggingFace 配置
|
||||
if (env.HF_TOKEN) {
|
||||
huggingfaceChannels.push({
|
||||
@@ -236,7 +238,7 @@ export async function getUploadConfig(db, env) {
|
||||
fixed: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
for (const hf of settingsKV.huggingface?.channels || []) {
|
||||
// 如果 savePath 是 environment variable,修改可变参数
|
||||
if (hf.savePath === 'environment variable') {
|
||||
|
||||
@@ -119,14 +119,17 @@ export async function onRequest(context) { // Contents of context object
|
||||
}
|
||||
}
|
||||
|
||||
// 获取TG图片真实地址
|
||||
// 获取TG图片真实地址(支持代理域名)
|
||||
const TgBotToken = imgRecord.metadata?.TgBotToken || env.TG_BOT_TOKEN;
|
||||
const tgApi = new TelegramAPI(TgBotToken);
|
||||
const TgProxyUrl = imgRecord.metadata?.TgProxyUrl || '';
|
||||
const tgApi = new TelegramAPI(TgBotToken, TgProxyUrl);
|
||||
const filePath = await tgApi.getFilePath(TgFileID);
|
||||
if (filePath === null) {
|
||||
return new Response('Error: Failed to fetch image path', { status: 500 });
|
||||
}
|
||||
targetUrl = `https://api.telegram.org/file/bot${TgBotToken}/${filePath}`;
|
||||
// 使用代理域名或官方域名
|
||||
const fileDomain = TgProxyUrl ? `https://${TgProxyUrl}` : 'https://api.telegram.org';
|
||||
targetUrl = `${fileDomain}/file/bot${TgBotToken}/${filePath}`;
|
||||
} else {
|
||||
targetUrl = 'https://telegra.ph/' + url.pathname + url.search;
|
||||
}
|
||||
@@ -162,6 +165,7 @@ async function handleTelegramChunkedFile(context, imgRecord, encodedFileName, fi
|
||||
|
||||
const metadata = imgRecord.metadata;
|
||||
const TgBotToken = metadata.TgBotToken || env.TG_BOT_TOKEN;
|
||||
const TgProxyUrl = metadata.TgProxyUrl || '';
|
||||
|
||||
// 从KV的value中读取分片信息
|
||||
let chunks = [];
|
||||
@@ -258,8 +262,8 @@ async function handleTelegramChunkedFile(context, imgRecord, encodedFileName, fi
|
||||
break;
|
||||
}
|
||||
|
||||
// 获取分片数据
|
||||
const chunkData = await fetchTelegramChunkWithRetry(TgBotToken, chunk, 3);
|
||||
// 获取分片数据(支持代理域名)
|
||||
const chunkData = await fetchTelegramChunkWithRetry(TgBotToken, chunk, TgProxyUrl, 3);
|
||||
if (!chunkData) {
|
||||
throw new Error(`Failed to fetch chunk ${chunk.index} after retries`);
|
||||
}
|
||||
@@ -308,11 +312,11 @@ async function handleTelegramChunkedFile(context, imgRecord, encodedFileName, fi
|
||||
}
|
||||
}
|
||||
|
||||
// 带重试机制的Telegram分片获取函数
|
||||
async function fetchTelegramChunkWithRetry(botToken, chunk, maxRetries = 3) {
|
||||
// 带重试机制的Telegram分片获取函数(支持代理域名)
|
||||
async function fetchTelegramChunkWithRetry(botToken, chunk, proxyUrl = '', maxRetries = 3) {
|
||||
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
||||
try {
|
||||
const tgApi = new TelegramAPI(botToken);
|
||||
const tgApi = new TelegramAPI(botToken, proxyUrl);
|
||||
|
||||
const response = await tgApi.getFileContent(chunk.fileId);
|
||||
|
||||
|
||||
@@ -432,6 +432,10 @@ async function mergeTelegramChunksInfo(context, uploadId, completedChunks, metad
|
||||
metadata.ChannelName = tgChannel.name;
|
||||
metadata.TgChatId = tgChatId;
|
||||
metadata.TgBotToken = tgBotToken;
|
||||
// 保存代理域名配置(如果有)
|
||||
if (tgChannel.proxyUrl) {
|
||||
metadata.TgProxyUrl = tgChannel.proxyUrl;
|
||||
}
|
||||
metadata.IsChunked = true;
|
||||
metadata.TotalChunks = completedChunks.length;
|
||||
metadata.FileSize = (totalSize / 1024 / 1024).toFixed(2);
|
||||
|
||||
@@ -553,15 +553,17 @@ async function uploadSingleChunkToTelegram(context, chunkData, chunkIndex, total
|
||||
|
||||
const tgBotToken = tgChannel.botToken;
|
||||
const tgChatId = tgChannel.chatId;
|
||||
const tgProxyUrl = tgChannel.proxyUrl || '';
|
||||
|
||||
// 创建分块文件名
|
||||
const chunkFileName = `${originalFileName}.part${chunkIndex.toString().padStart(3, '0')}`;
|
||||
const chunkBlob = new Blob([chunkData], { type: 'application/octet-stream' });
|
||||
|
||||
// 上传分块到Telegram
|
||||
// 上传分块到Telegram(支持代理域名)
|
||||
const chunkInfo = await uploadChunkToTelegramWithRetry(
|
||||
tgBotToken,
|
||||
tgChatId,
|
||||
tgProxyUrl,
|
||||
chunkBlob,
|
||||
chunkFileName,
|
||||
chunkIndex,
|
||||
@@ -1218,11 +1220,11 @@ export async function uploadLargeFileToTelegram(context, file, fullId, metadata,
|
||||
}
|
||||
}
|
||||
|
||||
// 将每个分块上传至Telegram,支持失败重试
|
||||
async function uploadChunkToTelegramWithRetry(tgBotToken, tgChatId, chunkBlob, chunkFileName, chunkIndex, totalChunks, maxRetries = 2) {
|
||||
// 将每个分块上传至Telegram,支持失败重试(支持代理域名)
|
||||
async function uploadChunkToTelegramWithRetry(tgBotToken, tgChatId, tgProxyUrl, chunkBlob, chunkFileName, chunkIndex, totalChunks, maxRetries = 2) {
|
||||
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
||||
try {
|
||||
const tgAPI = new TelegramAPI(tgBotToken);
|
||||
const tgAPI = new TelegramAPI(tgBotToken, tgProxyUrl);
|
||||
|
||||
const caption = `Part ${chunkIndex + 1}/${totalChunks}`;
|
||||
|
||||
|
||||
@@ -412,10 +412,11 @@ async function uploadFileToTelegram(context, fullId, metadata, fileExt, fileName
|
||||
|
||||
const tgBotToken = tgChannel.botToken;
|
||||
const tgChatId = tgChannel.chatId;
|
||||
const tgProxyUrl = tgChannel.proxyUrl || '';
|
||||
const file = formdata.get('file');
|
||||
const fileSize = file.size;
|
||||
|
||||
const telegramAPI = new TelegramAPI(tgBotToken);
|
||||
const telegramAPI = new TelegramAPI(tgBotToken, tgProxyUrl);
|
||||
|
||||
// 16MB 分片阈值 (TG Bot getFile download limit: 20MB, leave 4MB safety margin)
|
||||
const CHUNK_SIZE = 16 * 1024 * 1024; // 16MB
|
||||
@@ -484,8 +485,9 @@ async function uploadFileToTelegram(context, fullId, metadata, fileExt, fileName
|
||||
);
|
||||
|
||||
|
||||
// 图像审查
|
||||
const moderateUrl = `https://api.telegram.org/file/bot${tgBotToken}/${filePath}`;
|
||||
// 图像审查(使用代理域名或官方域名)
|
||||
const moderateDomain = tgProxyUrl ? `https://${tgProxyUrl}` : 'https://api.telegram.org';
|
||||
const moderateUrl = `${moderateDomain}/file/bot${tgBotToken}/${filePath}`;
|
||||
metadata.Label = await moderateContent(env, moderateUrl);
|
||||
|
||||
// 更新metadata,写入KV数据库
|
||||
@@ -496,6 +498,10 @@ async function uploadFileToTelegram(context, fullId, metadata, fileExt, fileName
|
||||
metadata.TgFileId = id;
|
||||
metadata.TgChatId = tgChatId;
|
||||
metadata.TgBotToken = tgBotToken;
|
||||
// 保存代理域名配置
|
||||
if (tgProxyUrl) {
|
||||
metadata.TgProxyUrl = tgProxyUrl;
|
||||
}
|
||||
await db.put(fullId, "", {
|
||||
metadata: metadata,
|
||||
});
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
* Telegram API 封装类
|
||||
*/
|
||||
export class TelegramAPI {
|
||||
constructor(botToken) {
|
||||
constructor(botToken, proxyUrl = '') {
|
||||
this.botToken = botToken;
|
||||
this.baseURL = `https://api.telegram.org/bot${this.botToken}`;
|
||||
this.proxyUrl = proxyUrl;
|
||||
// 如果设置了代理域名,使用代理域名,否则使用官方 API
|
||||
const apiDomain = proxyUrl ? `https://${proxyUrl}` : 'https://api.telegram.org';
|
||||
this.baseURL = `${apiDomain}/bot${this.botToken}`;
|
||||
this.fileDomain = proxyUrl ? `https://${proxyUrl}` : 'https://api.telegram.org';
|
||||
this.defaultHeaders = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0"
|
||||
};
|
||||
@@ -36,8 +40,8 @@ export class TelegramAPI {
|
||||
headers: this.defaultHeaders,
|
||||
body: formData
|
||||
});
|
||||
console.log('Telegram API response:', response.status, response.statusText);
|
||||
if (!response.ok) {
|
||||
console.log('Telegram API response:', response.status, response.statusText);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Telegram API error: ${response.statusText}`);
|
||||
}
|
||||
|
||||
@@ -54,10 +58,10 @@ export class TelegramAPI {
|
||||
*/
|
||||
getFileInfo(responseData) {
|
||||
const getFileDetails = (file) => ({
|
||||
file_id: file.file_id,
|
||||
file_name: file.file_name || file.file_unique_id,
|
||||
file_size: file.file_size,
|
||||
});
|
||||
file_id: file.file_id,
|
||||
file_name: file.file_name || file.file_unique_id,
|
||||
file_size: file.file_size,
|
||||
});
|
||||
|
||||
try {
|
||||
if (!responseData.ok) {
|
||||
@@ -127,7 +131,7 @@ export class TelegramAPI {
|
||||
throw new Error(`File path not found for fileId: ${fileId}`);
|
||||
}
|
||||
|
||||
const fullURL = `https://api.telegram.org/file/bot${this.botToken}/${filePath}`;
|
||||
const fullURL = `${this.fileDomain}/file/bot${this.botToken}/${filePath}`;
|
||||
const response = await fetch(fullURL, {
|
||||
headers: this.defaultHeaders
|
||||
});
|
||||
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/logo.png"><link rel="apple-touch-icon" href="/logo.png"><link rel="mask-icon" href="/logo.png" color="#f4b400"><meta name="description" content="Sanyue ImgHub - A modern file hosting platform"><meta name="keywords" content="Sanyue, ImgHub, file hosting, image hosting, cloud storage"><meta name="author" content="SanyueQi"><title>Sanyue ImgHub</title><script defer="defer" src="/js/chunk-vendors.780b6559.js"></script><script defer="defer" src="/js/app.41abafbc.js"></script><link href="/css/chunk-vendors.4363ed49.css" rel="stylesheet"><link href="/css/app.14879ca1.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but sanyue_imghub doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/logo.png"><link rel="apple-touch-icon" href="/logo.png"><link rel="mask-icon" href="/logo.png" color="#f4b400"><meta name="description" content="Sanyue ImgHub - A modern file hosting platform"><meta name="keywords" content="Sanyue, ImgHub, file hosting, image hosting, cloud storage"><meta name="author" content="SanyueQi"><title>Sanyue ImgHub</title><script defer="defer" src="/js/chunk-vendors.780b6559.js"></script><script defer="defer" src="/js/app.633fc8d5.js"></script><link href="/css/chunk-vendors.4363ed49.css" rel="stylesheet"><link href="/css/app.be4a11ae.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but sanyue_imghub doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
BIN
index.html.gz
BIN
index.html.gz
Binary file not shown.
2
js/163.477f8202.js
Normal file
2
js/163.477f8202.js
Normal file
File diff suppressed because one or more lines are too long
BIN
js/163.477f8202.js.gz
Normal file
BIN
js/163.477f8202.js.gz
Normal file
Binary file not shown.
1
js/163.477f8202.js.map
Normal file
1
js/163.477f8202.js.map
Normal file
File diff suppressed because one or more lines are too long
BIN
js/163.477f8202.js.map.gz
Normal file
BIN
js/163.477f8202.js.map.gz
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
2
js/171.ce5e9b2d.js
Normal file
2
js/171.ce5e9b2d.js
Normal file
File diff suppressed because one or more lines are too long
BIN
js/171.ce5e9b2d.js.gz
Normal file
BIN
js/171.ce5e9b2d.js.gz
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
js/171.ce5e9b2d.js.map.gz
Normal file
BIN
js/171.ce5e9b2d.js.map.gz
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
2
js/226.725c32ec.js
Normal file
2
js/226.725c32ec.js
Normal file
File diff suppressed because one or more lines are too long
BIN
js/226.725c32ec.js.gz
Normal file
BIN
js/226.725c32ec.js.gz
Normal file
Binary file not shown.
1
js/226.725c32ec.js.map
Normal file
1
js/226.725c32ec.js.map
Normal file
File diff suppressed because one or more lines are too long
BIN
js/226.725c32ec.js.map.gz
Normal file
BIN
js/226.725c32ec.js.map.gz
Normal file
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
2
js/417.1472ac96.js
Normal file
2
js/417.1472ac96.js
Normal file
File diff suppressed because one or more lines are too long
BIN
js/417.1472ac96.js.gz
Normal file
BIN
js/417.1472ac96.js.gz
Normal file
Binary file not shown.
1
js/417.1472ac96.js.map
Normal file
1
js/417.1472ac96.js.map
Normal file
File diff suppressed because one or more lines are too long
BIN
js/417.1472ac96.js.map.gz
Normal file
BIN
js/417.1472ac96.js.map.gz
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
2
js/845.e45a075a.js
Normal file
2
js/845.e45a075a.js
Normal file
File diff suppressed because one or more lines are too long
BIN
js/845.e45a075a.js.gz
Normal file
BIN
js/845.e45a075a.js.gz
Normal file
Binary file not shown.
1
js/845.e45a075a.js.map
Normal file
1
js/845.e45a075a.js.map
Normal file
File diff suppressed because one or more lines are too long
BIN
js/845.e45a075a.js.map.gz
Normal file
BIN
js/845.e45a075a.js.map.gz
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
js/855.8e40903c.js.gz
Normal file
BIN
js/855.8e40903c.js.gz
Normal file
Binary file not shown.
1
js/855.8e40903c.js.map
Normal file
1
js/855.8e40903c.js.map
Normal file
File diff suppressed because one or more lines are too long
BIN
js/855.8e40903c.js.map.gz
Normal file
BIN
js/855.8e40903c.js.map.gz
Normal file
Binary file not shown.
2
js/917.49df25ec.js
Normal file
2
js/917.49df25ec.js
Normal file
File diff suppressed because one or more lines are too long
BIN
js/917.49df25ec.js.gz
Normal file
BIN
js/917.49df25ec.js.gz
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
js/917.49df25ec.js.map.gz
Normal file
BIN
js/917.49df25ec.js.map.gz
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
js/app.633fc8d5.js.map.gz
Normal file
BIN
js/app.633fc8d5.js.map.gz
Normal file
Binary file not shown.
Reference in New Issue
Block a user