Skip to content

Commit

Permalink
Merge pull request #113 from blokfyuh/add-time-offset-support
Browse files Browse the repository at this point in the history
Add time offset support
  • Loading branch information
leandromoreira authored Nov 9, 2017
2 parents c9bf75b + d6ec551 commit d8b717d
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 1 deletion.
22 changes: 22 additions & 0 deletions m3u8/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import errno
import math

from m3u8.protocol import ext_x_start
from m3u8.parser import parse, format_date_time
from m3u8.mixins import BasePathMixin, GroupedBasePathMixin

Expand Down Expand Up @@ -178,6 +179,9 @@ def _initialize_attributes(self):
)
self.segment_map = self.data.get('segment_map')

start = self.data.get('start', None)
self.start = start and Start(**start)

def __unicode__(self):
return self.dumps()

Expand Down Expand Up @@ -251,6 +255,8 @@ def dumps(self):
output.append('#EXT-X-PROGRAM-DATE-TIME:' + format_date_time(self.program_date_time))
if not (self.playlist_type is None or self.playlist_type == ''):
output.append('#EXT-X-PLAYLIST-TYPE:%s' % str(self.playlist_type).upper())
if self.start:
output.append(str(self.start))
if self.is_i_frames_only:
output.append('#EXT-X-I-FRAMES-ONLY')
if self.is_variant:
Expand Down Expand Up @@ -676,6 +682,22 @@ def __str__(self):
return '\n'.join(output)


class Start(object):

def __init__(self, time_offset, precise=None):
self.time_offset = float(time_offset)
self.precise = precise

def __str__(self):
output = [
'TIME-OFFSET=' + str(self.time_offset)
]
if self.precise and self.precise in ['YES', 'NO']:
output.append('PRECISE=' + str(self.precise))

return ext_x_start + ':' + ','.join(output)


def find_key(keydata, keylist):
if not keydata:
return None
Expand Down
9 changes: 8 additions & 1 deletion m3u8/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def parse(content, strict=False):
'segments': [],
'iframe_playlists': [],
'media': [],
'keys': [],
'keys': []
}

state = {
Expand Down Expand Up @@ -141,6 +141,13 @@ def parse(content, strict=False):
segment_map_info = _parse_attribute_list(protocol.ext_x_map, line, quoted_parser)
data['segment_map'] = segment_map_info

elif line.startswith(protocol.ext_x_start):
attribute_parser = {
"time_offset": lambda x: float(x)
}
start_info = _parse_attribute_list(protocol.ext_x_start, line, attribute_parser)
data['start'] = start_info

# Comments and whitespace
elif line.startswith('#'):
# comment
Expand Down
1 change: 1 addition & 0 deletions m3u8/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@
ext_x_cue_end = '#EXT-X-CUE-IN'
ext_x_cue_span = '#EXT-X-CUE-SPAN'
ext_x_map = '#EXT-X-MAP'
ext_x_start = '#EXT-X-START'
18 changes: 18 additions & 0 deletions tests/playlists.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@
#EXT-X-ENDLIST
'''

SIMPLE_PLAYLIST_WITH_START_NEGATIVE_OFFSET = '''
#EXTM3U
#EXT-X-TARGETDURATION:5220
#EXT-X-START:TIME-OFFSET=-2.0
#EXTINF:5220,
http://media.example.com/entire.ts
#EXT-X-ENDLIST
'''

SIMPLE_PLAYLIST_WITH_START_PRECISE = '''
#EXTM3U
#EXT-X-TARGETDURATION:5220
#EXT-X-START:TIME-OFFSET=10.5,PRECISE=YES
#EXTINF:5220,
http://media.example.com/entire.ts
#EXT-X-ENDLIST
'''

SIMPLE_PLAYLIST_FILENAME = abspath(
join(dirname(__file__), 'playlists/simple-playlist.m3u8'))

Expand Down
18 changes: 18 additions & 0 deletions tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

import arrow
import datetime

from m3u8.protocol import ext_x_start

import m3u8
import playlists
from m3u8.model import Segment, Key, Media
Expand Down Expand Up @@ -712,6 +715,21 @@ def test_segment_map_uri_attribute_with_byterange():
obj = m3u8.M3U8(playlists.MAP_URI_PLAYLIST_WITH_BYTERANGE)
assert obj.segment_map['uri'] == "main.mp4"


def test_start_with_negative_offset():
obj = m3u8.M3U8(playlists.SIMPLE_PLAYLIST_WITH_START_NEGATIVE_OFFSET)
assert obj.start.time_offset == -2.0
assert obj.start.precise is None
assert ext_x_start + ':TIME-OFFSET=-2.0\n' in obj.dumps()


def test_start_with_precise():
obj = m3u8.M3U8(playlists.SIMPLE_PLAYLIST_WITH_START_PRECISE)
assert obj.start.time_offset == 10.5
assert obj.start.precise == 'YES'
assert ext_x_start + ':TIME-OFFSET=10.5,PRECISE=YES\n' in obj.dumps()


# custom asserts


Expand Down
12 changes: 12 additions & 0 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,15 @@ def test_should_parse_empty_uri_with_base_path():
assert media.uri is None
assert media.base_path is None
assert 'base_uri/' == media.base_uri


def test_should_parse_start_with_negative_time_offset():
data = m3u8.parse(playlists.SIMPLE_PLAYLIST_WITH_START_NEGATIVE_OFFSET)
assert data['start']['time_offset'] == -2.0
assert not hasattr(data['start'], 'precise')


def test_should_parse_start_with_precise():
data = m3u8.parse(playlists.SIMPLE_PLAYLIST_WITH_START_PRECISE)
assert data['start']['time_offset'] == 10.5
assert data['start']['precise'] == 'YES'

0 comments on commit d8b717d

Please sign in to comment.