Taylor Fox Dahlin commited on
Commit
b4ef682
·
unverified ·
1 Parent(s): 8ff1168

Improvement/reduce network calls (#842)

Browse files

* Added package-wide variables for caching player js and js_url.

docs/user/playlist.rst CHANGED
@@ -39,8 +39,8 @@ Or, if we're only interested in the URLs for the videos, we can look at those as
39
 
40
  >>> for url in p.video_urls[:3]:
41
  >>> print(url)
42
- Python Tutorial for Beginers 1 - Getting Started and Installing Python (For Absolute Beginners)
43
- Python Tutorial for Beginers 2 - Numbers and Math in Python
44
- Python Tutorial for Beginers 3 - Variables and Inputs
45
 
46
  And that's basically all there is to it! The Playlist class is relatively straightforward.
 
39
 
40
  >>> for url in p.video_urls[:3]:
41
  >>> print(url)
42
+ Python Tutorial for Beginners 1 - Getting Started and Installing Python (For Absolute Beginners)
43
+ Python Tutorial for Beginners 2 - Numbers and Math in Python
44
+ Python Tutorial for Beginners 3 - Variables and Inputs
45
 
46
  And that's basically all there is to it! The Playlist class is relatively straightforward.
pytube/__init__.py CHANGED
@@ -8,6 +8,8 @@ __title__ = "pytube3"
8
  __author__ = "Nick Ficano, Harold Martin"
9
  __license__ = "MIT License"
10
  __copyright__ = "Copyright 2019 Nick Ficano"
 
 
11
 
12
  from pytube.version import __version__
13
  from pytube.streams import Stream
 
8
  __author__ = "Nick Ficano, Harold Martin"
9
  __license__ = "MIT License"
10
  __copyright__ = "Copyright 2019 Nick Ficano"
11
+ __js__ = None
12
+ __js_url__ = None
13
 
14
  from pytube.version import __version__
15
  from pytube.streams import Stream
pytube/__main__.py CHANGED
@@ -14,6 +14,7 @@ from typing import List
14
  from typing import Optional
15
  from urllib.parse import parse_qsl
16
 
 
17
  from pytube import Caption
18
  from pytube import CaptionQuery
19
  from pytube import extract
@@ -165,12 +166,6 @@ class YouTube:
165
  apply_descrambler(self.vid_info, fmt)
166
  apply_descrambler(self.player_config_args, fmt)
167
 
168
- if not self.js:
169
- if not self.embed_html:
170
- self.embed_html = request.get(url=self.embed_url)
171
- self.js_url = extract.js_url(self.embed_html)
172
- self.js = request.get(self.js_url)
173
-
174
  apply_signature(self.player_config_args, fmt, self.js)
175
 
176
  # build instances of :class:`Stream <Stream>`
@@ -206,17 +201,25 @@ class YouTube:
206
  self.vid_info_url = extract.video_info_url_age_restricted(
207
  self.video_id, self.watch_url
208
  )
 
209
  else:
210
  self.vid_info_url = extract.video_info_url(
211
  video_id=self.video_id, watch_url=self.watch_url
212
  )
 
213
 
214
  self.initial_data = extract.initial_data(self.watch_html)
215
 
216
  self.vid_info_raw = request.get(self.vid_info_url)
217
- if not self.age_restricted:
218
- self.js_url = extract.js_url(self.watch_html)
 
 
219
  self.js = request.get(self.js_url)
 
 
 
 
220
 
221
  def initialize_stream_objects(self, fmt: str) -> None:
222
  """Convert manifest data to instances of :class:`Stream <Stream>`.
 
14
  from typing import Optional
15
  from urllib.parse import parse_qsl
16
 
17
+ import pytube
18
  from pytube import Caption
19
  from pytube import CaptionQuery
20
  from pytube import extract
 
166
  apply_descrambler(self.vid_info, fmt)
167
  apply_descrambler(self.player_config_args, fmt)
168
 
 
 
 
 
 
 
169
  apply_signature(self.player_config_args, fmt, self.js)
170
 
171
  # build instances of :class:`Stream <Stream>`
 
201
  self.vid_info_url = extract.video_info_url_age_restricted(
202
  self.video_id, self.watch_url
203
  )
204
+ self.js_url = extract.js_url(self.embed_html)
205
  else:
206
  self.vid_info_url = extract.video_info_url(
207
  video_id=self.video_id, watch_url=self.watch_url
208
  )
209
+ self.js_url = extract.js_url(self.watch_html)
210
 
211
  self.initial_data = extract.initial_data(self.watch_html)
212
 
213
  self.vid_info_raw = request.get(self.vid_info_url)
214
+
215
+ # If the js_url doesn't match the cached url, fetch the new js and update
216
+ # the cache; otherwise, load the cache.
217
+ if pytube.__js_url__ != self.js_url:
218
  self.js = request.get(self.js_url)
219
+ pytube.__js__ = self.js
220
+ pytube.__js_url__ = self.js_url
221
+ else:
222
+ self.js = pytube.__js__
223
 
224
  def initialize_stream_objects(self, fmt: str) -> None:
225
  """Convert manifest data to instances of :class:`Stream <Stream>`.
tests/test_main.py CHANGED
@@ -3,6 +3,7 @@ from unittest import mock
3
 
4
  import pytest
5
 
 
6
  from pytube import YouTube
7
  from pytube.exceptions import VideoUnavailable
8
 
@@ -54,3 +55,24 @@ def test_video_keywords(cipher_signature):
54
  'BLACKPINK', 'Year in Review'
55
  ]
56
  assert cipher_signature.keywords == expected
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
 
4
  import pytest
5
 
6
+ import pytube
7
  from pytube import YouTube
8
  from pytube.exceptions import VideoUnavailable
9
 
 
55
  'BLACKPINK', 'Year in Review'
56
  ]
57
  assert cipher_signature.keywords == expected
58
+
59
+
60
+ def test_js_caching(cipher_signature):
61
+ assert pytube.__js__ is not None
62
+ assert pytube.__js_url__ is not None
63
+ assert pytube.__js__ == cipher_signature.js
64
+ assert pytube.__js_url__ == cipher_signature.js_url
65
+
66
+ with mock.patch('pytube.request.urlopen') as mock_urlopen:
67
+ mock_urlopen_object = mock.Mock()
68
+
69
+ # We should never read the js from this
70
+ mock_urlopen_object.read.side_effect = [
71
+ cipher_signature.watch_html.encode('utf-8'),
72
+ cipher_signature.vid_info_raw.encode('utf-8'),
73
+ cipher_signature.js.encode('utf-8')
74
+ ]
75
+
76
+ mock_urlopen.return_value = mock_urlopen_object
77
+ cipher_signature.prefetch()
78
+ assert mock_urlopen.call_count == 2