Publish updated WeChat Radar

This commit is contained in:
joeseesun
2026-05-26 09:10:04 +08:00
parent 8abb29e13e
commit de7ec99fed
44 changed files with 2900 additions and 746 deletions
+24
View File
@@ -0,0 +1,24 @@
import { NextRequest, NextResponse } from 'next/server';
import { backfillMessageLinks } from '@/lib/message-links';
export const dynamic = 'force-dynamic';
export const maxDuration = 300;
const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
export async function POST(req: NextRequest) {
const body = (await req.json().catch(() => ({}))) as {
since?: string;
until?: string;
};
if (body.since && !DATE_RE.test(body.since)) {
return NextResponse.json({ ok: false, error: 'invalid since' }, { status: 400 });
}
if (body.until && !DATE_RE.test(body.until)) {
return NextResponse.json({ ok: false, error: 'invalid until' }, { status: 400 });
}
const result = backfillMessageLinks(body.since, body.until);
return NextResponse.json({ ok: true, ...result });
}
+52
View File
@@ -0,0 +1,52 @@
import { NextRequest, NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { wxSessions } from '@/lib/wx';
import { todayStr } from '@/lib/range';
export const dynamic = 'force-dynamic';
type RawLinkRow = {
chatroom_id: string;
local_id: number;
sender: string;
time: string;
url: string;
canonical_url: string;
title: string | null;
domain: string;
source: string;
raw_kind: string;
};
export async function GET(req: NextRequest) {
const date = new URL(req.url).searchParams.get('date') ?? todayStr();
const names = await groupNames();
const rows = db()
.prepare(
`SELECT chatroom_id, local_id, sender, time, url, canonical_url, title, domain, source, raw_kind
FROM message_links
WHERE date = ?
AND canonical_url LIKE '%://mp.weixin.qq.com/%'
ORDER BY timestamp DESC
LIMIT 200`,
)
.all(date) as RawLinkRow[];
return NextResponse.json({
ok: true,
date,
links: rows.map((row) => ({
...row,
chat_name: names.get(row.chatroom_id) ?? row.chatroom_id,
})),
});
}
async function groupNames() {
const names = new Map<string, string>();
try {
const sessions = await wxSessions(500);
for (const s of sessions) names.set(s.username, s.chat);
} catch {}
return names;
}
+48
View File
@@ -0,0 +1,48 @@
import { NextRequest, NextResponse } from 'next/server';
import { upsertResolvedLinkForMessage } from '@/lib/message-links';
export const dynamic = 'force-dynamic';
export async function POST(req: NextRequest) {
const body = (await req.json().catch(() => ({}))) as {
chatroom_id?: string;
local_id?: number;
url?: string;
title?: string;
description?: string;
source?: 'public_search' | 'manual';
confidence?: number;
};
if (!body.chatroom_id || !Number.isInteger(body.local_id) || !body.url) {
return NextResponse.json(
{ ok: false, error: 'chatroom_id, local_id and url are required' },
{ status: 400 },
);
}
const localId = body.local_id;
if (localId === undefined) {
return NextResponse.json({ ok: false, error: 'local_id is required' }, { status: 400 });
}
const source = body.source ?? 'manual';
if (source !== 'manual' && source !== 'public_search') {
return NextResponse.json({ ok: false, error: 'invalid source' }, { status: 400 });
}
const result = upsertResolvedLinkForMessage({
chatroom_id: body.chatroom_id,
local_id: localId,
url: body.url,
title: body.title,
description: body.description,
source,
confidence: body.confidence,
});
if (!result.ok) {
return NextResponse.json(result, { status: 400 });
}
return NextResponse.json({ ok: true });
}