Update readme, precommit config, and makefile
Browse files- .pre-commit-config.yaml +50 -23
- Makefile +39 -33
- README.md +67 -137
- images/pytube.png +0 -0
.pre-commit-config.yaml
CHANGED
@@ -1,27 +1,54 @@
|
|
1 |
-
|
2 |
-
|
|
|
3 |
hooks:
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
hooks:
|
18 |
-
|
19 |
-
|
20 |
-
-
|
21 |
-
|
22 |
hooks:
|
23 |
-
|
24 |
-
|
25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
hooks:
|
27 |
-
-
|
|
|
|
|
|
|
|
|
|
1 |
+
repos:
|
2 |
+
- repo: 'https://github.com/pre-commit/pre-commit-hooks'
|
3 |
+
rev: v3.1.0
|
4 |
hooks:
|
5 |
+
- id: pretty-format-json
|
6 |
+
name: 'Pretty format JSON'
|
7 |
+
args:
|
8 |
+
- '--no-sort-keys'
|
9 |
+
- '--autofix'
|
10 |
+
- '--indent=2'
|
11 |
+
- id: trailing-whitespace
|
12 |
+
name: 'Fix trailing whitespace'
|
13 |
+
exclude: setup.cfg
|
14 |
+
- id: end-of-file-fixer
|
15 |
+
name: 'Fix missing EOF'
|
16 |
+
exclude: setup.cfg
|
17 |
+
- id: check-executables-have-shebangs
|
18 |
+
name: 'Check exeutables for shebangs'
|
19 |
+
- id: check-merge-conflict
|
20 |
+
name: 'Check for merge conflict fragments'
|
21 |
+
- id: check-case-conflict
|
22 |
+
name: 'Check for filesystem character case conflicts'
|
23 |
+
- id: detect-private-key
|
24 |
+
name: 'Check for cleartext private keys stored'
|
25 |
+
- id: check-json
|
26 |
+
name: 'Validate JSON'
|
27 |
+
- id: check-ast
|
28 |
+
name: 'Check Python abstract syntax tree'
|
29 |
+
- repo: 'https://github.com/asottile/reorder_python_imports'
|
30 |
+
rev: v1.8.0
|
31 |
hooks:
|
32 |
+
- id: reorder-python-imports
|
33 |
+
name: 'Reorder Python imports'
|
34 |
+
- repo: 'https://github.com/pre-commit/mirrors-autopep8'
|
35 |
+
rev: ''
|
36 |
hooks:
|
37 |
+
- id: autopep8
|
38 |
+
name: 'Pretty format Python'
|
39 |
+
args:
|
40 |
+
- '--in-place'
|
41 |
+
- '--aggressive'
|
42 |
+
- '--aggressive'
|
43 |
+
- '--experimental'
|
44 |
+
- '--remove-all-unused-imports'
|
45 |
+
- '--ignore-init-module-imports'
|
46 |
+
- '--remove-unused-variable'
|
47 |
+
- repo: https://github.com/psf/black
|
48 |
+
rev: stable
|
49 |
hooks:
|
50 |
+
- id: black
|
51 |
+
name: 'Ruthlessly format Python'
|
52 |
+
language_version: python3.7
|
53 |
+
args:
|
54 |
+
- '--line-length=79'
|
Makefile
CHANGED
@@ -1,22 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
help:
|
2 |
@echo "clean - remove all build, test, coverage and Python artifacts"
|
3 |
@echo "clean-build - remove build artifacts"
|
4 |
@echo "clean-pyc - remove Python file artifacts"
|
5 |
@echo "install - install the package to the active Python's site-packages"
|
6 |
|
7 |
-
|
8 |
pip install pipenv
|
9 |
-
pipenv install --dev
|
10 |
-
|
11 |
-
|
12 |
-
pipenv run flake8 pytube/
|
13 |
-
pipenv run flake8 tests/
|
14 |
-
pipenv run black pytube --check
|
15 |
-
pipenv run black tests --check
|
16 |
-
pipenv run mypy pytube
|
17 |
-
pipenv run pytest --cov-report term-missing --cov=pytube
|
18 |
-
|
19 |
-
ci: pipenv test
|
20 |
|
21 |
clean: clean-build clean-pyc
|
22 |
|
@@ -33,27 +60,6 @@ clean-pyc:
|
|
33 |
find . -name '*.pyo' -exec rm -f {} +
|
34 |
find . -name '*~' -exec rm -f {} +
|
35 |
find . -name '__pycache__' -exec rm -fr {} +
|
36 |
-
find . -name '.pytest_cache' -exec rm -fr {} +
|
37 |
-
find . -name '.mypy_cache' -exec rm -fr {} +
|
38 |
|
39 |
install: clean
|
40 |
python setup.py install
|
41 |
-
|
42 |
-
package: clean
|
43 |
-
pipenv run python setup.py sdist bdist_wheel
|
44 |
-
|
45 |
-
upload:
|
46 |
-
twine upload dist/*
|
47 |
-
|
48 |
-
tag:
|
49 |
-
git diff-index --quiet HEAD -- # checks for unstaged/uncomitted files
|
50 |
-
git tag "v`pipenv run python pytube/version.py`"
|
51 |
-
git push --tags
|
52 |
-
|
53 |
-
check-master:
|
54 |
-
if [[ `git rev-parse --abbrev-ref HEAD` != "master" ]]; then exit 1; fi
|
55 |
-
|
56 |
-
pull:
|
57 |
-
git pull
|
58 |
-
|
59 |
-
release: check-master pull clean test tag package upload
|
|
|
1 |
+
dev:
|
2 |
+
pipenv install --dev
|
3 |
+
|
4 |
+
pipenv:
|
5 |
+
pip install pipenv
|
6 |
+
pipenv install --dev
|
7 |
+
|
8 |
+
deploy-patch: clean requirements bumpversion-patch upload clean
|
9 |
+
|
10 |
+
deploy-minor: clean requirements bumpversion-minor upload clean
|
11 |
+
|
12 |
+
deploy-major: clean requirements bumpversion-major upload clean
|
13 |
+
|
14 |
+
requirements:
|
15 |
+
pipenv_to_requirements
|
16 |
+
|
17 |
+
bumpversion-patch:
|
18 |
+
bumpversion patch
|
19 |
+
git push
|
20 |
+
git push --tags
|
21 |
+
|
22 |
+
bumpversion-minor:
|
23 |
+
bumpversion minor
|
24 |
+
git push
|
25 |
+
git push --tags
|
26 |
+
|
27 |
+
bumpversion-major:
|
28 |
+
bumpversion major
|
29 |
+
git push
|
30 |
+
git push --tags
|
31 |
+
|
32 |
+
upload:
|
33 |
+
python setup.py sdist bdist_wheel
|
34 |
+
twine upload dist/*
|
35 |
+
|
36 |
help:
|
37 |
@echo "clean - remove all build, test, coverage and Python artifacts"
|
38 |
@echo "clean-build - remove build artifacts"
|
39 |
@echo "clean-pyc - remove Python file artifacts"
|
40 |
@echo "install - install the package to the active Python's site-packages"
|
41 |
|
42 |
+
ci:
|
43 |
pip install pipenv
|
44 |
+
pipenv install --dev --skip-lock
|
45 |
+
pipenv run flake8
|
46 |
+
pipenv run pytest --cov-report term-missing --cov=humps
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
|
48 |
clean: clean-build clean-pyc
|
49 |
|
|
|
60 |
find . -name '*.pyo' -exec rm -f {} +
|
61 |
find . -name '*~' -exec rm -f {} +
|
62 |
find . -name '__pycache__' -exec rm -fr {} +
|
|
|
|
|
63 |
|
64 |
install: clean
|
65 |
python setup.py install
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
README.md
CHANGED
@@ -1,68 +1,74 @@
|
|
1 |
|
2 |
<div align="center">
|
|
|
|
|
|
|
3 |
<p align="center">
|
4 |
-
<
|
5 |
-
<a href="https://
|
6 |
-
<a href="
|
7 |
-
<a href=
|
8 |
-
|
9 |
-
<a href="https://
|
10 |
-
|
11 |
</p>
|
12 |
</div>
|
13 |
|
14 |
-
#
|
|
|
15 |
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
* [Features](#features)
|
20 |
-
* [Usage](#usage)
|
21 |
-
* [Command-line interface](#command-line-interface)
|
22 |
-
* [Development](#development)
|
23 |
-
* [GUIs and other libraries](#guis-and-other-libraries)
|
24 |
|
25 |
-
##
|
|
|
26 |
|
27 |
-
|
28 |
|
29 |
-
|
30 |
-
$ pip install pytube3 --upgrade
|
31 |
-
```
|
32 |
-
(Mac/homebrew users may need to use ``pip3``)
|
33 |
|
|
|
|
|
|
|
34 |
|
35 |
-
## Quick start
|
36 |
```python
|
37 |
-
>>>
|
38 |
-
>>> YouTube('https://youtu.be/9bZkp7q19f0').streams.get_highest_resolution().download()
|
39 |
-
>>>
|
40 |
>>> yt = YouTube('http://youtube.com/watch?v=9bZkp7q19f0')
|
41 |
>>> yt.streams
|
42 |
... .filter(progressive=True, file_extension='mp4')
|
43 |
-
... .order_by('resolution')
|
|
|
|
|
44 |
... .download()
|
45 |
```
|
46 |
-
A GUI frontend for pytube3 is available at [YouTubeDownload](https://github.com/YouTubeDownload/YouTubeDownload)
|
47 |
|
48 |
## Features
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
|
61 |
Let's begin with showing how easy it is to download a video with pytube:
|
62 |
|
63 |
```python
|
64 |
>>> from pytube import YouTube
|
65 |
-
>>> YouTube('http://youtube.com/watch?v=9bZkp7q19f0').streams
|
66 |
```
|
67 |
This example will download the highest quality progressive download stream available.
|
68 |
|
@@ -70,7 +76,7 @@ Next, let's explore how we would view what video streams are available:
|
|
70 |
|
71 |
```python
|
72 |
>>> yt = YouTube('http://youtube.com/watch?v=9bZkp7q19f0')
|
73 |
-
>>>
|
74 |
[<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">,
|
75 |
<Stream: itag="43" mime_type="video/webm" res="360p" fps="30fps" vcodec="vp8.0" acodec="vorbis">,
|
76 |
<Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">,
|
@@ -94,9 +100,6 @@ Next, let's explore how we would view what video streams are available:
|
|
94 |
<Stream: itag="250" mime_type="audio/webm" abr="70kbps" acodec="opus">,
|
95 |
<Stream: itag="251" mime_type="audio/webm" abr="160kbps" acodec="opus">]
|
96 |
```
|
97 |
-
|
98 |
-
### Selecting an itag
|
99 |
-
|
100 |
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).
|
101 |
|
102 |
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.
|
@@ -106,7 +109,7 @@ The legacy streams that contain the audio and video in a single file (referred t
|
|
106 |
To only view these progressive download streams:
|
107 |
|
108 |
```python
|
109 |
-
>>> yt.streams.filter(progressive=True)
|
110 |
[<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">,
|
111 |
<Stream: itag="43" mime_type="video/webm" res="360p" fps="30fps" vcodec="vp8.0" acodec="vorbis">,
|
112 |
<Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">,
|
@@ -117,7 +120,7 @@ To only view these progressive download streams:
|
|
117 |
Conversely, if you only want to see the DASH streams (also referred to as "adaptive") you can do:
|
118 |
|
119 |
```python
|
120 |
-
>>> yt.streams.filter(adaptive=True)
|
121 |
[<Stream: itag="137" mime_type="video/mp4" res="1080p" fps="30fps" vcodec="avc1.640028">,
|
122 |
<Stream: itag="248" mime_type="video/webm" res="1080p" fps="30fps" vcodec="vp9">,
|
123 |
<Stream: itag="136" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.4d401f">,
|
@@ -137,26 +140,24 @@ Conversely, if you only want to see the DASH streams (also referred to as "adapt
|
|
137 |
<Stream: itag="251" mime_type="audio/webm" abr="160kbps" acodec="opus">]
|
138 |
```
|
139 |
|
140 |
-
### Playlists
|
141 |
-
|
142 |
You can also download a complete Youtube playlist:
|
143 |
|
144 |
```python
|
145 |
>>> from pytube import Playlist
|
146 |
-
>>>
|
147 |
-
>>>
|
148 |
-
>>>
|
|
|
149 |
```
|
150 |
-
This will download the highest progressive stream available (generally 720p) from the given playlist.
|
151 |
-
|
152 |
-
### Filtering
|
153 |
|
154 |
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.
|
155 |
|
156 |
To list the audio only streams:
|
157 |
|
158 |
```python
|
159 |
-
>>> yt.streams.filter(only_audio=True)
|
160 |
[<Stream: itag="140" mime_type="audio/mp4" abr="128kbps" acodec="mp4a.40.2">,
|
161 |
<Stream: itag="171" mime_type="audio/webm" abr="128kbps" acodec="vorbis">,
|
162 |
<Stream: itag="249" mime_type="audio/webm" abr="50kbps" acodec="opus">,
|
@@ -167,7 +168,7 @@ To list the audio only streams:
|
|
167 |
To list only ``mp4`` streams:
|
168 |
|
169 |
```python
|
170 |
-
>>> yt.streams.filter(subtype='mp4')
|
171 |
[<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">,
|
172 |
<Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">,
|
173 |
<Stream: itag="137" mime_type="video/mp4" res="1080p" fps="30fps" vcodec="avc1.640028">,
|
@@ -182,9 +183,9 @@ To list only ``mp4`` streams:
|
|
182 |
Multiple filters can also be specified:
|
183 |
|
184 |
```python
|
185 |
-
>>> yt.streams.filter(subtype='mp4', progressive=True)
|
186 |
>>> # this can also be expressed as:
|
187 |
-
>>> yt.streams.filter(subtype='mp4').filter(progressive=True)
|
188 |
[<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">,
|
189 |
<Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">]
|
190 |
```
|
@@ -198,16 +199,14 @@ You also have an interface to select streams by their itag, without needing to f
|
|
198 |
If you need to optimize for a specific feature, such as the "highest resolution" or "lowest average bitrate":
|
199 |
|
200 |
```python
|
201 |
-
>>> yt.streams.filter(progressive=True).order_by('resolution').desc()
|
202 |
```
|
203 |
-
Note
|
204 |
-
|
205 |
-
### Callbacks
|
206 |
|
207 |
If your application requires post-processing logic, pytube allows you to specify an "on download complete" callback function:
|
208 |
|
209 |
```python
|
210 |
-
>>> def convert_to_aac(stream
|
211 |
return # do work
|
212 |
|
213 |
>>> yt.register_on_complete_callback(convert_to_aac)
|
@@ -216,7 +215,7 @@ If your application requires post-processing logic, pytube allows you to specify
|
|
216 |
Similarly, if your application requires on-download progress logic, pytube exposes a callback for this as well:
|
217 |
|
218 |
```python
|
219 |
-
>>> def show_progress_bar(stream
|
220 |
return # do work
|
221 |
|
222 |
>>> yt.register_on_progress_callback(show_progress_bar)
|
@@ -224,86 +223,17 @@ Similarly, if your application requires on-download progress logic, pytube expos
|
|
224 |
|
225 |
## Command-line interface
|
226 |
|
227 |
-
|
228 |
|
229 |
Let's start with downloading:
|
230 |
|
231 |
```bash
|
232 |
-
$
|
233 |
```
|
234 |
To view available streams:
|
235 |
|
236 |
```bash
|
237 |
-
$
|
238 |
-
```
|
239 |
-
|
240 |
-
The complete set of flags are:
|
241 |
-
|
242 |
-
```
|
243 |
-
usage: pytube3 [-h] [--version] [--itag ITAG] [-r RESOLUTION] [-l] [-v]
|
244 |
-
[--build-playback-report] [-c [CAPTION_CODE]] [-t TARGET]
|
245 |
-
[-a [AUDIO]] [-f [FFMPEG]]
|
246 |
-
[url]
|
247 |
-
|
248 |
-
Command line application to download youtube videos.
|
249 |
-
|
250 |
-
positional arguments:
|
251 |
-
url The YouTube /watch or /playlist url
|
252 |
-
|
253 |
-
optional arguments:
|
254 |
-
-h, --help show this help message and exit
|
255 |
-
--version show program's version number and exit
|
256 |
-
--itag ITAG The itag for the desired stream
|
257 |
-
-r RESOLUTION, --resolution RESOLUTION
|
258 |
-
The resolution for the desired stream
|
259 |
-
-l, --list The list option causes pytube cli to return a list of
|
260 |
-
streams available to download
|
261 |
-
-v, --verbose Verbosity level, use up to 4 to increase logging -vvvv
|
262 |
-
--build-playback-report
|
263 |
-
Save the html and js to disk
|
264 |
-
-c [CAPTION_CODE], --caption-code [CAPTION_CODE]
|
265 |
-
Download srt captions for given language code. Prints
|
266 |
-
available language codes if no argument given
|
267 |
-
-t TARGET, --target TARGET
|
268 |
-
The output directory for the downloaded stream.
|
269 |
-
Default is current working directory
|
270 |
-
-a [AUDIO], --audio [AUDIO]
|
271 |
-
Download the audio for a given URL at the highest
|
272 |
-
bitrate availableDefaults to mp4 format if none is
|
273 |
-
specified
|
274 |
-
-f [FFMPEG], --ffmpeg [FFMPEG]
|
275 |
-
Downloads the audio and video stream for resolution
|
276 |
-
providedIf no resolution is provided, downloads the
|
277 |
-
best resolutionRuns the command line program ffmpeg to
|
278 |
-
combine the audio and video
|
279 |
```
|
280 |
|
281 |
-
|
282 |
-
## Development
|
283 |
-
|
284 |
-
<a href="https://deepsource.io/gh/hbmartin/pytube3/?ref=repository-badge" target="_blank"><img alt="DeepSource" title="DeepSource" src="https://static.deepsource.io/deepsource-badge-light-mini.svg"></a>
|
285 |
-
<a href="https://www.codacy.com/manual/hbmartin/pytube3?utm_source=github.com&utm_medium=referral&utm_content=hbmartin/pytube3&utm_campaign=Badge_Grade"><img src="https://api.codacy.com/project/badge/Grade/53794f06983a46829620b3284c6a5596"/></a>
|
286 |
-
<a href="https://github.com/ambv/black"><img src="https://img.shields.io/badge/code%20style-black-000000.svg" /></a>
|
287 |
-
|
288 |
-
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
|
289 |
-
|
290 |
-
To run code checking before a PR use ``make test``
|
291 |
-
|
292 |
-
#### Virtual environment
|
293 |
-
|
294 |
-
Virtual environment is setup with [pipenv](https://pipenv-fork.readthedocs.io/en/latest/) and can be automatically activated with [direnv](https://direnv.net/docs/installation.html)
|
295 |
-
|
296 |
-
#### Code Formatting
|
297 |
-
|
298 |
-
This project is linted with [pyflakes](https://github.com/PyCQA/pyflakes), formatted with [black](https://github.com/ambv/black), and typed with [mypy](https://mypy.readthedocs.io/en/latest/introduction.html)
|
299 |
-
|
300 |
-
|
301 |
-
#### Code of Conduct
|
302 |
-
|
303 |
-
Treat other people with helpfulness, gratitude, and consideration! See the [Python Community Code of Conduct](https://www.python.org/psf/codeofconduct/).
|
304 |
-
|
305 |
-
## GUIs and other libraries
|
306 |
-
* [YouTubeDownload](https://github.com/YouTubeDownload/YouTubeDownload) - Featured GUI frontend for pytube3
|
307 |
-
* [Pytube-GUI](https://github.com/GAO23/Pytube-GUI) - Simple GUI frontend for pytube3
|
308 |
-
* [StackOverflow questions](https://stackoverflow.com/questions/tagged/pytube)
|
309 |
-
* [PySlackers](https://pyslackers.com/web) - Python Slack group
|
|
|
1 |
|
2 |
<div align="center">
|
3 |
+
<p>
|
4 |
+
<img src="https://github.com/nficano/pytube/blob/master/images/pytube.png?raw=true" width="350" height="328" alt="pytube logo" />
|
5 |
+
</p>
|
6 |
<p align="center">
|
7 |
+
<img src="https://img.shields.io/pypi/v/pytube.svg" alt="pypi">
|
8 |
+
<a href="https://travis-ci.org/nficano/pytube"><img src="https://travis-ci.org/nficano/pytube.svg?branch=master" /></a>
|
9 |
+
<a href="http://python-pytube.readthedocs.io/en/latest/?badge=latest"><img src="https://readthedocs.org/projects/python-pytube/badge/?version=latest" /></a>
|
10 |
+
<a href="https://coveralls.io/github/nficano/pytube?branch=master"><img src="https://coveralls.io/repos/github/nficano/pytube/badge.svg?branch=master#23e6f7ac56dd3bde" /></a>
|
11 |
+
<a href="https://pypi.org/project/pytube/"><img src="https://img.shields.io/pypi/dm/pytube.svg" alt="pypi"></a>
|
12 |
+
<a href="https://pypi.python.org/pypi/pytube/"><img src="https://img.shields.io/pypi/pyversions/pytube.svg" /></a>
|
13 |
+
<p>
|
14 |
</p>
|
15 |
</div>
|
16 |
|
17 |
+
# pytube
|
18 |
+
*pytube* is a very serious, lightweight, dependency-free Python library (and command-line utility) for downloading YouTube Videos.
|
19 |
|
20 |
+
*pytube* is sponsored by:
|
21 |
+
<a href="https://tracking.gitads.io/?repo=pytube/"><img src="https://images.gitads.io/pytube/" alt="GitAds"/></a>
|
22 |
+
</p>
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
+
## Description
|
25 |
+
YouTube is the most popular video-sharing platform in the world and as a hacker you may encounter a situation where you want to script something to download videos. For this I present to you *pytube*.
|
26 |
|
27 |
+
*pytube* is a lightweight library written in Python. It has no third party dependencies and aims to be highly reliable.
|
28 |
|
29 |
+
*pytube* also makes pipelining easy, allowing you to specify callback functions for different download events, such as ``on progress`` or ``on complete``.
|
|
|
|
|
|
|
30 |
|
31 |
+
Finally *pytube* also includes a command-line utility, allowing you to quickly download videos right from terminal.
|
32 |
+
|
33 |
+
### Behold, a perfect balance of simplicity versus flexibility:
|
34 |
|
|
|
35 |
```python
|
36 |
+
>>> YouTube('https://youtu.be/9bZkp7q19f0').streams.first().download()
|
|
|
|
|
37 |
>>> yt = YouTube('http://youtube.com/watch?v=9bZkp7q19f0')
|
38 |
>>> yt.streams
|
39 |
... .filter(progressive=True, file_extension='mp4')
|
40 |
+
... .order_by('resolution')
|
41 |
+
... .desc()
|
42 |
+
... .first()
|
43 |
... .download()
|
44 |
```
|
|
|
45 |
|
46 |
## Features
|
47 |
+
- Support for Both Progressive & DASH Streams
|
48 |
+
- Support for downloading complete playlist
|
49 |
+
- Easily Register ``on_download_progress`` & ``on_download_complete`` callbacks
|
50 |
+
- Command-line Interfaced Included
|
51 |
+
- Caption Track Support
|
52 |
+
- Outputs Caption Tracks to .srt format (SubRip Subtitle)
|
53 |
+
- Ability to Capture Thumbnail URL.
|
54 |
+
- Extensively Documented Source Code
|
55 |
+
- No Third-Party Dependencies
|
56 |
+
|
57 |
+
## Installation
|
58 |
+
|
59 |
+
Download using pip via pypi.
|
60 |
+
|
61 |
+
```bash
|
62 |
+
$ pip install pytube
|
63 |
+
```
|
64 |
+
|
65 |
+
## Getting started
|
66 |
|
67 |
Let's begin with showing how easy it is to download a video with pytube:
|
68 |
|
69 |
```python
|
70 |
>>> from pytube import YouTube
|
71 |
+
>>> YouTube('http://youtube.com/watch?v=9bZkp7q19f0').streams.first().download()
|
72 |
```
|
73 |
This example will download the highest quality progressive download stream available.
|
74 |
|
|
|
76 |
|
77 |
```python
|
78 |
>>> yt = YouTube('http://youtube.com/watch?v=9bZkp7q19f0')
|
79 |
+
>>> yt.streams.all()
|
80 |
[<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">,
|
81 |
<Stream: itag="43" mime_type="video/webm" res="360p" fps="30fps" vcodec="vp8.0" acodec="vorbis">,
|
82 |
<Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">,
|
|
|
100 |
<Stream: itag="250" mime_type="audio/webm" abr="70kbps" acodec="opus">,
|
101 |
<Stream: itag="251" mime_type="audio/webm" abr="160kbps" acodec="opus">]
|
102 |
```
|
|
|
|
|
|
|
103 |
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).
|
104 |
|
105 |
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.
|
|
|
109 |
To only view these progressive download streams:
|
110 |
|
111 |
```python
|
112 |
+
>>> yt.streams.filter(progressive=True).all()
|
113 |
[<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">,
|
114 |
<Stream: itag="43" mime_type="video/webm" res="360p" fps="30fps" vcodec="vp8.0" acodec="vorbis">,
|
115 |
<Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">,
|
|
|
120 |
Conversely, if you only want to see the DASH streams (also referred to as "adaptive") you can do:
|
121 |
|
122 |
```python
|
123 |
+
>>> yt.streams.filter(adaptive=True).all()
|
124 |
[<Stream: itag="137" mime_type="video/mp4" res="1080p" fps="30fps" vcodec="avc1.640028">,
|
125 |
<Stream: itag="248" mime_type="video/webm" res="1080p" fps="30fps" vcodec="vp9">,
|
126 |
<Stream: itag="136" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.4d401f">,
|
|
|
140 |
<Stream: itag="251" mime_type="audio/webm" abr="160kbps" acodec="opus">]
|
141 |
```
|
142 |
|
|
|
|
|
143 |
You can also download a complete Youtube playlist:
|
144 |
|
145 |
```python
|
146 |
>>> from pytube import Playlist
|
147 |
+
>>> pl = Playlist("https://www.youtube.com/watch?v=Edpy1szoG80&list=PL153hDY-y1E00uQtCVCVC8xJ25TYX8yPU")
|
148 |
+
>>> pl.download_all()
|
149 |
+
>>> # or if you want to download in a specific directory
|
150 |
+
>>> pl.download_all('/path/to/directory/')
|
151 |
```
|
152 |
+
This will download the highest progressive stream available (generally 720p) from the given playlist. Later more options would be given for user's flexibility
|
153 |
+
to choose video resolution.
|
|
|
154 |
|
155 |
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.
|
156 |
|
157 |
To list the audio only streams:
|
158 |
|
159 |
```python
|
160 |
+
>>> yt.streams.filter(only_audio=True).all()
|
161 |
[<Stream: itag="140" mime_type="audio/mp4" abr="128kbps" acodec="mp4a.40.2">,
|
162 |
<Stream: itag="171" mime_type="audio/webm" abr="128kbps" acodec="vorbis">,
|
163 |
<Stream: itag="249" mime_type="audio/webm" abr="50kbps" acodec="opus">,
|
|
|
168 |
To list only ``mp4`` streams:
|
169 |
|
170 |
```python
|
171 |
+
>>> yt.streams.filter(subtype='mp4').all()
|
172 |
[<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">,
|
173 |
<Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">,
|
174 |
<Stream: itag="137" mime_type="video/mp4" res="1080p" fps="30fps" vcodec="avc1.640028">,
|
|
|
183 |
Multiple filters can also be specified:
|
184 |
|
185 |
```python
|
186 |
+
>>> yt.streams.filter(subtype='mp4', progressive=True).all()
|
187 |
>>> # this can also be expressed as:
|
188 |
+
>>> yt.streams.filter(subtype='mp4').filter(progressive=True).all()
|
189 |
[<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2">,
|
190 |
<Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">]
|
191 |
```
|
|
|
199 |
If you need to optimize for a specific feature, such as the "highest resolution" or "lowest average bitrate":
|
200 |
|
201 |
```python
|
202 |
+
>>> yt.streams.filter(progressive=True).order_by('resolution').desc().all()
|
203 |
```
|
204 |
+
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.
|
|
|
|
|
205 |
|
206 |
If your application requires post-processing logic, pytube allows you to specify an "on download complete" callback function:
|
207 |
|
208 |
```python
|
209 |
+
>>> def convert_to_aac(stream, file_handle):
|
210 |
return # do work
|
211 |
|
212 |
>>> yt.register_on_complete_callback(convert_to_aac)
|
|
|
215 |
Similarly, if your application requires on-download progress logic, pytube exposes a callback for this as well:
|
216 |
|
217 |
```python
|
218 |
+
>>> def show_progress_bar(stream, chunk, file_handle, bytes_remaining):
|
219 |
return # do work
|
220 |
|
221 |
>>> yt.register_on_progress_callback(show_progress_bar)
|
|
|
223 |
|
224 |
## Command-line interface
|
225 |
|
226 |
+
pytube also ships with a tiny cli interface for downloading and probing videos.
|
227 |
|
228 |
Let's start with downloading:
|
229 |
|
230 |
```bash
|
231 |
+
$ pytube http://youtube.com/watch?v=9bZkp7q19f0 --itag=22
|
232 |
```
|
233 |
To view available streams:
|
234 |
|
235 |
```bash
|
236 |
+
$ pytube http://youtube.com/watch?v=9bZkp7q19f0 --list
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
237 |
```
|
238 |
|
239 |
+
Finally, if you're filing a bug report, the cli contains a switch called ``--build-playback-report``, which bundles up the state, allowing others to easily replay your issue.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
images/pytube.png
ADDED