Merge branch 'master' into playlist_exception
Browse files- .gitignore +2 -1
- LICENSE +1 -1
- Makefile +1 -0
- Pipfile +3 -0
- Pipfile.lock +226 -25
- README.md +2 -1
- docs/conf.py +1 -1
- pytube/__init__.py +2 -2
- pytube/captions.py +1 -1
- pytube/contrib/playlist.py +35 -0
- pytube/query.py +5 -3
- pytube/streams.py +1 -1
- setup.cfg +1 -1
- setup.py +50 -11
.gitignore
CHANGED
@@ -39,8 +39,9 @@ _build
|
|
39 |
_static
|
40 |
_templates
|
41 |
_autosummary
|
42 |
-
|
43 |
.pytest_cache*
|
44 |
|
45 |
# IDE Files
|
46 |
.idea/
|
|
|
|
|
|
39 |
_static
|
40 |
_templates
|
41 |
_autosummary
|
|
|
42 |
.pytest_cache*
|
43 |
|
44 |
# IDE Files
|
45 |
.idea/
|
46 |
+
#Pycharm stuff
|
47 |
+
.idea/*
|
LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
Copyright (c)
|
2 |
|
3 |
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4 |
this software and associated documentation files (the "Software"), to deal in
|
|
|
1 |
+
Copyright (c) 2018 Nick Ficano
|
2 |
|
3 |
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4 |
this software and associated documentation files (the "Software"), to deal in
|
Makefile
CHANGED
@@ -25,6 +25,7 @@ clean-pyc:
|
|
25 |
find . -name '*.pyo' -exec rm -f {} +
|
26 |
find . -name '*~' -exec rm -f {} +
|
27 |
find . -name '__pycache__' -exec rm -fr {} +
|
|
|
28 |
|
29 |
install: clean
|
30 |
python setup.py install
|
|
|
25 |
find . -name '*.pyo' -exec rm -f {} +
|
26 |
find . -name '*~' -exec rm -f {} +
|
27 |
find . -name '__pycache__' -exec rm -fr {} +
|
28 |
+
find . -name '.pytest_cache' -exec rm -fr {} +
|
29 |
|
30 |
install: clean
|
31 |
python setup.py install
|
Pipfile
CHANGED
@@ -15,6 +15,9 @@ pre-commit = "*"
|
|
15 |
pytest-cov = "*"
|
16 |
"pathlib2" = "*"
|
17 |
"scandir" = "*"
|
|
|
|
|
|
|
18 |
|
19 |
[requires]
|
20 |
python_version = "3.6"
|
|
|
15 |
pytest-cov = "*"
|
16 |
"pathlib2" = "*"
|
17 |
"scandir" = "*"
|
18 |
+
bumpversion = "*"
|
19 |
+
coveralls = "*"
|
20 |
+
twine = "*"
|
21 |
|
22 |
[requires]
|
23 |
python_version = "3.6"
|
Pipfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
{
|
2 |
"_meta": {
|
3 |
"hash": {
|
4 |
-
"sha256": "
|
5 |
},
|
6 |
"pipfile-spec": 6,
|
7 |
"requires": {
|
@@ -29,7 +29,6 @@
|
|
29 |
"sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0",
|
30 |
"sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee"
|
31 |
],
|
32 |
-
"markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.3.*'",
|
33 |
"version": "==1.2.1"
|
34 |
},
|
35 |
"attrs": {
|
@@ -39,6 +38,21 @@
|
|
39 |
],
|
40 |
"version": "==18.2.0"
|
41 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
"cached-property": {
|
43 |
"hashes": [
|
44 |
"sha256:3a026f1a54135677e7da5ce819b0c690f156f37976f3e30c5430740725203d7f",
|
@@ -46,6 +60,50 @@
|
|
46 |
],
|
47 |
"version": "==1.5.1"
|
48 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
"cfgv": {
|
50 |
"hashes": [
|
51 |
"sha256:73f48a752bd7aab103c4b882d6596c6360b7aa63b34073dd2c35c7b4b8f93010",
|
@@ -53,6 +111,46 @@
|
|
53 |
],
|
54 |
"version": "==1.1.0"
|
55 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
"coverage": {
|
57 |
"hashes": [
|
58 |
"sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba",
|
@@ -89,6 +187,28 @@
|
|
89 |
],
|
90 |
"version": "==4.5.1"
|
91 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
"enum34": {
|
93 |
"hashes": [
|
94 |
"sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850",
|
@@ -107,12 +227,25 @@
|
|
107 |
"index": "pypi",
|
108 |
"version": "==3.5.0"
|
109 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
"identify": {
|
111 |
"hashes": [
|
112 |
-
"sha256:
|
113 |
-
"sha256:
|
114 |
],
|
115 |
-
"version": "==1.1.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
},
|
117 |
"mccabe": {
|
118 |
"hashes": [
|
@@ -153,34 +286,39 @@
|
|
153 |
},
|
154 |
"pbr": {
|
155 |
"hashes": [
|
156 |
-
"sha256:
|
157 |
-
"sha256:
|
158 |
],
|
159 |
-
"version": "==
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
},
|
161 |
"pluggy": {
|
162 |
"hashes": [
|
163 |
-
"sha256:
|
164 |
-
"sha256:
|
165 |
],
|
166 |
-
"
|
167 |
-
"version": "==0.7.1"
|
168 |
},
|
169 |
"pre-commit": {
|
170 |
"hashes": [
|
171 |
-
"sha256:
|
172 |
-
"sha256:
|
173 |
],
|
174 |
"index": "pypi",
|
175 |
-
"version": "==1.11.
|
176 |
},
|
177 |
"py": {
|
178 |
"hashes": [
|
179 |
-
"sha256:
|
180 |
-
"sha256:
|
181 |
],
|
182 |
-
"
|
183 |
-
"version": "==1.6.0"
|
184 |
},
|
185 |
"pycodestyle": {
|
186 |
"hashes": [
|
@@ -189,6 +327,12 @@
|
|
189 |
],
|
190 |
"version": "==2.3.1"
|
191 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
192 |
"pyflakes": {
|
193 |
"hashes": [
|
194 |
"sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f",
|
@@ -196,13 +340,20 @@
|
|
196 |
],
|
197 |
"version": "==1.6.0"
|
198 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
"pytest": {
|
200 |
"hashes": [
|
201 |
-
"sha256:
|
202 |
-
"sha256:
|
203 |
],
|
204 |
"index": "pypi",
|
205 |
-
"version": "==3.
|
206 |
},
|
207 |
"pytest-cov": {
|
208 |
"hashes": [
|
@@ -236,6 +387,27 @@
|
|
236 |
],
|
237 |
"version": "==3.13"
|
238 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
239 |
"scandir": {
|
240 |
"hashes": [
|
241 |
"sha256:04b8adb105f2ed313a7c2ef0f1cf7aff4871aa7a1883fa4d8c44b5551ab052d6",
|
@@ -262,10 +434,32 @@
|
|
262 |
},
|
263 |
"toml": {
|
264 |
"hashes": [
|
265 |
-
"sha256:
|
266 |
-
"sha256:
|
267 |
],
|
268 |
-
"version": "==0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
269 |
},
|
270 |
"virtualenv": {
|
271 |
"hashes": [
|
@@ -273,6 +467,13 @@
|
|
273 |
"sha256:ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752"
|
274 |
],
|
275 |
"version": "==16.0.0"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
276 |
}
|
277 |
}
|
278 |
}
|
|
|
1 |
{
|
2 |
"_meta": {
|
3 |
"hash": {
|
4 |
+
"sha256": "7b66cc55f724f5fad32bf12e902f3505f261760bf5a32fa26b7961002594b3dc"
|
5 |
},
|
6 |
"pipfile-spec": 6,
|
7 |
"requires": {
|
|
|
29 |
"sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0",
|
30 |
"sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee"
|
31 |
],
|
|
|
32 |
"version": "==1.2.1"
|
33 |
},
|
34 |
"attrs": {
|
|
|
38 |
],
|
39 |
"version": "==18.2.0"
|
40 |
},
|
41 |
+
"bleach": {
|
42 |
+
"hashes": [
|
43 |
+
"sha256:48d39675b80a75f6d1c3bdbffec791cf0bbbab665cf01e20da701c77de278718",
|
44 |
+
"sha256:73d26f018af5d5adcdabf5c1c974add4361a9c76af215fe32fdec8a6fc5fb9b9"
|
45 |
+
],
|
46 |
+
"version": "==3.0.2"
|
47 |
+
},
|
48 |
+
"bumpversion": {
|
49 |
+
"hashes": [
|
50 |
+
"sha256:6744c873dd7aafc24453d8b6a1a0d6d109faf63cd0cd19cb78fd46e74932c77e",
|
51 |
+
"sha256:6753d9ff3552013e2130f7bc03c1007e24473b4835952679653fb132367bdd57"
|
52 |
+
],
|
53 |
+
"index": "pypi",
|
54 |
+
"version": "==0.5.3"
|
55 |
+
},
|
56 |
"cached-property": {
|
57 |
"hashes": [
|
58 |
"sha256:3a026f1a54135677e7da5ce819b0c690f156f37976f3e30c5430740725203d7f",
|
|
|
60 |
],
|
61 |
"version": "==1.5.1"
|
62 |
},
|
63 |
+
"certifi": {
|
64 |
+
"hashes": [
|
65 |
+
"sha256:339dc09518b07e2fa7eda5450740925974815557727d6bd35d319c1524a04a4c",
|
66 |
+
"sha256:6d58c986d22b038c8c0df30d639f23a3e6d172a05c3583e766f4c0b785c0986a"
|
67 |
+
],
|
68 |
+
"version": "==2018.10.15"
|
69 |
+
},
|
70 |
+
"cffi": {
|
71 |
+
"hashes": [
|
72 |
+
"sha256:151b7eefd035c56b2b2e1eb9963c90c6302dc15fbd8c1c0a83a163ff2c7d7743",
|
73 |
+
"sha256:1553d1e99f035ace1c0544050622b7bc963374a00c467edafac50ad7bd276aef",
|
74 |
+
"sha256:1b0493c091a1898f1136e3f4f991a784437fac3673780ff9de3bcf46c80b6b50",
|
75 |
+
"sha256:2ba8a45822b7aee805ab49abfe7eec16b90587f7f26df20c71dd89e45a97076f",
|
76 |
+
"sha256:3bb6bd7266598f318063e584378b8e27c67de998a43362e8fce664c54ee52d30",
|
77 |
+
"sha256:3c85641778460581c42924384f5e68076d724ceac0f267d66c757f7535069c93",
|
78 |
+
"sha256:3eb6434197633b7748cea30bf0ba9f66727cdce45117a712b29a443943733257",
|
79 |
+
"sha256:495c5c2d43bf6cebe0178eb3e88f9c4aa48d8934aa6e3cddb865c058da76756b",
|
80 |
+
"sha256:4c91af6e967c2015729d3e69c2e51d92f9898c330d6a851bf8f121236f3defd3",
|
81 |
+
"sha256:57b2533356cb2d8fac1555815929f7f5f14d68ac77b085d2326b571310f34f6e",
|
82 |
+
"sha256:770f3782b31f50b68627e22f91cb182c48c47c02eb405fd689472aa7b7aa16dc",
|
83 |
+
"sha256:79f9b6f7c46ae1f8ded75f68cf8ad50e5729ed4d590c74840471fc2823457d04",
|
84 |
+
"sha256:7a33145e04d44ce95bcd71e522b478d282ad0eafaf34fe1ec5bbd73e662f22b6",
|
85 |
+
"sha256:857959354ae3a6fa3da6651b966d13b0a8bed6bbc87a0de7b38a549db1d2a359",
|
86 |
+
"sha256:87f37fe5130574ff76c17cab61e7d2538a16f843bb7bca8ebbc4b12de3078596",
|
87 |
+
"sha256:95d5251e4b5ca00061f9d9f3d6fe537247e145a8524ae9fd30a2f8fbce993b5b",
|
88 |
+
"sha256:9d1d3e63a4afdc29bd76ce6aa9d58c771cd1599fbba8cf5057e7860b203710dd",
|
89 |
+
"sha256:a36c5c154f9d42ec176e6e620cb0dd275744aa1d804786a71ac37dc3661a5e95",
|
90 |
+
"sha256:a6a5cb8809091ec9ac03edde9304b3ad82ad4466333432b16d78ef40e0cce0d5",
|
91 |
+
"sha256:ae5e35a2c189d397b91034642cb0eab0e346f776ec2eb44a49a459e6615d6e2e",
|
92 |
+
"sha256:b0f7d4a3df8f06cf49f9f121bead236e328074de6449866515cea4907bbc63d6",
|
93 |
+
"sha256:b75110fb114fa366b29a027d0c9be3709579602ae111ff61674d28c93606acca",
|
94 |
+
"sha256:ba5e697569f84b13640c9e193170e89c13c6244c24400fc57e88724ef610cd31",
|
95 |
+
"sha256:be2a9b390f77fd7676d80bc3cdc4f8edb940d8c198ed2d8c0be1319018c778e1",
|
96 |
+
"sha256:ca1bd81f40adc59011f58159e4aa6445fc585a32bb8ac9badf7a2c1aa23822f2",
|
97 |
+
"sha256:d5d8555d9bfc3f02385c1c37e9f998e2011f0db4f90e250e5bc0c0a85a813085",
|
98 |
+
"sha256:e55e22ac0a30023426564b1059b035973ec82186ddddbac867078435801c7801",
|
99 |
+
"sha256:e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4",
|
100 |
+
"sha256:ecbb7b01409e9b782df5ded849c178a0aa7c906cf8c5a67368047daab282b184",
|
101 |
+
"sha256:ed01918d545a38998bfa5902c7c00e0fee90e957ce036a4000a88e3fe2264917",
|
102 |
+
"sha256:edabd457cd23a02965166026fd9bfd196f4324fe6032e866d0f3bd0301cd486f",
|
103 |
+
"sha256:fdf1c1dc5bafc32bc5d08b054f94d659422b05aba244d6be4ddc1c72d9aa70fb"
|
104 |
+
],
|
105 |
+
"version": "==1.11.5"
|
106 |
+
},
|
107 |
"cfgv": {
|
108 |
"hashes": [
|
109 |
"sha256:73f48a752bd7aab103c4b882d6596c6360b7aa63b34073dd2c35c7b4b8f93010",
|
|
|
111 |
],
|
112 |
"version": "==1.1.0"
|
113 |
},
|
114 |
+
"chardet": {
|
115 |
+
"hashes": [
|
116 |
+
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
117 |
+
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
118 |
+
],
|
119 |
+
"version": "==3.0.4"
|
120 |
+
},
|
121 |
+
"cmarkgfm": {
|
122 |
+
"hashes": [
|
123 |
+
"sha256:0186dccca79483e3405217993b83b914ba4559fe9a8396efc4eea56561b74061",
|
124 |
+
"sha256:1a625afc6f62da428df96ec325dc30866cc5781520cbd904ff4ec44cf018171c",
|
125 |
+
"sha256:207b7673ff4e177374c572feeae0e4ef33be620ec9171c08fd22e2b796e03e3d",
|
126 |
+
"sha256:275905bb371a99285c74931700db3f0c078e7603bed383e8cf1a09f3ee05a3de",
|
127 |
+
"sha256:50098f1c4950722521f0671e54139e0edc1837d63c990cf0f3d2c49607bb51a2",
|
128 |
+
"sha256:50ed116d0b60a07df0dc7b180c28569064b9d37d1578d4c9021cff04d725cb63",
|
129 |
+
"sha256:61a72def110eed903cd1848245897bcb80d295cd9d13944d4f9f30cba5b76655",
|
130 |
+
"sha256:64186fb75d973a06df0e6ea12879533b71f6e7ba1ab01ffee7fc3e7534758889",
|
131 |
+
"sha256:665303d34d7f14f10d7b0651082f25ebf7107f29ef3d699490cac16cdc0fc8ce",
|
132 |
+
"sha256:70b18f843aec58e4e64aadce48a897fe7c50426718b7753aaee399e72df64190",
|
133 |
+
"sha256:761ee7b04d1caee2931344ac6bfebf37102ffb203b136b676b0a71a3f0ea3c87",
|
134 |
+
"sha256:811527e9b7280b136734ed6cb6845e5fbccaeaa132ddf45f0246cbe544016957",
|
135 |
+
"sha256:987b0e157f70c72a84f3c2f9ef2d7ab0f26c08f2bf326c12c087ff9eebcb3ff5",
|
136 |
+
"sha256:9fc6a2183d0a9b0974ec7cdcdad42bd78a3be674cc3e65f87dd694419b3b0ab7",
|
137 |
+
"sha256:a3d17ee4ae739fe16f7501a52255c2e287ac817cfd88565b9859f70520afffea",
|
138 |
+
"sha256:ba5b5488719c0f2ced0aa1986376f7baff1a1653a8eb5fdfcf3f84c7ce46ef8d",
|
139 |
+
"sha256:c573ea89dd95d41b6d8cf36799c34b6d5b1eac4aed0212dee0f0a11fb7b01e8f",
|
140 |
+
"sha256:c5f1b9e8592d2c448c44e6bc0d91224b16ea5f8293908b1561de1f6d2d0658b1",
|
141 |
+
"sha256:cbe581456357d8f0674d6a590b1aaf46c11d01dd0a23af147a51a798c3818034",
|
142 |
+
"sha256:cf219bec69e601fe27e3974b7307d2f06082ab385d42752738ad2eb630a47d65",
|
143 |
+
"sha256:cf5014eb214d814a83a7a47407272d5db10b719dbeaf4d3cfe5969309d0fcf4b",
|
144 |
+
"sha256:d08bad67fa18f7e8ff738c090628ee0cbf0505d74a991c848d6d04abfe67b697",
|
145 |
+
"sha256:d6f716d7b1182bf35862b5065112f933f43dd1aa4f8097c9bcfb246f71528a34",
|
146 |
+
"sha256:e08e479102627641c7cb4ece421c6ed4124820b1758765db32201136762282d9",
|
147 |
+
"sha256:e20ac21418af0298437d29599f7851915497ce9f2866bc8e86b084d8911ee061",
|
148 |
+
"sha256:e25f53c37e319241b9a412382140dffac98ca756ba8f360ac7ab5e30cad9670a",
|
149 |
+
"sha256:e8932bddf159064f04e946fbb64693753488de21586f20e840b3be51745c8c09",
|
150 |
+
"sha256:f20900f16377f2109783ae9348d34bc80530808439591c3d3df73d5c7ef1a00c"
|
151 |
+
],
|
152 |
+
"version": "==0.4.2"
|
153 |
+
},
|
154 |
"coverage": {
|
155 |
"hashes": [
|
156 |
"sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba",
|
|
|
187 |
],
|
188 |
"version": "==4.5.1"
|
189 |
},
|
190 |
+
"coveralls": {
|
191 |
+
"hashes": [
|
192 |
+
"sha256:ab638e88d38916a6cedbf80a9cd8992d5fa55c77ab755e262e00b36792b7cd6d",
|
193 |
+
"sha256:b2388747e2529fa4c669fb1e3e2756e4e07b6ee56c7d9fce05f35ccccc913aa0"
|
194 |
+
],
|
195 |
+
"index": "pypi",
|
196 |
+
"version": "==1.5.1"
|
197 |
+
},
|
198 |
+
"docopt": {
|
199 |
+
"hashes": [
|
200 |
+
"sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"
|
201 |
+
],
|
202 |
+
"version": "==0.6.2"
|
203 |
+
},
|
204 |
+
"docutils": {
|
205 |
+
"hashes": [
|
206 |
+
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
|
207 |
+
"sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274",
|
208 |
+
"sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6"
|
209 |
+
],
|
210 |
+
"version": "==0.14"
|
211 |
+
},
|
212 |
"enum34": {
|
213 |
"hashes": [
|
214 |
"sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850",
|
|
|
227 |
"index": "pypi",
|
228 |
"version": "==3.5.0"
|
229 |
},
|
230 |
+
"future": {
|
231 |
+
"hashes": [
|
232 |
+
"sha256:e39ced1ab767b5936646cedba8bcce582398233d6a627067d4c6a454c90cfedb"
|
233 |
+
],
|
234 |
+
"version": "==0.16.0"
|
235 |
+
},
|
236 |
"identify": {
|
237 |
"hashes": [
|
238 |
+
"sha256:5e956558a9a1e3b3891d7c6609fc9709657a11878af288ace484d1a46a93922b",
|
239 |
+
"sha256:623086059219cc7b86c77a3891f3700cb175d4ce02b8fb8802b047301d71e783"
|
240 |
],
|
241 |
+
"version": "==1.1.7"
|
242 |
+
},
|
243 |
+
"idna": {
|
244 |
+
"hashes": [
|
245 |
+
"sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
|
246 |
+
"sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"
|
247 |
+
],
|
248 |
+
"version": "==2.7"
|
249 |
},
|
250 |
"mccabe": {
|
251 |
"hashes": [
|
|
|
286 |
},
|
287 |
"pbr": {
|
288 |
"hashes": [
|
289 |
+
"sha256:ab94783019179bf48f5784edc63f5bc8328ec5ff93f33591567f266d21ac7323",
|
290 |
+
"sha256:bfcff1a3878eebf559392c2130a17f612a03f96a0d44c3559d9c1e62a4235a2d"
|
291 |
],
|
292 |
+
"version": "==5.0.0"
|
293 |
+
},
|
294 |
+
"pkginfo": {
|
295 |
+
"hashes": [
|
296 |
+
"sha256:5878d542a4b3f237e359926384f1dde4e099c9f5525d236b1840cf704fa8d474",
|
297 |
+
"sha256:a39076cb3eb34c333a0dd390b568e9e1e881c7bf2cc0aee12120636816f55aee"
|
298 |
+
],
|
299 |
+
"version": "==1.4.2"
|
300 |
},
|
301 |
"pluggy": {
|
302 |
"hashes": [
|
303 |
+
"sha256:447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095",
|
304 |
+
"sha256:bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f"
|
305 |
],
|
306 |
+
"version": "==0.8.0"
|
|
|
307 |
},
|
308 |
"pre-commit": {
|
309 |
"hashes": [
|
310 |
+
"sha256:98ec318db1f255e3d5089ae416959ef3c775215a3509620027d446eeabbba740",
|
311 |
+
"sha256:b68f9219c56b50ebafb57f378c5325f9876d06fb29e9cd05daf5cbd6676ce8f2"
|
312 |
],
|
313 |
"index": "pypi",
|
314 |
+
"version": "==1.11.2"
|
315 |
},
|
316 |
"py": {
|
317 |
"hashes": [
|
318 |
+
"sha256:bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694",
|
319 |
+
"sha256:e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6"
|
320 |
],
|
321 |
+
"version": "==1.7.0"
|
|
|
322 |
},
|
323 |
"pycodestyle": {
|
324 |
"hashes": [
|
|
|
327 |
],
|
328 |
"version": "==2.3.1"
|
329 |
},
|
330 |
+
"pycparser": {
|
331 |
+
"hashes": [
|
332 |
+
"sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"
|
333 |
+
],
|
334 |
+
"version": "==2.19"
|
335 |
+
},
|
336 |
"pyflakes": {
|
337 |
"hashes": [
|
338 |
"sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f",
|
|
|
340 |
],
|
341 |
"version": "==1.6.0"
|
342 |
},
|
343 |
+
"pygments": {
|
344 |
+
"hashes": [
|
345 |
+
"sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
|
346 |
+
"sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"
|
347 |
+
],
|
348 |
+
"version": "==2.2.0"
|
349 |
+
},
|
350 |
"pytest": {
|
351 |
"hashes": [
|
352 |
+
"sha256:10e59f84267370ab20cec9305bafe7505ba4d6b93ecbf66a1cce86193ed511d5",
|
353 |
+
"sha256:8c827e7d4816dfe13e9329c8226aef8e6e75d65b939bc74fda894143b6d1df59"
|
354 |
],
|
355 |
"index": "pypi",
|
356 |
+
"version": "==3.9.1"
|
357 |
},
|
358 |
"pytest-cov": {
|
359 |
"hashes": [
|
|
|
387 |
],
|
388 |
"version": "==3.13"
|
389 |
},
|
390 |
+
"readme-renderer": {
|
391 |
+
"hashes": [
|
392 |
+
"sha256:237ca8705ffea849870de41101dba41543561da05c0ae45b2f1c547efa9843d2",
|
393 |
+
"sha256:f75049a3a7afa57165551e030dd8f9882ebf688b9600535a3f7e23596651875d"
|
394 |
+
],
|
395 |
+
"version": "==22.0"
|
396 |
+
},
|
397 |
+
"requests": {
|
398 |
+
"hashes": [
|
399 |
+
"sha256:99dcfdaaeb17caf6e526f32b6a7b780461512ab3f1d992187801694cba42770c",
|
400 |
+
"sha256:a84b8c9ab6239b578f22d1c21d51b696dcfe004032bb80ea832398d6909d7279"
|
401 |
+
],
|
402 |
+
"version": "==2.20.0"
|
403 |
+
},
|
404 |
+
"requests-toolbelt": {
|
405 |
+
"hashes": [
|
406 |
+
"sha256:42c9c170abc2cacb78b8ab23ac957945c7716249206f90874651971a4acff237",
|
407 |
+
"sha256:f6a531936c6fa4c6cfce1b9c10d5c4f498d16528d2a54a22ca00011205a187b5"
|
408 |
+
],
|
409 |
+
"version": "==0.8.0"
|
410 |
+
},
|
411 |
"scandir": {
|
412 |
"hashes": [
|
413 |
"sha256:04b8adb105f2ed313a7c2ef0f1cf7aff4871aa7a1883fa4d8c44b5551ab052d6",
|
|
|
434 |
},
|
435 |
"toml": {
|
436 |
"hashes": [
|
437 |
+
"sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c",
|
438 |
+
"sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"
|
439 |
],
|
440 |
+
"version": "==0.10.0"
|
441 |
+
},
|
442 |
+
"tqdm": {
|
443 |
+
"hashes": [
|
444 |
+
"sha256:a0be569511161220ff709a5b60d0890d47921f746f1c737a11d965e1b29e7b2e",
|
445 |
+
"sha256:e293e6d7a7f41a529a27f8d6624ab11544ccbfe82a205af6fad102545099fc21"
|
446 |
+
],
|
447 |
+
"version": "==4.27.0"
|
448 |
+
},
|
449 |
+
"twine": {
|
450 |
+
"hashes": [
|
451 |
+
"sha256:7d89bc6acafb31d124e6e5b295ef26ac77030bf098960c2a4c4e058335827c5c",
|
452 |
+
"sha256:fad6f1251195f7ddd1460cb76d6ea106c93adb4e56c41e0da79658e56e547d2c"
|
453 |
+
],
|
454 |
+
"index": "pypi",
|
455 |
+
"version": "==1.12.1"
|
456 |
+
},
|
457 |
+
"urllib3": {
|
458 |
+
"hashes": [
|
459 |
+
"sha256:41c3db2fc01e5b907288010dec72f9d0a74e37d6994e6eb56849f59fea2265ae",
|
460 |
+
"sha256:8819bba37a02d143296a4d032373c4dd4aca11f6d4c9973335ca75f9c8475f59"
|
461 |
+
],
|
462 |
+
"version": "==1.24"
|
463 |
},
|
464 |
"virtualenv": {
|
465 |
"hashes": [
|
|
|
467 |
"sha256:ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752"
|
468 |
],
|
469 |
"version": "==16.0.0"
|
470 |
+
},
|
471 |
+
"webencodings": {
|
472 |
+
"hashes": [
|
473 |
+
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
|
474 |
+
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
|
475 |
+
],
|
476 |
+
"version": "==0.5.1"
|
477 |
}
|
478 |
}
|
479 |
}
|
README.md
CHANGED
@@ -1,13 +1,14 @@
|
|
1 |
|
2 |
<div align="center">
|
3 |
<p>
|
4 |
-
<img src="
|
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.python.org/pypi/pytube/"><img src="https://img.shields.io/pypi/pyversions/pytube.svg" /></a>
|
12 |
</p>
|
13 |
</div>
|
|
|
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 |
</div>
|
docs/conf.py
CHANGED
@@ -35,7 +35,7 @@ master_doc = 'index'
|
|
35 |
|
36 |
# General information about the project.
|
37 |
project = 'pytube'
|
38 |
-
copyright = '
|
39 |
author = 'Nick Ficano'
|
40 |
|
41 |
# The version info for the project you're documenting, acts as replacement for
|
|
|
35 |
|
36 |
# General information about the project.
|
37 |
project = 'pytube'
|
38 |
+
copyright = '2018, Nick Ficano'
|
39 |
author = 'Nick Ficano'
|
40 |
|
41 |
# The version info for the project you're documenting, acts as replacement for
|
pytube/__init__.py
CHANGED
@@ -5,10 +5,10 @@
|
|
5 |
Pytube: a very serious Python library for downloading YouTube Videos.
|
6 |
"""
|
7 |
__title__ = 'pytube'
|
8 |
-
__version__ = '9.
|
9 |
__author__ = 'Nick Ficano'
|
10 |
__license__ = 'MIT License'
|
11 |
-
__copyright__ = 'Copyright
|
12 |
|
13 |
from pytube.logging import create_logger
|
14 |
from pytube.query import CaptionQuery
|
|
|
5 |
Pytube: a very serious Python library for downloading YouTube Videos.
|
6 |
"""
|
7 |
__title__ = 'pytube'
|
8 |
+
__version__ = '9.3.4'
|
9 |
__author__ = 'Nick Ficano'
|
10 |
__license__ = 'MIT License'
|
11 |
+
__copyright__ = 'Copyright 2018 Nick Ficano'
|
12 |
|
13 |
from pytube.logging import create_logger
|
14 |
from pytube.query import CaptionQuery
|
pytube/captions.py
CHANGED
@@ -45,7 +45,7 @@ class Caption:
|
|
45 |
'00:00:03,890'
|
46 |
"""
|
47 |
frac, whole = math.modf(d)
|
48 |
-
time_fmt = time.strftime('
|
49 |
ms = '{:.3f}'.format(frac).replace('0.', '')
|
50 |
return time_fmt + ms
|
51 |
|
|
|
45 |
'00:00:03,890'
|
46 |
"""
|
47 |
frac, whole = math.modf(d)
|
48 |
+
time_fmt = time.strftime('%H:%M:%S,', time.gmtime(whole))
|
49 |
ms = '{:.3f}'.format(frac).replace('0.', '')
|
50 |
return time_fmt + ms
|
51 |
|
pytube/contrib/playlist.py
CHANGED
@@ -2,7 +2,10 @@
|
|
2 |
"""
|
3 |
Module to download a complete playlist from a youtube channel
|
4 |
"""
|
|
|
5 |
import logging
|
|
|
|
|
6 |
|
7 |
from pytube import request
|
8 |
from pytube.__main__ import YouTube
|
@@ -36,6 +39,21 @@ class Playlist(object):
|
|
36 |
# url is already in the desired format, so just return it
|
37 |
return self.playlist_url
|
38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
def parse_links(self):
|
40 |
"""Parse the video links from the page source, extracts and
|
41 |
returns the /watch?v= part from video link href
|
@@ -51,6 +69,23 @@ class Playlist(object):
|
|
51 |
content = [x for x in req.split('\n') if 'pl-video-title-link' in x]
|
52 |
link_list = [x.split('href="', 1)[1].split('&', 1)[0] for x in content]
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
return link_list
|
55 |
|
56 |
def populate_video_urls(self):
|
|
|
2 |
"""
|
3 |
Module to download a complete playlist from a youtube channel
|
4 |
"""
|
5 |
+
import json
|
6 |
import logging
|
7 |
+
import re
|
8 |
+
from collections import OrderedDict
|
9 |
|
10 |
from pytube import request
|
11 |
from pytube.__main__ import YouTube
|
|
|
39 |
# url is already in the desired format, so just return it
|
40 |
return self.playlist_url
|
41 |
|
42 |
+
def _load_more_url(self, req):
|
43 |
+
"""Given an html page or a fragment thereof, looks for
|
44 |
+
and returns the "load more" url if found.
|
45 |
+
|
46 |
+
:return: string
|
47 |
+
"""
|
48 |
+
try:
|
49 |
+
load_more_url = 'https://www.youtube.com' + re.search(
|
50 |
+
r'data-uix-load-more-href=\"(/browse_ajax\?'
|
51 |
+
'action_continuation=.*?)\"', req,
|
52 |
+
).group(1)
|
53 |
+
except AttributeError:
|
54 |
+
load_more_url = ''
|
55 |
+
return load_more_url
|
56 |
+
|
57 |
def parse_links(self):
|
58 |
"""Parse the video links from the page source, extracts and
|
59 |
returns the /watch?v= part from video link href
|
|
|
69 |
content = [x for x in req.split('\n') if 'pl-video-title-link' in x]
|
70 |
link_list = [x.split('href="', 1)[1].split('&', 1)[0] for x in content]
|
71 |
|
72 |
+
# The above only returns 100 or fewer links
|
73 |
+
# Simulating a browser request for the load more link
|
74 |
+
load_more_url = self._load_more_url(req)
|
75 |
+
while len(load_more_url): # there is an url found
|
76 |
+
logger.debug('load more url: %s' % load_more_url)
|
77 |
+
req = request.get(load_more_url)
|
78 |
+
load_more = json.loads(req)
|
79 |
+
videos = re.findall(
|
80 |
+
r'href=\"(/watch\?v=[\w-]*)',
|
81 |
+
load_more['content_html'],
|
82 |
+
)
|
83 |
+
# remove duplicates
|
84 |
+
link_list.extend(list(OrderedDict.fromkeys(videos)))
|
85 |
+
load_more_url = self._load_more_url(
|
86 |
+
load_more['load_more_widget_html'],
|
87 |
+
)
|
88 |
+
|
89 |
return link_list
|
90 |
|
91 |
def populate_video_urls(self):
|
pytube/query.py
CHANGED
@@ -167,14 +167,16 @@ class StreamQuery:
|
|
167 |
attr = getattr(stream, attribute_name)
|
168 |
if attr is None:
|
169 |
break
|
170 |
-
num =
|
171 |
integer_attr_repr[attr] = int(''.join(num)) if num else None
|
172 |
|
173 |
# if every attribute has an integer representation
|
174 |
if integer_attr_repr and all(integer_attr_repr.values()):
|
175 |
-
def key(s):
|
|
|
176 |
else:
|
177 |
-
def key(s):
|
|
|
178 |
|
179 |
fmt_streams = sorted(
|
180 |
self.fmt_streams,
|
|
|
167 |
attr = getattr(stream, attribute_name)
|
168 |
if attr is None:
|
169 |
break
|
170 |
+
num = ''.join(x for x in attr if x.isdigit())
|
171 |
integer_attr_repr[attr] = int(''.join(num)) if num else None
|
172 |
|
173 |
# if every attribute has an integer representation
|
174 |
if integer_attr_repr and all(integer_attr_repr.values()):
|
175 |
+
def key(s):
|
176 |
+
return integer_attr_repr[getattr(s, attribute_name)]
|
177 |
else:
|
178 |
+
def key(s):
|
179 |
+
return getattr(s, attribute_name)
|
180 |
|
181 |
fmt_streams = sorted(
|
182 |
self.fmt_streams,
|
pytube/streams.py
CHANGED
@@ -226,7 +226,7 @@ class Stream(object):
|
|
226 |
bytes_remaining -= len(chunk)
|
227 |
# send to the on_progress callback.
|
228 |
self.on_progress(chunk, fh, bytes_remaining)
|
229 |
-
|
230 |
return fp
|
231 |
|
232 |
def stream_to_buffer(self):
|
|
|
226 |
bytes_remaining -= len(chunk)
|
227 |
# send to the on_progress callback.
|
228 |
self.on_progress(chunk, fh, bytes_remaining)
|
229 |
+
self.on_complete(fh)
|
230 |
return fp
|
231 |
|
232 |
def stream_to_buffer(self):
|
setup.cfg
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
[bumpversion]
|
2 |
commit = True
|
3 |
tag = True
|
4 |
-
current_version = 9.
|
5 |
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?
|
6 |
serialize =
|
7 |
{major}.{minor}.{patch}
|
|
|
1 |
[bumpversion]
|
2 |
commit = True
|
3 |
tag = True
|
4 |
+
current_version = 9.3.4
|
5 |
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?
|
6 |
serialize =
|
7 |
{major}.{minor}.{patch}
|
setup.py
CHANGED
@@ -1,25 +1,61 @@
|
|
1 |
#!/usr/bin/env python
|
2 |
# -*- coding: utf-8 -*-
|
3 |
"""This module contains setup instructions for pytube."""
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
|
9 |
-
|
10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
-
with open('LICENSE') as readme_file:
|
13 |
-
license = readme_file.read()
|
14 |
|
15 |
setup(
|
16 |
name='pytube',
|
17 |
-
version='9.
|
18 |
author='Nick Ficano',
|
19 |
author_email='nficano@gmail.com',
|
20 |
packages=['pytube', 'pytube.contrib'],
|
|
|
|
|
|
|
21 |
url='https://github.com/nficano/pytube',
|
22 |
-
license=
|
23 |
entry_points={
|
24 |
'console_scripts': [
|
25 |
'pytube = pytube.cli:main',
|
@@ -48,6 +84,9 @@ setup(
|
|
48 |
'Topic :: Utilities',
|
49 |
],
|
50 |
description=('A pythonic library for downloading YouTube Videos.'),
|
51 |
-
|
|
|
|
|
52 |
zip_safe=True,
|
|
|
53 |
)
|
|
|
1 |
#!/usr/bin/env python
|
2 |
# -*- coding: utf-8 -*-
|
3 |
"""This module contains setup instructions for pytube."""
|
4 |
+
import codecs
|
5 |
+
import os
|
6 |
+
import sys
|
7 |
+
from shutil import rmtree
|
8 |
|
9 |
+
from setuptools import Command
|
10 |
+
from setuptools import setup
|
11 |
+
|
12 |
+
here = os.path.abspath(os.path.dirname(__file__))
|
13 |
+
|
14 |
+
with codecs.open(os.path.join(here, 'README.md'), encoding='utf-8') as fh:
|
15 |
+
long_description = '\n' + fh.read()
|
16 |
+
|
17 |
+
|
18 |
+
class UploadCommand(Command):
|
19 |
+
"""Support setup.py publish."""
|
20 |
+
|
21 |
+
description = 'Build and publish the package.'
|
22 |
+
user_options = []
|
23 |
+
|
24 |
+
@staticmethod
|
25 |
+
def status(s):
|
26 |
+
"""Prints things in bold."""
|
27 |
+
print('\033[1m{0}\033[0m'.format(s))
|
28 |
+
|
29 |
+
def initialize_options(self):
|
30 |
+
pass
|
31 |
+
|
32 |
+
def finalize_options(self):
|
33 |
+
pass
|
34 |
+
|
35 |
+
def run(self):
|
36 |
+
try:
|
37 |
+
self.status('Removing previous builds ...')
|
38 |
+
rmtree(os.path.join(here, 'dist'))
|
39 |
+
except Exception:
|
40 |
+
pass
|
41 |
+
self.status('Building Source distribution ...')
|
42 |
+
os.system('{0} setup.py sdist bdist_wheel'.format(sys.executable))
|
43 |
+
self.status('Uploading the package to PyPI via Twine ...')
|
44 |
+
os.system('twine upload dist/*')
|
45 |
+
sys.exit()
|
46 |
|
|
|
|
|
47 |
|
48 |
setup(
|
49 |
name='pytube',
|
50 |
+
version='9.3.4',
|
51 |
author='Nick Ficano',
|
52 |
author_email='nficano@gmail.com',
|
53 |
packages=['pytube', 'pytube.contrib'],
|
54 |
+
package_data={
|
55 |
+
'': ['LICENSE'],
|
56 |
+
},
|
57 |
url='https://github.com/nficano/pytube',
|
58 |
+
license='MIT',
|
59 |
entry_points={
|
60 |
'console_scripts': [
|
61 |
'pytube = pytube.cli:main',
|
|
|
84 |
'Topic :: Utilities',
|
85 |
],
|
86 |
description=('A pythonic library for downloading YouTube Videos.'),
|
87 |
+
include_package_data=True,
|
88 |
+
long_description_content_type='text/markdown',
|
89 |
+
long_description=long_description,
|
90 |
zip_safe=True,
|
91 |
+
cmdclass={'upload': UploadCommand},
|
92 |
)
|