Update station_parser.py

This commit is contained in:
2025-12-17 17:16:36 +00:00
parent fb273db3b1
commit 5812899b76

View File

@@ -1,10 +1,4 @@
#!/usr/bin/env python3
"""
Radio Station Playlist Parser.
Supports parsing of M3U, M3U8, and PLS playlist formats to resolving
actual stream URLs. Handles recursive playlists and HLS stream detection.
"""
import re
import asyncio
@@ -15,9 +9,7 @@ import logging
logger = logging.getLogger(__name__)
class StationParser:
"""Parses playlist files to extract the underlying media stream URL."""
def __init__(self, timeout: int = 10):
self.timeout = aiohttp.ClientTimeout(total=timeout)
@@ -38,13 +30,11 @@ class StationParser:
return None
def is_playlist_url(self, url: str) -> bool:
"""Checks if a URL points to a supported playlist format."""
parsed = urlparse(url.lower())
path = parsed.path
return any(path.endswith(ext) for ext in ['.m3u', '.m3u8', '.pls'])
def parse_m3u(self, content: str, base_url: str = "") -> List[Dict[str, str]]:
"""Parses M3U/M3U8 content."""
streams = []
lines = content.strip().split('\n')
@@ -69,7 +59,6 @@ class StationParser:
}
continue
# Handle M3U8 stream attributes (bandwidth, resolution)
if line.startswith('#EXT-X-STREAM-INF:'):
attrs = self._parse_attributes(line[18:])
current_info = {
@@ -95,7 +84,6 @@ class StationParser:
return streams
def parse_pls(self, content: str) -> List[Dict[str, str]]:
"""Parses PLS INI-style content."""
streams = []
entries = {}
@@ -124,7 +112,6 @@ class StationParser:
return streams
def _parse_attributes(self, attr_string: str) -> Dict[str, str]:
"""Helper to parse key="value" attributes in M3U8 tags."""
attrs = {}
pattern = r'([A-Z-]+)=(?:"([^"]+)"|([^,]+))'
for match in re.finditer(pattern, attr_string):
@@ -134,12 +121,6 @@ class StationParser:
return attrs
async def resolve_stream_url(self, url: str) -> Tuple[Optional[str], Optional[Dict]]:
"""
Recursively resolves a URL until a raw stream is found.
Returns:
Tuple containing the resolved URL and its metadata.
"""
if not self.is_playlist_url(url):
return url, {'original_url': url}
@@ -147,7 +128,6 @@ class StationParser:
if not content:
return None, None
# Return the URL immediately if it's an HLS master playlist, as ffmpeg handles these.
if '#EXT-X-TARGETDURATION' in content:
logger.info(f"Detected HLS Media Playlist: {url}")
return url, {'original_url': url, 'is_hls': True}
@@ -160,7 +140,6 @@ class StationParser:
if not streams:
return None, None
# Default to the first stream, but prefer higher bandwidth for adaptive streams.
best_stream = streams[0]
if url.lower().endswith('.m3u8'):
@@ -171,7 +150,6 @@ class StationParser:
stream_url = best_stream['url']
# Recurse if the result is another playlist (nested playlists).
if self.is_playlist_url(stream_url):
return await self.resolve_stream_url(stream_url)