Skip to content

Commit 6920076

Browse files
committed
add framerate to playlist and parser
1 parent f5826be commit 6920076

File tree

3 files changed

+58
-13
lines changed

3 files changed

+58
-13
lines changed

resources/lib/twitch/api/usher.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def live_request(channel):
7171
q.add_param(keys.FAST_BREAD, Boolean.TRUE)
7272
q.add_param(keys.CDM, keys.WV)
7373
q.add_param(keys.REASSIGNMENT_SUPPORTED, Boolean.TRUE)
74+
q.add_param(keys.PLAYLIST_INCLUDE_FRAMERATE, Boolean.TRUE)
7475
q.add_param(keys.RTQOS, keys.CONTROL)
7576
q.add_param(keys.PLAYER_BACKEND, keys.MEDIAPLAYER)
7677
url = '?'.join([q.url, urlencode(q.params)])
@@ -91,6 +92,7 @@ def _live(channel, token):
9192
q.add_param(keys.FAST_BREAD, Boolean.TRUE)
9293
q.add_param(keys.CDM, keys.WV)
9394
q.add_param(keys.REASSIGNMENT_SUPPORTED, Boolean.TRUE)
95+
q.add_param(keys.PLAYLIST_INCLUDE_FRAMERATE, Boolean.TRUE)
9496
q.add_param(keys.RTQOS, keys.CONTROL)
9597
q.add_param(keys.PLAYER_BACKEND, keys.MEDIAPLAYER)
9698
return q
@@ -120,6 +122,7 @@ def video_request(video_id):
120122
q.add_param(keys.ALLOW_AUDIO_ONLY, Boolean.TRUE)
121123
q.add_param(keys.CDM, keys.WV)
122124
q.add_param(keys.REASSIGNMENT_SUPPORTED, Boolean.TRUE)
125+
q.add_param(keys.PLAYLIST_INCLUDE_FRAMERATE, Boolean.TRUE)
123126
q.add_param(keys.RTQOS, keys.CONTROL)
124127
q.add_param(keys.PLAYER_BACKEND, keys.MEDIAPLAYER)
125128
q.add_param(keys.BAKING_BREAD, Boolean.TRUE)
@@ -143,6 +146,7 @@ def _vod(video_id, token):
143146
q.add_param(keys.ALLOW_AUDIO_ONLY, Boolean.TRUE)
144147
q.add_param(keys.CDM, keys.WV)
145148
q.add_param(keys.REASSIGNMENT_SUPPORTED, Boolean.TRUE)
149+
q.add_param(keys.PLAYLIST_INCLUDE_FRAMERATE, Boolean.TRUE)
146150
q.add_param(keys.RTQOS, keys.CONTROL)
147151
q.add_param(keys.PLAYER_BACKEND, keys.MEDIAPLAYER)
148152
q.add_param(keys.BAKING_BREAD, Boolean.TRUE)

resources/lib/twitch/keys.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
PERIOD = 'period'
8383
PLATFORM = 'platform'
8484
PLAYER_BACKEND = 'player_backend'
85+
PLAYLIST_INCLUDE_FRAMERATE = 'playlist_include_framerate'
8586
POSITION = 'position'
8687
POST_ID = 'post_id'
8788
QUERY = 'query'

resources/lib/twitch/parser.py

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,30 @@
2020
r'GROUP-ID="(?P<group_id>[^"]*)",'
2121
r'NAME="(?P<group_name>[^"]*)"[,=\w]*\n'
2222
r'#EXT-X-STREAM-INF:.*'
23-
r'BANDWIDTH=(?P<bandwidth>[0-9]+).*\n('
24-
r'?P<url>http.*)')
23+
r'BANDWIDTH=(?P<bandwidth>[0-9]+),'
24+
r'(?:.*FRAME-RATE=(?P<fps>[0-9.]+))?.*\n'
25+
r'(?P<url>http.*)')
2526

2627
_error_pattern = re.compile(r'.*<tr><td><b>error</b></td><td>(?P<message>.+?)</td></tr>.*', re.IGNORECASE)
2728

2829

30+
def _find_frame_rate(group_id, group_name):
31+
group_id = group_id.lower()
32+
33+
if group_id == 'audio_only':
34+
return None
35+
elif group_id == 'chunked':
36+
group_id = group_name.lower().replace('(source)', '').strip()
37+
38+
info = group_id.split('p')
39+
if len(info) > 1 and info[1]:
40+
fps = float(info[1])
41+
else:
42+
fps = 30.0
43+
44+
return fps
45+
46+
2947
def m3u8(f):
3048
def m3u8_wrapper(*args, **kwargs):
3149
results = f(*args, **kwargs)
@@ -54,13 +72,24 @@ def m3u8_to_dict(string):
5472
d = dict()
5573
matches = re.finditer(_m3u_pattern, string)
5674
for m in matches:
57-
name = 'Audio Only' if m.group('group_name') == 'audio_only' else m.group('group_name')
58-
name = 'Source' if m.group('group_id') == 'chunked' else name
75+
if m.group('group_name') == 'audio_only':
76+
name = 'Audio Only'
77+
elif m.group('group_id') == 'chunked':
78+
name = 'Source'
79+
else:
80+
name = m.group('group_name')
81+
82+
if m.group('fps'):
83+
fps = float(m.group('fps'))
84+
else:
85+
fps = _find_frame_rate(m.group('group_id'), m.group('group_name'))
86+
5987
d[m.group('group_id')] = {
6088
'id': m.group('group_id'),
6189
'name': name,
6290
'url': m.group('url'),
63-
'bandwidth': int(m.group('bandwidth'))
91+
'bandwidth': int(m.group('bandwidth')),
92+
'fps': fps
6493
}
6594
log.debug('m3u8_to_dict result:\n{0}'.format(d))
6695
return d
@@ -71,13 +100,24 @@ def m3u8_to_list(string):
71100
l = list()
72101
matches = re.finditer(_m3u_pattern, string)
73102
for m in matches:
74-
name = 'Audio Only' if m.group('group_name') == 'audio_only' else m.group('group_name')
75-
name = 'Source' if m.group('group_id') == 'chunked' else name
103+
if m.group('group_name') == 'audio_only':
104+
name = 'Audio Only'
105+
elif m.group('group_id') == 'chunked':
106+
name = 'Source'
107+
else:
108+
name = m.group('group_name')
109+
110+
if m.group('fps'):
111+
fps = float(m.group('fps'))
112+
else:
113+
fps = _find_frame_rate(m.group('group_id'), m.group('group_name'))
114+
76115
l.append({
77116
'id': m.group('group_id'),
78117
'name': name,
79118
'url': m.group('url'),
80-
'bandwidth': int(m.group('bandwidth'))
119+
'bandwidth': int(m.group('bandwidth')),
120+
'fps': fps
81121
})
82122

83123
log.debug('m3u8_to_list result:\n{0}'.format(l))
@@ -96,11 +136,11 @@ def clip_embed_to_list(response):
96136

97137
if qualities:
98138
l = [{
99-
'id': item['quality'],
100-
'name': item['quality'],
101-
'url': item['source'],
102-
'bandwidth': -1
103-
} for item in qualities]
139+
'id': item['quality'],
140+
'name': item['quality'],
141+
'url': item['source'],
142+
'bandwidth': -1
143+
} for item in qualities]
104144
if l:
105145
l.insert(0, {
106146
'id': 'Source',

0 commit comments

Comments
 (0)