v2: SQLite + 多路流 + 鉴权 + 导入/删除 + 资源本地化 + 模块化重构
This commit is contained in:
1 parent
fa6eeb25b9
commit
65b6f8cf62
30 files changed
+3506
-2231
No files matched your search
+188
@@ -0,0 +1,188 @@
|
||||
"use strict";
|
||||
const { getDb } = require("./db");
|
||||
const { naturalCompare } = require("./util");
|
||||
|
||||
/* ==================== songs ==================== */
|
||||
function getSongByFile(file) {
|
||||
return getDb().prepare("SELECT * FROM songs WHERE file = ?").get(file);
|
||||
}
|
||||
function getSongById(id) {
|
||||
return getDb().prepare("SELECT * FROM songs WHERE id = ?").get(id);
|
||||
}
|
||||
function getAllSongs() {
|
||||
const rows = getDb().prepare("SELECT * FROM songs").all();
|
||||
return rows.sort((a, b) => naturalCompare(a.file, b.file));
|
||||
}
|
||||
function upsertSong(s) {
|
||||
const d = getDb();
|
||||
const ex = getSongByFile(s.file);
|
||||
if (ex) {
|
||||
d.prepare(
|
||||
`UPDATE songs SET name=?, artist=?, cover=?, duration=?, file_size=? WHERE file=?`
|
||||
).run(
|
||||
s.name != null ? s.name : ex.name,
|
||||
s.artist != null ? s.artist : ex.artist,
|
||||
s.cover != null ? s.cover : ex.cover,
|
||||
s.duration != null ? s.duration : ex.duration,
|
||||
s.file_size != null ? s.file_size : ex.file_size,
|
||||
s.file
|
||||
);
|
||||
return getSongByFile(s.file);
|
||||
}
|
||||
d.prepare(
|
||||
`INSERT INTO songs (file, name, artist, cover, duration, file_size, heat, cache_status, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, 0, 'pending', ?)`
|
||||
).run(
|
||||
s.file,
|
||||
s.name || "",
|
||||
s.artist || "",
|
||||
s.cover || "",
|
||||
s.duration != null ? s.duration : null,
|
||||
s.file_size || 0,
|
||||
Date.now()
|
||||
);
|
||||
return getSongByFile(s.file);
|
||||
}
|
||||
function updateSong(file, fields) {
|
||||
const keys = Object.keys(fields);
|
||||
if (!keys.length) return;
|
||||
const set = keys.map((k) => `${k}=?`).join(", ");
|
||||
getDb()
|
||||
.prepare(`UPDATE songs SET ${set} WHERE file=?`)
|
||||
.run(...keys.map((k) => fields[k]), file);
|
||||
}
|
||||
function deleteSongByFile(file) {
|
||||
return getDb().prepare("DELETE FROM songs WHERE file = ?").run(file);
|
||||
}
|
||||
function setCacheStatus(file, status) {
|
||||
getDb().prepare("UPDATE songs SET cache_status=? WHERE file=?").run(status, file);
|
||||
}
|
||||
function incrementHeat(file) {
|
||||
getDb().prepare("UPDATE songs SET heat = heat + 1 WHERE file=?").run(file);
|
||||
return getSongByFile(file)?.heat || 0;
|
||||
}
|
||||
|
||||
/* ==================== streams ==================== */
|
||||
function createStream(id, name) {
|
||||
getDb()
|
||||
.prepare(
|
||||
"INSERT INTO streams (id, name, enabled, current_pos, media_seq, created_at) VALUES (?, ?, 1, 0, 0, ?)"
|
||||
)
|
||||
.run(id, name || id, Date.now());
|
||||
return getStream(id);
|
||||
}
|
||||
function listStreams() {
|
||||
return getDb().prepare("SELECT * FROM streams ORDER BY created_at ASC").all();
|
||||
}
|
||||
function getStream(id) {
|
||||
return getDb().prepare("SELECT * FROM streams WHERE id = ?").get(id);
|
||||
}
|
||||
function deleteStream(id) {
|
||||
return getDb().prepare("DELETE FROM streams WHERE id = ?").run(id);
|
||||
}
|
||||
function setStreamState(id, fields) {
|
||||
const keys = Object.keys(fields);
|
||||
if (!keys.length) return;
|
||||
const set = keys.map((k) => `${k}=?`).join(", ");
|
||||
getDb()
|
||||
.prepare(`UPDATE streams SET ${set} WHERE id=?`)
|
||||
.run(...keys.map((k) => fields[k]), id);
|
||||
}
|
||||
function setStreamEnabled(id, enabled) {
|
||||
setStreamState(id, { enabled: enabled ? 1 : 0 });
|
||||
}
|
||||
|
||||
/* ==================== stream_playlist ==================== */
|
||||
function getPlaylistRows(streamId) {
|
||||
return getDb()
|
||||
.prepare(
|
||||
`SELECT sp.id AS entry_id, sp.position, s.*
|
||||
FROM stream_playlist sp JOIN songs s ON s.id = sp.song_id
|
||||
WHERE sp.stream_id = ? ORDER BY sp.position ASC`
|
||||
)
|
||||
.all(streamId);
|
||||
}
|
||||
function playlistCount(streamId) {
|
||||
return getDb()
|
||||
.prepare("SELECT COUNT(*) c FROM stream_playlist WHERE stream_id=?")
|
||||
.get(streamId).c;
|
||||
}
|
||||
function addToPlaylist(streamId, songId) {
|
||||
const d = getDb();
|
||||
const max =
|
||||
d.prepare("SELECT COALESCE(MAX(position),-1) m FROM stream_playlist WHERE stream_id=?")
|
||||
.get(streamId).m + 1;
|
||||
d.prepare(
|
||||
"INSERT INTO stream_playlist (stream_id, song_id, position) VALUES (?, ?, ?)"
|
||||
).run(streamId, songId, max);
|
||||
}
|
||||
function removePlaylistEntry(streamId, entryId) {
|
||||
const d = getDb();
|
||||
const row = d.prepare("SELECT position FROM stream_playlist WHERE id=? AND stream_id=?").get(entryId, streamId);
|
||||
if (!row) return false;
|
||||
d.prepare("DELETE FROM stream_playlist WHERE id=?").run(entryId);
|
||||
d.prepare("UPDATE stream_playlist SET position = position - 1 WHERE stream_id=? AND position > ?")
|
||||
.run(streamId, row.position);
|
||||
return true;
|
||||
}
|
||||
function setPlaylistOrder(streamId, entryIds) {
|
||||
const d = getDb();
|
||||
const stmt = d.prepare("UPDATE stream_playlist SET position=? WHERE id=? AND stream_id=?");
|
||||
const tx = d.transaction((ids) => {
|
||||
ids.forEach((id, i) => stmt.run(i, id, streamId));
|
||||
});
|
||||
tx(entryIds);
|
||||
}
|
||||
function clearPlaylist(streamId) {
|
||||
getDb().prepare("DELETE FROM stream_playlist WHERE stream_id=?").run(streamId);
|
||||
}
|
||||
|
||||
/* ==================== sessions ==================== */
|
||||
function createSession(token, expiresAt) {
|
||||
getDb()
|
||||
.prepare("INSERT INTO sessions (token, created_at, expires_at) VALUES (?, ?, ?)")
|
||||
.run(token, Date.now(), expiresAt);
|
||||
}
|
||||
function getSession(token) {
|
||||
const s = getDb().prepare("SELECT * FROM sessions WHERE token=?").get(token);
|
||||
if (!s) return null;
|
||||
if (s.expires_at < Date.now()) {
|
||||
deleteSession(token);
|
||||
return null;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
function deleteSession(token) {
|
||||
getDb().prepare("DELETE FROM sessions WHERE token=?").run(token);
|
||||
}
|
||||
function purgeExpiredSessions() {
|
||||
return getDb().prepare("DELETE FROM sessions WHERE expires_at < ?").run(Date.now()).changes;
|
||||
}
|
||||
|
||||
/* ==================== settings ==================== */
|
||||
function getSetting(key, def = null) {
|
||||
const r = getDb().prepare("SELECT value FROM settings WHERE key=?").get(key);
|
||||
if (!r) return def;
|
||||
try {
|
||||
return JSON.parse(r.value);
|
||||
} catch (_) {
|
||||
return r.value;
|
||||
}
|
||||
}
|
||||
function setSetting(key, value) {
|
||||
getDb()
|
||||
.prepare(
|
||||
"INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value"
|
||||
)
|
||||
.run(key, JSON.stringify(value));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getSongByFile, getSongById, getAllSongs, upsertSong, updateSong,
|
||||
deleteSongByFile, setCacheStatus, incrementHeat,
|
||||
createStream, listStreams, getStream, deleteStream, setStreamState, setStreamEnabled,
|
||||
getPlaylistRows, playlistCount, addToPlaylist, removePlaylistEntry,
|
||||
setPlaylistOrder, clearPlaylist,
|
||||
createSession, getSession, deleteSession, purgeExpiredSessions,
|
||||
getSetting, setSetting,
|
||||
};
|
||||
Reference in new issue
Block a user