Plugin sms: lettura SMS/iMessage da Messaggi, invio con scelta del servizio, fonte per il monitor
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
6aac16b679
commit
6fad5e1f4a
7 files changed
+241
-9
No files matched your search
+26
-1
@@ -101,6 +101,30 @@ class Monitor:
|
||||
self.state["wa_ts"] = max(r[1] for r in rows)
|
||||
return [{"fonte": "WhatsApp", "chi": chat if sender == chat else f"{sender} (gruppo {chat})", "testo": text[:300], "ref": f"wa:{rid}"} for rid, ts, chat, sender, text in rows]
|
||||
|
||||
def _collect_sms(self, baseline: bool) -> list[dict]:
|
||||
try:
|
||||
import importlib
|
||||
from avatar.plugins import registry
|
||||
registry.load()
|
||||
sms = importlib.import_module("avatar_plugins.sms")
|
||||
except Exception:
|
||||
return []
|
||||
if not sms.DB.exists():
|
||||
return []
|
||||
last = self.state.get("sms_rowid")
|
||||
try:
|
||||
rows = sms._query("AND m.is_from_me = 0 AND m.ROWID > ?", (last if last is not None else 10**12,), 40) if not (last is None or baseline) else []
|
||||
if last is None or baseline:
|
||||
top = sms._query("", (), 1)
|
||||
self.state["sms_rowid"] = top[0]["id"] if top else 0
|
||||
return []
|
||||
except Exception as err:
|
||||
print(f"[monitor] messaggi: {err}")
|
||||
return []
|
||||
if rows:
|
||||
self.state["sms_rowid"] = max(r["id"] for r in rows)
|
||||
return [{"fonte": "Messaggi", "chi": r["chi"], "testo": r["testo"][:300], "ref": f"sms:{r['id']}"} for r in rows]
|
||||
|
||||
def _collect_telegram(self, baseline: bool) -> list[dict]:
|
||||
try:
|
||||
from avatar import telegram_client as tg
|
||||
@@ -176,7 +200,8 @@ class Monitor:
|
||||
def scan(self, baseline: bool = False) -> list[dict]:
|
||||
with _lock:
|
||||
first = self.state.get("mail_rowid") is None and self.state.get("wa_ts") is None and not self.state.get("tg")
|
||||
items = self._collect_mail(baseline or first) + self._collect_whatsapp(baseline or first) + self._collect_telegram(baseline or first)
|
||||
items = (self._collect_mail(baseline or first) + self._collect_whatsapp(baseline or first)
|
||||
+ self._collect_sms(baseline or first) + self._collect_telegram(baseline or first))
|
||||
seen = set(self.state.get("seen", []))
|
||||
items = [it for it in items if it["ref"] not in seen]
|
||||
self.state.setdefault("seen", []).extend(it["ref"] for it in items)
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
"""Rubrica: numeri di telefono ed email → nomi, dai Contatti di macOS (cache in memoria)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import threading
|
||||
import time
|
||||
|
||||
_map: dict[str, str] = {}
|
||||
_loaded_at = 0.0
|
||||
_lock = threading.Lock()
|
||||
|
||||
|
||||
def normalize(number: str) -> str:
|
||||
digits = re.sub(r"\D", "", number or "")
|
||||
if digits.startswith("00"):
|
||||
digits = digits[2:]
|
||||
if len(digits) == 10 and digits.startswith("3"):
|
||||
digits = "39" + digits
|
||||
return digits
|
||||
|
||||
|
||||
def _load() -> None:
|
||||
global _loaded_at
|
||||
import Contacts
|
||||
store = Contacts.CNContactStore.alloc().init()
|
||||
keys = [Contacts.CNContactGivenNameKey, Contacts.CNContactFamilyNameKey, Contacts.CNContactOrganizationNameKey,
|
||||
Contacts.CNContactPhoneNumbersKey, Contacts.CNContactEmailAddressesKey]
|
||||
req = Contacts.CNContactFetchRequest.alloc().initWithKeysToFetch_(keys)
|
||||
new: dict[str, str] = {}
|
||||
|
||||
def visit(c, stop):
|
||||
name = f"{c.givenName()} {c.familyName()}".strip() or c.organizationName()
|
||||
if not name:
|
||||
return
|
||||
for ph in c.phoneNumbers():
|
||||
d = normalize(ph.value().stringValue())
|
||||
if len(d) >= 8:
|
||||
new[d] = name
|
||||
for e in c.emailAddresses():
|
||||
new[str(e.value()).lower()] = name
|
||||
|
||||
store.enumerateContactsWithFetchRequest_error_usingBlock_(req, None, visit)
|
||||
_map.clear()
|
||||
_map.update(new)
|
||||
_loaded_at = time.time()
|
||||
|
||||
|
||||
def name_for(handle: str) -> str:
|
||||
"""Nome del contatto per un numero o un'email; altrimenti il valore originale."""
|
||||
with _lock:
|
||||
if time.time() - _loaded_at > 3600:
|
||||
try:
|
||||
_load()
|
||||
except Exception:
|
||||
pass
|
||||
h = (handle or "").strip()
|
||||
if "@" in h:
|
||||
return _map.get(h.lower(), h)
|
||||
d = normalize(h)
|
||||
return _map.get(d) or _map.get(d[-10:]) or h
|
||||
Reference in new issue
Block a user