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:
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user