summaryrefslogtreecommitdiff
path: root/Biz/PodcastItLater/Web.py
diff options
context:
space:
mode:
Diffstat (limited to 'Biz/PodcastItLater/Web.py')
-rw-r--r--Biz/PodcastItLater/Web.py66
1 files changed, 63 insertions, 3 deletions
diff --git a/Biz/PodcastItLater/Web.py b/Biz/PodcastItLater/Web.py
index a4c3c16..ee63b60 100644
--- a/Biz/PodcastItLater/Web.py
+++ b/Biz/PodcastItLater/Web.py
@@ -79,6 +79,36 @@ RSS_CONFIG = {
}
+def format_duration(seconds: int | None) -> str:
+ """Format duration from seconds to human-readable format.
+
+ Examples:
+ 300 -> "5m"
+ 3840 -> "1h 4m"
+ 11520 -> "3h 12m"
+ """
+ if seconds is None or seconds <= 0:
+ return "Unknown"
+
+ # Constants for time conversion
+ seconds_per_minute = 60
+ minutes_per_hour = 60
+
+ # Round up to nearest minute
+ minutes = (seconds + seconds_per_minute - 1) // seconds_per_minute
+
+ if minutes < minutes_per_hour:
+ return f"{minutes}m"
+
+ hours = minutes // minutes_per_hour
+ remaining_minutes = minutes % minutes_per_hour
+
+ if remaining_minutes == 0:
+ return f"{hours}h"
+
+ return f"{hours}h {remaining_minutes}m"
+
+
def extract_og_metadata(url: str) -> tuple[str | None, str | None]:
"""Extract Open Graph title and author from URL.
@@ -409,9 +439,7 @@ class EpisodeList(Component[AnyChildren, EpisodeListAttrs]):
episode_items = []
for episode in episodes:
- duration_str = (
- f"{episode['duration']}s" if episode["duration"] else "Unknown"
- )
+ duration_str = format_duration(episode.get("duration"))
episode_items.append(
html.div(
html.h4(episode["title"]),
@@ -970,6 +998,37 @@ class BaseWebTest(Test.TestCase):
Core.Database.teardown()
+class TestDurationFormatting(Test.TestCase):
+ """Test duration formatting functionality."""
+
+ def test_format_duration_minutes_only(self) -> None:
+ """Test formatting durations less than an hour."""
+ self.assertEqual(format_duration(60), "1m")
+ self.assertEqual(format_duration(240), "4m")
+ self.assertEqual(format_duration(300), "5m")
+ self.assertEqual(format_duration(3599), "60m")
+
+ def test_format_duration_hours_and_minutes(self) -> None:
+ """Test formatting durations with hours and minutes."""
+ self.assertEqual(format_duration(3600), "1h")
+ self.assertEqual(format_duration(3840), "1h 4m")
+ self.assertEqual(format_duration(11520), "3h 12m")
+ self.assertEqual(format_duration(7320), "2h 2m")
+
+ def test_format_duration_round_up(self) -> None:
+ """Test that seconds are rounded up to nearest minute."""
+ self.assertEqual(format_duration(61), "2m")
+ self.assertEqual(format_duration(119), "2m")
+ self.assertEqual(format_duration(121), "3m")
+ self.assertEqual(format_duration(3601), "1h 1m")
+
+ def test_format_duration_edge_cases(self) -> None:
+ """Test edge cases for duration formatting."""
+ self.assertEqual(format_duration(None), "Unknown")
+ self.assertEqual(format_duration(0), "Unknown")
+ self.assertEqual(format_duration(-100), "Unknown")
+
+
class TestAuthentication(BaseWebTest):
"""Test authentication functionality."""
@@ -1509,6 +1568,7 @@ def test() -> None:
Test.run(
App.Area.Test,
[
+ TestDurationFormatting,
TestAuthentication,
TestArticleSubmission,
TestRSSFeed,