upstream: integrar Oasis 1.3.1
Base del merge a tres bandas: git 0.9.5 de epsylon, esta rama y el src de la
APK oficial 1.3.1 (la variante movil: OASIS_MOBILE, regex sin \p{}, audio y
video de Android). Corre en el mismo nodejs-mobile 18.20.4 que ya usabamos.
Se conserva de la rama: Karvan, identidades y multicuenta, topbar y barra
inferior, borrado de EXIF sin sharp, filtro hot del foro, RTC sin STUN y los
modulos apagados en movil (wallet, banking, torrents).
Se toma de upstream lo que ya hace de serie: respuesta citada en chats, ssb-lan
en movil, configuracion en ~/.ssb/oasis (sobrevive a reinstalar el backend).
El asistente de bienvenida deja elegir workflow tambien en movil.
This commit is contained in:
parent
8d838dd8b1
commit
c332afd6ea
265 changed files with 80970 additions and 29167 deletions
80
src/backend/desktopNotify.js
Normal file
80
src/backend/desktopNotify.js
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { spawn } = require('child_process');
|
||||
const { getConfig } = require('../configs/config-manager.js');
|
||||
|
||||
const REPEAT_MS = 60000;
|
||||
const ICON = path.join(__dirname, '..', 'client', 'assets', 'images', 'snh-oasis.jpg');
|
||||
const recent = new Map();
|
||||
|
||||
const onPath = (bin) => (process.env.PATH || '').split(path.delimiter).some(d => d && fs.existsSync(path.join(d, bin)));
|
||||
|
||||
const i18nNow = () => {
|
||||
const all = require('../client/assets/translations/i18n');
|
||||
let lang = 'en';
|
||||
try { lang = getConfig().language || 'en'; } catch (_) {}
|
||||
return { ...all.en, ...(all[lang] || {}) };
|
||||
};
|
||||
|
||||
const displayName = (id, name) => {
|
||||
const n = String(name || '').trim();
|
||||
if (!n || n === 'Redacted' || n === String(id || '').replace(/^@/, '').slice(0, 8)) return String(id || '');
|
||||
return n.startsWith('@') ? n : `@${n}`;
|
||||
};
|
||||
|
||||
const MOBILE_QUEUE = path.join(__dirname, '..', '..', '.notifications.json');
|
||||
const queueForAndroid = (keyword, body, line, key) => {
|
||||
try {
|
||||
let list = [];
|
||||
try { list = JSON.parse(fs.readFileSync(MOBILE_QUEUE, 'utf8')); } catch (_) { list = []; }
|
||||
if (!Array.isArray(list)) list = [];
|
||||
const t = i18nNow();
|
||||
const k = String(keyword || '');
|
||||
const route = k === t.phoneTitle ? '/phone' : k === t.inbox ? '/inbox' : k === t.emergenciesTitle ? '/emergencies' : '/';
|
||||
const entry = { id: Date.now() + '-' + Math.random().toString(36).slice(2, 8), keyword: k || 'Oasis', body, line, route, key: key ? String(key) : null, ts: Date.now() };
|
||||
if (entry.key && entry.key.indexOf('call:') === 0) {
|
||||
const ringing = String(t.phoneIsCalling || '');
|
||||
entry.caller = ringing && body.endsWith(ringing) ? body.slice(0, body.length - ringing.length).trim() : body;
|
||||
entry.accept = String(t.phoneAnswer || '');
|
||||
entry.reject = String(t.phoneReject || '');
|
||||
}
|
||||
list.push(entry);
|
||||
while (list.length > 20) list.shift();
|
||||
fs.writeFileSync(MOBILE_QUEUE, JSON.stringify(list));
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const notify = (keyword, text, key = null, opts = {}) => {
|
||||
const onMobile = process.env.OASIS_MOBILE === '1';
|
||||
if (!onMobile && !onPath('notify-send')) return false;
|
||||
const body = String(text || '').replace(/\s+/g, ' ').trim().replace(/[.。!…]+$/, '').slice(0, 200);
|
||||
const line = `${String(keyword || 'Oasis').toUpperCase()}: ${body}...`;
|
||||
const now = Date.now();
|
||||
const dedupe = key || line;
|
||||
for (const [k, t] of recent) if (now - t > REPEAT_MS) recent.delete(k);
|
||||
if (recent.has(dedupe)) return false;
|
||||
recent.set(dedupe, now);
|
||||
if (onMobile) return queueForAndroid(keyword, body, line, key);
|
||||
const actions = Array.isArray(opts.actions) ? opts.actions.filter(x => x && x.key && x.label) : [];
|
||||
const extra = [
|
||||
...(opts.timeoutMs > 0 ? ['-t', String(Math.round(opts.timeoutMs))] : []),
|
||||
...actions.flatMap(x => ['-A', `${x.key}=${x.label}`])
|
||||
];
|
||||
try {
|
||||
const p = spawn('notify-send', ['-a', 'Oasis', ...(fs.existsSync(ICON) ? ['-i', ICON] : []), ...extra, line], { stdio: ['ignore', actions.length ? 'pipe' : 'ignore', 'ignore'] });
|
||||
p.on('error', () => {});
|
||||
if (actions.length && typeof opts.onAction === 'function') {
|
||||
let out = '';
|
||||
p.stdout.on('data', (d) => { out += d; });
|
||||
p.on('close', () => { const chosen = out.trim(); if (actions.some(x => x.key === chosen)) opts.onAction(chosen); });
|
||||
}
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { notify, i18nNow, displayName };
|
||||
Loading…
Add table
Add a link
Reference in a new issue