v3: follows, notifications, invite-only registration, unread markers

This commit is contained in:
khannurien
2026-03-21 18:42:47 +00:00
parent 7c098e7c4c
commit 608c6bc6a8
55 changed files with 4743 additions and 884 deletions

View File

@@ -22,14 +22,19 @@ import {
broadcastPlaylistDumpsUpdated,
broadcastPlaylistUpdated,
} from "./ws-service.ts";
import { notifyPlaylistFollowersNewDump } from "./notification-service.ts";
const DUMP_SELECT_COLS =
"id, kind, title, comment, user_id, created_at, url, rich_content, file_name, file_mime, file_size, vote_count, is_private";
const PLAYLIST_SELECT = `p.*, u.username as owner_username,
(SELECT COUNT(*) FROM playlist_dumps pd WHERE pd.playlist_id = p.id) as dump_count
FROM playlists p LEFT JOIN users u ON u.id = p.user_id`;
function getPlaylistById(playlistId: string): Playlist {
const row = db.prepare(`SELECT * FROM playlists WHERE id = ?;`).get(
playlistId,
);
const row = db.prepare(
`SELECT ${PLAYLIST_SELECT} WHERE p.id = ?;`,
).get(playlistId);
if (!row || !isPlaylistRow(row)) {
throw new APIException(APIErrorCode.NOT_FOUND, 404, "Playlist not found");
}
@@ -90,9 +95,7 @@ export function getPlaylist(
const dumps: Dump[] = rows.filter(isDumpRow).map(dumpRowToApi);
// Owners always see their own private dumps; strip them for non-owners regardless
const visibleDumps = isOwner
? dumps
: dumps.filter((d) => !d.isPrivate);
const visibleDumps = isOwner ? dumps : dumps.filter((d) => !d.isPrivate);
return { ...playlist, dumps: visibleDumps };
}
@@ -110,10 +113,8 @@ export function listPlaylistsByUser(
? `SELECT COUNT(*) as count FROM playlists WHERE user_id = ?;`
: `SELECT COUNT(*) as count FROM playlists WHERE user_id = ? AND is_public = 1;`;
const sql = isOwner
? `SELECT p.*, (SELECT COUNT(*) FROM playlist_dumps pd WHERE pd.playlist_id = p.id) as dump_count
FROM playlists p WHERE p.user_id = ? ORDER BY p.created_at DESC LIMIT ? OFFSET ?;`
: `SELECT p.*, (SELECT COUNT(*) FROM playlist_dumps pd WHERE pd.playlist_id = p.id) as dump_count
FROM playlists p WHERE p.user_id = ? AND p.is_public = 1 ORDER BY p.created_at DESC LIMIT ? OFFSET ?;`;
? `SELECT ${PLAYLIST_SELECT} WHERE p.user_id = ? ORDER BY p.created_at DESC LIMIT ? OFFSET ?;`
: `SELECT ${PLAYLIST_SELECT} WHERE p.user_id = ? AND p.is_public = 1 ORDER BY p.created_at DESC LIMIT ? OFFSET ?;`;
const totalRow = db.prepare(countSql).get(userId) as
| { count: number }
@@ -227,6 +228,20 @@ export function addDumpToPlaylist(
const dumpIds = getCurrentDumpIds(playlistId);
broadcastPlaylistDumpsUpdated(playlist, dumpIds);
if (playlist.isPublic) {
const dumpRow = db.prepare(`SELECT title FROM dumps WHERE id = ?;`).get(
dumpId,
) as { title: string } | undefined;
if (dumpRow) {
notifyPlaylistFollowersNewDump(
playlistId,
playlist.title,
dumpId,
dumpRow.title,
);
}
}
}
export function removeDumpFromPlaylist(