113 lines
3.6 KiB
Python
113 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""TeamPulse — Teams meeting chat audit tool.
|
|
|
|
Usage:
|
|
.venv/bin/python main.py [meeting-url]
|
|
|
|
If no URL is given, the clipboard is checked for a Teams meeting link.
|
|
If neither yields a URL, navigate manually in the browser window.
|
|
Post !start "Presenter Name" and !stop in the chat to define a time window.
|
|
A Markdown memo is saved to the current directory when the window closes.
|
|
"""
|
|
import platform
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent / "src"))
|
|
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
from teampulse.auth import create_context, ensure_logged_in
|
|
from teampulse.memo import generate_memo, save_memo
|
|
from teampulse.models import AuditEntry
|
|
from teampulse.monitor import Monitor
|
|
from teampulse.resolver import Resolver
|
|
|
|
CACHE_PATH = Path.home() / ".teampulse" / "cache.json"
|
|
TEAMS_URL = "https://teams.microsoft.com"
|
|
|
|
|
|
def _read_clipboard() -> str:
|
|
try:
|
|
system = platform.system()
|
|
if system == "Darwin":
|
|
return subprocess.check_output(["pbpaste"]).decode("utf-8").strip()
|
|
elif system == "Linux":
|
|
return subprocess.check_output(["xclip", "-selection", "clipboard", "-o"]).decode("utf-8").strip()
|
|
elif system == "Windows":
|
|
return subprocess.check_output(
|
|
["powershell", "-command", "Get-Clipboard"], text=True
|
|
).strip()
|
|
except Exception:
|
|
pass
|
|
return ""
|
|
|
|
|
|
def _get_meeting_url() -> str | None:
|
|
if len(sys.argv) > 1:
|
|
url = sys.argv[1].strip()
|
|
if "teams.microsoft.com" in url or "teams.live.com" in url:
|
|
print(f"Meeting-URL aus Argument: {url[:60]}...")
|
|
return url
|
|
|
|
clip = _read_clipboard()
|
|
if "teams.microsoft.com" in clip or "teams.live.com" in clip:
|
|
print(f"Meeting-URL aus Clipboard: {clip[:60]}...")
|
|
return clip
|
|
|
|
return None
|
|
|
|
|
|
def main():
|
|
meeting_url = _get_meeting_url()
|
|
|
|
with sync_playwright() as playwright:
|
|
print("Starte Browser...")
|
|
context = create_context(playwright, headless=False)
|
|
ensure_logged_in(context)
|
|
|
|
page = context.new_page()
|
|
|
|
# Always load Teams main first so user-name selectors are available
|
|
page.goto(TEAMS_URL)
|
|
|
|
monitor = Monitor(page=page, current_user="")
|
|
print("Lese eingeloggten Nutzer...")
|
|
current_user = monitor.get_current_user_display_name()
|
|
monitor._current_user = current_user
|
|
print(f"Eingeloggt als: {current_user}")
|
|
|
|
if meeting_url:
|
|
print(f"\nNavigiere zur Meeting-Chat-Seite...")
|
|
page.goto(meeting_url)
|
|
else:
|
|
print("\nKeine Meeting-URL gefunden — bitte im Browser zur Chat-Seite navigieren.")
|
|
print("Tipp: Meeting-Link aus Teams kopieren, dann Skript neu starten.\n")
|
|
|
|
print("\nPoste '!start \"Name des Vortragenden\"' im Chat um zu beginnen.\n")
|
|
|
|
window = monitor.run()
|
|
|
|
resolver = Resolver(cache_path=CACHE_PATH, page=page)
|
|
print(f"\nLöse {len(window.entries)} E-Mail-Adresse(n) auf...")
|
|
resolved_entries = []
|
|
for entry in window.entries:
|
|
email = resolver.resolve(entry.display_name)
|
|
print(f" {entry.display_name} → {email}")
|
|
resolved_entries.append(AuditEntry(display_name=entry.display_name, email=email))
|
|
|
|
window.entries = resolved_entries
|
|
|
|
memo_content = generate_memo(window)
|
|
path = save_memo(memo_content)
|
|
|
|
print(f"\nMemo gespeichert: {path}")
|
|
print("\n" + memo_content)
|
|
|
|
context.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|