Files
yaoayanui/src/services/subtitleTemplateCatalog.js
fengchuanhn@gmail.com 8f05a8e414 1
2026-05-25 02:47:32 +08:00

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(),
}));
}