Track media first_seen_at and last_seen_at timestamps

- Add last_seen_at column to Media table (updated on every encounter)
- first_seen_at tracks initial discovery
- last_seen_at tracks most recent sighting
- MediaSource.discovered_at already tracks per-page first link time
- Enables tracking media reuse across the web
This commit is contained in:
Russell Ballestrini 2026-01-01 16:41:52 -05:00
parent 6491a2763f
commit e61b9cfd04

View file

@ -74,6 +74,7 @@ class Media(Base):
title = Column(Text)
score = Column(Integer, default=SCORE_THUMBNAIL) # Quality score
first_seen_at = Column(Text, nullable=False)
last_seen_at = Column(Text) # Updated each time media is encountered
upgraded_at = Column(Text) # When score was upgraded (for live feed)
analysis_status = Column(String(20), default='pending')
analysis_result = Column(Text) # JSON
@ -85,6 +86,7 @@ class Media(Base):
Index('idx_media_analysis', 'analysis_status'),
Index('idx_media_score', 'score'),
Index('idx_media_upgraded', 'upgraded_at'),
Index('idx_media_last_seen', 'last_seen_at'),
)
@ -235,6 +237,13 @@ class Database:
except Exception:
pass
# Add last_seen_at column to media table
try:
await conn.execute(text("ALTER TABLE media ADD COLUMN last_seen_at TEXT"))
await conn.execute(text("CREATE INDEX IF NOT EXISTS idx_media_last_seen ON media(last_seen_at)"))
except Exception:
pass # Column already exists
# Create FTS5 virtual table (SQLAlchemy doesn't handle virtual tables)
# Includes description and keywords for better search scoring
# Check if FTS table needs rebuilding (old schema didn't have description/keywords)
@ -402,15 +411,19 @@ class Database:
now = datetime.now(timezone.utc).isoformat()
async with self.session() as session:
# Insert or ignore media record using SQLite upsert
# Insert or update media record - always update last_seen_at
media_stmt = sqlite_insert(Media).values(
md5_hash=md5_hash,
media_type=media_type,
mime_type=mime_type,
file_size=file_size,
score=score,
first_seen_at=now
).on_conflict_do_nothing(index_elements=['md5_hash'])
first_seen_at=now,
last_seen_at=now
).on_conflict_do_update(
index_elements=['md5_hash'],
set_={'last_seen_at': now}
)
await session.execute(media_stmt)
# Insert or ignore source context