Fix: the server crashed on every Search; Search now covers tasks and events and explains itself
build-container / build (push) Successful in 1m55s
build-container / build (push) Successful in 1m55s
- Restore ddgAnswer, which an earlier edit deleted: /api/ddg threw a ReferenceError and killed the whole server process whenever Search ran - One failing request can no longer take the server down (errors are logged and answered with a 500) - tools/smoke-test.js starts the real server and calls every endpoint; the Gitea workflow runs it before building the image, so a missing function or a crash stops the build - Search: also searches NE Hub tasks and calendar events; Seafile file search falls back to scanning file names when the search index returns nothing; Plex search falls back to the library's artists/albums; a status line shows what was searched, per-source counts and errors, with sign-in links Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ea882cafbf
commit
489ea0aaf0
8 files changed
+229
-40
No files matched your search
@@ -0,0 +1,31 @@
|
||||
// Search over what lives in NE Hub itself (tasks and calendar events). Files and music are searched from the browser,
|
||||
// because those need the person's own Seafile / Plex sign-in.
|
||||
const cal = require('./cal');
|
||||
const tasks = require('./tasks');
|
||||
|
||||
const json = (res, code, obj) => { res.writeHead(code, { 'content-type': 'application/json' }); res.end(JSON.stringify(obj)); };
|
||||
const ymd = d => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
||||
|
||||
async function handle(req, res) {
|
||||
const q = (new URL(req.url, 'http://x').searchParams.get('q') || '').trim().toLowerCase().slice(0, 100);
|
||||
if (q.length < 2) return json(res, 200, { tasks: [], events: [], errors: [] });
|
||||
const errors = [];
|
||||
let foundTasks = [], foundEvents = [];
|
||||
try {
|
||||
foundTasks = (await tasks.allTasks()).filter(t => (t.title + ' ' + t.notes).toLowerCase().includes(q))
|
||||
.sort((a, b) => (a.done - b.done) || (a.due || '9999').localeCompare(b.due || '9999')).slice(0, 8);
|
||||
} catch (e) { errors.push('Tasks: ' + e.message); }
|
||||
try { // two months back to just over a year ahead
|
||||
const now = new Date(), from = new Date(now); from.setDate(from.getDate() - 60); from.setHours(0, 0, 0, 0);
|
||||
const to = new Date(now); to.setDate(to.getDate() + 400); to.setHours(23, 59, 59, 999);
|
||||
const r = await cal.collectEvents({ from: from.getTime(), to: to.getTime(), fd: ymd(from), td: ymd(to) });
|
||||
errors.push(...r.errors);
|
||||
const when = e => e.allDay ? Date.parse(e.start + 'T00:00:00') : e.start, t0 = Date.now() - 864e5;
|
||||
foundEvents = r.events.filter(e => (e.title + ' ' + (e.location || '')).toLowerCase().includes(q))
|
||||
.sort((a, b) => { const ua = when(a) >= t0, ub = when(b) >= t0; return ua === ub ? (ua ? when(a) - when(b) : when(b) - when(a)) : ua ? -1 : 1; }) // upcoming first (soonest), then recent past
|
||||
.slice(0, 8);
|
||||
} catch (e) { errors.push('Calendar: ' + e.message); }
|
||||
json(res, 200, { tasks: foundTasks, events: foundEvents, errors });
|
||||
}
|
||||
|
||||
module.exports = { handle };
|
||||
Reference in new issue
Block a user