feat: 新增角色下载脚本,取代此前浏览器手动下载逻辑
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
/** 清洗 Fandom CDN 缩略图链接,去掉 scale-to-width-down 参数还原原图地址 */
|
||||
function cleanImageUrl(url) {
|
||||
return url.replace(/(\/scale-to-width-down\/\d+\?.*)$/, '');
|
||||
}
|
||||
|
||||
/** 从图片 URL 提取文件名并规范化(小写、下划线转短横线) */
|
||||
function generateImageName(url) {
|
||||
const fileNameMatch = url.match(/\/([^/]+)\.png/i);
|
||||
if (fileNameMatch && fileNameMatch[1]) {
|
||||
return fileNameMatch[1].toLowerCase().replace(/_/g, '-');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 对 Wiki 原始文件名应用站点自定义转换,得到最终保存用的基础名 */
|
||||
function toOutputBaseName(rawName, nameTransform) {
|
||||
const transformed = nameTransform ? nameTransform(rawName) : rawName;
|
||||
return transformed;
|
||||
}
|
||||
|
||||
/** 根据 Fandom 站点根地址和页面标题拼接 parse API 请求 URL */
|
||||
function buildParseApiUrl(baseUrl, wikiTitle) {
|
||||
const apiBase = baseUrl.replace(/\/$/, '');
|
||||
const params = new URLSearchParams({
|
||||
action: 'parse',
|
||||
page: wikiTitle,
|
||||
prop: 'text',
|
||||
format: 'json',
|
||||
});
|
||||
return `${apiBase}/api.php?${params.toString()}`;
|
||||
}
|
||||
|
||||
/** 判断图片 URL 是否为懒加载占位图 */
|
||||
function isPlaceholderImageUrl(url) {
|
||||
return !url || url.startsWith('data:image/gif');
|
||||
}
|
||||
|
||||
/** 从 img 元素读取图片地址,src 为占位图时自动回退到 data-src */
|
||||
function resolveImageUrl($img, imageUrlAttr = 'src') {
|
||||
const primary = $img.attr(imageUrlAttr);
|
||||
if (!isPlaceholderImageUrl(primary)) {
|
||||
return primary;
|
||||
}
|
||||
|
||||
if (imageUrlAttr === 'src') {
|
||||
const fallback = $img.attr('data-src');
|
||||
if (!isPlaceholderImageUrl(fallback)) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 延迟指定毫秒,用于控制下载请求间隔 */
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/** 从图片路径提取不含扩展名的文件名,兼容绝对 URL 与相对路径 */
|
||||
function getFileBaseNameFromUrl(url) {
|
||||
const normalized = url.split('?')[0].split('#')[0];
|
||||
const fileName = path.basename(normalized);
|
||||
return path.basename(fileName, path.extname(fileName));
|
||||
}
|
||||
|
||||
/** 读取本地保存目录中所有 .webp 角色的基础文件名列表 */
|
||||
function listLocalCharacters(savePath) {
|
||||
if (!fs.existsSync(savePath)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return fs
|
||||
.readdirSync(savePath)
|
||||
.filter((file) => file.endsWith('.webp'))
|
||||
.map((file) => path.basename(file, '.webp'))
|
||||
.sort();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
cleanImageUrl,
|
||||
generateImageName,
|
||||
toOutputBaseName,
|
||||
buildParseApiUrl,
|
||||
isPlaceholderImageUrl,
|
||||
resolveImageUrl,
|
||||
getFileBaseNameFromUrl,
|
||||
listLocalCharacters,
|
||||
sleep,
|
||||
};
|
||||
Reference in New Issue
Block a user