2026-07-08 07:05:48 +08:00
|
|
|
|
"use server";
|
|
|
|
|
|
|
|
|
|
|
|
import type { Config, Version, CurseForgeFile } from "@/types";
|
|
|
|
|
|
import { modrinthClient, curseforgeClient } from "./clients";
|
|
|
|
|
|
import { listVersions } from "@/lib/modrinth";
|
|
|
|
|
|
import { getFiles } from "@/lib/curseforge";
|
|
|
|
|
|
import { Template } from "@/lib/utils/template";
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取 Modrinth 项目的全部已有版本(不含 changelog 以减小响应体)。
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function fetchModrinthVersions(
|
|
|
|
|
|
config: Config,
|
|
|
|
|
|
): Promise<Version[]> {
|
|
|
|
|
|
return listVersions(modrinthClient, config.modrinth.project_id, {
|
|
|
|
|
|
include_changelog: false,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取 CurseForge 项目的全部已有文件(自动遍历所有分页)。
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function fetchCurseForgeVersions(
|
|
|
|
|
|
config: Config,
|
|
|
|
|
|
): Promise<CurseForgeFile[]> {
|
|
|
|
|
|
const pageSize = 50;
|
|
|
|
|
|
let index = 0;
|
|
|
|
|
|
const allFiles: CurseForgeFile[] = [];
|
|
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
|
const response = await getFiles(curseforgeClient, {
|
|
|
|
|
|
modId: config.curseforge.project_id,
|
|
|
|
|
|
index,
|
|
|
|
|
|
pageSize,
|
|
|
|
|
|
});
|
|
|
|
|
|
allFiles.push(...response.data);
|
|
|
|
|
|
|
|
|
|
|
|
if (allFiles.length >= response.pagination.totalCount) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
index += pageSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return allFiles;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 单个 MC 版本的比较结果 */
|
|
|
|
|
|
export interface VersionMatch {
|
|
|
|
|
|
exists: boolean;
|
|
|
|
|
|
existingVersion?: Version;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 单个 MC 版本的文件比较结果 */
|
|
|
|
|
|
export interface FileMatch {
|
|
|
|
|
|
exists: boolean;
|
|
|
|
|
|
existingFile?: CurseForgeFile;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 版本确认的完整比较结果 */
|
|
|
|
|
|
export interface VersionComparison {
|
|
|
|
|
|
modrinth: Record<string, VersionMatch>;
|
|
|
|
|
|
curseforge: Record<string, FileMatch>;
|
2026-07-18 10:04:16 +08:00
|
|
|
|
/** Modrinth 全量已有版本(含未匹配项),用于第一页展示 */
|
|
|
|
|
|
modrinthVersions: Version[];
|
|
|
|
|
|
/** CurseForge 全量已有文件(含未匹配项),用于第一页展示 */
|
|
|
|
|
|
curseforgeFiles: CurseForgeFile[];
|
2026-07-08 07:05:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 将待发布版本与两个平台的已有版本进行比对。
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param config 项目配置
|
|
|
|
|
|
* @param version 项目版本号(如 "1.0.0")
|
|
|
|
|
|
* @param mc_versions 待发布的 MC 版本列表
|
2026-07-18 10:04:16 +08:00
|
|
|
|
* @returns 按 MC 版本分组的比对结果 + 两平台全量已有版本列表
|
2026-07-08 07:05:48 +08:00
|
|
|
|
*/
|
|
|
|
|
|
export async function compareVersions(
|
|
|
|
|
|
config: Config,
|
|
|
|
|
|
version: string,
|
|
|
|
|
|
mc_versions: string[],
|
|
|
|
|
|
): Promise<VersionComparison> {
|
|
|
|
|
|
// 并行获取两个平台的已有版本
|
|
|
|
|
|
const [modrinthVersions, curseforgeFiles] = await Promise.all([
|
|
|
|
|
|
fetchModrinthVersions(config),
|
|
|
|
|
|
fetchCurseForgeVersions(config),
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
// ── Modrinth:按 version 模板生成 version_number 后匹配 ──
|
|
|
|
|
|
const modrinth: Record<string, VersionMatch> = {};
|
|
|
|
|
|
const modrinthTmpl = new Template(config.modrinth.version);
|
|
|
|
|
|
|
|
|
|
|
|
for (const mc_version of mc_versions) {
|
|
|
|
|
|
const generatedVersion = modrinthTmpl.format({ version, mc_version });
|
|
|
|
|
|
const existing = modrinthVersions.find(
|
|
|
|
|
|
(v) => v.version_number === generatedVersion,
|
|
|
|
|
|
);
|
|
|
|
|
|
modrinth[mc_version] = existing
|
|
|
|
|
|
? { exists: true, existingVersion: existing }
|
|
|
|
|
|
: { exists: false };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ── CurseForge:按 filename_format 模板生成文件名后匹配 ──
|
|
|
|
|
|
const curseforge: Record<string, FileMatch> = {};
|
|
|
|
|
|
const curseforgeTmpl = new Template(config.filename_format);
|
|
|
|
|
|
|
|
|
|
|
|
for (const mc_version of mc_versions) {
|
|
|
|
|
|
const generatedFilename = curseforgeTmpl.format({ version, mc_version });
|
|
|
|
|
|
const existing = curseforgeFiles.find(
|
|
|
|
|
|
(f) => f.fileName === generatedFilename,
|
|
|
|
|
|
);
|
|
|
|
|
|
curseforge[mc_version] = existing
|
|
|
|
|
|
? { exists: true, existingFile: existing }
|
|
|
|
|
|
: { exists: false };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-18 10:04:16 +08:00
|
|
|
|
return { modrinth, curseforge, modrinthVersions, curseforgeFiles };
|
2026-07-08 07:05:48 +08:00
|
|
|
|
}
|