{"id":4094,"library":"m3u8","title":"m3u8","description":"m3u8 is a Python library designed to parse M3U8 HTTP Live Streaming (HLS) playlists. It allows loading playlists from URIs, file paths, or strings, and provides access to segments, streams, and other HLS tag information. The library is actively maintained, with its current version being 6.0.0, and receives regular updates to support new HLS specifications and bug fixes.","status":"active","version":"6.0.0","language":"en","source_language":"en","source_url":"https://github.com/globocom/m3u8","tags":["HLS","m3u8","parser","media-streaming","video"],"install":[{"cmd":"pip install m3u8","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Used for parsing ISO 8601 date/time strings within M3U8 playlists.","package":"iso8601","optional":false}],"imports":[{"note":"The primary functions `load` and `loads` are typically accessed directly from the imported `m3u8` module.","wrong":"from m3u8 import load # While technically correct, 'import m3u8' is more idiomatic for the main API functions.","symbol":"load","correct":"import m3u8\nplaylist = m3u8.load('http://example.com/playlist.m3u8')"},{"note":"Used for parsing M3U8 content directly from a string.","symbol":"loads","correct":"import m3u8\nplaylist = m3u8.loads('#EXTM3U8\\n...')"}],"quickstart":{"code":"import m3u8\nimport requests\nimport os\n\n# Example: Load a remote M3U8 playlist\n# In a real scenario, use a specific, stable M3U8 URL.\n# For a runnable example, we'll use a placeholder or local file.\n# For demonstration, we'll simulate a playlist string.\n\n# --- Option 1: Load from a URL (requires internet access) ---\n# remote_m3u8_url = 'https://example.com/path/to/playlist.m3u8' # Replace with a real M3U8 URL if testing live\n# try:\n#     playlist = m3u8.load(remote_m3u8_url)\n#     print(f\"Loaded playlist from URL: {remote_m3u8_url}\")\n#     if playlist.segments:\n#         print(f\"First segment URI: {playlist.segments[0].uri}\")\n#     else:\n#         print(\"No segments found in remote playlist.\")\n# except requests.exceptions.RequestException as e:\n#     print(f\"Error loading remote playlist: {e}\")\n\n# --- Option 2: Load from a string (always runnable) ---\nlocal_m3u8_content = \"\"\"\n#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-TARGETDURATION:10\n#EXT-X-MEDIA-SEQUENCE:0\n#EXTINF:9.009,\nhttp://example.com/segment0.ts\n#EXTINF:10.000,\nhttp://example.com/segment1.ts\n#EXT-X-ENDLIST\n\"\"\"\n\nplaylist_from_string = m3u8.loads(local_m3u8_content)\nprint(\"\\n--- Playlist from String ---\")\nprint(f\"Target Duration: {playlist_from_string.target_duration}\")\nprint(f\"Number of segments: {len(playlist_from_string.segments)}\")\nif playlist_from_string.segments:\n    print(f\"First segment URI: {playlist_from_string.segments[0].uri}\")\n\n# Iterate through segments\nprint(\"\\nSegments:\")\nfor i, segment in enumerate(playlist_from_string.segments):\n    print(f\"  Segment {i}: Duration={segment.duration}, URI={segment.uri}\")\n","lang":"python","description":"This quickstart demonstrates how to load an M3U8 playlist from a string using `m3u8.loads()` and access its basic properties like target duration and individual segments. An commented-out section shows how to load directly from a URL using `m3u8.load()` for live HLS streams."},"warnings":[{"fix":"Ensure your code handles `BITRATE` values as integers. If string representation is required, cast it explicitly: `str(playlist.playlists[0].stream_info.bandwidth['BITRATE'])`.","message":"In version 6.0.0, the 'BITRATE' attribute within `StreamInfo` (e.g., `playlist.playlists[0].stream_info.bandwidth['BITRATE']`) is now parsed as an integer type instead of a string. Code expecting a string for bitrate values will need to be updated.","severity":"breaking","affected_versions":"6.0.0 and later"},{"fix":"Adjust code to expect and handle `playlist.target_duration` as an integer. Cast if other types are explicitly needed: `float(playlist.target_duration)`.","message":"Starting from version 5.2.0, `target_duration` is consistently parsed as an integer. Previous versions might have returned it as a float or string, which could break code expecting those types.","severity":"breaking","affected_versions":"5.2.0 and later"},{"fix":"Upgrade your Python environment to 3.7 or higher. Review and update any Python 2 specific code if migrating an older project.","message":"Version 4.0.0 dropped compatibility with Python 2.x and updated to require Python 3.7 or newer. Additionally, it now leverages built-in ISO 8601 parsing for Python 3.11+.","severity":"breaking","affected_versions":"4.0.0 and later"},{"fix":"Always prefer `segment.absolute_uri` when constructing URLs for segments or keys to ensure correct resolution against the playlist's `base_uri`.","message":"When parsing playlists, especially those loaded from a URI, segment URIs can be relative. Accessing `segment.uri` directly might yield a relative path. Use `segment.absolute_uri` to get the full, resolved URL if absolute paths are required for downloading or further processing.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Pass a `custom_tags_parser` function to `m3u8.load()` or `m3u8.loads()`. This function will be called for each line of the playlist, allowing you to process and store custom tag data.","message":"The library, by default, ignores non-standard M3U8 tags (i.e., tags not defined in the HLS specification). If you need to parse or extract information from custom tags (e.g., `#MOVIE-NAME:`), you must provide a custom parser function.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}