fix: playlist truncation overflow and align logging across plugins

- Fix format_playlist truncation: +4 → +5 to account for ", ..." suffix
- Add API error logging to all Sopel command handlers (matching Limnoria)
- Add long-track truncation test case

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-12 03:24:29 -04:00
parent b63c851d14
commit 05bcf184ac
3 changed files with 18 additions and 5 deletions

View File

@@ -94,7 +94,7 @@ def format_playlist(data: dict) -> str:
for t in tracks: for t in tracks:
entry = f"{t.get('title', '')} by {t.get('artist', '')}" entry = f"{t.get('title', '')} by {t.get('artist', '')}"
sep = ", " if parts else "" sep = ", " if parts else ""
if length + len(sep) + len(entry) + 4 > _MAX_IRC_LINE: # +4 for " ..." if length + len(sep) + len(entry) + 5 > _MAX_IRC_LINE: # +5 for ", ..."
parts.append("...") parts.append("...")
break break
parts.append(entry) parts.append(entry)

View File

@@ -104,7 +104,7 @@ def format_playlist(data: dict) -> str:
for t in tracks: for t in tracks:
entry = f"{t.get('title', '')} by {t.get('artist', '')}" entry = f"{t.get('title', '')} by {t.get('artist', '')}"
sep = ", " if parts else "" sep = ", " if parts else ""
if length + len(sep) + len(entry) + 4 > _MAX_IRC_LINE: # +4 for " ..." if length + len(sep) + len(entry) + 5 > _MAX_IRC_LINE: # +5 for ", ..."
parts.append("...") parts.append("...")
break break
parts.append(entry) parts.append(entry)
@@ -175,12 +175,14 @@ def ntr_playlist(bot, trigger):
try: try:
data = _api_get(base_url, f"/shows/by-episode/{episode}") data = _api_get(base_url, f"/shows/by-episode/{episode}")
except ApiError as e: except ApiError as e:
LOGGER.warning("API error for !playlist: %s", e)
bot.say(e.detail) bot.say(e.detail)
return return
else: else:
try: try:
data = _api_get(base_url, "/playlist") data = _api_get(base_url, "/playlist")
except ApiError as e: except ApiError as e:
LOGGER.warning("API error for !playlist: %s", e)
bot.say(e.detail) bot.say(e.detail)
return return
bot.say(format_playlist(data)) bot.say(format_playlist(data))
@@ -192,6 +194,7 @@ def ntr_status(bot, trigger):
try: try:
data = _api_get(base_url, "/health") data = _api_get(base_url, "/health")
except ApiError as e: except ApiError as e:
LOGGER.warning("API error for !status: %s", e)
bot.say(e.detail) bot.say(e.detail)
return return
status = data.get("status", "unknown") status = data.get("status", "unknown")
@@ -214,6 +217,7 @@ def ntr_refresh(bot, trigger):
try: try:
data = _api_post(base_url, "/admin/refresh", token) data = _api_post(base_url, "/admin/refresh", token)
except ApiError as e: except ApiError as e:
LOGGER.warning("API error for !refresh: %s", e)
bot.say(f"Refresh failed: {e.detail}") bot.say(f"Refresh failed: {e.detail}")
return return
count = data.get("track_count", 0) count = data.get("track_count", 0)

View File

@@ -90,9 +90,9 @@ def format_playlist(data: dict) -> str:
parts: list[str] = [] parts: list[str] = []
length = len(prefix) length = len(prefix)
for t in tracks: for t in tracks:
entry = f"{t.get("title", "")} by {t.get("artist", "")}" entry = f"{t.get('title', '')} by {t.get('artist', '')}"
sep = ", " if parts else "" sep = ", " if parts else ""
if length + len(sep) + len(entry) + 4 > _MAX_IRC_LINE: if length + len(sep) + len(entry) + 5 > _MAX_IRC_LINE: # +5 for ", ..."
parts.append("...") parts.append("...")
break break
parts.append(entry) parts.append(entry)
@@ -197,7 +197,7 @@ class TestFormatPlaylist:
data = {"tracks": [{"title": "A", "artist": "B"}]} data = {"tracks": [{"title": "A", "artist": "B"}]}
assert format_playlist(data).startswith("Episode ?") assert format_playlist(data).startswith("Episode ?")
def test_truncation(self): def test_truncation_many_tracks(self):
tracks = [ tracks = [
{"title": f"Track{i:03d} With A Longer Name", "artist": f"Artist{i:03d}"} {"title": f"Track{i:03d} With A Longer Name", "artist": f"Artist{i:03d}"}
for i in range(50) for i in range(50)
@@ -207,6 +207,15 @@ class TestFormatPlaylist:
assert len(result) <= _MAX_IRC_LINE assert len(result) <= _MAX_IRC_LINE
assert result.endswith("...") assert result.endswith("...")
def test_truncation_long_single_track(self):
tracks = [
{"title": "A" * 200, "artist": "B" * 200},
{"title": "Second", "artist": "Track"},
]
data = {"episode_number": 1, "tracks": tracks}
result = format_playlist(data)
assert len(result) <= _MAX_IRC_LINE
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# _api_get # _api_get