📋 准备工作
1.Telegram Bot Token:
在 Telegram 中搜索 @BotFather
。
发送 /newbot
命令,并按照提示为您的机器人命名和设置用户名。
BotFather 将为您提供一个 HTTP API Token
。请务必保存好这个 Token,这是机器人与 Telegram API 通信的凭证。
就是这个东西
2.Cloudflare 账号
如果您还没有,请前往 Cloudflare 官网 注册一个免费账号。
🛠️ 部署步骤
步骤 1: 创建 Cloudflare Worker
-
登录您的 Cloudflare Dashboard。
-
在左侧导航栏中,点击计算(Workers)-> 点击 Workers 和 Pages。
-
点击右侧的 创建按钮。
-
在弹出的页面中,点击 从 Hello World! 开始 -> 开始使用。
-
为您的 Worker 命名(例如:
tg-image-uploader
),然后点击 部署。
步骤 2: 粘贴机器人代码
-
部署成功后,点击您刚刚创建的 Worker 名称(例如:tg-image-uploader)。
-
进入 Worker 页面后,点击右上角 编辑代码 按钮。
-
您会看到一个默认的 Worker 代码。请删除所有默认代码,然后将本文档中提供的 最新 JavaScript 代码粘贴到编辑器中。
-
点击右上角的 部署 按钮。
步骤 3: 配置环境变量
环境变量是存储敏感信息(如 API Token)和配置(如允许的用户列表)的最佳方式,而无需将它们直接硬编码到代码中。
-
在您的 Worker 页面中,点击顶部的 设置 选项卡。
-
向下滚动找到 变量和机密 部分。
-
点击 添加 按钮,并添加以下变量:
-
变量名: TELEGRAM_BOT_TOKEN
-
值: 粘贴您从 BotFather 获得的 Telegram Bot Token。
-
-
变量名: IMAGE_HOST_BASE_URL
- 值: 填写 https://i.111666.best
-
变量名: IMAGE_HOST_AUTH_TOKEN
- 值: 粘贴您为16图床生成的随机字符串。从官网获取
- 值: 粘贴您为16图床生成的随机字符串。从官网获取
-
变量名: ALLOWED_USERS (可选)
- 值: 如果您想限制只有特定用户才能使用机器人,请在此处填写允许的 Telegram 用户 ID 列表,用逗号 , 分隔(例如:12345,67890,98765)。
可以再这里获取
- 值: 如果您想限制只有特定用户才能使用机器人,请在此处填写允许的 Telegram 用户 ID 列表,用逗号 , 分隔(例如:12345,67890,98765)。
如果您想让所有用户都能使用机器人,请将此字段留空。
步骤 4: 设置 Telegram Webhook
现在,您需要告诉 Telegram,当有新消息时,它应该将更新发送到您的 Cloudflare Worker。
-
获取您的 Worker 的 URL。在 Worker 页面的 设置 选项卡中,您会看到一个 URL,通常是 https://your-worker-name.your-account-id.workers.dev。复制这个 URL。在这里
-
在浏览器中打开以下 URL,将 <YOUR_BOT_TOKEN> 替换为您的 Telegram Bot Token,将 <YOUR_WORKER_URL> 替换为您刚刚复制的 Worker URL:
https://api.telegram.org/bot<YOUR_BOT_TOKEN>/setWebhook?url=<YOUR_WORKER_URL>
示例:如果您的 Bot Token 是 123456:ABC-DEF1234ghIkl-zyx57W2E1u12u1
,Worker URL 是 https://tg-image-uploader.your-account-id.workers.dev
,那么您应该访问:
https://api.telegram.org/bot123456:ABC-DEF1234ghIkl-zyx57W2E1u12u1/setWebhook?url=https://tg-image-uploader.your-account-id.workers.dev
如果成功,您将在浏览器中看到类似 {"ok":true,"result":true,"description":"Webhook was set"}
的响应。
✅ 测试您的机器人
现在,您的机器人已经部署并配置完毕!
-
在 Telegram 中找到您的机器人。
-
发送
/start
命令,机器人应该会回复欢迎消息。 -
尝试向机器人发送一张图片。
-
如果一切正常,机器人应该会回复一个包含多个链接选项的消息。点击这些按钮,检查链接是否正确。
🖼️效果图
主页面 | 直链 | Markdown |
---|---|---|
![]() |
![]() |
![]() |
其他以此类推,点击链接自动复制
如果对你有帮助,可以去我的Github给我点个⭐嘛 链接直达
export default {
async fetch(request, env, ctx) {
if (request.method !== 'POST') {
return new Response('Expected POST request', { status: 405 });
}
try {
const update = await request.json();
const TELEGRAM_BOT_TOKEN = env.TELEGRAM_BOT_TOKEN;
const IMAGE_HOST_BASE_URL = (env.IMAGE_HOST_BASE_URL || 'https://i.111666.best').replace(/\/+$/, '');
const IMAGE_HOST_AUTH_TOKEN = env.IMAGE_HOST_AUTH_TOKEN;
const ALLOWED_USERS = env.ALLOWED_USERS ? env.ALLOWED_USERS.split(',').map(id => id.trim()) : [];
if (!TELEGRAM_BOT_TOKEN || !IMAGE_HOST_AUTH_TOKEN) {
console.error("Error: Missing required environment variables (TELEGRAM_BOT_TOKEN or IMAGE_HOST_AUTH_TOKEN).");
return new Response("Bot configuration error.", { status: 500 });
}
const sendTelegramApiRequest = async (method, payload) => {
const url = `https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/${method}`;
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
if (!response.ok) {
const errorText = await response.text();
console.error(`Telegram API error (${method}): ${response.status} - ${errorText}`);
throw new Error(`Telegram API error: ${errorText}`);
}
return response.json();
};
const isUserAllowed = (userId) => {
return ALLOWED_USERS.length === 0 || ALLOWED_USERS.includes(String(userId));
};
if (update.message) {
const message = update.message;
const chatId = message.chat.id;
const userId = message.from.id;
const firstName = message.from.first_name || "用户";
console.log(`Received message from user ${userId} (${firstName}) in chat ${chatId}`);
if (!isUserAllowed(userId)) {
console.log(`User ${userId} is not allowed.`);
await sendTelegramApiRequest('sendMessage', {
chat_id: chatId,
text: "您没有权限使用此机器人。",
});
return new Response('Unauthorized user', { status: 200 });
}
await sendTelegramApiRequest('sendChatAction', {
chat_id: chatId,
action: 'upload_photo',
});
let fileId = null;
let mimeType = null;
let fileName = null;
if (message.photo && message.photo.length > 0) {
fileId = message.photo[message.photo.length - 1].file_id;
mimeType = 'image/jpeg';
fileName = `${fileId}.jpg`;
console.log(`Detected photo with file_id: ${fileId}`);
} else if (message.document && message.document.mime_type && message.document.mime_type.startsWith('image/')) {
fileId = message.document.file_id;
mimeType = message.document.mime_type;
fileName = message.document.file_name;
console.log(`Detected image document with file_id: ${fileId}, mime_type: ${mimeType}`);
} else if (message.text === '/start') {
await sendTelegramApiRequest('sendMessage', {
chat_id: chatId,
text: `您好,我是一个16图床机器人,${firstName}!请直接发送图片以获取上传链接。`,
});
return new Response('Start command handled', { status: 200 });
} else {
console.log("Received unsupported message type.");
await sendTelegramApiRequest('sendMessage', {
chat_id: chatId,
text: "不支持的文件类型,请发送图片。",
});
return new Response('Unsupported file type', { status: 200 });
}
if (!fileId) {
console.error("No file_id found in message.");
await sendTelegramApiRequest('sendMessage', {
chat_id: chatId,
text: "无法获取文件ID,请重试或联系管理员。",
});
return new Response('File ID not found', { status: 200 });
}
try {
console.log(`Fetching file info for file_id: ${fileId}`);
const fileInfoResponse = await sendTelegramApiRequest('getFile', { file_id: fileId });
const filePath = fileInfoResponse.result.file_path;
const downloadUrl = `https://api.telegram.org/file/bot${TELEGRAM_BOT_TOKEN}/${filePath}`;
console.log(`File download URL: ${downloadUrl}`);
const imageResponse = await fetch(downloadUrl);
if (!imageResponse.ok) {
const errorText = await imageResponse.text();
throw new Error(`Failed to download image from Telegram: ${imageResponse.status} - ${errorText}`);
}
const imageBlob = await imageResponse.blob();
console.log(`Image downloaded from Telegram. Size: ${imageBlob.size} bytes`);
const uploadApiUrl = `${IMAGE_HOST_BASE_URL}/image`;
console.log(`Uploading image to 16图床: ${uploadApiUrl}`);
const formData = new FormData();
formData.append('image', imageBlob, fileName);
const uploadHeaders = {
'Auth-Token': IMAGE_HOST_AUTH_TOKEN,
};
const imageHostResponse = await fetch(uploadApiUrl, {
method: 'POST',
headers: uploadHeaders,
body: formData,
});
const imageHostResponseClone = imageHostResponse.clone();
let imageHostResult;
try {
imageHostResult = await imageHostResponseClone.json();
} catch (jsonError) {
const rawResponseText = await imageHostResponse.text();
console.error('16图床 API response was not JSON. Raw response:', rawResponseText);
throw new Error(`16图床 API 返回非 JSON 响应。原始内容: ${rawResponseText.substring(0, 200)}... (查看 Worker 日志获取完整内容)`);
}
console.log('16图床 API response status:', imageHostResponse.status);
console.log('16图床 API response content:', JSON.stringify(imageHostResult));
if (imageHostResponse.ok && imageHostResult.ok === true && imageHostResult.src) {
const uploadedUrl = `${IMAGE_HOST_BASE_URL}${imageHostResult.src}`;
console.log(`16图床 upload successful: ${uploadedUrl}`);
const encodedRelativePath = encodeURIComponent(imageHostResult.src);
console.log(`DEBUG (Upload): Encoded relative path for callback_data: ${encodedRelativePath}`);
const messageText = `🎉 图片上传成功!\n\n💡 点击下方按钮可直接复制对应内容`;
const keyboard = [
[{ text: "复制直链", callback_data: `copy:direct:${encodedRelativePath}` }],
[{ text: "复制HTML", callback_data: `copy:html:${encodedRelativePath}` }],
[{ text: "复制BBCode", callback_data: `copy:bbcode:${encodedRelativePath}` }],
[{ text: "复制Markdown", callback_data: `copy:markdown:${encodedRelativePath}` }],
];
const replyMarkup = { inline_keyboard: keyboard };
await sendTelegramApiRequest('sendMessage', {
chat_id: chatId,
text: messageText,
parse_mode: 'Markdown',
reply_markup: replyMarkup,
});
} else {
const errorMsg = imageHostResult.message || JSON.stringify(imageHostResult);
throw new Error(`16图床上传失败,状态码:${imageHostResponse.status},响应:${errorMsg}`);
}
} catch (e) {
console.error(`Error during image upload process: ${e.message}`);
await sendTelegramApiRequest('sendMessage', {
chat_id: chatId,
text: `上传图片时出错: ${e.message}`,
});
}
return new Response('Message processed', { status: 200 });
}
if (update.callback_query) {
const query = update.callback_query;
const chatId = query.message.chat.id;
const messageId = query.message.message_id;
const data = query.data;
console.log(`Received callback query: ${data}`);
await sendTelegramApiRequest('answerCallbackQuery', {
callback_query_id: query.id,
});
const parts = data.split(':');
const action = parts[0];
let format = null;
let encodedRelativePath = null;
if (action === 'copy') {
format = parts[1];
encodedRelativePath = parts.slice(2).join(':');
} else if (action === 'return') {
encodedRelativePath = parts[1];
}
console.log(`DEBUG (Callback): Action: ${action}, Format: ${format}, Raw encodedRelativePath from data: ${encodedRelativePath}`);
const relativePath = decodeURIComponent(encodedRelativePath);
console.log(`DEBUG (Callback): Decoded relative path: ${relativePath}`);
const IMAGE_HOST_BASE_URL = (env.IMAGE_HOST_BASE_URL || 'https://i.111666.best').replace(/\/+$/, '');
console.log(`DEBUG (Callback): IMAGE_HOST_BASE_URL: ${IMAGE_HOST_BASE_URL}`);
const fullUrl = new URL(relativePath, IMAGE_HOST_BASE_URL).toString();
console.log(`DEBUG (Callback): Constructed fullUrl: ${fullUrl}`);
let content = '';
let messageText = '';
let keyboard = [];
if (action === 'copy') {
switch (format) {
case 'direct':
content = fullUrl;
console.log(`DEBUG (Callback): Direct link content: ${content}`);
break;
case 'html':
content = `<img src="${fullUrl}" alt="image">`;
console.log(`DEBUG (Callback): HTML content: ${content}`);
break;
case 'bbcode':
content = `[img]${fullUrl}[/img]`;
console.log(`DEBUG (Callback): BBCode content: ${content}`);
break;
case 'markdown':
content = ``;
console.log(`DEBUG (Callback): Markdown content: ${content}`);
break;
default:
content = '未找到内容';
}
messageText = `已为您准备好内容,请手动复制:\n\`${content}\``;
keyboard = [[{ text: "返回", callback_data: `return:${encodedRelativePath}` }]];
} else if (action === 'return') {
console.log(`DEBUG (Return Action): Rebuilding keyboard with encodedRelativePath: ${encodedRelativePath}`);
messageText = `🎉 图片上传成功!\n\n💡 点击下方按钮可直接复制对应内容`;
keyboard = [
[{ text: "复制直链", callback_data: `copy:direct:${encodedRelativePath}` }],
[{ text: "复制HTML", callback_data: `copy:html:${encodedRelativePath}` }],
[{ text: "复制BBCode", callback_data: `copy:bbcode:${encodedRelativePath}` }],
[{ text: "复制Markdown", callback_data: `copy:markdown:${encodedRelativePath}` }],
];
} else {
messageText = "未知操作";
keyboard = [[{ text: "返回", callback_data: `return:${encodedRelativePath}` }]];
}
await sendTelegramApiRequest('editMessageText', {
chat_id: chatId,
message_id: messageId,
text: messageText,
parse_mode: 'Markdown',
reply_markup: { inline_keyboard: keyboard },
});
return new Response('Callback query processed', { status: 200 });
}
return new Response('OK', { status: 200 });
} catch (error) {
console.error('Unhandled error:', error);
return new Response(`Error: ${error.message}`, { status: 500 });
}
},
};