Not much cleanup

This commit is contained in:
2025-09-24 10:14:53 -05:00
parent 72376b3478
commit c17ffd154c
6 changed files with 71 additions and 156 deletions
+1
View File
@@ -2,3 +2,4 @@ config.yaml
*.db
__pycache__
.env
.env/
+16 -1
View File
@@ -1,8 +1,23 @@
# titbot
Title-bot for Jupiter Broadcasting's "The Launch" chat room. Why didn't I just use the old bot?
## Usage
- Single entry point: `python3 titlebot.py`
- Configuration:
- config.yaml (ignored by git) or environment variables:
- TITLEBOT_USERNAME, TITLEBOT_PASSWORD, TITLEBOT_ROOM_ID, TITLEBOT_HOMESERVER
- TITLEBOT_LOOKBACK_LIMIT, TITLEBOT_BATCH_SIZE, TITLEBOT_DB_NAME
- dbName is optional; if unset, a per-room DB name is derived automatically.
## TODO:
## Notes
- scraper.py and post_results.py are deprecated wrappers around titlebot.py.
- db.py is deprecated; DB logic lives in room.Room.
- Do not commit virtualenvs. Remove the tracked .env folder:
- git rm -r --cached .env
- git commit -m "Remove tracked venv"
- .gitignore already ignores `.env/`
## TODO:
- Re-write in Rust
- Re-write in Go
- Re-write in Zig
-120
View File
@@ -1,120 +0,0 @@
import re
import sqlite3
import time
import datetime
def safe_db_name(room_id):
safe = re.sub(r'[^a-zA-Z0-9_-]', '_', room_id)
return f"suggestions_{safe}.db"
def init_db(db_path):
conn = sqlite3.connect(db_path)
c = conn.cursor()
c.execute('''
CREATE TABLE IF NOT EXISTS suggestions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user TEXT,
display_name TEXT,
message TEXT,
timestamp INTEGER,
age INTEGER,
is_posted INTEGER DEFAULT 0,
UNIQUE(user, message, timestamp)
)
''')
# Add is_posted column if it doesn't exist
c.execute("PRAGMA table_info(suggestions)")
cols = [row[1] for row in c.fetchall()]
if 'is_posted' not in cols:
c.execute('ALTER TABLE suggestions ADD COLUMN is_posted INTEGER DEFAULT 0')
# New: table for logging !gettitles detections
c.execute('''
CREATE TABLE IF NOT EXISTS gettitles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
event_id TEXT,
sender TEXT,
timestamp INTEGER,
datetime TEXT,
UNIQUE(event_id),
UNIQUE(sender, timestamp)
)
''')
conn.commit()
conn.close()
def write_to_db(posts, db_path):
conn = sqlite3.connect(db_path)
c = conn.cursor()
c.execute('''
CREATE TABLE IF NOT EXISTS suggestions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user TEXT,
display_name TEXT,
message TEXT,
timestamp INTEGER,
age INTEGER,
is_posted INTEGER DEFAULT 0,
UNIQUE(user, message, timestamp)
)
''')
# Add is_posted column if it doesn't exist
c.execute("PRAGMA table_info(suggestions)")
cols = [row[1] for row in c.fetchall()]
if 'is_posted' not in cols:
c.execute('ALTER TABLE suggestions ADD COLUMN is_posted INTEGER DEFAULT 0')
for post in posts:
try:
c.execute(
"INSERT INTO suggestions (user, display_name, message, timestamp, age, is_posted) VALUES (?, ?, ?, ?, ?, ?)",
post.as_tuple()
)
except sqlite3.IntegrityError:
continue
conn.commit()
conn.close()
def update_last_run(room_id):
conn = sqlite3.connect("last_run.db")
c = conn.cursor()
c.execute('''
CREATE TABLE IF NOT EXISTS last_run (
room_id TEXT PRIMARY KEY,
timestamp INTEGER,
datetime TEXT
)
''')
c.execute("PRAGMA table_info(last_run)")
cols = [row[1] for row in c.fetchall()]
if 'datetime' not in cols:
c.execute('ALTER TABLE last_run ADD COLUMN datetime TEXT')
now = int(time.time())
now_str = datetime.datetime.now().isoformat(sep=' ', timespec='seconds')
c.execute('INSERT OR REPLACE INTO last_run (room_id, timestamp, datetime) VALUES (?, ?, ?)', (room_id, now, now_str))
conn.commit()
conn.close()
def get_last_run(room_id):
conn = sqlite3.connect("last_run.db")
c = conn.cursor()
c.execute('''
CREATE TABLE IF NOT EXISTS last_run (
room_id TEXT PRIMARY KEY,
timestamp INTEGER,
datetime TEXT
)
''')
c.execute("PRAGMA table_info(last_run)")
cols = [row[1] for row in c.fetchall()]
if 'datetime' not in cols:
c.execute('ALTER TABLE last_run ADD COLUMN datetime TEXT')
c.execute('SELECT timestamp FROM last_run WHERE room_id = ?', (room_id,))
row = c.fetchone()
conn.close()
if row and row[0] is not None:
try:
return int(row[0])
except Exception:
return 0
return 0
+23 -16
View File
@@ -15,25 +15,32 @@ async def main():
return
# Initial sync establishes the next-batch; after this, listen from "now"
await room.client.sync(timeout=3000)
listen_since_ms = int(time.time() * 1000)
await room.client.sync(timeout=300)
room.get_last_run()
last_post = getattr(room, "last_run", None)
if last_post:
print(f"Last run for this room was at UNIX timestamp {last_post}")
try:
while True:
listen_since_ms = int(time.time() * 1000)
# Wait for !gettitles before posting
await asyncio.wait_for(room.wait_for_gettitles(since_ms=listen_since_ms), timeout=None)
# Then read and post
room.read_db(since_timestamp=last_post, only_unposted=True)
await room.post_suggestions()
await room.close()
room.get_last_run()
last_post = getattr(room, "last_run", None)
if last_post:
print(f"Last run for this room was at UNIX timestamp {last_post}")
# Wait for !gettitles before posting
await room.wait_for_gettitles(since_ms=listen_since_ms)
# Then read and post
room.read_db(since_timestamp=last_post, only_unposted=True)
if room.posts:
await room.post_suggestions()
room.update_last_post()
else:
await room.alert_post("No new unposted suggestions found.")
await asyncio.sleep(1)
finally:
await room.close()
if __name__ == "__main__":
while True:
asyncio.run(main())
time.sleep(2)
asyncio.run(main())
+11 -2
View File
@@ -47,6 +47,7 @@ class Room:
self.db_path = self.safe_db_name(self.config.room_id)
self.init_db()
def safe_db_name(self, room_id):
safe = re.sub(r'[^a-zA-Z0-9_-]', '_', room_id)
@@ -89,7 +90,15 @@ class Room:
conn.close()
async def login_to_matrix(self):
self.client = AsyncClient(self.config.homeserver, self.config.username)
# Initialize client if needed
if self.client is None:
self.client = AsyncClient(self.config.homeserver, self.config.username)
# Reuse existing login if present
if getattr(self.client, "access_token", None):
print("Reusing existing login.")
self.user_id = self.client.user_id
return True
resp = await self.client.login(self.config.password)
if isinstance(resp, LoginResponse):
print("Logged in!")
@@ -416,5 +425,5 @@ class Room:
async def close(self):
if self.client:
await self.client.close()
+20 -17
View File
@@ -7,7 +7,6 @@ import time
from post import Post
from room import Room
async def main():
room = Room()
@@ -16,24 +15,28 @@ async def main():
print("Failed to login")
return
await room.alert_post("SCRAPER LOGGED IN")
# Initial sync
await room.client.sync(timeout=3000)
# Get last run timestamp
room.get_last_run()
if room.last_run:
print(f"Last run for this room was at UNIX timestamp {room.last_run}")
# Initial scrape and write to database
await room.get_convos()
room.write_to_db()
room.update_last_run()
# Close connection
await room.close()
try:
while True:
# Get last run timestamp
room.get_last_run()
if room.last_run:
print(f"Last run for this room was at UNIX timestamp {room.last_run}")
# Scrape and write to database
await room.get_convos()
room.write_to_db()
room.update_last_run()
print(f"Stored {len(room.posts)} suggestions in database.")
await asyncio.sleep(0.5)
finally:
# Close connection
await room.close()
if __name__ == "__main__":
while True:
asyncio.run(main())
time.sleep(5)
print("Loop completed, waiting before next iteration...")
asyncio.run(main())