dockerize!

This commit is contained in:
Matteo Rosati
2026-01-14 23:54:51 +01:00
parent 1e76403565
commit 46ddcc16da
14 changed files with 1362 additions and 18 deletions

View File

@@ -5,6 +5,20 @@ import re
class EventType(Enum):
"""Enumeration of possible Ingress event types.
Attributes:
RESONATOR_DEPLOYED: A resonator was deployed on a portal.
RESONATOR_DESTROYED: A resonator was destroyed on a portal.
PORTAL_CAPTURED: A portal was captured by a faction.
PORTAL_NEUTRALIZED: A portal was neutralized.
PORTAL_UNDER_ATTACK: A portal is under attack.
LINK_CREATED: A link was created between portals.
LINK_DESTROYED: A link was destroyed.
CONTROL_FIELD_CREATED: A control field was created.
UNKNOWN: Unknown event type.
"""
RESONATOR_DEPLOYED = "RESONATOR_DEPLOYED"
RESONATOR_DESTROYED = "RESONATOR_DESTROYED"
PORTAL_CAPTURED = "PORTAL_CAPTURED"
@@ -30,6 +44,18 @@ EVENT_TYPE_KEYWORDS = {
@dataclass
class Markup:
"""Represents markup data within a plext message.
Attributes:
type: The type of markup (e.g., "PLAYER", "PORTAL").
plain: Plain text representation of the markup.
team: Team affiliation (e.g., "RESISTANCE", "ENLIGHTENED").
name: Name associated with the markup (e.g., player name, portal name).
address: Address of the location (for portals).
latE6: Latitude in microdegrees (E6 format).
lngE6: Longitude in microdegrees (E6 format).
"""
type: str
plain: str
team: str = ""
@@ -41,6 +67,18 @@ class Markup:
@dataclass
class Plext:
"""Represents a plext (message) from the Ingress Intel API.
Attributes:
id: Unique identifier for the plext.
timestamp: Timestamp in milliseconds since epoch.
text: The text content of the plext.
team: Team affiliation (e.g., "RESISTANCE", "ENLIGHTENED").
plext_type: Type of plext (e.g., "SYSTEM_BROADCAST", "PLAYER_GENERATED").
categories: Category flags for the plext.
markup: List of Markup objects containing structured data.
"""
id: str
timestamp: int
text: str
@@ -51,6 +89,15 @@ class Plext:
@classmethod
def from_json(cls, data: List[Any]) -> "Plext":
"""Create a Plext instance from raw JSON data.
Args:
data: Raw JSON data from the Ingress API. Expected format is a list
where index 2 contains a dict with a "plext" key.
Returns:
A new Plext instance populated with data from the JSON.
"""
plext_data = data[2]["plext"]
markup_data = plext_data["markup"]
@@ -81,6 +128,12 @@ class Plext:
)
def get_event_type(self) -> EventType:
"""Determine the event type based on the plext text content.
Returns:
The EventType that matches the plext text, or EventType.UNKNOWN if
no match is found.
"""
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"
@@ -90,6 +143,14 @@ class Plext:
return EventType.UNKNOWN
def get_player_name(self) -> str:
"""Extract the player name from the plext.
First attempts to find the player name in the markup. If not found,
attempts to extract it from the text using regex.
Returns:
The player name if found, otherwise an empty string.
"""
for m in self.markup:
if m.type == "PLAYER":
return m.plain
@@ -101,11 +162,23 @@ class Plext:
return ""
def get_portal_name(self) -> str:
"""Extract the portal name from the plext.
First attempts to find the portal name in the markup. If not found,
attempts to extract it from the text using regex patterns for various
event types.
Returns:
The portal name if found, otherwise an empty string.
"""
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)
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:
@@ -115,6 +188,14 @@ class Plext:
return ""
def get_event_coordinates(self) -> Optional[tuple[int, int]]:
"""Extract the coordinates of the portal associated with this event.
Searches the markup for a PORTAL type entry and returns its coordinates.
Returns:
A tuple of (latitude, longitude) in microdegrees (E6 format) if found,
otherwise None.
"""
for m in self.markup:
if m.type == "PORTAL":
return m.latE6, m.lngE6