From dc9f179048204c91cdfbad8b6b7b3bbe0950583c Mon Sep 17 00:00:00 2001 From: Nick Ficano Date: Mon, 9 Oct 2017 01:13:38 -0400 Subject: [PATCH] updated readme, added orderby --- README.rst | 134 ++++++++++++++++++++++++++++++++++++++++++++++-- pytube/query.py | 15 +++++- 2 files changed, 145 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index d1694fdeb..29ebeb898 100644 --- a/README.rst +++ b/README.rst @@ -38,12 +38,140 @@ Download using pip via pypi. pip install pytube -Easy as Pie 💥 -============== +Getting started +=============== -Behold, the power of pytube: +Let's begin with showing how easy it is to download a video with pytube: .. code-block:: python >>> from pytube import YouTube >>> YouTube('http://youtube.com/watch?v=9bZkp7q19f0').streams.first().download() + +This example will download the highest quality progressive download stream available. + +Next, let's explore how we would view what video streams are available: + +.. code-block:: python + + >>> yt = YouTube('http://youtube.com/watch?v=9bZkp7q19f0') + >>> yt.streams.all() + [, + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ] + +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). + +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. + +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. + +To only view these progressive download streams: + +.. code:: bash + + >>> yt.streams.filter(progressive=True).all() + [, + , + , + , + ] + +Conversely, if you only want to see the DASH streams (also referred to as "adaptive") you can do: + +.. code:: bash + + >>> yt.streams.filter(adaptive=True).all() + [, + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ] + + +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. + +To list the audio only streams: + +.. code:: bash + + >>> yt.streams.filter(only_audio=True).all() + [, + , + , + , + ] + + +To list only ``mp4`` streams: + +.. code:: bash + + >>> yt.streams.filter(subtype='mp4').all() + [, + , + , + , + , + , + , + , + ] + + +Multiple filters can also be specified: + +.. code:: bash + + >>> yt.streams.filter(subtype='mp4', progressive=True).all() + >>> # this can also be expressed as: + >>> yt.streams.filter(subtype='mp4').filter(progressive=True).all() + [, + ] + +You also have an interface to select streams by their itag, without needing to filter: + +.. code:: bash + + >>> yt.streams.get_by_itag(22) + + + +If you need to optimize for a specific feature, such as the "highest resolution" or "lowest average bitrate": + +.. code:: bash + + >>> yt.streams.filter(progressive=True).order_by('resolution').desc().all() + +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. diff --git a/pytube/query.py b/pytube/query.py index 7954f0a81..fc09822aa 100644 --- a/pytube/query.py +++ b/pytube/query.py @@ -103,7 +103,7 @@ def filter( filters.append(lambda s: s.is_progressive) if adaptive: - filters.append(lambda s: s.is_progressive) + filters.append(lambda s: s.is_adaptive) if custom_filter_functions: for fn in custom_filter_functions: @@ -114,6 +114,19 @@ def filter( fmt_streams = list(filter(fn, fmt_streams)) return StreamQuery(fmt_streams) + def order_by(self, attribute_name): + fmt_streams = sorted( + self.fmt_streams, + key=lambda s: getattr(s, attribute_name), + ) + return StreamQuery(fmt_streams) + + def desc(self): + return StreamQuery(self.fmt_streams[::-1]) + + def asc(self): + return self + def get_by_itag(self, itag): """Get a :class:`Stream ` for an itag, or None if not found.