fix:优化代码

This commit is contained in:
Daniel
2026-03-07 23:35:08 +08:00
parent 382aa955ef
commit c3d219efc1
9 changed files with 179 additions and 158 deletions

View File

@@ -1,131 +1,122 @@
/**
* SQLite统计、留言、后端配置弹幕开关与位置
* 纯 JSON 文件存储,替代 SQLite。无 node-gyp / 原生依赖,任意环境可运行。
*/
const Database = require('better-sqlite3');
const fs = require('fs');
const path = require('path');
const DB_PATH = path.join(__dirname, 'data', 'pano.db');
const DATA_DIR = path.join(__dirname, 'data');
const STORE_PATH = path.join(DATA_DIR, 'store.json');
function getDb() {
const db = new Database(DB_PATH);
db.pragma('journal_mode = WAL');
return db;
const DEFAULT_STORE = {
stats: {
view_count: 0,
like_count: 0,
share_count: 0,
watching_now: 0,
},
viewers: {},
comments: [],
settings: {
danmaku_enabled: '0',
danmaku_position: 'top',
},
};
let _store = null;
function load() {
if (_store) return _store;
if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true });
if (fs.existsSync(STORE_PATH)) {
try {
_store = JSON.parse(fs.readFileSync(STORE_PATH, 'utf8'));
if (!_store.stats) _store.stats = DEFAULT_STORE.stats;
if (!_store.viewers) _store.viewers = {};
if (!Array.isArray(_store.comments)) _store.comments = [];
if (!_store.settings) _store.settings = DEFAULT_STORE.settings;
return _store;
} catch (e) {}
}
_store = JSON.parse(JSON.stringify(DEFAULT_STORE));
save();
return _store;
}
function save() {
if (!_store) return;
fs.writeFileSync(STORE_PATH, JSON.stringify(_store, null, 0), 'utf8');
}
function initDb() {
const fs = require('fs');
const dir = path.join(__dirname, 'data');
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
const db = getDb();
db.exec(`
CREATE TABLE IF NOT EXISTS stats (
id INTEGER PRIMARY KEY CHECK (id = 1),
view_count INTEGER NOT NULL DEFAULT 0,
like_count INTEGER NOT NULL DEFAULT 0,
share_count INTEGER NOT NULL DEFAULT 0,
watching_now INTEGER NOT NULL DEFAULT 0
);
INSERT OR IGNORE INTO stats (id, view_count, like_count, share_count, watching_now) VALUES (1, 0, 0, 0, 0);
CREATE TABLE IF NOT EXISTS viewers (
viewer_id TEXT PRIMARY KEY,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS comments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content TEXT NOT NULL,
nickname TEXT,
created_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
INSERT OR IGNORE INTO settings (key, value) VALUES ('danmaku_enabled', '0');
INSERT OR IGNORE INTO settings (key, value) VALUES ('danmaku_position', 'top');
`);
db.close();
load();
}
function getConfig() {
const db = getDb();
const rows = db.prepare('SELECT key, value FROM settings').all();
db.close();
const map = {};
rows.forEach((r) => { map[r.key] = r.value; });
const s = load().settings;
return {
danmakuEnabled: map.danmaku_enabled === '1',
danmakuPosition: (map.danmaku_position || 'top').toLowerCase(),
danmakuEnabled: s.danmaku_enabled === '1',
danmakuPosition: (s.danmaku_position || 'top').toLowerCase(),
};
}
function getStats() {
const db = getDb();
const row = db.prepare('SELECT view_count, like_count, share_count, watching_now FROM stats WHERE id = 1').get();
const commentRow = db.prepare('SELECT COUNT(*) as n FROM comments').get();
db.close();
const st = load().stats;
const commentCount = load().comments.length;
return {
viewCount: row.view_count,
commentCount: commentRow.n,
likeCount: row.like_count,
shareCount: row.share_count,
watchingNow: row.watching_now,
viewCount: st.view_count,
commentCount,
likeCount: st.like_count,
shareCount: st.share_count,
watchingNow: st.watching_now,
};
}
function incView() {
const db = getDb();
db.prepare('UPDATE stats SET view_count = view_count + 1 WHERE id = 1').run();
const out = getStats();
db.close();
return out;
const s = load();
s.stats.view_count += 1;
save();
return getStats();
}
function incLike() {
const db = getDb();
db.prepare('UPDATE stats SET like_count = like_count + 1 WHERE id = 1').run();
const row = db.prepare('SELECT like_count FROM stats WHERE id = 1').get();
db.close();
return { likeCount: row.like_count };
const s = load();
s.stats.like_count += 1;
save();
return { likeCount: s.stats.like_count };
}
function incShare() {
const db = getDb();
db.prepare('UPDATE stats SET share_count = share_count + 1 WHERE id = 1').run();
const row = db.prepare('SELECT share_count FROM stats WHERE id = 1').get();
db.close();
return { shareCount: row.share_count };
const s = load();
s.stats.share_count += 1;
save();
return { shareCount: s.stats.share_count };
}
function joinViewer(viewerId) {
const db = getDb();
const s = load();
const now = Date.now();
db.prepare('INSERT OR REPLACE INTO viewers (viewer_id, updated_at) VALUES (?, ?)').run(viewerId, now);
db.prepare('DELETE FROM viewers WHERE updated_at < ?').run(now - 120000);
const row = db.prepare('SELECT COUNT(*) as n FROM viewers').get();
db.prepare('UPDATE stats SET watching_now = ? WHERE id = 1').run(row.n);
db.close();
return row.n;
s.viewers[viewerId] = now;
const cutoff = now - 120000;
Object.keys(s.viewers).forEach((id) => {
if (s.viewers[id] < cutoff) delete s.viewers[id];
});
s.stats.watching_now = Object.keys(s.viewers).length;
save();
return s.stats.watching_now;
}
function leaveViewer(viewerId) {
const db = getDb();
db.prepare('DELETE FROM viewers WHERE viewer_id = ?').run(viewerId);
const row = db.prepare('SELECT COUNT(*) as n FROM viewers').get();
db.prepare('UPDATE stats SET watching_now = ? WHERE id = 1').run(row.n);
db.close();
return row.n;
const s = load();
delete s.viewers[viewerId];
s.stats.watching_now = Object.keys(s.viewers).length;
save();
return s.stats.watching_now;
}
function getComments(limit = 100) {
const db = getDb();
const rows = db.prepare(
'SELECT id, content, nickname, created_at FROM comments ORDER BY id DESC LIMIT ?'
).all(limit);
db.close();
return rows.reverse().map((r) => ({
const list = load().comments;
const slice = list.slice(-Math.min(limit, list.length));
return slice.map((r) => ({
id: r.id,
content: r.content,
nickname: r.nickname || '游客',
@@ -134,15 +125,23 @@ function getComments(limit = 100) {
}
function addComment(content, nickname) {
const db = getDb();
const s = load();
const now = Date.now();
const r = db.prepare('INSERT INTO comments (content, nickname, created_at) VALUES (?, ?, ?)').run(
String(content).trim().slice(0, 200) || '(空)',
nickname ? String(nickname).trim().slice(0, 32) : null,
now
);
db.close();
return { id: r.lastInsertRowid, content: content.trim().slice(0, 200), nickname: nickname || '游客', createdAt: now };
const id = s.comments.length ? Math.max(...s.comments.map((c) => c.id)) + 1 : 1;
const row = {
id,
content: String(content).trim().slice(0, 200) || '(空)',
nickname: nickname ? String(nickname).trim().slice(0, 32) : null,
created_at: now,
};
s.comments.push(row);
save();
return {
id: row.id,
content: row.content,
nickname: row.nickname || '游客',
createdAt: row.created_at,
};
}
module.exports = {