HPI/my/smscalls.py
Sean Breckenridge 44b756cc6b smscalls: use stdlib for tz, attach readable date
pytz is overkill for this, use the builin
datetime.timezone module (since py ver 3.2)

attach the readable datetime
like 'Sep 12, 2020 9:12:19 AM' to each
of the calls/messages
2020-10-02 19:11:48 +02:00

100 lines
2.7 KiB
Python

"""
Phone calls and SMS messages
"""
from datetime import datetime, timezone
from pathlib import Path
from typing import NamedTuple, Iterator, Set, Tuple
from lxml import etree # type: ignore
from .core.common import get_files
from my.config import smscalls as config
class Call(NamedTuple):
dt: datetime
dt_readable: str
duration_s: int
who: str
@property
def summary(self) -> str:
return f"talked with {self.who} for {self.duration_s} secs"
def _extract_calls(path: Path) -> Iterator[Call]:
tr = etree.parse(str(path))
for cxml in tr.findall('call'):
# TODO we've got local tz here, not sure if useful..
# ok, so readable date is local datetime, changing throughout the backup
yield Call(
dt=_parse_dt_ms(cxml.get('date')),
dt_readable=cxml.get('readable_date'),
duration_s=int(cxml.get('duration')),
who=cxml.get('contact_name') # TODO number if contact is unavail??
# TODO type? must be missing/outgoing/incoming
)
def calls() -> Iterator[Call]:
files = get_files(config.export_path, glob='calls-*.xml')
# TODO always replacing with the latter is good, we get better contact names??
emitted: Set[datetime] = set()
for p in files:
for c in _extract_calls(p):
if c.dt in emitted:
continue
emitted.add(c.dt)
yield c
class Message(NamedTuple):
dt: datetime
dt_readable: str
who: str
message: str
phone_number: str
from_me: bool
def messages() -> Iterator[Message]:
files = get_files(config.export_path, glob='sms-*.xml')
emitted: Set[Tuple[datetime, str, bool]] = set()
for p in files:
for c in _extract_messages(p):
key = (c.dt, c.who, c.from_me)
if key in emitted:
continue
emitted.add(key)
yield c
def _extract_messages(path: Path) -> Iterator[Message]:
tr = etree.parse(str(path))
for mxml in tr.findall('sms'):
yield Message(
dt=_parse_dt_ms(mxml.get('date')),
dt_readable=mxml.get('readable_date'),
who=mxml.get('contact_name'),
message=mxml.get('body'),
phone_number=mxml.get('address'),
from_me=mxml.get('type') == '2', # 1 is received message, 2 is sent message
)
# See https://github.com/karlicoss/HPI/pull/90#issuecomment-702422351
# for potentially parsing timezone from the readable_date
def _parse_dt_ms(d: str) -> datetime:
return datetime.fromtimestamp(int(d) / 1000, tz=timezone.utc)
def stats():
from .core import stat
return {
**stat(calls),
**stat(messages),
}