Skip to content

Commit 0b72288

Browse files
authored
增加剧名映射表,.env不存在的情况下自动生成 (#127)
* 手机端UI缩小body内间距 * 修复了移动端UI系统配置多选元素不能拖动的问题 * 修复移动端UI系统配置多选不能删除元素的问题 * 在Node和Docker环境下,如果config目录下没有.env和config.yaml,则自动从.env.example拷贝一份生成.env * 添加剧名映射表 * 增加ui配置界面的剧名映射表配置 * 修改小版本号 * 修复空间ui css
1 parent d6b92fd commit 0b72288

File tree

12 files changed

+460
-15
lines changed

12 files changed

+460
-15
lines changed

config/.env.example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,11 @@ MAX_LAST_SELECT_MAP=100
278278
# 在建立 HTTPS 连接时是否验证服务器的 SSL/TLS 证书,0表示忽略
279279
# 默认值:1
280280
# NODE_TLS_REJECT_UNAUTHORIZED=1
281+
282+
# ==================== 标题映射表配置 ====================
283+
284+
# 标题映射表(用于自动匹配时替换标题进行搜索)
285+
# 格式:原始标题->映射标题;原始标题->映射标题;...
286+
# 示例:TITLE_MAPPING_TABLE: "唐朝诡事录->唐朝诡事录之西行;国色芳华->锦绣芳华"
287+
# 默认值:空(不启用标题映射)
288+
TITLE_MAPPING_TABLE=

config/config.yaml.example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,3 +272,11 @@ MAX_LAST_SELECT_MAP: 100
272272
# 在建立 HTTPS 连接时是否验证服务器的 SSL/TLS 证书,0表示忽略
273273
# 默认值:1
274274
# NODE_TLS_REJECT_UNAUTHORIZED: 1
275+
276+
# ==================== 标题映射表配置 ====================
277+
278+
# 标题映射表(用于自动匹配时替换标题进行搜索)
279+
# 格式:原始标题->映射标题;原始标题->映射标题;...
280+
# 示例:TITLE_MAPPING_TABLE: "唐朝诡事录->唐朝诡事录之西行;国色芳华->锦绣芳华"
281+
# 默认值:空(不启用标题映射)
282+
TITLE_MAPPING_TABLE: ""

danmu_api/apis/dandan-api.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,15 @@ export async function matchAnime(url, req) {
635635

636636
let {title, season, episode, year} = await extractTitleSeasonEpisode(cleanFileName);
637637

638+
// 使用剧名映射表转换剧名
639+
if (globals.titleMappingTable && globals.titleMappingTable.size > 0) {
640+
const mappedTitle = globals.titleMappingTable.get(title);
641+
if (mappedTitle) {
642+
title = mappedTitle;
643+
log("info", `Title mapped from original: ${url.searchParams.get("keyword")} to: ${title}`);
644+
}
645+
}
646+
638647
// 获取prefer animeIdgetPreferAnimeId
639648
const [preferAnimeId, preferSource] = getPreferAnimeId(title);
640649
log("info", `prefer animeId: ${preferAnimeId} from ${preferSource}`);

danmu_api/configs/envs.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,32 @@ export class Envs {
179179
return this.get('CONVERT_COLOR', convertColorToWhite ? 'white': 'default', 'string');
180180
}
181181

182+
/**
183+
* 解析剧名映射表
184+
* @returns {Map} 剧名映射表
185+
*/
186+
static resolveTitleMappingTable() {
187+
const mappingStr = this.get('TITLE_MAPPING_TABLE', '', 'string').trim();
188+
const mappingTable = new Map();
189+
190+
if (!mappingStr) {
191+
return mappingTable;
192+
}
193+
194+
// 解析格式:"唐朝诡事录->唐朝诡事录之西行;国色芳华->锦绣芳华"
195+
const pairs = mappingStr.split(';');
196+
for (const pair of pairs) {
197+
if (pair.includes('->')) {
198+
const [original, mapped] = pair.split('->').map(s => s.trim());
199+
if (original && mapped) {
200+
mappingTable.set(original, mapped);
201+
}
202+
}
203+
}
204+
205+
return mappingTable;
206+
}
207+
182208
/**
183209
* 获取记录的环境变量 JSON
184210
* @returns {Map<any, any>} JSON 字符串
@@ -219,6 +245,7 @@ export class Envs {
219245
'ENABLE_EPISODE_FILTER': { category: 'match', type: 'boolean', description: '集标题过滤开关' },
220246
'STRICT_TITLE_MATCH': { category: 'match', type: 'boolean', description: '严格标题匹配模式' },
221247
'TITLE_TO_CHINESE': { category: 'match', type: 'boolean', description: '外语标题转换中文开关' },
248+
'TITLE_MAPPING_TABLE': { category: 'match', type: 'map', description: '剧名映射表,用于自动匹配时替换标题进行搜索,格式:原始标题->映射标题;原始标题->映射标题;... ,例如:"唐朝诡事录->唐朝诡事录之西行;国色芳华->锦绣芳华"' },
222249

223250
// 弹幕配置
224251
'BLOCKED_WORDS': { category: 'danmu', type: 'text', description: '屏蔽词列表' },
@@ -282,6 +309,7 @@ export class Envs {
282309
danmuOutputFormat: this.get('DANMU_OUTPUT_FORMAT', 'json', 'string'), // 弹幕输出格式配置(默认 json,可选值:json, xml)
283310
strictTitleMatch: this.get('STRICT_TITLE_MATCH', false, 'boolean'), // 严格标题匹配模式配置(默认 false,宽松模糊匹配)
284311
titleToChinese: this.get('TITLE_TO_CHINESE', false, 'boolean'), // 外语标题转换中文开关
312+
titleMappingTable: this.resolveTitleMappingTable(), // 剧名映射表,用于自动匹配时替换标题进行搜索
285313
rememberLastSelect: this.get('REMEMBER_LAST_SELECT', true, 'boolean'), // 是否记住手动选择结果,用于match自动匹配时优选上次的选择(默认 true,记住)
286314
MAX_LAST_SELECT_MAP: this.get('MAX_LAST_SELECT_MAP', 100, 'number'), // 记住上次选择映射缓存大小限制(默认 100)
287315
deployPlatformAccount: this.get('DEPLOY_PLATFROM_ACCOUNT', '', 'string', true), // 部署平台账号ID配置(默认空)

danmu_api/configs/globals.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const Globals = {
1313
accessedEnvVars: {},
1414

1515
// 静态常量
16-
VERSION: '1.10.2',
16+
VERSION: '1.10.3',
1717
MAX_LOGS: 500, // 日志存储,最多保存 500 行
1818
MAX_ANIMES: 100,
1919

danmu_api/server.js

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,43 @@ const dotenv = require('dotenv');
77
const yaml = require('js-yaml');
88

99
// 配置文件路径在项目根目录(server.js 的上一级目录)
10-
const envPath = path.join(__dirname, '..', 'config', '.env');
11-
const yamlPath = path.join(__dirname, '..', 'config', 'config.yaml');
10+
const configDir = path.join(__dirname, '..', 'config');
11+
const envPath = path.join(configDir, '.env');
12+
const yamlPath = path.join(configDir, 'config.yaml');
13+
14+
// 在启动时检查并复制配置文件
15+
checkAndCopyConfigFiles();
16+
17+
/**
18+
* 检查并自动复制配置文件
19+
* 在Node环境下,如果config目录下没有.env和config.yaml,则自动从.env.example拷贝一份生成.env
20+
*/
21+
function checkAndCopyConfigFiles() {
22+
const envExamplePath = path.join(configDir, '.env.example');
23+
24+
const envExists = fs.existsSync(envPath);
25+
const yamlExists = fs.existsSync(yamlPath);
26+
const envExampleExists = fs.existsSync(envExamplePath);
27+
28+
// 如果存在.env或config.yaml,则不需要复制
29+
if (envExists || yamlExists) {
30+
console.log('[server] Configuration files exist, skipping auto-copy');
31+
return;
32+
}
33+
34+
// 只有当.env.example存在时才进行复制
35+
if (envExampleExists) {
36+
try {
37+
// 从.env.example复制到.env
38+
fs.copyFileSync(envExamplePath, envPath);
39+
console.log('[server] Copied .env.example to .env successfully');
40+
} catch (error) {
41+
console.log('[server] Error copying .env.example to .env:', error.message);
42+
}
43+
} else {
44+
console.log('[server] .env.example not found, cannot auto-copy');
45+
}
46+
}
1247

1348
/**
1449
* 从 YAML 文件加载配置

danmu_api/ui/css/base.css.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ body {
1111
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
1212
background: linear-gradient(135deg, #a0b9e8ff 0%, #e39db4ff 100%);
1313
min-height: 100vh;
14-
padding: 20px;
14+
padding: 5px;
1515
}
1616
1717
.container {

danmu_api/ui/css/components.css.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,10 @@ export const componentsCssContent = /* css */ `
515515
background: #ff6b6b;
516516
}
517517
518+
.value-type-badge.map {
519+
background: #9b59b6;
520+
}
521+
518522
/* 进度条 */
519523
.progress-container {
520524
position: fixed;

danmu_api/ui/css/forms.css.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,4 +315,56 @@ input:checked + .slider:before {
315315
background: #e8eaf6 !important;
316316
border-color: #667eea !important;
317317
}
318+
319+
/* 映射表样式 */
320+
.map-container {
321+
margin-top: 10px;
322+
}
323+
324+
.map-item {
325+
display: flex;
326+
align-items: center;
327+
gap: 10px;
328+
margin-bottom: 10px;
329+
padding: 10px;
330+
border: 1px solid #ddd;
331+
border-radius: 6px;
332+
background-color: #f9f9f9;
333+
}
334+
335+
.map-input-left, .map-input-right {
336+
flex: 1;
337+
padding: 8px;
338+
border: 1px solid #ddd;
339+
border-radius: 4px;
340+
}
341+
342+
.map-separator {
343+
font-weight: bold;
344+
color: #666;
345+
}
346+
347+
.map-remove-btn {
348+
margin-left: 10px;
349+
padding: 6px 12px;
350+
font-size: 12px;
351+
}
352+
353+
.map-item-template {
354+
display: none;
355+
}
356+
357+
/* 必填标记 */
358+
.form-group label:after {
359+
content: " *";
360+
color: #e74c3c;
361+
}
362+
363+
/* 表单帮助文本 */
364+
.form-help {
365+
font-size: 12px;
366+
color: #666;
367+
margin-top: 5px;
368+
font-style: italic;
369+
}
318370
`;

0 commit comments

Comments
 (0)