diff --git a/m3u8/model.py b/m3u8/model.py index 465bd69d..ea6c5a04 100644 --- a/m3u8/model.py +++ b/m3u8/model.py @@ -362,7 +362,7 @@ def add_segment(self, segment): def add_rendition_report(self, report): self.rendition_reports.append(report) - def dumps(self, timespec="milliseconds"): + def dumps(self, timespec="milliseconds", infspec="auto"): """ Returns the current m3u8 as a string. You could also use unicode() or str() @@ -414,7 +414,7 @@ def dumps(self, timespec="milliseconds"): for key in self.session_keys: output.append(str(key)) - output.append(self.segments.dumps(timespec)) + output.append(self.segments.dumps(timespec, infspec)) if self.preload_hint: output.append(str(self.preload_hint)) @@ -586,7 +586,7 @@ def __init__( def add_part(self, part): self.parts.append(part) - def dumps(self, last_segment, timespec="milliseconds"): + def dumps(self, last_segment, timespec="milliseconds", infspec="auto"): output = [] if last_segment and self.key != last_segment.key: @@ -659,7 +659,13 @@ def dumps(self, last_segment, timespec="milliseconds"): if self.uri: if self.duration is not None: - output.append("#EXTINF:%s," % number_to_string(self.duration)) + if infspec == "milliseconds": + duration = "{:.3f}".format(self.duration) + elif infspec == "microseconds": + duration = "{:.6f}".format(self.duration) + else: + duration = number_to_string(self.duration) + output.append("#EXTINF:%s," % duration) if self.title: output.append(self.title) output.append("\n") @@ -704,11 +710,11 @@ def base_uri(self, newbase_uri): class SegmentList(list, GroupedBasePathMixin): - def dumps(self, timespec="milliseconds"): + def dumps(self, timespec="milliseconds", infspec="auto"): output = [] last_segment = None for segment in self: - output.append(segment.dumps(last_segment, timespec)) + output.append(segment.dumps(last_segment, timespec, infspec)) last_segment = segment return "\n".join(output) diff --git a/tests/test_model.py b/tests/test_model.py index 2961b403..a6adb09f 100755 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -798,6 +798,12 @@ def test_dump_should_not_ignore_zero_duration(): assert "EXTINF:0" in obj.dumps().strip() assert "EXTINF:5220" in obj.dumps().strip() + assert "EXTINF:0.000" in obj.dumps(infspec="milliseconds").strip() + assert "EXTINF:5220.000" in obj.dumps(infspec="milliseconds").strip() + + assert "EXTINF:0.000000" in obj.dumps(infspec="microseconds").strip() + assert "EXTINF:5220.000000" in obj.dumps(infspec="microseconds").strip() + def test_dump_should_use_decimal_floating_point_for_very_short_durations(): obj = m3u8.M3U8(playlists.SIMPLE_PLAYLIST_WITH_VERY_SHORT_DURATION) @@ -806,6 +812,14 @@ def test_dump_should_use_decimal_floating_point_for_very_short_durations(): assert "EXTINF:5218.5" in obj.dumps().strip() assert "EXTINF:0.000011" in obj.dumps().strip() + assert "EXTINF:5220.000" in obj.dumps(infspec="milliseconds").strip() + assert "EXTINF:5218.500" in obj.dumps(infspec="milliseconds").strip() + assert "EXTINF:0.000" in obj.dumps(infspec="milliseconds").strip() + + assert "EXTINF:5220.000000" in obj.dumps(infspec="microseconds").strip() + assert "EXTINF:5218.500" in obj.dumps(infspec="microseconds").strip() + assert "EXTINF:0.000011" in obj.dumps(infspec="microseconds").strip() + def test_dump_should_include_segment_level_program_date_time(): obj = m3u8.M3U8(playlists.DISCONTINUITY_PLAYLIST_WITH_PROGRAM_DATE_TIME)