nficano commited on
Commit
dc9f179
·
1 Parent(s): 49374ef

updated readme, added orderby

Browse files
Files changed (2) hide show
  1. README.rst +131 -3
  2. pytube/query.py +14 -1
README.rst CHANGED
@@ -38,12 +38,140 @@ Download using pip via pypi.
38
 
39
  pip install pytube
40
 
41
- Easy as Pie 💥
42
- ==============
43
 
44
- Behold, the power of pytube:
45
 
46
  .. code-block:: python
47
 
48
  >>> from pytube import YouTube
49
  >>> YouTube('http://youtube.com/watch?v=9bZkp7q19f0').streams.first().download()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
  pip install pytube
40
 
41
+ Getting started
42
+ ===============
43
 
44
+ Let's begin with showing how easy it is to download a video with pytube:
45
 
46
  .. code-block:: python
47
 
48
  >>> from pytube import YouTube
49
  >>> YouTube('http://youtube.com/watch?v=9bZkp7q19f0').streams.first().download()
50
+
51
+ This example will download the highest quality progressive download stream available.
52
+
53
+ Next, let's explore how we would view what video streams are available:
54
+
55
+ .. code-block:: python
56
+
57
+ >>> yt = YouTube('http://youtube.com/watch?v=9bZkp7q19f0')
58
+ >>> yt.streams.all()
59
+ [<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">,
60
+ <Stream: itag="43" mime_type="video/webm" res="360p" fps="30fps" vcodec="vp8.0" acodec="vorbis">,
61
+ <Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">,
62
+ <Stream: itag="36" mime_type="video/3gpp" res="240p" fps="30fps" vcodec="mp4v.20.3" acodec="mp4a.40.2">,
63
+ <Stream: itag="17" mime_type="video/3gpp" res="144p" fps="30fps" vcodec="mp4v.20.3" acodec="mp4a.40.2">,
64
+ <Stream: itag="137" mime_type="video/mp4" res="1080p" fps="30fps" vcodec="avc1.640028">,
65
+ <Stream: itag="248" mime_type="video/webm" res="1080p" fps="30fps" vcodec="vp9">,
66
+ <Stream: itag="136" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.4d401f">,
67
+ <Stream: itag="247" mime_type="video/webm" res="720p" fps="30fps" vcodec="vp9">,
68
+ <Stream: itag="135" mime_type="video/mp4" res="480p" fps="30fps" vcodec="avc1.4d401e">,
69
+ <Stream: itag="244" mime_type="video/webm" res="480p" fps="30fps" vcodec="vp9">,
70
+ <Stream: itag="134" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.4d401e">,
71
+ <Stream: itag="243" mime_type="video/webm" res="360p" fps="30fps" vcodec="vp9">,
72
+ <Stream: itag="133" mime_type="video/mp4" res="240p" fps="30fps" vcodec="avc1.4d4015">,
73
+ <Stream: itag="242" mime_type="video/webm" res="240p" fps="30fps" vcodec="vp9">,
74
+ <Stream: itag="160" mime_type="video/mp4" res="144p" fps="30fps" vcodec="avc1.4d400c">,
75
+ <Stream: itag="278" mime_type="video/webm" res="144p" fps="30fps" vcodec="vp9">,
76
+ <Stream: itag="140" mime_type="audio/mp4" abr="128kbps" acodec="mp4a.40.2">,
77
+ <Stream: itag="171" mime_type="audio/webm" abr="128kbps" acodec="vorbis">,
78
+ <Stream: itag="249" mime_type="audio/webm" abr="50kbps" acodec="opus">,
79
+ <Stream: itag="250" mime_type="audio/webm" abr="70kbps" acodec="opus">,
80
+ <Stream: itag="251" mime_type="audio/webm" abr="160kbps" acodec="opus">]
81
+
82
+ You may notice that some streams listed have both a video codec and audio codec, while others have just video or just audio, this is a result of YouTube supporting a streaming technique called Dynamic Adaptive Streaming over HTTP (DASH).
83
+
84
+ In the context of pytube, the implications are for the highest quality streams; you now need to download both the audio and video tracks and then post-process them with software like FFmpeg to merge them.
85
+
86
+ The legacy streams that contain the audio and video in a single file (referred to as "progressive download") are still available, but only for resolutions 720p and below.
87
+
88
+ To only view these progressive download streams:
89
+
90
+ .. code:: bash
91
+
92
+ >>> yt.streams.filter(progressive=True).all()
93
+ [<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">,
94
+ <Stream: itag="43" mime_type="video/webm" res="360p" fps="30fps" vcodec="vp8.0" acodec="vorbis">,
95
+ <Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">,
96
+ <Stream: itag="36" mime_type="video/3gpp" res="240p" fps="30fps" vcodec="mp4v.20.3" acodec="mp4a.40.2">,
97
+ <Stream: itag="17" mime_type="video/3gpp" res="144p" fps="30fps" vcodec="mp4v.20.3" acodec="mp4a.40.2">]
98
+
99
+ Conversely, if you only want to see the DASH streams (also referred to as "adaptive") you can do:
100
+
101
+ .. code:: bash
102
+
103
+ >>> yt.streams.filter(adaptive=True).all()
104
+ [<Stream: itag="137" mime_type="video/mp4" res="1080p" fps="30fps" vcodec="avc1.640028">,
105
+ <Stream: itag="248" mime_type="video/webm" res="1080p" fps="30fps" vcodec="vp9">,
106
+ <Stream: itag="136" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.4d401f">,
107
+ <Stream: itag="247" mime_type="video/webm" res="720p" fps="30fps" vcodec="vp9">,
108
+ <Stream: itag="135" mime_type="video/mp4" res="480p" fps="30fps" vcodec="avc1.4d401e">,
109
+ <Stream: itag="244" mime_type="video/webm" res="480p" fps="30fps" vcodec="vp9">,
110
+ <Stream: itag="134" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.4d401e">,
111
+ <Stream: itag="243" mime_type="video/webm" res="360p" fps="30fps" vcodec="vp9">,
112
+ <Stream: itag="133" mime_type="video/mp4" res="240p" fps="30fps" vcodec="avc1.4d4015">,
113
+ <Stream: itag="242" mime_type="video/webm" res="240p" fps="30fps" vcodec="vp9">,
114
+ <Stream: itag="160" mime_type="video/mp4" res="144p" fps="30fps" vcodec="avc1.4d400c">,
115
+ <Stream: itag="278" mime_type="video/webm" res="144p" fps="30fps" vcodec="vp9">,
116
+ <Stream: itag="140" mime_type="audio/mp4" abr="128kbps" acodec="mp4a.40.2">,
117
+ <Stream: itag="171" mime_type="audio/webm" abr="128kbps" acodec="vorbis">,
118
+ <Stream: itag="249" mime_type="audio/webm" abr="50kbps" acodec="opus">,
119
+ <Stream: itag="250" mime_type="audio/webm" abr="70kbps" acodec="opus">,
120
+ <Stream: itag="251" mime_type="audio/webm" abr="160kbps" acodec="opus">]
121
+
122
+
123
+ Pytube allows you to filter on every property available (see the documentation for the complete list), let's take a look at some of the most useful ones.
124
+
125
+ To list the audio only streams:
126
+
127
+ .. code:: bash
128
+
129
+ >>> yt.streams.filter(only_audio=True).all()
130
+ [<Stream: itag="140" mime_type="audio/mp4" abr="128kbps" acodec="mp4a.40.2">,
131
+ <Stream: itag="171" mime_type="audio/webm" abr="128kbps" acodec="vorbis">,
132
+ <Stream: itag="249" mime_type="audio/webm" abr="50kbps" acodec="opus">,
133
+ <Stream: itag="250" mime_type="audio/webm" abr="70kbps" acodec="opus">,
134
+ <Stream: itag="251" mime_type="audio/webm" abr="160kbps" acodec="opus">]
135
+
136
+
137
+ To list only ``mp4`` streams:
138
+
139
+ .. code:: bash
140
+
141
+ >>> yt.streams.filter(subtype='mp4').all()
142
+ [<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">,
143
+ <Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">,
144
+ <Stream: itag="137" mime_type="video/mp4" res="1080p" fps="30fps" vcodec="avc1.640028">,
145
+ <Stream: itag="136" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.4d401f">,
146
+ <Stream: itag="135" mime_type="video/mp4" res="480p" fps="30fps" vcodec="avc1.4d401e">,
147
+ <Stream: itag="134" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.4d401e">,
148
+ <Stream: itag="133" mime_type="video/mp4" res="240p" fps="30fps" vcodec="avc1.4d4015">,
149
+ <Stream: itag="160" mime_type="video/mp4" res="144p" fps="30fps" vcodec="avc1.4d400c">,
150
+ <Stream: itag="140" mime_type="audio/mp4" abr="128kbps" acodec="mp4a.40.2">]
151
+
152
+
153
+ Multiple filters can also be specified:
154
+
155
+ .. code:: bash
156
+
157
+ >>> yt.streams.filter(subtype='mp4', progressive=True).all()
158
+ >>> # this can also be expressed as:
159
+ >>> yt.streams.filter(subtype='mp4').filter(progressive=True).all()
160
+ [<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">,
161
+ <Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">]
162
+
163
+ You also have an interface to select streams by their itag, without needing to filter:
164
+
165
+ .. code:: bash
166
+
167
+ >>> yt.streams.get_by_itag(22)
168
+ <Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">
169
+
170
+
171
+ If you need to optimize for a specific feature, such as the "highest resolution" or "lowest average bitrate":
172
+
173
+ .. code:: bash
174
+
175
+ >>> yt.streams.filter(progressive=True).order_by('resolution').desc().all()
176
+
177
+ Note that ``order_by`` cannot be used if your attribute is undefined in any of the Stream instances, so be sure to apply a filter to remove those before calling it.
pytube/query.py CHANGED
@@ -103,7 +103,7 @@ class StreamQuery:
103
  filters.append(lambda s: s.is_progressive)
104
 
105
  if adaptive:
106
- filters.append(lambda s: s.is_progressive)
107
 
108
  if custom_filter_functions:
109
  for fn in custom_filter_functions:
@@ -114,6 +114,19 @@ class StreamQuery:
114
  fmt_streams = list(filter(fn, fmt_streams))
115
  return StreamQuery(fmt_streams)
116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  def get_by_itag(self, itag):
118
  """Get a :class:`Stream <Stream>` for an itag, or None if not found.
119
 
 
103
  filters.append(lambda s: s.is_progressive)
104
 
105
  if adaptive:
106
+ filters.append(lambda s: s.is_adaptive)
107
 
108
  if custom_filter_functions:
109
  for fn in custom_filter_functions:
 
114
  fmt_streams = list(filter(fn, fmt_streams))
115
  return StreamQuery(fmt_streams)
116
 
117
+ def order_by(self, attribute_name):
118
+ fmt_streams = sorted(
119
+ self.fmt_streams,
120
+ key=lambda s: getattr(s, attribute_name),
121
+ )
122
+ return StreamQuery(fmt_streams)
123
+
124
+ def desc(self):
125
+ return StreamQuery(self.fmt_streams[::-1])
126
+
127
+ def asc(self):
128
+ return self
129
+
130
  def get_by_itag(self, itag):
131
  """Get a :class:`Stream <Stream>` for an itag, or None if not found.
132