| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- const fs = require('fs');
- const path = require('path');
- const { getConfig } = require('../configs/config-manager.js');
- const COOLDOWN_MS = 5 * 60 * 1000;
- const statePath = path.join(__dirname, '../configs/follow_state.json');
- const readJson = (p, fallback) => {
- try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch (e) { return fallback; }
- };
- const writeJson = (p, data) => {
- try { fs.writeFileSync(p, JSON.stringify(data, null, 2)); } catch (e) {}
- };
- const loadState = () => {
- const s = readJson(statePath, { pending: [], accepted: [], lastAcceptMs: 0 });
- if (!Array.isArray(s.pending)) s.pending = [];
- if (!Array.isArray(s.accepted)) s.accepted = [];
- if (typeof s.lastAcceptMs !== 'number') s.lastAcceptMs = 0;
- return s;
- };
- const saveState = (s) => writeJson(statePath, s);
- const wishMutualsOnly = () => getConfig().wish === 'mutuals';
- const pmMutualsOnly = () => getConfig().pmVisibility === 'mutuals';
- const isFrictionActive = () => wishMutualsOnly() || pmMutualsOnly();
- const listPending = () => loadState().pending;
- const enqueuePending = (followerId, extra = {}) => {
- if (!followerId) return false;
- const s = loadState();
- if (s.pending.some(x => x.followerId === followerId)) return false;
- s.pending.push({ followerId, at: new Date().toISOString(), ...extra });
- saveState(s);
- return true;
- };
- const removePending = (followerId) => {
- const s = loadState();
- s.pending = s.pending.filter(x => x.followerId !== followerId);
- saveState(s);
- };
- const loadAccepted = () => loadState().accepted;
- const isAccepted = (followerId) => loadState().accepted.includes(followerId);
- const addAccepted = (followerId) => {
- if (!followerId) return;
- const s = loadState();
- if (!s.accepted.includes(followerId)) { s.accepted.push(followerId); saveState(s); }
- };
- const removeAccepted = (followerId) => {
- const s = loadState();
- s.accepted = s.accepted.filter(x => x !== followerId);
- saveState(s);
- };
- const canAutoAcceptNow = () => (Date.now() - loadState().lastAcceptMs) >= COOLDOWN_MS;
- const markAutoAccept = () => {
- const s = loadState();
- s.lastAcceptMs = Date.now();
- saveState(s);
- };
- const makeMutualCache = (friendModel) => {
- const cache = new Map();
- const frictionActive = isFrictionActive();
- return async (otherId) => {
- if (!otherId) return false;
- if (cache.has(otherId)) return cache.get(otherId);
- try {
- const rel = await friendModel.getRelationship(otherId);
- const basic = !!(rel && rel.following && rel.followsMe);
- const mutual = frictionActive ? (basic && isAccepted(otherId)) : basic;
- cache.set(otherId, mutual);
- return mutual;
- } catch (e) {
- cache.set(otherId, false);
- return false;
- }
- };
- };
- const authorOf = (item) => {
- if (!item) return null;
- if (item.value && item.value.author) return item.value.author;
- if (item.author) return item.author;
- if (item.feed) return item.feed;
- if (item.id && typeof item.id === 'string' && item.id.startsWith('@')) return item.id;
- return null;
- };
- const applyMutualSupportFilter = async (items, viewerId, friendModel) => {
- if (!wishMutualsOnly()) return items;
- if (!Array.isArray(items)) return items;
- const isMutual = makeMutualCache(friendModel);
- const out = [];
- for (const it of items) {
- const a = authorOf(it);
- if (!a || a === viewerId) { out.push(it); continue; }
- if (await isMutual(a)) out.push(it);
- }
- return out;
- };
- const canSendPmTo = async (viewerId, recipientId, friendModel) => {
- if (!pmMutualsOnly()) return { allowed: true };
- if (viewerId === recipientId) return { allowed: true };
- const isMutual = makeMutualCache(friendModel);
- if (await isMutual(recipientId)) return { allowed: true };
- return { allowed: false, reason: 'non-mutual' };
- };
- module.exports = {
- COOLDOWN_MS,
- wishMutualsOnly,
- pmMutualsOnly,
- isFrictionActive,
- listPending,
- enqueuePending,
- removePending,
- loadAccepted,
- isAccepted,
- addAccepted,
- removeAccepted,
- canAutoAcceptNow,
- markAutoAccept,
- makeMutualCache,
- applyMutualSupportFilter,
- canSendPmTo,
- authorOf,
- };
|