Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions joinly/providers/browser/platforms/google_meet.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import asyncio
import contextlib
import re
from datetime import UTC, datetime
from typing import Any, ClassVar

from playwright.async_api import Page
Expand Down Expand Up @@ -107,16 +106,12 @@ async def get_chat_history(self, page: Page) -> MeetingChatHistory:
parts = [p.strip() for p in inner_text.splitlines() if p.strip()]

sender: str | None = None
ts: float | None = None
ts: str | None = None
for part in parts:
clean = re.sub(r"[\u00A0\u202F]", "", part).strip()

if _TIME_RX.fullmatch(clean):
fmt = "%I:%M%p" if clean[-2:].upper() in ("AM", "PM") else "%H:%M"
t = datetime.strptime(clean.upper(), fmt).replace(tzinfo=UTC)
today = datetime.now(UTC).date()
t = t.replace(year=today.year, month=today.month, day=today.day)
ts = t.timestamp()
ts = clean
elif sender is None:
sender = clean or None

Expand Down
8 changes: 1 addition & 7 deletions joinly/providers/browser/platforms/teams.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import asyncio
import logging
import re
from datetime import datetime
from typing import Any, ClassVar

from playwright.async_api import Page
Expand Down Expand Up @@ -119,12 +118,7 @@ async def get_chat_history(self, page: Page) -> MeetingChatHistory:
if not await content_el.count():
continue
text = (await content_el.first.inner_text()).strip()
dt_attr = await el.locator("time[datetime]").first.get_attribute("datetime")
ts = (
datetime.fromisoformat(dt_attr.rstrip("Z")).timestamp()
if dt_attr
else None
)
ts = await el.locator("time[datetime]").first.get_attribute("datetime")
author_locator = el.locator('[data-tid="message-author-name"]').first
sender_text = await author_locator.text_content() or ""
sender = sender_text.strip() or None
Expand Down
13 changes: 2 additions & 11 deletions joinly/providers/browser/platforms/zoom.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import contextlib
import logging
import re
from datetime import UTC, datetime
from typing import Any, ClassVar

from playwright.async_api import Page
Expand Down Expand Up @@ -155,7 +154,7 @@ async def get_chat_history(self, page: Page) -> MeetingChatHistory:
parts = [p.strip() for p in aria.split(",")]

sender: str | None = None
ts: float | None = None
ts: str | None = None

if parts and len(parts) >= 3: # noqa: PLR2004
first = parts[0]
Expand All @@ -167,15 +166,7 @@ async def get_chat_history(self, page: Page) -> MeetingChatHistory:

raw_time = re.sub(r"[\u00A0\u202F]", "", parts[1]).strip()
if _TIME_RX.fullmatch(raw_time):
if raw_time[-2:].upper() in {"AM", "PM"}:
fmt = "%I:%M %p" if " " in raw_time else "%I:%M%p"
else:
fmt = "%H:%M"
clean_time = raw_time.upper().strip()
t = datetime.strptime(clean_time, fmt).replace(tzinfo=UTC)
today = datetime.now(UTC).date()
t = t.replace(year=today.year, month=today.month, day=today.day)
ts = t.timestamp()
ts = raw_time

text = ",".join(parts[2:]).strip()

Expand Down
13 changes: 2 additions & 11 deletions joinly/types.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from collections.abc import Iterable
from dataclasses import dataclass
from datetime import UTC, datetime
from enum import Enum

from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, computed_field
Expand Down Expand Up @@ -226,24 +225,16 @@ class MeetingChatMessage(BaseModel):

Attributes:
text (str): The content of the chat message.
timestamp (float): The timestamp of when the message was sent.
timestamp (str | None): The timestamp of when the message was sent.
sender (str | None): The sender of the message, if available.
"""

text: str
timestamp: float | None = Field(..., exclude=True)
timestamp: str | None = None
sender: str | None = None

model_config = ConfigDict(frozen=True)

@computed_field(alias="timestamp")
@property
def timestamp_readable(self) -> str | None:
"""Expose ISO-formatted timestamp in JSON instead of the float."""
if self.timestamp:
return datetime.fromtimestamp(self.timestamp, tz=UTC).isoformat()
return None


class MeetingChatHistory(BaseModel):
"""A class to represent the chat history of a meeting."""
Expand Down