doc updates
Browse files- pytube/cipher.py +33 -40
- pytube/extract.py +23 -12
- pytube/query.py +15 -7
pytube/cipher.py
CHANGED
@@ -51,19 +51,17 @@ def get_transform_plan(js):
|
|
51 |
:param str js:
|
52 |
The contents of the base.js asset file.
|
53 |
|
54 |
-
**
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
'DE.kT(a,21)']
|
66 |
-
|
67 |
"""
|
68 |
name = re.escape(get_initial_function_name(js))
|
69 |
pattern = r'%s=function\(\w\){[a-z=\.\(\"\)]*;(.*);(?:.+)}' % name
|
@@ -85,13 +83,12 @@ def get_transform_object(js, var):
|
|
85 |
The obfuscated variable name that stores an object with all functions
|
86 |
that descrambles the signature.
|
87 |
|
88 |
-
**
|
89 |
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
'kT:function(a,b){var c=a[0];a[0]=a[b%a.length];a[b]=c}']
|
95 |
|
96 |
"""
|
97 |
pattern = r'var %s={(.*?)};' % re.escape(var)
|
@@ -133,13 +130,13 @@ def reverse(arr, b):
|
|
133 |
|
134 |
.. code-block:: javascript
|
135 |
|
136 |
-
function(a, b) { a.reverse() }
|
137 |
|
138 |
This method takes an unused ``b`` variable as their transform functions
|
139 |
universally sent two arguments.
|
140 |
|
141 |
-
**Example
|
142 |
-
|
143 |
>>> reverse([1, 2, 3, 4])
|
144 |
[4, 3, 2, 1]
|
145 |
"""
|
@@ -153,10 +150,10 @@ def splice(arr, b):
|
|
153 |
|
154 |
.. code-block:: javascript
|
155 |
|
156 |
-
function(a, b) { a.splice(0, b) }
|
|
|
|
|
157 |
|
158 |
-
**Example usage**:
|
159 |
-
~~~~~~~~~~~~~~
|
160 |
>>> splice([1, 2, 3, 4], 2)
|
161 |
[1, 2]
|
162 |
"""
|
@@ -170,10 +167,10 @@ def swap(arr, b):
|
|
170 |
|
171 |
.. code-block:: javascript
|
172 |
|
173 |
-
function(a, b) { var c=a[0];a[0]=a[b%a.length];a[b]=c }
|
|
|
|
|
174 |
|
175 |
-
**Example usage**:
|
176 |
-
~~~~~~~~~~~~~~
|
177 |
>>> swap([1, 2, 3, 4], 2)
|
178 |
[3, 2, 1, 4]
|
179 |
"""
|
@@ -212,20 +209,16 @@ def parse_function(js_func):
|
|
212 |
Break a JavaScript transform function down into a two element ``tuple``
|
213 |
containing the function name and some integer-based argument.
|
214 |
|
215 |
-
Sample input:
|
216 |
-
|
217 |
-
.. code-block:: javascript
|
218 |
-
|
219 |
-
DE.AJ(a,15)
|
220 |
-
|
221 |
-
Sample Output:
|
222 |
-
|
223 |
-
.. code-block:: python
|
224 |
-
|
225 |
-
('AJ', 15)
|
226 |
-
|
227 |
:param str js_func:
|
228 |
The JavaScript version of the transform function.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
229 |
|
230 |
"""
|
231 |
logger.debug('parsing transform function')
|
|
|
51 |
:param str js:
|
52 |
The contents of the base.js asset file.
|
53 |
|
54 |
+
**Example**:
|
55 |
+
|
56 |
+
>>> get_transform_plan(js)
|
57 |
+
['DE.AJ(a,15)',
|
58 |
+
'DE.VR(a,3)',
|
59 |
+
'DE.AJ(a,51)',
|
60 |
+
'DE.VR(a,3)',
|
61 |
+
'DE.kT(a,51)',
|
62 |
+
'DE.kT(a,8)',
|
63 |
+
'DE.VR(a,3)',
|
64 |
+
'DE.kT(a,21)']
|
|
|
|
|
65 |
"""
|
66 |
name = re.escape(get_initial_function_name(js))
|
67 |
pattern = r'%s=function\(\w\){[a-z=\.\(\"\)]*;(.*);(?:.+)}' % name
|
|
|
83 |
The obfuscated variable name that stores an object with all functions
|
84 |
that descrambles the signature.
|
85 |
|
86 |
+
**Example**:
|
87 |
|
88 |
+
>>> get_transform_object(js, 'DE')
|
89 |
+
['AJ:function(a){a.reverse()}',
|
90 |
+
'VR:function(a,b){a.splice(0,b)}',
|
91 |
+
'kT:function(a,b){var c=a[0];a[0]=a[b%a.length];a[b]=c}']
|
|
|
92 |
|
93 |
"""
|
94 |
pattern = r'var %s={(.*?)};' % re.escape(var)
|
|
|
130 |
|
131 |
.. code-block:: javascript
|
132 |
|
133 |
+
function(a, b) { a.reverse() }
|
134 |
|
135 |
This method takes an unused ``b`` variable as their transform functions
|
136 |
universally sent two arguments.
|
137 |
|
138 |
+
**Example**:
|
139 |
+
|
140 |
>>> reverse([1, 2, 3, 4])
|
141 |
[4, 3, 2, 1]
|
142 |
"""
|
|
|
150 |
|
151 |
.. code-block:: javascript
|
152 |
|
153 |
+
function(a, b) { a.splice(0, b) }
|
154 |
+
|
155 |
+
**Example**:
|
156 |
|
|
|
|
|
157 |
>>> splice([1, 2, 3, 4], 2)
|
158 |
[1, 2]
|
159 |
"""
|
|
|
167 |
|
168 |
.. code-block:: javascript
|
169 |
|
170 |
+
function(a, b) { var c=a[0];a[0]=a[b%a.length];a[b]=c }
|
171 |
+
|
172 |
+
**Example**:
|
173 |
|
|
|
|
|
174 |
>>> swap([1, 2, 3, 4], 2)
|
175 |
[3, 2, 1, 4]
|
176 |
"""
|
|
|
209 |
Break a JavaScript transform function down into a two element ``tuple``
|
210 |
containing the function name and some integer-based argument.
|
211 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
:param str js_func:
|
213 |
The JavaScript version of the transform function.
|
214 |
+
:rtype: tuple
|
215 |
+
:returns:
|
216 |
+
two element tuple containing the function name and an argument.
|
217 |
+
|
218 |
+
**Example**:
|
219 |
+
|
220 |
+
>>> parse_function('DE.AJ(a,15)')
|
221 |
+
('AJ', 15)
|
222 |
|
223 |
"""
|
224 |
logger.debug('parsing transform function')
|
pytube/extract.py
CHANGED
@@ -9,22 +9,30 @@ from pytube.helpers import regex_search
|
|
9 |
|
10 |
|
11 |
def video_id(url):
|
12 |
-
"""Extract the ``video_id``
|
13 |
|
14 |
-
|
15 |
-
|
|
|
|
|
16 |
|
|
|
|
|
|
|
|
|
|
|
17 |
"""
|
18 |
-
|
19 |
-
return regex_search(r'.*(?:v=|/v/|^)(?P<id>[^&]*)', url, group=1)
|
20 |
|
21 |
|
22 |
def watch_url(video_id):
|
23 |
-
"""Construct a YouTube watch url, given a video id.
|
24 |
|
25 |
:param str video_id:
|
26 |
A YouTube video identifer.
|
27 |
-
|
|
|
|
|
28 |
"""
|
29 |
return 'https://youtube.com/watch?v=' + video_id
|
30 |
|
@@ -79,13 +87,16 @@ def mime_type_codec(mime_type_codec):
|
|
79 |
mime type and codecs serialized together, and splits them into separate
|
80 |
elements.
|
81 |
|
|
|
|
|
|
|
|
|
|
|
82 |
:param str mime_type_codec:
|
83 |
-
String containing mime type and codecs
|
84 |
-
'audio/webm; codecs="opus"'
|
85 |
:rtype: tuple
|
86 |
:returns:
|
87 |
-
The mime type and a list of codecs
|
88 |
-
('audio/webm', ['opus'])
|
89 |
|
90 |
"""
|
91 |
pattern = r'(\w+\/\w+)\;\scodecs=\"([a-zA-Z-0-9.,\s]*)\"'
|
@@ -104,7 +115,7 @@ def get_ytplayer_config(watch_html):
|
|
104 |
The html contents of the watch page.
|
105 |
:rtype: str
|
106 |
:returns:
|
107 |
-
Substring of the html containing the
|
108 |
"""
|
109 |
pattern = r';ytplayer\.config\s*=\s*({.*?});'
|
110 |
yt_player_config = regex_search(pattern, watch_html, group=1)
|
|
|
9 |
|
10 |
|
11 |
def video_id(url):
|
12 |
+
"""Extract the ``video_id`` from a YouTube url.
|
13 |
|
14 |
+
This function supports the following patterns:
|
15 |
+
|
16 |
+
- :samp:`https://www.youtube.com/watch?v={video_id}`
|
17 |
+
- :samp:`https://youtu.be/{video_id}`
|
18 |
|
19 |
+
:param str url:
|
20 |
+
A YouTube url containing a video id.
|
21 |
+
:rtype: str
|
22 |
+
:returns:
|
23 |
+
YouTube video id.
|
24 |
"""
|
25 |
+
return regex_search(r'(?:v=|\/)([0-9A-Za-z_-]{11}).*', url, group=1)
|
|
|
26 |
|
27 |
|
28 |
def watch_url(video_id):
|
29 |
+
"""Construct a sanitized YouTube watch url, given a video id.
|
30 |
|
31 |
:param str video_id:
|
32 |
A YouTube video identifer.
|
33 |
+
:rtype: str
|
34 |
+
:returns:
|
35 |
+
Sanitized YouTube watch url.
|
36 |
"""
|
37 |
return 'https://youtube.com/watch?v=' + video_id
|
38 |
|
|
|
87 |
mime type and codecs serialized together, and splits them into separate
|
88 |
elements.
|
89 |
|
90 |
+
**Example**:
|
91 |
+
|
92 |
+
>>> mime_type_codec('audio/webm; codecs="opus"')
|
93 |
+
('audio/webm', ['opus'])
|
94 |
+
|
95 |
:param str mime_type_codec:
|
96 |
+
String containing mime type and codecs.
|
|
|
97 |
:rtype: tuple
|
98 |
:returns:
|
99 |
+
The mime type and a list of codecs.
|
|
|
100 |
|
101 |
"""
|
102 |
pattern = r'(\w+\/\w+)\;\scodecs=\"([a-zA-Z-0-9.,\s]*)\"'
|
|
|
115 |
The html contents of the watch page.
|
116 |
:rtype: str
|
117 |
:returns:
|
118 |
+
Substring of the html containing the encoded manifest data.
|
119 |
"""
|
120 |
pattern = r';ytplayer\.config\s*=\s*({.*?});'
|
121 |
yt_player_config = regex_search(pattern, watch_html, group=1)
|
pytube/query.py
CHANGED
@@ -174,10 +174,14 @@ class StreamQuery:
|
|
174 |
return self
|
175 |
|
176 |
def get_by_itag(self, itag):
|
177 |
-
"""Get
|
178 |
|
179 |
:param str itag:
|
180 |
YouTube format identifier code.
|
|
|
|
|
|
|
|
|
181 |
|
182 |
"""
|
183 |
try:
|
@@ -186,10 +190,12 @@ class StreamQuery:
|
|
186 |
pass
|
187 |
|
188 |
def first(self):
|
189 |
-
"""Get the first
|
190 |
|
191 |
-
|
192 |
-
|
|
|
|
|
193 |
|
194 |
"""
|
195 |
try:
|
@@ -198,10 +204,12 @@ class StreamQuery:
|
|
198 |
pass
|
199 |
|
200 |
def last(self):
|
201 |
-
"""Get the last
|
202 |
|
203 |
-
|
204 |
-
|
|
|
|
|
205 |
|
206 |
"""
|
207 |
try:
|
|
|
174 |
return self
|
175 |
|
176 |
def get_by_itag(self, itag):
|
177 |
+
"""Get the corresponding :class:`Stream <Stream>` for a given itag.
|
178 |
|
179 |
:param str itag:
|
180 |
YouTube format identifier code.
|
181 |
+
:rtype: :class:`Stream <Stream>` or ``None``
|
182 |
+
:returns:
|
183 |
+
The :class:`Stream <Stream>` matching the given itag or ``None`` if
|
184 |
+
not found.
|
185 |
|
186 |
"""
|
187 |
try:
|
|
|
190 |
pass
|
191 |
|
192 |
def first(self):
|
193 |
+
"""Get the first :class:`Stream <Stream>` in the results.
|
194 |
|
195 |
+
:rtype: :class:`Stream <Stream>` or ``None``
|
196 |
+
:returns:
|
197 |
+
the first result of this query or ``None`` if the result doesn't
|
198 |
+
contain any streams.
|
199 |
|
200 |
"""
|
201 |
try:
|
|
|
204 |
pass
|
205 |
|
206 |
def last(self):
|
207 |
+
"""Get the last :class:`Stream <Stream>` in the results.
|
208 |
|
209 |
+
:rtype: :class:`Stream <Stream>` or ``None``
|
210 |
+
:returns:
|
211 |
+
Return the last result of this query or ``None`` if the result
|
212 |
+
doesn't contain any streams.
|
213 |
|
214 |
"""
|
215 |
try:
|