first commit

This commit is contained in:
JohnsonRan
2025-08-12 21:50:58 +08:00
commit b4ed660eca
121 changed files with 36497 additions and 0 deletions

View File

@@ -0,0 +1,229 @@
#!/usr/bin / env node
/* eslint-disable */
const fs = require('fs');
const path = require('path');
function parseChangelog(content) {
const lines = content.split('\n');
const versions = [];
let currentVersion = null;
let currentSection = null;
let inVersionContent = false;
for (const line of lines) {
const trimmedLine = line.trim();
// 匹配版本行: ## [X.Y.Z] - YYYY-MM-DD
const versionMatch = trimmedLine.match(
/^## \[([\d.]+)\] - (\d{4}-\d{2}-\d{2})$/
);
if (versionMatch) {
if (currentVersion) {
versions.push(currentVersion);
}
currentVersion = {
version: versionMatch[1],
date: versionMatch[2],
added: [],
changed: [],
fixed: [],
content: [], // 用于存储原始内容,当没有分类时使用
};
currentSection = null;
inVersionContent = true;
continue;
}
// 如果遇到下一个版本或到达文件末尾,停止处理当前版本
if (inVersionContent && currentVersion) {
// 匹配章节标题
if (trimmedLine === '### Added') {
currentSection = 'added';
continue;
} else if (trimmedLine === '### Changed') {
currentSection = 'changed';
continue;
} else if (trimmedLine === '### Fixed') {
currentSection = 'fixed';
continue;
}
// 匹配条目: - 内容
if (trimmedLine.startsWith('- ') && currentSection) {
const entry = trimmedLine.substring(2);
currentVersion[currentSection].push(entry);
} else if (
trimmedLine &&
!trimmedLine.startsWith('#') &&
!trimmedLine.startsWith('###')
) {
currentVersion.content.push(trimmedLine);
}
}
}
// 添加最后一个版本
if (currentVersion) {
versions.push(currentVersion);
}
// 后处理:如果某个版本没有分类内容,但有 content则将 content 放到 changed 中
versions.forEach((version) => {
const hasCategories =
version.added.length > 0 ||
version.changed.length > 0 ||
version.fixed.length > 0;
if (!hasCategories && version.content.length > 0) {
version.changed = version.content;
}
// 清理 content 字段
delete version.content;
});
return { versions };
}
function generateTypeScript(changelogData) {
const entries = changelogData.versions
.map((version) => {
const addedEntries = version.added
.map((entry) => ` "${entry}"`)
.join(',\n');
const changedEntries = version.changed
.map((entry) => ` "${entry}"`)
.join(',\n');
const fixedEntries = version.fixed
.map((entry) => ` "${entry}"`)
.join(',\n');
return ` {
version: "${version.version}",
date: "${version.date}",
added: [
${addedEntries || ' // 无新增内容'}
],
changed: [
${changedEntries || ' // 无变更内容'}
],
fixed: [
${fixedEntries || ' // 无修复内容'}
]
}`;
})
.join(',\n');
return `// 此文件由 scripts/convert-changelog.js 自动生成
// 请勿手动编辑
export interface ChangelogEntry {
version: string;
date: string;
added: string[];
changed: string[];
fixed: string[];
}
export const changelog: ChangelogEntry[] = [
${entries}
];
export default changelog;
`;
}
function updateVersionFile(version) {
const versionTxtPath = path.join(process.cwd(), 'VERSION.txt');
try {
fs.writeFileSync(versionTxtPath, version, 'utf8');
console.log(`✅ 已更新 VERSION.txt: ${version}`);
} catch (error) {
console.error(`❌ 无法更新 VERSION.txt:`, error.message);
process.exit(1);
}
}
function updateVersionTs(version) {
const versionTsPath = path.join(process.cwd(), 'src/lib/version.ts');
try {
let content = fs.readFileSync(versionTsPath, 'utf8');
// 替换 CURRENT_VERSION 常量
const updatedContent = content.replace(
/const CURRENT_VERSION = ['"`][^'"`]+['"`];/,
`const CURRENT_VERSION = '${version}';`
);
fs.writeFileSync(versionTsPath, updatedContent, 'utf8');
console.log(`✅ 已更新 version.ts: ${version}`);
} catch (error) {
console.error(`❌ 无法更新 version.ts:`, error.message);
process.exit(1);
}
}
function main() {
try {
const changelogPath = path.join(process.cwd(), 'CHANGELOG');
const outputPath = path.join(process.cwd(), 'src/lib/changelog.ts');
console.log('正在读取 CHANGELOG 文件...');
const changelogContent = fs.readFileSync(changelogPath, 'utf-8');
console.log('正在解析 CHANGELOG 内容...');
const changelogData = parseChangelog(changelogContent);
if (changelogData.versions.length === 0) {
console.error('❌ 未在 CHANGELOG 中找到任何版本');
process.exit(1);
}
// 获取最新版本号CHANGELOG中的第一个版本
const latestVersion = changelogData.versions[0].version;
console.log(`🔢 最新版本: ${latestVersion}`);
console.log('正在生成 TypeScript 文件...');
const tsContent = generateTypeScript(changelogData);
// 确保输出目录存在
const outputDir = path.dirname(outputPath);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
fs.writeFileSync(outputPath, tsContent, 'utf-8');
// 检查是否在 GitHub Actions 环境中运行
const isGitHubActions = process.env.GITHUB_ACTIONS === 'true';
if (isGitHubActions) {
// 在 GitHub Actions 中,更新版本文件
console.log('正在更新版本文件...');
updateVersionFile(latestVersion);
updateVersionTs(latestVersion);
} else {
// 在本地运行时,只提示但不更新版本文件
console.log('🔧 本地运行模式:跳过版本文件更新');
console.log('💡 版本文件更新将在 git tag 触发的 release 工作流中完成');
}
console.log(`✅ 成功生成 ${outputPath}`);
console.log(`📊 版本统计:`);
changelogData.versions.forEach((version) => {
console.log(
` ${version.version} (${version.date}): +${version.added.length} ~${version.changed.length} !${version.fixed.length}`
);
});
console.log('\n🎉 转换完成!');
} catch (error) {
console.error('❌ 转换失败:', error);
process.exit(1);
}
}
if (require.main === module) {
main();
}

61
scripts/convert-config.js Normal file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/env node
/* eslint-disable */
// AUTO-GENERATED SCRIPT: Converts config.json to TypeScript definition.
// Usage: node scripts/convert-config.js
const fs = require('fs');
const path = require('path');
// Resolve project root (one level up from scripts folder)
const projectRoot = path.resolve(__dirname, '..');
// Paths
const configPath = path.join(projectRoot, 'config.json');
const libDir = path.join(projectRoot, 'src', 'lib');
const oldRuntimePath = path.join(libDir, 'runtime.ts');
const newRuntimePath = path.join(libDir, 'runtime.ts');
// Delete the old runtime.ts file if it exists
if (fs.existsSync(oldRuntimePath)) {
fs.unlinkSync(oldRuntimePath);
console.log('旧的 runtime.ts 已删除');
}
// Read and parse config.json
let rawConfig;
try {
rawConfig = fs.readFileSync(configPath, 'utf8');
} catch (err) {
console.error(`无法读取 ${configPath}:`, err);
process.exit(1);
}
let config;
try {
config = JSON.parse(rawConfig);
} catch (err) {
console.error('config.json 不是有效的 JSON:', err);
process.exit(1);
}
// Prepare TypeScript file content
const tsContent =
`// 该文件由 scripts/convert-config.js 自动生成,请勿手动修改\n` +
`/* eslint-disable */\n\n` +
`export const config = ${JSON.stringify(config, null, 2)} as const;\n\n` +
`export type RuntimeConfig = typeof config;\n\n` +
`export default config;\n`;
// Ensure lib directory exists
if (!fs.existsSync(libDir)) {
fs.mkdirSync(libDir, { recursive: true });
}
// Write to runtime.ts
try {
fs.writeFileSync(newRuntimePath, tsContent, 'utf8');
console.log('已生成 src/lib/runtime.ts');
} catch (err) {
console.error('写入 runtime.ts 失败:', err);
process.exit(1);
}

View File

@@ -0,0 +1,63 @@
#!/usr/bin/env node
/* eslint-disable */
// 根据 NEXT_PUBLIC_SITE_NAME 动态生成 manifest.json
const fs = require('fs');
const path = require('path');
// 获取项目根目录
const projectRoot = path.resolve(__dirname, '..');
const publicDir = path.join(projectRoot, 'public');
const manifestPath = path.join(publicDir, 'manifest.json');
// 从环境变量获取站点名称
const siteName = process.env.NEXT_PUBLIC_SITE_NAME || 'MoonTV';
// manifest.json 模板
const manifestTemplate = {
name: siteName,
short_name: siteName,
description: '影视聚合',
start_url: '/',
scope: '/',
display: 'standalone',
background_color: '#000000',
'apple-mobile-web-app-capable': 'yes',
'apple-mobile-web-app-status-bar-style': 'black',
icons: [
{
src: '/icons/icon-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: '/icons/icon-256x256.png',
sizes: '256x256',
type: 'image/png',
},
{
src: '/icons/icon-384x384.png',
sizes: '384x384',
type: 'image/png',
},
{
src: '/icons/icon-512x512.png',
sizes: '512x512',
type: 'image/png',
},
],
};
try {
// 确保 public 目录存在
if (!fs.existsSync(publicDir)) {
fs.mkdirSync(publicDir, { recursive: true });
}
// 写入 manifest.json
fs.writeFileSync(manifestPath, JSON.stringify(manifestTemplate, null, 2));
console.log(`✅ Generated manifest.json with site name: ${siteName}`);
} catch (error) {
console.error('❌ Error generating manifest.json:', error);
process.exit(1);
}