Daniel Crane
commited on
[Bug Fix] Change from hardcoded FPS to dynamically extract from stream data (#920)
Browse files* Change from hardcoded FPS to dynamically extract from stream data
* Fix tests to correctly list video as 24 fps
- pytube/extract.py +2 -0
- pytube/itags.py +0 -2
- pytube/streams.py +1 -1
- tests/test_query.py +2 -2
- tests/test_streams.py +3 -3
pytube/extract.py
CHANGED
@@ -441,6 +441,7 @@ def apply_descrambler(stream_data: Dict, key: str) -> None:
|
|
441 |
"type": format_item["mimeType"],
|
442 |
"quality": format_item["quality"],
|
443 |
"itag": format_item["itag"],
|
|
|
444 |
"bitrate": format_item.get("bitrate"),
|
445 |
"is_otf": (format_item.get("type") == otf_type),
|
446 |
}
|
@@ -462,6 +463,7 @@ def apply_descrambler(stream_data: Dict, key: str) -> None:
|
|
462 |
"type": format_item["mimeType"],
|
463 |
"quality": format_item["quality"],
|
464 |
"itag": format_item["itag"],
|
|
|
465 |
"bitrate": format_item.get("bitrate"),
|
466 |
"is_otf": (format_item.get("type") == otf_type),
|
467 |
}
|
|
|
441 |
"type": format_item["mimeType"],
|
442 |
"quality": format_item["quality"],
|
443 |
"itag": format_item["itag"],
|
444 |
+
"fps": format_item["fps"] if 'video' in format_item["mimeType"] else None,
|
445 |
"bitrate": format_item.get("bitrate"),
|
446 |
"is_otf": (format_item.get("type") == otf_type),
|
447 |
}
|
|
|
463 |
"type": format_item["mimeType"],
|
464 |
"quality": format_item["quality"],
|
465 |
"itag": format_item["itag"],
|
466 |
+
"fps": format_item["fps"] if 'video' in format_item["mimeType"] else None,
|
467 |
"bitrate": format_item.get("bitrate"),
|
468 |
"is_otf": (format_item.get("type") == otf_type),
|
469 |
}
|
pytube/itags.py
CHANGED
@@ -117,7 +117,6 @@ ITAGS = {
|
|
117 |
}
|
118 |
|
119 |
HDR = [330, 331, 332, 333, 334, 335, 336, 337]
|
120 |
-
_60FPS = [272, 298, 299, 302, 303, 308, 315, 398, 399, 400, 401, 402, 571] + HDR
|
121 |
_3D = [82, 83, 84, 85, 100, 101, 102]
|
122 |
LIVE = [91, 92, 93, 94, 95, 96, 132, 151]
|
123 |
|
@@ -139,7 +138,6 @@ def get_format_profile(itag: int) -> Dict:
|
|
139 |
"is_live": itag in LIVE,
|
140 |
"is_3d": itag in _3D,
|
141 |
"is_hdr": itag in HDR,
|
142 |
-
"fps": 60 if itag in _60FPS else 30,
|
143 |
"is_dash": (
|
144 |
itag in DASH_AUDIO
|
145 |
or itag in DASH_VIDEO
|
|
|
117 |
}
|
118 |
|
119 |
HDR = [330, 331, 332, 333, 334, 335, 336, 337]
|
|
|
120 |
_3D = [82, 83, 84, 85, 100, 101, 102]
|
121 |
LIVE = [91, 92, 93, 94, 95, 96, 132, 151]
|
122 |
|
|
|
138 |
"is_live": itag in LIVE,
|
139 |
"is_3d": itag in _3D,
|
140 |
"is_hdr": itag in HDR,
|
|
|
141 |
"is_dash": (
|
142 |
itag in DASH_AUDIO
|
143 |
or itag in DASH_VIDEO
|
pytube/streams.py
CHANGED
@@ -75,7 +75,7 @@ class Stream:
|
|
75 |
itag_profile = get_format_profile(self.itag)
|
76 |
self.is_dash = itag_profile["is_dash"]
|
77 |
self.abr = itag_profile["abr"] # average bitrate (audio streams only)
|
78 |
-
self.fps =
|
79 |
"fps"
|
80 |
] # frames per second (video streams only)
|
81 |
self.resolution = itag_profile[
|
|
|
75 |
itag_profile = get_format_profile(self.itag)
|
76 |
self.is_dash = itag_profile["is_dash"]
|
77 |
self.abr = itag_profile["abr"] # average bitrate (audio streams only)
|
78 |
+
self.fps = stream[
|
79 |
"fps"
|
80 |
] # frames per second (video streams only)
|
81 |
self.resolution = itag_profile[
|
tests/test_query.py
CHANGED
@@ -9,7 +9,7 @@ import pytest
|
|
9 |
({"progressive": True}, [18, 22]),
|
10 |
({"resolution": "720p"}, [22, 136, 247, 398]),
|
11 |
({"res": "720p"}, [22, 136, 247, 398]),
|
12 |
-
({"fps":
|
13 |
({"mime_type": "audio/mp4"}, [140]),
|
14 |
({"type": "audio"}, [140, 249, 250, 251]),
|
15 |
({"subtype": "3gpp"}, []),
|
@@ -175,6 +175,6 @@ def test_repr(cipher_signature):
|
|
175 |
)
|
176 |
) == (
|
177 |
'[<Stream: itag="18" mime_type="video/mp4" '
|
178 |
-
'res="360p" fps="
|
179 |
'acodec="mp4a.40.2" progressive="True" type="video">]'
|
180 |
)
|
|
|
9 |
({"progressive": True}, [18, 22]),
|
10 |
({"resolution": "720p"}, [22, 136, 247, 398]),
|
11 |
({"res": "720p"}, [22, 136, 247, 398]),
|
12 |
+
({"fps": 24, "resolution": "480p"}, [135, 244, 397]),
|
13 |
({"mime_type": "audio/mp4"}, [140]),
|
14 |
({"type": "audio"}, [140, 249, 250, 251]),
|
15 |
({"subtype": "3gpp"}, []),
|
|
|
175 |
)
|
176 |
) == (
|
177 |
'[<Stream: itag="18" mime_type="video/mp4" '
|
178 |
+
'res="360p" fps="24fps" vcodec="avc1.42001E" '
|
179 |
'acodec="mp4a.40.2" progressive="True" type="video">]'
|
180 |
)
|
tests/test_streams.py
CHANGED
@@ -285,7 +285,7 @@ def test_repr_for_audio_streams(cipher_signature):
|
|
285 |
def test_repr_for_video_streams(cipher_signature):
|
286 |
stream = str(cipher_signature.streams.filter(only_video=True)[0])
|
287 |
expected = (
|
288 |
-
'<Stream: itag="137" mime_type="video/mp4" res="1080p" fps="
|
289 |
'vcodec="avc1.640028" progressive="False" type="video">'
|
290 |
)
|
291 |
assert stream == expected
|
@@ -294,7 +294,7 @@ def test_repr_for_video_streams(cipher_signature):
|
|
294 |
def test_repr_for_progressive_streams(cipher_signature):
|
295 |
stream = str(cipher_signature.streams.filter(progressive=True)[0])
|
296 |
expected = (
|
297 |
-
'<Stream: itag="18" mime_type="video/mp4" res="360p" fps="
|
298 |
'vcodec="avc1.42001E" acodec="mp4a.40.2" progressive="True" '
|
299 |
'type="video">'
|
300 |
)
|
@@ -304,7 +304,7 @@ def test_repr_for_progressive_streams(cipher_signature):
|
|
304 |
def test_repr_for_adaptive_streams(cipher_signature):
|
305 |
stream = str(cipher_signature.streams.filter(adaptive=True)[0])
|
306 |
expected = (
|
307 |
-
'<Stream: itag="137" mime_type="video/mp4" res="1080p" fps="
|
308 |
'vcodec="avc1.640028" progressive="False" type="video">'
|
309 |
)
|
310 |
assert stream == expected
|
|
|
285 |
def test_repr_for_video_streams(cipher_signature):
|
286 |
stream = str(cipher_signature.streams.filter(only_video=True)[0])
|
287 |
expected = (
|
288 |
+
'<Stream: itag="137" mime_type="video/mp4" res="1080p" fps="24fps" '
|
289 |
'vcodec="avc1.640028" progressive="False" type="video">'
|
290 |
)
|
291 |
assert stream == expected
|
|
|
294 |
def test_repr_for_progressive_streams(cipher_signature):
|
295 |
stream = str(cipher_signature.streams.filter(progressive=True)[0])
|
296 |
expected = (
|
297 |
+
'<Stream: itag="18" mime_type="video/mp4" res="360p" fps="24fps" '
|
298 |
'vcodec="avc1.42001E" acodec="mp4a.40.2" progressive="True" '
|
299 |
'type="video">'
|
300 |
)
|
|
|
304 |
def test_repr_for_adaptive_streams(cipher_signature):
|
305 |
stream = str(cipher_signature.streams.filter(adaptive=True)[0])
|
306 |
expected = (
|
307 |
+
'<Stream: itag="137" mime_type="video/mp4" res="1080p" fps="24fps" '
|
308 |
'vcodec="avc1.640028" progressive="False" type="video">'
|
309 |
)
|
310 |
assert stream == expected
|