Merge pull request #167 from fantasy-ke/main

添加文件夹的路径上传
This commit is contained in:
叁月柒
2025-03-05 17:58:07 +08:00
committed by GitHub
5 changed files with 62 additions and 94 deletions
@@ -13,17 +13,20 @@ export async function onRequest(context) {
// 组装 CDN URL
const url = new URL(request.url);
const cdnUrl = `https://${url.hostname}/file/${params.id}`;
// 解码params.id
params.id = decodeURIComponent(params.id);
if (params.path) {
params.path = String(params.path).split(',').join('/');
}
const cdnUrl = `https://${url.hostname}/file/${params.path}`;
// 解码params.path
params.path = decodeURIComponent(params.path);
//read the metadata
const value = await env.img_url.getWithMetadata(params.id);
const value = await env.img_url.getWithMetadata(params.path);
//change the metadata
value.metadata.ListType = "Block"
await env.img_url.put(params.id,"",{metadata: value.metadata});
await env.img_url.put(params.path,"",{metadata: value.metadata});
const info = JSON.stringify(value.metadata);
// 清除CDN缓存
@@ -13,18 +13,18 @@ export async function onRequest(context) {
} = context;
// 组装 CDN URL
const url = new URL(request.url);
const cdnUrl = `https://${url.hostname}/file/${params.id}`;
const cdnUrl = `https://${url.hostname}/file/${params.path}`;
// 解码params.id
params.id = decodeURIComponent(params.id);
// 解码params.path
params.path = decodeURIComponent(params.path);
try {
// 读取图片信息
const img = await env.img_url.getWithMetadata(params.id);
const img = await env.img_url.getWithMetadata(params.path);
// 如果是R2渠道的图片,删除R2中对应的图片
if (img.metadata?.Channel === 'CloudflareR2') {
await env.img_r2.delete(params.id);
await env.img_r2.delete(params.path);
}
// S3 渠道的图片,删除S3中对应的图片
@@ -55,8 +55,8 @@ export async function onRequest(context) {
}
// 删除KV中的图片信息
await env.img_url.delete(params.id);
const info = JSON.stringify(params.id);
await env.img_url.delete(params.path);
const info = JSON.stringify(params.path);
// 清除CDN缓存
await purgeCFCache(env, cdnUrl);
@@ -12,17 +12,20 @@ export async function onRequest(context) {
} = context;
// 组装 CDN URL
const url = new URL(request.url);
const cdnUrl = `https://${url.hostname}/file/${params.id}`;
// 解码params.id
params.id = decodeURIComponent(params.id);
if (params.path) {
params.path = String(params.path).split(',').join('/');
}
const cdnUrl = `https://${url.hostname}/file/${params.path}`;
// 解码params.path
params.path = decodeURIComponent(params.path);
//read the metadata
const value = await env.img_url.getWithMetadata(params.id);
const value = await env.img_url.getWithMetadata(params.path);
//change the metadata
value.metadata.ListType = "White"
await env.img_url.put(params.id,"",{metadata: value.metadata});
await env.img_url.put(params.path,"",{metadata: value.metadata});
const info = JSON.stringify(value.metadata);
// 清除CDN缓存
@@ -15,10 +15,13 @@ export async function onRequest(context) { // Contents of context object
next, // used for middleware or to fetch assets
data, // arbitrary space for passing data between middlewares
} = context;
let fileId;
try {
// 解码params.id
params.id = decodeURIComponent(params.id);
// 解码params.path
params.path = decodeURIComponent(params.path);
// 从path中提取文件ID
fileId = params.path.split(',').join('/');
} catch (e) {
return new Response('Error: Decode Image ID Failed', { status: 400 });
}
@@ -29,13 +32,13 @@ export async function onRequest(context) { // Contents of context object
whiteListMode = securityConfig.access.whiteListMode;
const url = new URL(request.url);
let Referer = request.headers.get('Referer');
let Referer = request.headers.get('Referer')
if (Referer) {
try {
let refererUrl = new URL(Referer);
if (allowedDomains && allowedDomains.trim() !== '') {
let allowedDomainsList = allowedDomains.split(',');
let isAllowed = allowedDomainsList.some(domain => {
const domains = allowedDomains.split(',');
let isAllowed = domains.some(domain => {
let domainPattern = new RegExp(`(^|\\.)${domain.replace('.', '\\.')}$`); // Escape dot in domain
return domainPattern.test(refererUrl.hostname);
});
@@ -51,10 +54,16 @@ export async function onRequest(context) { // Contents of context object
if (typeof env.img_url == "undefined" || env.img_url == null || env.img_url == "") {
return new Response('Error: Please configure KV database', { status: 500 });
}
const imgRecord = await env.img_url.getWithMetadata(params.id);
// 如果meatdata不存在,只可能是之前未设置KV,且存储在Telegraph上的图片,那么在后面获取时会返回404错误,此处不用处理
const imgRecord = await env.img_url.getWithMetadata(fileId);
if (!imgRecord) {
return new Response('Error: Image Not Found', { status: 404 });
}
// 如果metadata不存在,只可能是之前未设置KV,且存储在Telegraph上的图片
if (!imgRecord.metadata) {
imgRecord.metadata = {};
}
const fileName = imgRecord.metadata?.FileName || params.id;
const fileName = imgRecord.metadata?.FileName || fileId;
const encodedFileName = encodeURIComponent(fileName);
const fileType = imgRecord.metadata?.FileType || null;
@@ -63,9 +72,7 @@ export async function onRequest(context) { // Contents of context object
if (accessRes.status !== 200) {
return accessRes; // 如果不可访问,直接返回
}
// Cloudflare R2渠道
if (imgRecord.metadata?.Channel === 'CloudflareR2') {
// 检查是否配置了R2
@@ -74,7 +81,7 @@ export async function onRequest(context) { // Contents of context object
}
const R2DataBase = env.img_r2;
const object = await R2DataBase.get(params.id);
const object = await R2DataBase.get(fileId);
if (object === null) {
return new Response('Error: Failed to fetch image', { status: 500 });
@@ -103,7 +110,6 @@ export async function onRequest(context) { // Contents of context object
return newRes;
}
// S3渠道
if (imgRecord.metadata?.Channel === "S3") {
const s3Client = new S3Client({
@@ -150,15 +156,6 @@ export async function onRequest(context) { // Contents of context object
return new Response(`Error: Failed to fetch from S3 - ${error.message}`, { status: 500 });
}
}
// 外链渠道
if (imgRecord.metadata?.Channel === 'External') {
// 直接重定向到外链
return Response.redirect(imgRecord.metadata?.ExternalLink, 302);
}
// Telegram及Telegraph渠道
let TgFileID = ''; // Tg的file_id
@@ -174,7 +171,6 @@ export async function onRequest(context) { // Contents of context object
} else {
// 旧版telegraph
}
// 构建目标 URL
if (isTgChannel(imgRecord)) {
// 获取TG图片真实地址
@@ -187,14 +183,12 @@ export async function onRequest(context) { // Contents of context object
} else {
targetUrl = 'https://telegra.ph/' + url.pathname + url.search;
}
const response = await getFileContent(request);
if (response === null) {
return new Response('Error: Failed to fetch image', { status: 500 });
} else if (response.status === 404) {
return await return404(url);
}
try {
const headers = new Headers(response.headers);
headers.set('Content-Disposition', `inline; filename="${encodedFileName}"; filename*=UTF-8''${encodedFileName}`);
@@ -208,13 +202,11 @@ export async function onRequest(context) { // Contents of context object
} else {
headers.set('Cache-Control', 'public, max-age=604800');
}
const newRes = new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers,
});
if (response.ok) {
return newRes;
}
+17 -47
View File
@@ -97,6 +97,15 @@ export async function onRequestPost(context) { // Contents of context object
// 获得上传渠道
const urlParamUploadChannel = url.searchParams.get('uploadChannel');
// 获取上传文件夹路径
const uploadFolder = url.searchParams.get('uploadFolder') || '';
// 处理文件夹路径格式,确保没有开头的/
const normalizedFolder = uploadFolder
? uploadFolder.replace(/^\/+/, '') // 移除开头的/
.replace(/\/{2,}/g, '/') // 替换多个连续的/为单个/
.replace(/\/$/, '') // 移除末尾的/
: '';
let uploadChannel = 'TelegramNew';
switch (urlParamUploadChannel) {
case 'telegram':
@@ -108,9 +117,6 @@ export async function onRequestPost(context) { // Contents of context object
case 's3':
uploadChannel = 'S3';
break;
case 'external':
uploadChannel = 'External';
break;
default:
uploadChannel = 'TelegramNew';
break;
@@ -141,6 +147,7 @@ export async function onRequestPost(context) { // Contents of context object
ListType: "None",
TimeStamp: time,
Label: "None",
Folder: normalizedFolder || 'root',
}
@@ -164,24 +171,21 @@ export async function onRequestPost(context) { // Contents of context object
const unique_index = time + Math.floor(Math.random() * 10000);
let fullId = '';
if (nameType === 'index') {
// 仅前缀
fullId = unique_index + '.' + fileExt;
// 只在 normalizedFolder 非空时添加路径
fullId = normalizedFolder ? `${normalizedFolder}/${unique_index}.${fileExt}` : `${unique_index}.${fileExt}`;
} else if (nameType === 'origin') {
// 仅文件名
fullId = fileName? fileName : unique_index + '.' + fileExt;
fullId = normalizedFolder ? `${normalizedFolder}/${fileName}` : fileName;
} else if (nameType === 'short') {
// 短链接,8位大小写字母+数字的随机字符
while (true) {
const shortId = generateShortId(8);
const testFullId = shortId + '.' + fileExt;
const testFullId = normalizedFolder ? `${normalizedFolder}/${shortId}.${fileExt}` : `${shortId}.${fileExt}`;
if (await env.img_url.get(testFullId) === null) {
fullId = shortId + '.' + fileExt;
fullId = testFullId;
break;
}
}
} else {
// 默认方式:前缀+文件名
fullId = fileName? unique_index + '_' + fileName : unique_index + '.' + fileExt;
fullId = normalizedFolder ? `${normalizedFolder}/${unique_index}_${fileName}` : `${unique_index}_${fileName}`;
}
// 获得返回链接格式, default为返回/file/id, full为返回完整链接
@@ -220,10 +224,6 @@ export async function onRequestPost(context) { // Contents of context object
} else {
err = await res.text();
}
} else if (uploadChannel === 'External') {
// -------------外链渠道---------------
const res = await uploadFileToExternal(env, formdata, fullId, metadata, returnLink, url);
return res;
} else {
// ----------------Telegram New 渠道-------------------
const res = await uploadFileToTelegram(env, formdata, fullId, metadata, fileExt, fileName, fileType, url, clonedRequest, returnLink);
@@ -530,36 +530,6 @@ async function uploadFileToTelegram(env, formdata, fullId, metadata, fileExt, fi
}
// 外链渠道
async function uploadFileToExternal(env, formdata, fullId, metadata, returnLink, originUrl) {
// 直接将外链写入metadata
metadata.Channel = "External";
metadata.ChannelName = "External";
// 从 formdata 中获取外链
const extUrl = formdata.get('url');
if (extUrl === null || extUrl === undefined) {
return new Response('Error: No url provided', { status: 400 });
}
metadata.ExternalLink = extUrl;
// 写入KV数据库
try {
await env.img_url.put(fullId, "", {
metadata: metadata,
});
} catch (error) {
return new Response('Error: Failed to write to KV database', { status: 500 });
}
// 返回结果
return new Response(
JSON.stringify([{ 'src': `${returnLink}` }]),
{
status: 200,
headers: { 'Content-Type': 'application/json' }
}
);
}
// 图像审查
async function moderateContent(env, url, metadata) {
const apikey = moderateContentApiKey;
@@ -705,4 +675,4 @@ function generateShortId(length = 8) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
}