139 lines
3.4 KiB
JavaScript
139 lines
3.4 KiB
JavaScript
const STORAGE_KEY = "aiclient_custom_subtitle_templates";
|
|
|
|
let systemTemplatesCache = null;
|
|
|
|
/**
|
|
* @typedef {Object} SubtitleTemplateItem
|
|
* @property {string} id
|
|
* @property {string} name
|
|
* @property {string} [description]
|
|
* @property {Record<string, unknown>} config
|
|
* @property {boolean} [isSystem]
|
|
* @property {number} [is_system]
|
|
* @property {number} [createdAt]
|
|
*/
|
|
|
|
/**
|
|
* @returns {Promise<SubtitleTemplateItem[]>}
|
|
*/
|
|
export async function loadSystemSubtitleTemplates() {
|
|
if (systemTemplatesCache) return systemTemplatesCache;
|
|
const res = await fetch("/subtitle-templates/system-templates.json");
|
|
if (!res.ok) throw new Error("无法加载系统字幕模板");
|
|
const data = await res.json();
|
|
systemTemplatesCache = (data.subtitleTemplates || []).map((t) => ({
|
|
...t,
|
|
isSystem: true,
|
|
is_system: 1,
|
|
}));
|
|
return systemTemplatesCache;
|
|
}
|
|
|
|
/**
|
|
* @returns {SubtitleTemplateItem[]}
|
|
*/
|
|
export function loadCustomSubtitleTemplates() {
|
|
try {
|
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
if (!raw) return [];
|
|
const parsed = JSON.parse(raw);
|
|
return Array.isArray(parsed) ? parsed : [];
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {SubtitleTemplateItem[]} templates
|
|
*/
|
|
export function saveCustomSubtitleTemplates(templates) {
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(templates));
|
|
}
|
|
|
|
/**
|
|
* @returns {Promise<SubtitleTemplateItem[]>}
|
|
*/
|
|
export async function loadAllSubtitleTemplates() {
|
|
const system = await loadSystemSubtitleTemplates();
|
|
const custom = loadCustomSubtitleTemplates();
|
|
return [...system, ...custom];
|
|
}
|
|
|
|
/**
|
|
* @param {string} id
|
|
* @returns {Promise<SubtitleTemplateItem | null>}
|
|
*/
|
|
export async function getSubtitleTemplateById(id) {
|
|
const all = await loadAllSubtitleTemplates();
|
|
return all.find((t) => t.id === id) || null;
|
|
}
|
|
|
|
/**
|
|
* @param {string} id
|
|
*/
|
|
export function isSystemSubtitleTemplateId(id) {
|
|
return (
|
|
String(id || "").startsWith("template_system") ||
|
|
String(id || "").startsWith("system-")
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param {SubtitleTemplateItem} template
|
|
*/
|
|
export function cloneSubtitleTemplate(template) {
|
|
const now = Date.now();
|
|
return {
|
|
...JSON.parse(JSON.stringify(template)),
|
|
id: `custom_${now}`,
|
|
name: `${template.name} 副本`,
|
|
isSystem: false,
|
|
is_system: 0,
|
|
createdAt: now,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @param {SubtitleTemplateItem[]} templates
|
|
*/
|
|
export function downloadSubtitleTemplatesJson(templates, filename = "subtitle-templates.json") {
|
|
const blob = new Blob(
|
|
[
|
|
JSON.stringify(
|
|
{
|
|
version: "1.0.0",
|
|
exportedAt: new Date().toISOString(),
|
|
subtitleTemplates: templates,
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
],
|
|
{ type: "application/json" },
|
|
);
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement("a");
|
|
a.href = url;
|
|
a.download = filename;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
/**
|
|
* @param {File} file
|
|
* @returns {Promise<SubtitleTemplateItem[]>}
|
|
*/
|
|
export async function parseImportedSubtitleTemplates(file) {
|
|
const text = await file.text();
|
|
const data = JSON.parse(text);
|
|
const list = data.subtitleTemplates || data.templates || data;
|
|
if (!Array.isArray(list)) throw new Error("无效的模板文件格式");
|
|
return list.map((t, i) => ({
|
|
...t,
|
|
id: t.id || `imported_${Date.now()}_${i}`,
|
|
isSystem: false,
|
|
is_system: 0,
|
|
createdAt: t.createdAt || Date.now(),
|
|
}));
|
|
}
|