109 lines
3.0 KiB
TypeScript
Executable File
109 lines
3.0 KiB
TypeScript
Executable File
// @ts-nocheck
|
|
// 阿里云盘驱动 — 分享链接验证
|
|
// 依赖 aliyun-api.ts 统一端点模块 — URL 不再硬编码
|
|
import { ALIYUN_API_HOST, ALIYUN_WEB_HOST, EP as AE, getShareHeaders } from './aliyun-api';
|
|
|
|
export interface AliyunConfig {
|
|
cookie?: string;
|
|
nickname?: string;
|
|
}
|
|
|
|
export class AliyunDriver {
|
|
private config: AliyunConfig;
|
|
|
|
constructor(config: AliyunConfig = {}) {
|
|
this.config = config;
|
|
}
|
|
|
|
/**
|
|
* Extract share_id from an Aliyun share URL.
|
|
* Supports:
|
|
* https://www.aliyundrive.com/s/XXXYYY
|
|
* https://www.alipan.com/s/XXXYYY
|
|
* https://api.aliyundrive.com/v2/share_link/XXXYYY
|
|
*/
|
|
private extractShareId(shareUrl: string): string | null {
|
|
try {
|
|
const url = new URL(shareUrl);
|
|
const pathMatch = url.pathname.match(/\/s\/([a-zA-Z0-9]+)/);
|
|
if (pathMatch) return pathMatch[1];
|
|
|
|
const shareMatch = url.pathname.match(/\/share_link\/([a-zA-Z0-9]+)/);
|
|
if (shareMatch) return shareMatch[1];
|
|
|
|
return null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate a share link using Aliyun's public anonymous API.
|
|
* No cookie or token required — this endpoint is open.
|
|
*/
|
|
async validateShareLink(shareUrl: string): Promise<{
|
|
valid: boolean;
|
|
message: string;
|
|
fileCount?: number;
|
|
shareName?: string;
|
|
}> {
|
|
const shareId = this.extractShareId(shareUrl);
|
|
if (!shareId) {
|
|
return { valid: false, message: '无法解析阿里云盘链接格式' };
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(
|
|
ALIYUN_API_HOST + AE.SHARE_GET_BY_ANONYMOUS,
|
|
{
|
|
method: 'POST',
|
|
headers: getShareHeaders(),
|
|
body: JSON.stringify({
|
|
share_id: shareId,
|
|
share_pwd: '',
|
|
}),
|
|
signal: AbortSignal.timeout(10000),
|
|
}
|
|
);
|
|
|
|
if (!response.ok) {
|
|
return { valid: false, message: 'HTTP ' + response.status + ': API 请求失败' };
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.code) {
|
|
const errorMessages: Record<string, string> = {
|
|
'ShareLinkExpired': '分享链接已过期',
|
|
'ShareLinkCancelled': '分享链接已取消',
|
|
'ShareLinkNotFound': '分享链接不存在',
|
|
'ForbiddenFileInTheDrive': '文件已被禁止访问',
|
|
'UserNotAuthenticated': '需要登录才能访问',
|
|
'InvalidResource.NotFound': '资源不存在',
|
|
};
|
|
return {
|
|
valid: false,
|
|
message: errorMessages[data.code] || data.message || 'API 返回错误: ' + data.code,
|
|
};
|
|
}
|
|
|
|
// 成功:提取分享信息
|
|
const fileCount = data.file_infos?.length || 0;
|
|
const shareName = data.share_name || data.display_name || '';
|
|
|
|
return {
|
|
valid: true,
|
|
message: '链接有效',
|
|
fileCount,
|
|
shareName,
|
|
};
|
|
} catch (err) {
|
|
return { valid: false, message: '网络错误: ' + (err instanceof Error ? err.message : String(err)) };
|
|
}
|
|
}
|
|
|
|
async getNickname(): Promise<string | null> {
|
|
return this.config.nickname || null;
|
|
}
|
|
}
|