feat: add video duration to YouTube announcements

Fetches duration via InnerTube player API for new videos at
announcement time. Displayed as compact h:mm:ss before views/likes.
Gracefully omitted for Shorts and unavailable content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
user
2026-02-19 18:28:40 +01:00
parent 2d00360bc3
commit 8ce6922cc3
3 changed files with 111 additions and 6 deletions

View File

@@ -24,6 +24,7 @@ from plugins.youtube import ( # noqa: E402
_derive_name,
_errors,
_extract_channel_id,
_format_duration,
_is_youtube_url,
_load,
_parse_feed,
@@ -827,18 +828,26 @@ class TestCmdYtCheck:
}
_save(bot, "#test:news", data)
def fake_duration(video_id):
return {"def456": 1105, "ghi789": 62}.get(video_id, 0)
async def inner():
with patch.object(_mod, "_fetch_feed", _fake_fetch_ok):
with (
patch.object(_mod, "_fetch_feed", _fake_fetch_ok),
patch.object(_mod, "_fetch_duration", fake_duration),
):
await cmd_yt(bot, _msg("!yt check news"))
announcements = [s for t, s in bot.sent if t == "#test"]
assert len(announcements) == 2
assert "[news]" in announcements[0]
assert "Calculus" in announcements[0]
# Verify metadata suffix (views, likes, date)
assert "| " in announcements[0]
# Verify metadata suffix (duration, views, likes, date)
assert "18:25" in announcements[0]
assert "820kv" in announcements[0]
assert "32klk" in announcements[0]
assert "2026-02-01" in announcements[0]
# Second announcement has 1:02 duration
assert "1:02" in announcements[1]
asyncio.run(inner())
@@ -930,7 +939,10 @@ class TestPollOnce:
_channels[key] = data
async def inner():
with patch.object(_mod, "_fetch_feed", fake_big):
with (
patch.object(_mod, "_fetch_feed", fake_big),
patch.object(_mod, "_fetch_duration", lambda vid: 0),
):
await _poll_once(bot, key, announce=True)
messages = [s for t, s in bot.sent if t == "#test"]
# 5 individual + 1 "... and N more"
@@ -1177,3 +1189,33 @@ class TestCompactNum:
def test_fractional_m(self):
assert _compact_num(2_500_000) == "2.5M"
# ---------------------------------------------------------------------------
# TestFormatDuration
# ---------------------------------------------------------------------------
class TestFormatDuration:
def test_zero(self):
assert _format_duration(0) == ""
def test_negative(self):
assert _format_duration(-1) == ""
def test_seconds_only(self):
assert _format_duration(45) == "0:45"
def test_minutes_and_seconds(self):
assert _format_duration(125) == "2:05"
def test_exact_minutes(self):
assert _format_duration(600) == "10:00"
def test_hours(self):
assert _format_duration(3661) == "1:01:01"
def test_large_hours(self):
assert _format_duration(36000) == "10:00:00"
def test_one_second(self):
assert _format_duration(1) == "0:01"