Merge pull request #54 from hbmartin/live-and-complete-fixes
Browse files- pytube/__main__.py +3 -6
- pytube/extract.py +6 -5
- pytube/monostate.py +3 -4
- pytube/streams.py +6 -7
pytube/__main__.py
CHANGED
@@ -22,7 +22,7 @@ from pytube import Stream
|
|
22 |
from pytube import StreamQuery
|
23 |
from pytube.extract import apply_descrambler, apply_signature, get_ytplayer_config
|
24 |
from pytube.helpers import install_proxy
|
25 |
-
from pytube.exceptions import VideoUnavailable
|
26 |
from pytube.monostate import OnProgress, OnComplete, Monostate
|
27 |
|
28 |
logger = logging.getLogger(__name__)
|
@@ -164,11 +164,8 @@ class YouTube:
|
|
164 |
raise VideoUnavailable(video_id=self.video_id)
|
165 |
self.age_restricted = extract.is_age_restricted(self.watch_html)
|
166 |
|
167 |
-
if not self.age_restricted:
|
168 |
-
|
169 |
-
raise LiveStreamError(self.video_id)
|
170 |
-
if "This video is private" in self.watch_html:
|
171 |
-
raise VideoUnavailable(video_id=self.video_id)
|
172 |
|
173 |
if self.age_restricted:
|
174 |
if not self.embed_html:
|
|
|
22 |
from pytube import StreamQuery
|
23 |
from pytube.extract import apply_descrambler, apply_signature, get_ytplayer_config
|
24 |
from pytube.helpers import install_proxy
|
25 |
+
from pytube.exceptions import VideoUnavailable
|
26 |
from pytube.monostate import OnProgress, OnComplete, Monostate
|
27 |
|
28 |
logger = logging.getLogger(__name__)
|
|
|
164 |
raise VideoUnavailable(video_id=self.video_id)
|
165 |
self.age_restricted = extract.is_age_restricted(self.watch_html)
|
166 |
|
167 |
+
if not self.age_restricted and "This video is private" in self.watch_html:
|
168 |
+
raise VideoUnavailable(video_id=self.video_id)
|
|
|
|
|
|
|
169 |
|
170 |
if self.age_restricted:
|
171 |
if not self.embed_html:
|
pytube/extract.py
CHANGED
@@ -221,15 +221,16 @@ def apply_signature(config_args: Dict, fmt: str, js: str) -> None:
|
|
221 |
"""
|
222 |
cipher = Cipher(js=js)
|
223 |
stream_manifest = config_args[fmt]
|
224 |
-
|
225 |
-
json.loads(config_args["player_response"])
|
226 |
-
.get("playabilityStatus", {},)
|
227 |
-
.get("liveStreamability")
|
228 |
-
)
|
229 |
for i, stream in enumerate(stream_manifest):
|
230 |
try:
|
231 |
url: str = stream["url"]
|
232 |
except KeyError:
|
|
|
|
|
|
|
|
|
|
|
233 |
if live_stream:
|
234 |
raise LiveStreamError("UNKNOWN")
|
235 |
# 403 Forbidden fix.
|
|
|
221 |
"""
|
222 |
cipher = Cipher(js=js)
|
223 |
stream_manifest = config_args[fmt]
|
224 |
+
|
|
|
|
|
|
|
|
|
225 |
for i, stream in enumerate(stream_manifest):
|
226 |
try:
|
227 |
url: str = stream["url"]
|
228 |
except KeyError:
|
229 |
+
live_stream = (
|
230 |
+
json.loads(config_args["player_response"])
|
231 |
+
.get("playabilityStatus", {},)
|
232 |
+
.get("liveStreamability")
|
233 |
+
)
|
234 |
if live_stream:
|
235 |
raise LiveStreamError("UNKNOWN")
|
236 |
# 403 Forbidden fix.
|
pytube/monostate.py
CHANGED
@@ -33,17 +33,16 @@ class OnProgress(Protocol):
|
|
33 |
|
34 |
|
35 |
class OnComplete(Protocol):
|
36 |
-
def __call__(self, stream: Any,
|
37 |
"""On download complete handler function.
|
38 |
|
39 |
:param stream:
|
40 |
An instance of :class:`Stream <Stream>` being downloaded.
|
41 |
:type stream:
|
42 |
:py:class:`pytube.Stream`
|
43 |
-
:param
|
44 |
The file handle where the media is being written to.
|
45 |
-
:type
|
46 |
-
:py:class:`io.BufferedWriter`
|
47 |
|
48 |
:rtype: None
|
49 |
"""
|
|
|
33 |
|
34 |
|
35 |
class OnComplete(Protocol):
|
36 |
+
def __call__(self, stream: Any, file_path: Optional[str]) -> None:
|
37 |
"""On download complete handler function.
|
38 |
|
39 |
:param stream:
|
40 |
An instance of :class:`Stream <Stream>` being downloaded.
|
41 |
:type stream:
|
42 |
:py:class:`pytube.Stream`
|
43 |
+
:param file_path:
|
44 |
The file handle where the media is being written to.
|
45 |
+
:type file_path: str
|
|
|
46 |
|
47 |
:rtype: None
|
48 |
"""
|
pytube/streams.py
CHANGED
@@ -245,7 +245,7 @@ class Stream:
|
|
245 |
bytes_remaining -= len(chunk)
|
246 |
# send to the on_progress callback.
|
247 |
self.on_progress(chunk, fh, bytes_remaining)
|
248 |
-
self.on_complete(
|
249 |
return file_path
|
250 |
|
251 |
def stream_to_buffer(self) -> io.BytesIO:
|
@@ -264,7 +264,7 @@ class Stream:
|
|
264 |
bytes_remaining -= len(chunk)
|
265 |
# send to the on_progress callback.
|
266 |
self.on_progress(chunk, buffer, bytes_remaining)
|
267 |
-
self.on_complete(
|
268 |
return buffer
|
269 |
|
270 |
def on_progress(self, chunk, file_handler, bytes_remaining):
|
@@ -300,13 +300,12 @@ class Stream:
|
|
300 |
logger.debug("calling on_progress callback %s", on_progress)
|
301 |
on_progress(self, chunk, file_handler, bytes_remaining)
|
302 |
|
303 |
-
def on_complete(self,
|
304 |
"""On download complete handler function.
|
305 |
|
306 |
-
:param
|
307 |
The file handle where the media is being written to.
|
308 |
-
:type file_handle:
|
309 |
-
:py:class:`io.BufferedWriter`
|
310 |
|
311 |
:rtype: None
|
312 |
|
@@ -315,7 +314,7 @@ class Stream:
|
|
315 |
on_complete = self._monostate.on_complete
|
316 |
if on_complete:
|
317 |
logger.debug("calling on_complete callback %s", on_complete)
|
318 |
-
on_complete(self,
|
319 |
|
320 |
def __repr__(self) -> str:
|
321 |
"""Printable object representation.
|
|
|
245 |
bytes_remaining -= len(chunk)
|
246 |
# send to the on_progress callback.
|
247 |
self.on_progress(chunk, fh, bytes_remaining)
|
248 |
+
self.on_complete(file_path)
|
249 |
return file_path
|
250 |
|
251 |
def stream_to_buffer(self) -> io.BytesIO:
|
|
|
264 |
bytes_remaining -= len(chunk)
|
265 |
# send to the on_progress callback.
|
266 |
self.on_progress(chunk, buffer, bytes_remaining)
|
267 |
+
self.on_complete(None)
|
268 |
return buffer
|
269 |
|
270 |
def on_progress(self, chunk, file_handler, bytes_remaining):
|
|
|
300 |
logger.debug("calling on_progress callback %s", on_progress)
|
301 |
on_progress(self, chunk, file_handler, bytes_remaining)
|
302 |
|
303 |
+
def on_complete(self, file_path: Optional[str]):
|
304 |
"""On download complete handler function.
|
305 |
|
306 |
+
:param file_path:
|
307 |
The file handle where the media is being written to.
|
308 |
+
:type file_handle: str
|
|
|
309 |
|
310 |
:rtype: None
|
311 |
|
|
|
314 |
on_complete = self._monostate.on_complete
|
315 |
if on_complete:
|
316 |
logger.debug("calling on_complete callback %s", on_complete)
|
317 |
+
on_complete(self, file_path)
|
318 |
|
319 |
def __repr__(self) -> str:
|
320 |
"""Printable object representation.
|