This commit is contained in:
2025-10-19 14:29:51 -05:00
parent a5881d64eb
commit ece044302a
3 changed files with 137 additions and 3 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
username: "magbot"
password: "zC1b9qCKT8Cv0D"
room_id: "!ajyOBbqoCIbBhEqNPU:matrix.org" # Magbot Testing Space
# room_id: "!ajyOBbqoCIbBhEqNPU:matrix.org" # Magbot Testing Space
# room_id: "!HXiyYVEZOMRtkyvarN:jupiterbroadcasting.com" # Da Lunch
# room_id: "!gJYEKNllaubNlNkFIj:jupiterbroadcasting.com" # The Main Chat
room_id: "!gJYEKNllaubNlNkFIj:jupiterbroadcasting.com" # The Main Chat
lookback_seconds: 86400 # 24 hours
lookback_limit: 400
dump_mode: True
+134
View File
@@ -107,6 +107,19 @@ class Room:
UNIQUE(sender, timestamp)
)
''')
# New: table to log all !countvotes detections (prevents duplicates)
c.execute('''
CREATE TABLE IF NOT EXISTS countvotes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
event_id TEXT,
sender TEXT,
timestamp INTEGER,
datetime TEXT,
UNIQUE(event_id),
UNIQUE(sender, timestamp)
)
''')
conn.commit()
conn.close()
@@ -319,6 +332,116 @@ class Room:
conn.close()
return inserted
# New: record a !countvotes detection; returns True if newly recorded (not duplicate)
def record_countvotes(self, sender, timestamp, event_id=None):
"""Record a !countvotes detection; returns True if newly recorded (not duplicate)"""
conn = sqlite3.connect(self.db_path)
c = conn.cursor()
dt_str = datetime.datetime.fromtimestamp(int(timestamp)).isoformat(sep=' ', timespec='seconds')
c.execute('''
INSERT OR IGNORE INTO countvotes (event_id, sender, timestamp, datetime)
VALUES (?, ?, ?, ?)
''', (event_id, sender, int(timestamp), dt_str))
inserted = c.rowcount == 1
conn.commit()
conn.close()
return inserted
async def count_votes(self):
"""Count upvotes for each suggestion and return formatted results."""
# Get recent messages to find suggestion posts and their reactions
batch_size = self.config.batch_size
next_batch = None
suggestion_votes = {}
all_events = []
# First pass: collect all recent events (both messages and reactions)
for _ in range(15): # Look back further to catch more events
response = await self.client.room_messages(
self.config.room_id,
start=next_batch,
limit=batch_size,
direction="b"
)
if not hasattr(response, "chunk") or not response.chunk:
break
all_events.extend(response.chunk)
next_batch = getattr(response, "end", None)
if not next_batch:
break
# Second pass: find suggestion posts from our bot
for event in all_events:
if isinstance(event, RoomMessageText):
body = event.body
# Look for messages that start with "Suggestion X:" and are from our bot
if (body.startswith("Suggestion ") and ":" in body and
event.sender == self.user_id):
try:
# Extract suggestion number and content
parts = body.split(":", 2)
if len(parts) >= 2:
suggestion_num = parts[0].replace("Suggestion ", "").strip()
content = ":".join(parts[1:]).strip()
event_id = getattr(event, "event_id", None)
if event_id:
suggestion_votes[suggestion_num] = {
'content': content,
'event_id': event_id,
'votes': 0,
'voters': set()
}
except Exception as e:
print(f"Error parsing suggestion: {e}")
continue
if not suggestion_votes:
return "No suggestion posts found to count votes for."
# Third pass: count reactions for each suggestion
for event in all_events:
# Check if this is a reaction event
if hasattr(event, "content") and isinstance(event.content, dict):
relates_to = event.content.get("m.relates_to", {})
if (relates_to.get("rel_type") == "m.annotation" and
relates_to.get("key") == "👍"):
target_event_id = relates_to.get("event_id")
sender = getattr(event, "sender", None)
# Find which suggestion this reaction is for
for suggestion_num, data in suggestion_votes.items():
if (data['event_id'] == target_event_id and
sender and sender not in data['voters'] and
sender != self.user_id): # Don't count bot's own reactions
data['voters'].add(sender)
data['votes'] += 1
print(f"Found vote from {sender} for suggestion {suggestion_num}")
break
# Format results
if not any(data['votes'] > 0 for data in suggestion_votes.values()):
return "No votes found for any suggestions."
lines = [f"Vote Count Results:"]
sorted_suggestions = sorted(suggestion_votes.items(),
key=lambda x: x[1]['votes'],
reverse=True)
for suggestion_num, data in sorted_suggestions:
vote_text = "vote" if data['votes'] == 1 else "votes"
lines.append(f"Suggestion {suggestion_num}: {data['votes']} {vote_text}")
# Truncate long suggestions for readability
content = data['content']
if len(content) > 80:
content = content[:77] + "..."
lines.append(f" └─ {content}")
return "\n".join(lines)
# Renamed and expanded to handle both !gettitles and !mayhem commands
async def wait_for_commands(self, since_ms=None):
"""Wait for and handle commands like !gettitles and !mayhem"""
@@ -360,6 +483,17 @@ class Room:
if self.record_mayhem(event.sender, ts_seconds, event_id):
await self.alert_post("Standby. Ollama is being instructed to generate mayhem. This may take a moment...")
await self.alert_post(self.generate_mayhem())
# Handle !countvotes
elif body == "!countvotes":
event_id = getattr(event, "event_id", None)
ts_seconds = int(getattr(event, "server_timestamp", 0) // 1000)
if not self.record_countvotes(event.sender, ts_seconds, event_id):
continue
print("!countvotes detected")
await self.alert_post("Counting votes... This may take a moment...")
vote_results = await self.count_votes()
await self.alert_post(vote_results)
# Keep the old method name for backward compatibility but mark as deprecated
async def wait_for_gettitles(self, since_ms=None, exact=True):
+1 -1
View File
@@ -16,7 +16,7 @@ async def main():
return
await room.alert_post("SCRAPER LOGGED IN")
# await room.alert_post("SCRAPER LOGGED IN")
# Initial sync
await room.client.sync(timeout=3000)