Files
Ingress/models.py
Matteo Rosati 6416ad2018 init
2026-01-12 11:28:14 +01:00

122 lines
3.8 KiB
Python

from dataclasses import dataclass
from typing import List, Any, Optional
from enum import Enum
import re
class EventType(Enum):
RESONATOR_DEPLOYED = "RESONATOR_DEPLOYED"
RESONATOR_DESTROYED = "RESONATOR_DESTROYED"
PORTAL_CAPTURED = "PORTAL_CAPTURED"
PORTAL_NEUTRALIZED = "PORTAL_NEUTRALIZED"
PORTAL_UNDER_ATTACK = "PORTAL_UNDER_ATTACK"
LINK_CREATED = "LINK_CREATED"
LINK_DESTROYED = "LINK_DESTROYED"
CONTROL_FIELD_CREATED = "CONTROL_FIELD_CREATED"
UNKNOWN = "UNKNOWN"
EVENT_TYPE_KEYWORDS = {
EventType.RESONATOR_DEPLOYED: ["deployed a Resonator on"],
EventType.RESONATOR_DESTROYED: ["destroyed a Resonator on"],
EventType.LINK_DESTROYED: ["destroyed the", "Link"],
EventType.PORTAL_CAPTURED: ["captured"],
EventType.PORTAL_NEUTRALIZED: ["neutralized by"],
EventType.PORTAL_UNDER_ATTACK: ["is under attack by"],
EventType.LINK_CREATED: ["linked from"],
EventType.CONTROL_FIELD_CREATED: ["created a Control Field"],
}
@dataclass
class Markup:
type: str
plain: str
team: str = ""
name: str = ""
address: str = ""
latE6: int = 0
lngE6: int = 0
@dataclass
class Plext:
id: str
timestamp: int
text: str
team: str
plext_type: str
categories: int
markup: List[Markup]
@classmethod
def from_json(cls, data: List[Any]) -> "Plext":
plext_data = data[2]["plext"]
markup_data = plext_data["markup"]
markup = []
for m in markup_data:
markup_type = m[0]
markup_details = m[1]
markup.append(
Markup(
type=markup_type,
plain=markup_details.get("plain", ""),
team=markup_details.get("team", ""),
name=markup_details.get("name", ""),
address=markup_details.get("address", ""),
latE6=markup_details.get("latE6", 0),
lngE6=markup_details.get("lngE6", 0),
)
)
return cls(
id=data[0],
timestamp=data[1],
text=plext_data["text"],
team=plext_data["team"],
plext_type=plext_data["plextType"],
categories=plext_data["categories"],
markup=markup,
)
def get_event_type(self) -> EventType:
for event_type, keywords in EVENT_TYPE_KEYWORDS.items():
if all(keyword in self.text for keyword in keywords):
# A special case for "captured", to avoid matching "destroyed"
if event_type == EventType.PORTAL_CAPTURED and "destroyed" in self.text:
continue
return event_type
return EventType.UNKNOWN
def get_player_name(self) -> str:
for m in self.markup:
if m.type == "PLAYER":
return m.plain
# If player name is not in markup, try to extract from text
if "agent" in self.text:
match = re.search(r"agent (\w+)", self.text)
if match:
return match.group(1)
return ""
def get_portal_name(self) -> str:
for m in self.markup:
if m.type == "PORTAL":
return m.name
# If portal name is not in markup, try to extract from text
match = re.search(r"(?:deployed|destroyed|captured|linked from|created a Control Field @) (.+?) \(", self.text)
if not match:
match = re.search(r"Your Portal (.+?) is under attack by", self.text)
if not match:
match = re.search(r"Your Portal (.+?) neutralized by", self.text)
if match:
return match.group(1).strip()
return ""
def get_event_coordinates(self) -> Optional[tuple[int, int]]:
for m in self.markup:
if m.type == "PORTAL":
return m.latE6, m.lngE6
return None