188 lines
6.1 KiB
JavaScript
188 lines
6.1 KiB
JavaScript
"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,
|
|
}; |