hbmartin commited on
Commit
4c59ac5
·
1 Parent(s): c1a2fd8

fixes length and thumbnail properties

Browse files
pytube/__main__.py CHANGED
@@ -252,7 +252,17 @@ class YouTube(object):
252
  :rtype: str
253
 
254
  """
255
- return self.player_config_args["thumbnail_url"]
 
 
 
 
 
 
 
 
 
 
256
 
257
  @property
258
  def title(self) -> str:
@@ -273,10 +283,10 @@ class YouTube(object):
273
  return self.vid_descr
274
 
275
  @property
276
- def rating(self):
277
  """Get the video average rating.
278
 
279
- :rtype: str
280
 
281
  """
282
  return (
@@ -286,16 +296,18 @@ class YouTube(object):
286
  )
287
 
288
  @property
289
- def length(self):
290
  """Get the video length in seconds.
291
 
292
  :rtype: str
293
 
294
  """
295
- return self.player_config_args["length_seconds"]
 
 
296
 
297
  @property
298
- def views(self):
299
  """Get the number of the times the video has been viewed.
300
 
301
  :rtype: str
 
252
  :rtype: str
253
 
254
  """
255
+ player_response = self.player_config_args.get("player_response", {})
256
+ thumbnail_details = (
257
+ player_response.get("videoDetails", {})
258
+ .get("thumbnail", {})
259
+ .get("thumbnails")
260
+ )
261
+ if thumbnail_details:
262
+ thumbnail_details = thumbnail_details[-1] # last item has max size
263
+ return thumbnail_details["url"]
264
+
265
+ return "https://img.youtube.com/vi/" + self.video_id + "/maxresdefault.jpg"
266
 
267
  @property
268
  def title(self) -> str:
 
283
  return self.vid_descr
284
 
285
  @property
286
+ def rating(self) -> float:
287
  """Get the video average rating.
288
 
289
+ :rtype: float
290
 
291
  """
292
  return (
 
296
  )
297
 
298
  @property
299
+ def length(self) -> str:
300
  """Get the video length in seconds.
301
 
302
  :rtype: str
303
 
304
  """
305
+ return self.player_config_args["player_response"]["videoDetails"][
306
+ "lengthSeconds"
307
+ ]
308
 
309
  @property
310
+ def views(self) -> str:
311
  """Get the number of the times the video has been viewed.
312
 
313
  :rtype: str
pytube/helpers.py CHANGED
@@ -135,7 +135,7 @@ def safe_filename(s: str, max_length: int = 255) -> str:
135
  return filename[:max_length].rsplit(" ", 0)[0]
136
 
137
 
138
- def create_logger(level:int = logging.ERROR) -> logging.Logger:
139
  """Create a configured instance of logger.
140
 
141
  :param int level:
 
135
  return filename[:max_length].rsplit(" ", 0)[0]
136
 
137
 
138
+ def create_logger(level: int = logging.ERROR) -> logging.Logger:
139
  """Create a configured instance of logger.
140
 
141
  :param int level:
pytube/query.py CHANGED
@@ -167,7 +167,7 @@ class StreamQuery:
167
  return StreamQuery(fmt_streams)
168
 
169
  def order_by(self, attribute_name: str) -> "StreamQuery":
170
- """Apply a sort order to a resultset. Implicitly Filters out stream the do not have the attribute.
171
 
172
  :param str attribute_name:
173
  The name of the attribute to sort by.
@@ -195,10 +195,10 @@ class StreamQuery:
195
 
196
  # lookup integer values if we have them
197
  if integer_attr_repr is not None:
198
- return StreamQuery( # mypy: ignore
199
  sorted(
200
  has_attribute,
201
- key=lambda s: integer_attr_repr[getattr(s, attribute_name)], # type: ignore
202
  )
203
  )
204
  else:
 
167
  return StreamQuery(fmt_streams)
168
 
169
  def order_by(self, attribute_name: str) -> "StreamQuery":
170
+ """Apply a sort order to a resultset. Filters out stream the do not have the attribute.
171
 
172
  :param str attribute_name:
173
  The name of the attribute to sort by.
 
195
 
196
  # lookup integer values if we have them
197
  if integer_attr_repr is not None:
198
+ return StreamQuery(
199
  sorted(
200
  has_attribute,
201
+ key=lambda s: integer_attr_repr[getattr(s, attribute_name)], # type: ignore # noqa: E501
202
  )
203
  )
204
  else:
pytube/streams.py CHANGED
@@ -12,7 +12,7 @@ import io
12
  import logging
13
  import os
14
  import pprint
15
- from typing import Dict, Tuple, Optional
16
 
17
  from pytube import extract
18
  from pytube import request
@@ -42,18 +42,21 @@ class Stream(object):
42
  # (Borg pattern).
43
  self._monostate = monostate
44
 
 
 
 
 
 
 
45
  self.abr = None # average bitrate (audio streams only)
46
  self.fps = None # frames per second (video streams only)
47
- self.itag = None # stream format id (youtube nomenclature)
48
  self.res = None # resolution (e.g.: 480p, 720p, 1080p)
49
- self.url = None # signed download url
50
 
51
  self._filesize: Optional[int] = None # filesize in bytes
52
  self.mime_type = None # content identifier (e.g.: video/mp4)
53
- self.type = None # the part of the mime before the slash
54
  self.subtype = None # the part of the mime after the slash
55
 
56
- self.codecs = [] # audio/video encoders (e.g.: vp8, mp4a)
57
  self.audio_codec = None # audio codec of the stream (e.g.: vorbis)
58
  self.video_codec = None # video codec of the stream (e.g.: vp8)
59
 
@@ -63,7 +66,7 @@ class Stream(object):
63
 
64
  # Additional information about the stream format, such as resolution,
65
  # frame rate, and whether the stream is live (HLS) or 3D.
66
- self.fmt_profile = get_format_profile(self.itag)
67
 
68
  # Same as above, except for the format profile attributes.
69
  self.set_attributes_from_dict(self.fmt_profile)
 
12
  import logging
13
  import os
14
  import pprint
15
+ from typing import Dict, Tuple, Optional, List
16
 
17
  from pytube import extract
18
  from pytube import request
 
42
  # (Borg pattern).
43
  self._monostate = monostate
44
 
45
+ self.url = stream["url"] # signed download url
46
+ self.itag = int(stream["itag"]) # stream format id (youtube nomenclature)
47
+ self.type = stream[
48
+ "type"
49
+ ] # the part of the mime before the slash, overwritten later
50
+
51
  self.abr = None # average bitrate (audio streams only)
52
  self.fps = None # frames per second (video streams only)
 
53
  self.res = None # resolution (e.g.: 480p, 720p, 1080p)
 
54
 
55
  self._filesize: Optional[int] = None # filesize in bytes
56
  self.mime_type = None # content identifier (e.g.: video/mp4)
 
57
  self.subtype = None # the part of the mime after the slash
58
 
59
+ self.codecs: List[str] = [] # audio/video encoders (e.g.: vp8, mp4a)
60
  self.audio_codec = None # audio codec of the stream (e.g.: vorbis)
61
  self.video_codec = None # video codec of the stream (e.g.: vp8)
62
 
 
66
 
67
  # Additional information about the stream format, such as resolution,
68
  # frame rate, and whether the stream is live (HLS) or 3D.
69
+ self.fmt_profile: Dict = get_format_profile(self.itag)
70
 
71
  # Same as above, except for the format profile attributes.
72
  self.set_attributes_from_dict(self.fmt_profile)
tests/test_cli.py CHANGED
@@ -10,4 +10,4 @@ def test_download(MockYouTube, mock_sys):
10
  instance = MockYouTube.return_value
11
  instance.prefetch_descramble.return_value = None
12
  instance.streams = mock.Mock()
13
- cli.download("asdf", "asdf")
 
10
  instance = MockYouTube.return_value
11
  instance.prefetch_descramble.return_value = None
12
  instance.streams = mock.Mock()
13
+ cli.download("asdf", 123)