feat: add human-readable datetime formatting and !lastshow command

IRC plugins now format datetimes as "Wed Mar 11, 10:00 PM EDT" instead
of raw ISO 8601. Configurable timezone defaults to America/New_York.

Adds !lastshow N command to both Limnoria and Sopel plugins, returning
track N from the previous week's show via existing API endpoints.

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-12 05:31:50 -04:00
parent ae66242935
commit 9664b8225d
4 changed files with 167 additions and 2 deletions

View File

@@ -8,6 +8,8 @@ import logging
import re
import urllib.error
import urllib.request
from datetime import datetime
from zoneinfo import ZoneInfo
from supybot import callbacks
from supybot.commands import optional, wrap
@@ -73,6 +75,14 @@ def _api_post(base_url: str, path: str, token: str, body: dict | None = None) ->
# --- Formatting --------------------------------------------------------------
def format_dt(iso_string: str | None, tz_name: str = "America/New_York") -> str:
if not iso_string:
return "never"
dt = datetime.fromisoformat(iso_string)
local = dt.astimezone(ZoneInfo(tz_name))
return local.strftime("%a %b %-d, %-I:%M %p %Z")
_MAX_IRC_LINE = 430
@@ -195,6 +205,45 @@ class NtrPlaylist(callbacks.Plugin):
return
irc.reply(format_playlist(data))
@wrap([optional("text")])
def lastshow(self, irc, msg, args, text):
"""<position>
Returns a track from last week's show by position number.
"""
if not text or not text.strip():
irc.reply("Usage: !lastshow <position>")
return
try:
position = int(text.strip())
except ValueError:
irc.reply("Usage: !lastshow <position>")
return
base_url = self.registryValue("apiBaseUrl")
try:
shows = _api_get(base_url, "/shows?limit=2")
except ApiError as exc:
LOGGER.warning("API error for lastshow: %s", exc)
irc.reply(exc.detail)
return
if len(shows) < 2:
irc.reply("No previous show found")
return
prev_show_id = shows[1]["id"]
try:
data = _api_get(base_url, f"/shows/{prev_show_id}")
except ApiError as exc:
LOGGER.warning("API error for lastshow show %s: %s", prev_show_id, exc)
irc.reply(exc.detail)
return
tracks = data.get("tracks", [])
track = next((t for t in tracks if t.get("position") == position), None)
if not track:
episode = data.get("episode_number", "?")
irc.reply(f"No track at position {position} in episode {episode}")
return
irc.reply(format_track(track))
@wrap
def status(self, irc, msg, args):
"""takes no arguments
@@ -208,9 +257,10 @@ class NtrPlaylist(callbacks.Plugin):
LOGGER.warning("API error for status: %s", exc)
irc.reply(exc.detail)
return
tz = self.registryValue("displayTimezone")
status = data.get("status", "unknown")
poller = "alive" if data.get("poller_alive") else "dead"
last_fetch = data.get("last_fetch") or "never"
last_fetch = format_dt(data.get("last_fetch"), tz)
count = data.get("current_week_track_count", 0)
irc.reply(
f"Status: {status.upper()} | Poller: {poller} | Last fetch: {last_fetch} | Tracks this week: {count}"