/
/
/
1"""Helper functions for Radio Paradise provider."""
2
3import time
4from typing import Any
5
6from music_assistant.helpers.compare import compare_strings
7
8
9def get_current_block_position(block_data: dict[str, Any]) -> int:
10 """
11 Calculate current playback position within a Radio Paradise block.
12
13 :param block_data: Block data containing sched_time_millis.
14 """
15 current_time_ms = int(time.time() * 1000)
16 sched_time = int(block_data.get("sched_time_millis", current_time_ms))
17 return current_time_ms - sched_time
18
19
20def find_current_song(
21 songs: dict[str, dict[str, Any]], current_time_ms: int
22) -> dict[str, Any] | None:
23 """
24 Find which song should currently be playing based on elapsed time.
25
26 :param songs: Dictionary of songs from Radio Paradise block data.
27 :param current_time_ms: Current position in milliseconds within the block.
28 """
29 sorted_keys = sorted(songs.keys(), key=int)
30
31 for song_key in sorted_keys:
32 song = songs[song_key]
33 song_start = int(song.get("elapsed", 0))
34 song_duration = int(song.get("duration", 0))
35 song_end = song_start + song_duration
36
37 if song_start <= current_time_ms < song_end:
38 return song
39
40 # If no exact match, return first song
41 first_song = songs.get("0")
42 return first_song if first_song is not None else None
43
44
45def find_song_by_stream_title(
46 songs: dict[str, dict[str, Any]], stream_title: str
47) -> dict[str, Any] | None:
48 """
49 Find the block song matching an in-band ICY stream title.
50
51 Matches by composing "artist - title" from the block's structured fields;
52 the ICY string is never split, which would be ambiguous around " - ".
53
54 :param songs: Dictionary of songs from Radio Paradise block data.
55 :param stream_title: Cleaned in-band stream title.
56 """
57 if not stream_title.strip():
58 return None
59 for song in songs.values():
60 artist = song.get("artist") or ""
61 title = song.get("title") or ""
62 if not artist or not title:
63 continue
64 if compare_strings(f"{artist} - {title}", stream_title, strict=False):
65 return song
66 return None
67
68
69def get_next_song(songs: dict[str, Any], current_song: dict[str, Any]) -> dict[str, Any] | None:
70 """
71 Get the next song that will play after the current song.
72
73 :param songs: Dictionary of songs from Radio Paradise block data.
74 :param current_song: The currently playing song dictionary.
75 """
76 current_event = current_song.get("event")
77 current_elapsed = int(current_song.get("elapsed", 0))
78 sorted_keys = sorted(songs.keys(), key=int)
79
80 for song_key in sorted_keys:
81 song: dict[str, Any] = songs[song_key]
82 if song.get("event") != current_event and int(song.get("elapsed", 0)) > current_elapsed:
83 return song
84 return None
85