From 8f5a98a90690595fa35a168558818794913ebd06 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Wed, 26 Dec 2018 21:03:15 -0800 Subject: [PATCH] restreamer: Don't offer a variant on the master playlist if it's outside requested time range This prevents clients from picking a variant that they then can't play any content for. In general we expect the same content to be available on all variants being captured, but if the set of captured variants changes we still want to handle that gracefully. --- restreamer/restreamer/main.py | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/restreamer/restreamer/main.py b/restreamer/restreamer/main.py index c5bc873..7f32ad5 100644 --- a/restreamer/restreamer/main.py +++ b/restreamer/restreamer/main.py @@ -1,4 +1,5 @@ +import datetime import errno import functools import json @@ -85,6 +86,17 @@ def list_segments(stream, variant, hour): return json.dumps(listdir(path, error=False)) +def time_range_for_variant(stream, variant): + """Returns earliest and latest times that the given variant has segments for + (up to hour resolution), or 404 if it doesn't exist / is empty.""" + hours = listdir(os.path.join(app.static_folder, stream, variant)) + if not hours: + abort(404) + first, last = min(hours), max(hours) + # note last hour parses to _start_ of that hour, so we add 1h to go to end of that hour + return dateutil.parser.parse(first), dateutil.parser.parse(last) + datetime.timedelta(hours=1) + + @app.route('/playlist/.m3u8') @has_path_args def generate_master_playlist(stream): @@ -93,11 +105,24 @@ def generate_master_playlist(stream): start, end: The time to begin and end the stream at. See generate_media_playlist for details. """ + start = dateutil.parser.parse(request.args['start']) if 'start' in request.args else None + end = dateutil.parser.parse(request.args['end']) if 'end' in request.args else None variants = listdir(os.path.join(app.static_folder, stream)) - playlists = { - variant: url_for('generate_media_playlist', stream=stream, variant=variant, **request.args) - for variant in variants - } + + playlists = {} + for variant in variants: + # If start or end are given, try to restrict offered variants to ones which exist for that + # time range. + if start is not None or end is not None: + first, last = time_range_for_variant(stream, variant) + if start is not None and last < start: + continue # last time for variant is before our start time, don't offer variant + if end is not None and end < first: + continue # our end time is before first time for variant, don't offer variant + playlists[variant] = url_for( + 'generate_media_playlist', stream=stream, variant=variant, **request.args + ) + return generate_hls.generate_master(playlists)