family-guy commited on
Commit
3662099
·
2 Parent(s): 5e3d357 2ede878

Merge branch 'master' of https://github.com/nficano/pytube into video-metadata-#195

Browse files
Pipfile CHANGED
@@ -1,18 +1,11 @@
1
  [[source]]
2
-
3
  url = "https://pypi.python.org/simple"
4
  verify_ssl = true
5
  name = "pypi"
6
 
7
-
8
  [packages]
9
 
10
- "flake8" = "*"
11
- "enum34" = "*"
12
-
13
-
14
  [dev-packages]
15
-
16
  bumpversion = "*"
17
  coveralls = "*"
18
  "flake8" = "*"
@@ -26,3 +19,4 @@ sphinx-rtd-theme = "*"
26
  configparser = "*"
27
  "urllib3" = "*"
28
  pyopenssl = "*"
 
 
1
  [[source]]
 
2
  url = "https://pypi.python.org/simple"
3
  verify_ssl = true
4
  name = "pypi"
5
 
 
6
  [packages]
7
 
 
 
 
 
8
  [dev-packages]
 
9
  bumpversion = "*"
10
  coveralls = "*"
11
  "flake8" = "*"
 
19
  configparser = "*"
20
  "urllib3" = "*"
21
  pyopenssl = "*"
22
+ "enum34" = "*"
Pipfile.lock CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "_meta": {
3
  "hash": {
4
- "sha256": "e517b067af601141604f030b60fecfa67d34ff012465b87979a6baa106a56194"
5
  },
6
  "pipfile-spec": 6,
7
  "requires": {},
@@ -13,53 +13,7 @@
13
  }
14
  ]
15
  },
16
- "default": {
17
- "configparser": {
18
- "hashes": [
19
- "sha256:5308b47021bc2340965c371f0f058cc6971a04502638d4244225c49d80db273a"
20
- ],
21
- "markers": "python_version < '3.2'",
22
- "version": "==3.5.0"
23
- },
24
- "enum34": {
25
- "hashes": [
26
- "sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850",
27
- "sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a",
28
- "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79",
29
- "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1"
30
- ],
31
- "markers": "python_version < '3.4'",
32
- "version": "==1.1.6"
33
- },
34
- "flake8": {
35
- "hashes": [
36
- "sha256:7253265f7abd8b313e3892944044a365e3f4ac3fcdcfb4298f55ee9ddf188ba0",
37
- "sha256:c7841163e2b576d435799169b78703ad6ac1bbb0f199994fc05f700b2a90ea37"
38
- ],
39
- "version": "==3.5.0"
40
- },
41
- "mccabe": {
42
- "hashes": [
43
- "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
44
- "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
45
- ],
46
- "version": "==0.6.1"
47
- },
48
- "pycodestyle": {
49
- "hashes": [
50
- "sha256:682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766",
51
- "sha256:6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9"
52
- ],
53
- "version": "==2.3.1"
54
- },
55
- "pyflakes": {
56
- "hashes": [
57
- "sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f",
58
- "sha256:8d616a382f243dbf19b54743f280b80198be0bca3a5396f1d2e1fca6223e8805"
59
- ],
60
- "version": "==1.6.0"
61
- }
62
- },
63
  "develop": {
64
  "alabaster": {
65
  "hashes": [
@@ -77,17 +31,17 @@
77
  },
78
  "aspy.yaml": {
79
  "hashes": [
80
- "sha256:6215f44900ff65f27dbd00a36b06a7926276436ed377320cfd4febd69bbd4a94",
81
- "sha256:be70cc0ccd1ee1d30f589f2403792eb2ffa7546470af0a17179541b13d8374df"
82
  ],
83
- "version": "==1.0.0"
84
  },
85
  "attrs": {
86
  "hashes": [
87
- "sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9",
88
- "sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450"
89
  ],
90
- "version": "==17.4.0"
91
  },
92
  "babel": {
93
  "hashes": [
@@ -101,21 +55,22 @@
101
  "sha256:6744c873dd7aafc24453d8b6a1a0d6d109faf63cd0cd19cb78fd46e74932c77e",
102
  "sha256:6753d9ff3552013e2130f7bc03c1007e24473b4835952679653fb132367bdd57"
103
  ],
 
104
  "version": "==0.5.3"
105
  },
106
  "cached-property": {
107
  "hashes": [
108
- "sha256:6e6935ec62567fbcbc346fad84fcea9bc77e3547b7267e62bc5b7ed8e5438ae8",
109
- "sha256:a2fa0f89dd422f7e5dd992a4a3e0ce209d5d1e47a4db28fd0a7b5273ec8da3f0"
110
  ],
111
- "version": "==1.4.0"
112
  },
113
  "certifi": {
114
  "hashes": [
115
- "sha256:14131608ad2fd56836d33a71ee60fa1c82bc9d2c8d98b7bdbc631fe1b3cd1296",
116
- "sha256:edbc3f203427eef571f79a7692bb160a2b0f7ccaa31953e99bd17e307cf63f7d"
117
  ],
118
- "version": "==2018.1.18"
119
  },
120
  "cffi": {
121
  "hashes": [
@@ -147,7 +102,7 @@
147
  "sha256:edabd457cd23a02965166026fd9bfd196f4324fe6032e866d0f3bd0301cd486f",
148
  "sha256:fdf1c1dc5bafc32bc5d08b054f94d659422b05aba244d6be4ddc1c72d9aa70fb"
149
  ],
150
- "markers": "platform_python_implementation != 'PyPy'",
151
  "version": "==1.11.5"
152
  },
153
  "cfgv": {
@@ -168,7 +123,7 @@
168
  "hashes": [
169
  "sha256:5308b47021bc2340965c371f0f058cc6971a04502638d4244225c49d80db273a"
170
  ],
171
- "markers": "python_version < '3.2'",
172
  "version": "==3.5.0"
173
  },
174
  "coverage": {
@@ -217,35 +172,30 @@
217
  "sha256:32569a43c9dbc13fa8199247580a4ab182ef439f51f65bb7f8316d377a1340e8",
218
  "sha256:664794748d2e5673e347ec476159a9d87f43e0d2d44950e98ed0e27b98da8346"
219
  ],
 
220
  "version": "==1.3.0"
221
  },
222
  "cryptography": {
223
  "hashes": [
224
- "sha256:0d39a93cf25edeae1f796bbc5960e587f34513a852564f6345ea4491a86c5997",
225
- "sha256:18d0b0fc21f39b35ea469a82584f55eeecec1f65a92d85af712c425bdef627b3",
226
- "sha256:27a208b9600166976182351174948e128818e7fc95cbdba18143f3106a211546",
227
- "sha256:28e4e9a97713aa47b5ef9c5003def2eb58aec89781ef3ef82b1c2916a8b0639b",
228
- "sha256:2cfcee8829c5dec55597826d52c26bc26e7ce39adb4771584459d0636b0b7108",
229
- "sha256:33b564196dcd563e309a0b07444e31611368afe3a3822160c046f5e4c3b5cdd7",
230
- "sha256:41f94194ae78f83fd94ca94fb8ad65f92210a76a2421169ffa5c33c3ec7605f4",
231
- "sha256:4f385ee7d39ee1ed74f1d6b1da03d0734ea82855a7b28a9e6e88c4091bc58664",
232
- "sha256:55555d784cfdf9033e81f044c0df04babed2aa141213765d960d233b0139e353",
233
- "sha256:69285f5615507b6625f89ea1048addd1d9218585fb886eb90bdebb1d2b2d26f5",
234
- "sha256:6cb1224da391fa90f1be524eafb375b62baf8d3df9690b32e8cc475ccfccee5e",
235
- "sha256:6fb22f63e17813f3d1d8e30dd1e249e2c34233ba1d3de977fd31cb5db764c7d0",
236
- "sha256:7a2409f1564c84bcf2563d379c9b6148c5bc6b0ae46e109f6a7b4bebadf551df",
237
- "sha256:8487524a1212223ca6dc7e2c8913024618f7ff29855c98869088e3818d5f6733",
238
- "sha256:9a2945efcff84830c8e237ab037d0269380d75d400a89cc9e5628e52647e21be",
239
- "sha256:9a47a80f65f4feaaf8415a40c339806c7d7d867152ddccc6ca87f707c8b7b565",
240
- "sha256:a3c180d12ffb1d8ee5b33a514a5bcb2a9cc06cc89aa74038015591170c82f55d",
241
- "sha256:a5f2c681fd040ed648513939a1dd2242af19bd5e9e79e53b6dcfa33bdae61217",
242
- "sha256:b984523d28737e373c7c35c8b6db6001537609d47534892de189bebebaa42a47",
243
- "sha256:d18df9cf3f3212df28d445ea82ce702c4d7a35817ef7a38ee38879ffa8f7e857",
244
- "sha256:e4d967371c5b6b2e67855066471d844c5d52d210c36c28d49a8507b96e2c5291",
245
- "sha256:ee245f185fae723133511e2450be08a66c2eebb53ad27c0c19b228029f4748a5",
246
- "sha256:fc2208d95d9ecc8032f5e38330d5ace2e3b0b998e42b08c30c35b2ab3a4a3bc8"
247
- ],
248
- "version": "==2.1.4"
249
  },
250
  "docopt": {
251
  "hashes": [
@@ -268,7 +218,7 @@
268
  "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79",
269
  "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1"
270
  ],
271
- "markers": "python_version < '3.4'",
272
  "version": "==1.1.6"
273
  },
274
  "flake8": {
@@ -276,22 +226,15 @@
276
  "sha256:7253265f7abd8b313e3892944044a365e3f4ac3fcdcfb4298f55ee9ddf188ba0",
277
  "sha256:c7841163e2b576d435799169b78703ad6ac1bbb0f199994fc05f700b2a90ea37"
278
  ],
 
279
  "version": "==3.5.0"
280
  },
281
- "funcsigs": {
282
- "hashes": [
283
- "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca",
284
- "sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"
285
- ],
286
- "markers": "python_version < '3.3'",
287
- "version": "==1.0.2"
288
- },
289
  "identify": {
290
  "hashes": [
291
- "sha256:53be6ea950a5f40e13be2dd87e67413eb6879527b831333196ab2a54de38f499",
292
- "sha256:c0bfb29634e04cde8e54aee2d55aff9dad30d6ea1f3e9e3ce731934d78635aa1"
293
  ],
294
- "version": "==1.0.8"
295
  },
296
  "idna": {
297
  "hashes": [
@@ -307,13 +250,6 @@
307
  ],
308
  "version": "==1.0.0"
309
  },
310
- "ipaddress": {
311
- "hashes": [
312
- "sha256:200d8686011d470b5e4de207d803445deee427455cd0cb7c982b68cf82524f81"
313
- ],
314
- "markers": "python_version < '3'",
315
- "version": "==1.0.19"
316
- },
317
  "jinja2": {
318
  "hashes": [
319
  "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
@@ -339,14 +275,22 @@
339
  "sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1",
340
  "sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba"
341
  ],
342
- "markers": "python_version < '3.0'",
343
  "version": "==2.0.0"
344
  },
 
 
 
 
 
 
 
 
345
  "nodeenv": {
346
  "hashes": [
347
- "sha256:98835dab727f94a713eacc7234e3db6777a55cafb60f391485011899e5c818df"
348
  ],
349
- "version": "==1.2.0"
350
  },
351
  "packaging": {
352
  "hashes": [
@@ -357,30 +301,33 @@
357
  },
358
  "pbr": {
359
  "hashes": [
360
- "sha256:05f61c71aaefc02d8e37c0a3eeb9815ff526ea28b3b76324769e6158d7f95be1",
361
- "sha256:60c25b7dfd054ef9bb0ae327af949dd4676aa09ac3a9471cdc871d8a9213f9ac"
362
  ],
363
- "version": "==3.1.1"
364
  },
365
  "pluggy": {
366
  "hashes": [
367
- "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff"
 
 
368
  ],
369
  "version": "==0.6.0"
370
  },
371
  "pre-commit": {
372
  "hashes": [
373
- "sha256:1b96ef893c003fcf81ac7c39cc790b01438dea05d9298e73bb61b9bf572282c3",
374
- "sha256:89ab725f311e6785f2f391ecfb6730b12b991d9488ae08d9d382104364527110"
375
  ],
376
- "version": "==1.8.1"
 
377
  },
378
  "py": {
379
  "hashes": [
380
- "sha256:8cca5c229d225f8c1e3085be4fcf306090b00850fefad892f9d96c7b6e2f310f",
381
- "sha256:ca18943e28235417756316bfada6cd96b23ce60dd532642690dcfdaba988a76d"
382
  ],
383
- "version": "==1.5.2"
384
  },
385
  "pycodestyle": {
386
  "hashes": [
@@ -414,6 +361,7 @@
414
  "sha256:07a2de1a54de07448732a81e38a55df7da109b2f47f599f8bb35b0cbec69d4bd",
415
  "sha256:2c10cfba46a52c0b0950118981d61e72c1e5b1aac451ca1bc77de1a679456773"
416
  ],
 
417
  "version": "==17.5.0"
418
  },
419
  "pyparsing": {
@@ -430,38 +378,34 @@
430
  },
431
  "pytest": {
432
  "hashes": [
433
- "sha256:062027955bccbc04d2fcd5d79690947e018ba31abe4c90b2c6721abec734261b",
434
- "sha256:117bad36c1a787e1a8a659df35de53ba05f9f3398fb9e4ac17e80ad5903eb8c5"
435
  ],
436
- "version": "==3.4.2"
 
437
  },
438
  "pytest-cov": {
439
  "hashes": [
440
  "sha256:03aa752cf11db41d281ea1d807d954c4eda35cfa1b21d6971966cc041bbf6e2d",
441
  "sha256:890fe5565400902b0c78b5357004aab1c814115894f4f21370e2433256a3eeec"
442
  ],
 
443
  "version": "==2.5.1"
444
  },
445
  "pytest-mock": {
446
  "hashes": [
447
- "sha256:03a2fea79d0a83a8de2e77e92afe5f0a5ca99a58cc68f843f9a74de34800a943",
448
- "sha256:b879dff61e31fcd4727c227c182f15f222a155293cc64ed5a02d55e0020cf949"
449
  ],
450
- "version": "==1.7.1"
 
451
  },
452
  "pytz": {
453
  "hashes": [
454
- "sha256:07edfc3d4d2705a20a6e99d97f0c4b61c800b8232dc1c04d87e8554f130148dd",
455
- "sha256:3a47ff71597f821cd84a162e71593004286e5be07a340fd462f0d33a760782b5",
456
- "sha256:410bcd1d6409026fbaa65d9ed33bf6dd8b1e94a499e32168acfc7b332e4095c0",
457
- "sha256:5bd55c744e6feaa4d599a6cbd8228b4f8f9ba96de2c38d56f08e534b3c9edf0d",
458
- "sha256:61242a9abc626379574a166dc0e96a66cd7c3b27fc10868003fa210be4bff1c9",
459
- "sha256:887ab5e5b32e4d0c86efddd3d055c1f363cbaa583beb8da5e22d2fa2f64d51ef",
460
- "sha256:ba18e6a243b3625513d85239b3e49055a2f0318466e0b8a92b8fb8ca7ccdf55f",
461
- "sha256:ed6509d9af298b7995d69a440e2822288f2eca1681b8cce37673dbb10091e5fe",
462
- "sha256:f93ddcdd6342f94cea379c73cddb5724e0d6d0a1c91c9bdef364dc0368ba4fda"
463
  ],
464
- "version": "==2018.3"
465
  },
466
  "pyyaml": {
467
  "hashes": [
@@ -505,17 +449,19 @@
505
  },
506
  "sphinx": {
507
  "hashes": [
508
- "sha256:41ae26acc6130ccf6ed47e5cca73742b80d55a134f0ab897c479bba8d3640b8e",
509
- "sha256:da987de5fcca21a4acc7f67a86a363039e67ac3e8827161e61b91deb131c0ee8"
510
  ],
511
- "version": "==1.7.1"
 
512
  },
513
  "sphinx-rtd-theme": {
514
  "hashes": [
515
- "sha256:2df74b8ff6fae6965c527e97cca6c6c944886aae474b490e17f92adfbe843417",
516
- "sha256:62ee4752716e698bad7de8a18906f42d33664128eea06c46b718fc7fbd1a9f5c"
517
  ],
518
- "version": "==0.2.4"
 
519
  },
520
  "sphinxcontrib-websupport": {
521
  "hashes": [
@@ -524,28 +470,20 @@
524
  ],
525
  "version": "==1.0.1"
526
  },
527
- "typing": {
528
- "hashes": [
529
- "sha256:3a887b021a77b292e151afb75323dea88a7bc1b3dfa92176cff8e44c8b68bddf",
530
- "sha256:b2c689d54e1144bbcfd191b0832980a21c2dbcf7b5ff7a66248a60c90e951eb8",
531
- "sha256:d400a9344254803a2368533e4533a4200d21eb7b6b729c173bc38201a74db3f2"
532
- ],
533
- "markers": "python_version < '3.5'",
534
- "version": "==3.6.4"
535
- },
536
  "urllib3": {
537
  "hashes": [
538
  "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
539
  "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
540
  ],
 
541
  "version": "==1.22"
542
  },
543
  "virtualenv": {
544
  "hashes": [
545
- "sha256:02f8102c2436bb03b3ee6dede1919d1dac8a427541652e5ec95171ec8adbc93a",
546
- "sha256:39d88b533b422825d644087a21e78c45cf5af0ef7a99a1fc9fbb7b481e5c85b0"
547
  ],
548
- "version": "==15.1.0"
549
  }
550
  }
551
  }
 
1
  {
2
  "_meta": {
3
  "hash": {
4
+ "sha256": "c601d22d66227c0d7c54837b8aad349a5f578cf1cf540ab38f56b48fe1313cab"
5
  },
6
  "pipfile-spec": 6,
7
  "requires": {},
 
13
  }
14
  ]
15
  },
16
+ "default": {},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  "develop": {
18
  "alabaster": {
19
  "hashes": [
 
31
  },
32
  "aspy.yaml": {
33
  "hashes": [
34
+ "sha256:c959530fab398e2391516bc8d5146489f9273b07d87dd8ba5e8b73406f7cc1fa",
35
+ "sha256:da95110d120a9168c9f43601b9cb732f006d8f193ee2c9b402c823026e4a9387"
36
  ],
37
+ "version": "==1.1.0"
38
  },
39
  "attrs": {
40
  "hashes": [
41
+ "sha256:4b90b09eeeb9b88c35bc642cbac057e45a5fd85367b985bd2809c62b7b939265",
42
+ "sha256:e0d0eb91441a3b53dab4d9b743eafc1ac44476296a2053b6ca3af0b139faf87b"
43
  ],
44
+ "version": "==18.1.0"
45
  },
46
  "babel": {
47
  "hashes": [
 
55
  "sha256:6744c873dd7aafc24453d8b6a1a0d6d109faf63cd0cd19cb78fd46e74932c77e",
56
  "sha256:6753d9ff3552013e2130f7bc03c1007e24473b4835952679653fb132367bdd57"
57
  ],
58
+ "index": "pypi",
59
  "version": "==0.5.3"
60
  },
61
  "cached-property": {
62
  "hashes": [
63
+ "sha256:67acb3ee8234245e8aea3784a492272239d9c4b487eba2fdcce9d75460d34520",
64
+ "sha256:bf093e640b7294303c7cc7ba3212f00b7a07d0416c1d923465995c9ef860a139"
65
  ],
66
+ "version": "==1.4.2"
67
  },
68
  "certifi": {
69
  "hashes": [
70
+ "sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7",
71
+ "sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0"
72
  ],
73
+ "version": "==2018.4.16"
74
  },
75
  "cffi": {
76
  "hashes": [
 
102
  "sha256:edabd457cd23a02965166026fd9bfd196f4324fe6032e866d0f3bd0301cd486f",
103
  "sha256:fdf1c1dc5bafc32bc5d08b054f94d659422b05aba244d6be4ddc1c72d9aa70fb"
104
  ],
105
+ "markers": "platform_python_implementation != 'pypy'",
106
  "version": "==1.11.5"
107
  },
108
  "cfgv": {
 
123
  "hashes": [
124
  "sha256:5308b47021bc2340965c371f0f058cc6971a04502638d4244225c49d80db273a"
125
  ],
126
+ "index": "pypi",
127
  "version": "==3.5.0"
128
  },
129
  "coverage": {
 
172
  "sha256:32569a43c9dbc13fa8199247580a4ab182ef439f51f65bb7f8316d377a1340e8",
173
  "sha256:664794748d2e5673e347ec476159a9d87f43e0d2d44950e98ed0e27b98da8346"
174
  ],
175
+ "index": "pypi",
176
  "version": "==1.3.0"
177
  },
178
  "cryptography": {
179
  "hashes": [
180
+ "sha256:3f3b65d5a16e6b52fba63dc860b62ca9832f51f1a2ae5083c78b6840275f12dd",
181
+ "sha256:551a3abfe0c8c6833df4192a63371aa2ff43afd8f570ed345d31f251d78e7e04",
182
+ "sha256:5cb990056b7cadcca26813311187ad751ea644712022a3976443691168781b6f",
183
+ "sha256:60bda7f12ecb828358be53095fc9c6edda7de8f1ef571f96c00b2363643fa3cd",
184
+ "sha256:6fef51ec447fe9f8351894024e94736862900d3a9aa2961528e602eb65c92bdb",
185
+ "sha256:77d0ad229d47a6e0272d00f6bf8ac06ce14715a9fd02c9a97f5a2869aab3ccb2",
186
+ "sha256:808fe471b1a6b777f026f7dc7bd9a4959da4bfab64972f2bbe91e22527c1c037",
187
+ "sha256:9b62fb4d18529c84b961efd9187fecbb48e89aa1a0f9f4161c61b7fc42a101bd",
188
+ "sha256:9e5bed45ec6b4f828866ac6a6bedf08388ffcfa68abe9e94b34bb40977aba531",
189
+ "sha256:9fc295bf69130a342e7a19a39d7bbeb15c0bcaabc7382ec33ef3b2b7d18d2f63",
190
+ "sha256:abd070b5849ed64e6d349199bef955ee0ad99aefbad792f0c587f8effa681a5e",
191
+ "sha256:ba6a774749b6e510cffc2fb98535f717e0e5fd91c7c99a61d223293df79ab351",
192
+ "sha256:c332118647f084c983c6a3e1dba0f3bcb051f69d12baccac68db8d62d177eb8a",
193
+ "sha256:d6f46e862ee36df81e6342c2177ba84e70f722d9dc9c6c394f9f1f434c4a5563",
194
+ "sha256:db6013746f73bf8edd9c3d1d3f94db635b9422f503db3fc5ef105233d4c011ab",
195
+ "sha256:f57008eaff597c69cf692c3518f6d4800f0309253bb138b526a37fe9ef0c7471",
196
+ "sha256:f6c821ac253c19f2ad4c8691633ae1d1a17f120d5b01ea1d256d7b602bc59887"
197
+ ],
198
+ "version": "==2.2.2"
 
 
 
 
 
 
199
  },
200
  "docopt": {
201
  "hashes": [
 
218
  "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79",
219
  "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1"
220
  ],
221
+ "index": "pypi",
222
  "version": "==1.1.6"
223
  },
224
  "flake8": {
 
226
  "sha256:7253265f7abd8b313e3892944044a365e3f4ac3fcdcfb4298f55ee9ddf188ba0",
227
  "sha256:c7841163e2b576d435799169b78703ad6ac1bbb0f199994fc05f700b2a90ea37"
228
  ],
229
+ "index": "pypi",
230
  "version": "==3.5.0"
231
  },
 
 
 
 
 
 
 
 
232
  "identify": {
233
  "hashes": [
234
+ "sha256:8c127f455e8503eb3a5ed5388527719e1fef00a41b5e58dc036bc116f3bb8a16",
235
+ "sha256:bb5bdf324b4a24def86757c8dd8a4e91a9c28bbf1bf8505d702ce4b8d2508270"
236
  ],
237
+ "version": "==1.0.16"
238
  },
239
  "idna": {
240
  "hashes": [
 
250
  ],
251
  "version": "==1.0.0"
252
  },
 
 
 
 
 
 
 
253
  "jinja2": {
254
  "hashes": [
255
  "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
 
275
  "sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1",
276
  "sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba"
277
  ],
278
+ "index": "pypi",
279
  "version": "==2.0.0"
280
  },
281
+ "more-itertools": {
282
+ "hashes": [
283
+ "sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea",
284
+ "sha256:11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2442e",
285
+ "sha256:c9ce7eccdcb901a2c75d326ea134e0886abfbea5f93e91cc95de9507c0816c44"
286
+ ],
287
+ "version": "==4.1.0"
288
+ },
289
  "nodeenv": {
290
  "hashes": [
291
+ "sha256:dd0a34001090ff042cfdb4b0c8d6a6f7ec9baa49733f00b695bb8a8b4700ba6c"
292
  ],
293
+ "version": "==1.3.0"
294
  },
295
  "packaging": {
296
  "hashes": [
 
301
  },
302
  "pbr": {
303
  "hashes": [
304
+ "sha256:4e8a0ed6a8705a26768f4c3da26026013b157821fe5f95881599556ea9d91c19",
305
+ "sha256:dae4aaa78eafcad10ce2581fc34d694faa616727837fd8e55c1a00951ad6744f"
306
  ],
307
+ "version": "==4.0.2"
308
  },
309
  "pluggy": {
310
  "hashes": [
311
+ "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff",
312
+ "sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c",
313
+ "sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5"
314
  ],
315
  "version": "==0.6.0"
316
  },
317
  "pre-commit": {
318
  "hashes": [
319
+ "sha256:01bb5f44606735ca30c8be641fa24f5760fcc599a0260ead0067bcde2f0305f9",
320
+ "sha256:823452163aa9fb024a9ff30947ba7f5a2778708db7554a4d36438b9bbead6bbb"
321
  ],
322
+ "index": "pypi",
323
+ "version": "==1.8.2"
324
  },
325
  "py": {
326
  "hashes": [
327
+ "sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881",
328
+ "sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a"
329
  ],
330
+ "version": "==1.5.3"
331
  },
332
  "pycodestyle": {
333
  "hashes": [
 
361
  "sha256:07a2de1a54de07448732a81e38a55df7da109b2f47f599f8bb35b0cbec69d4bd",
362
  "sha256:2c10cfba46a52c0b0950118981d61e72c1e5b1aac451ca1bc77de1a679456773"
363
  ],
364
+ "index": "pypi",
365
  "version": "==17.5.0"
366
  },
367
  "pyparsing": {
 
378
  },
379
  "pytest": {
380
  "hashes": [
381
+ "sha256:54713b26c97538db6ff0703a12b19aeaeb60b5e599de542e7fca0ec83b9038e8",
382
+ "sha256:829230122facf05a5f81a6d4dfe6454a04978ea3746853b2b84567ecf8e5c526"
383
  ],
384
+ "index": "pypi",
385
+ "version": "==3.5.1"
386
  },
387
  "pytest-cov": {
388
  "hashes": [
389
  "sha256:03aa752cf11db41d281ea1d807d954c4eda35cfa1b21d6971966cc041bbf6e2d",
390
  "sha256:890fe5565400902b0c78b5357004aab1c814115894f4f21370e2433256a3eeec"
391
  ],
392
+ "index": "pypi",
393
  "version": "==2.5.1"
394
  },
395
  "pytest-mock": {
396
  "hashes": [
397
+ "sha256:53801e621223d34724926a5c98bd90e8e417ce35264365d39d6c896388dcc928",
398
+ "sha256:d89a8209d722b8307b5e351496830d5cc5e192336003a485443ae9adeb7dd4c0"
399
  ],
400
+ "index": "pypi",
401
+ "version": "==1.10.0"
402
  },
403
  "pytz": {
404
  "hashes": [
405
+ "sha256:65ae0c8101309c45772196b21b74c46b2e5d11b6275c45d251b150d5da334555",
406
+ "sha256:c06425302f2cf668f1bba7a0a03f3c1d34d4ebeef2c72003da308b3947c7f749"
 
 
 
 
 
 
 
407
  ],
408
+ "version": "==2018.4"
409
  },
410
  "pyyaml": {
411
  "hashes": [
 
449
  },
450
  "sphinx": {
451
  "hashes": [
452
+ "sha256:2e7ad92e96eff1b2006cf9f0cdb2743dacbae63755458594e9e8238b0c3dc60b",
453
+ "sha256:e9b1a75a3eae05dded19c80eb17325be675e0698975baae976df603b6ed1eb10"
454
  ],
455
+ "index": "pypi",
456
+ "version": "==1.7.4"
457
  },
458
  "sphinx-rtd-theme": {
459
  "hashes": [
460
+ "sha256:32424dac2779f0840b4788fbccb032ba2496c1ca47a439ad2510c8b1e55dfd33",
461
+ "sha256:6d0481532b5f441b075127a2d755f430f1f8410a50112b1af6b069518548381d"
462
  ],
463
+ "index": "pypi",
464
+ "version": "==0.3.1"
465
  },
466
  "sphinxcontrib-websupport": {
467
  "hashes": [
 
470
  ],
471
  "version": "==1.0.1"
472
  },
 
 
 
 
 
 
 
 
 
473
  "urllib3": {
474
  "hashes": [
475
  "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
476
  "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
477
  ],
478
+ "index": "pypi",
479
  "version": "==1.22"
480
  },
481
  "virtualenv": {
482
  "hashes": [
483
+ "sha256:1d7e241b431e7afce47e77f8843a276f652699d1fa4f93b9d8ce0076fd7b0b54",
484
+ "sha256:e8e05d4714a1c51a2f5921e62f547fcb0f713ebbe959e0a7f585cc8bef71d11f"
485
  ],
486
+ "version": "==15.2.0"
487
  }
488
  }
489
  }
README.md CHANGED
@@ -13,7 +13,7 @@
13
  </div>
14
 
15
  # pytube
16
- *pytube* is a lightweight, dependency-free Python library (and command-line utility) for downloading YouTube Videos.
17
 
18
  ## Description
19
  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*.
 
13
  </div>
14
 
15
  # pytube
16
+ *pytube* is a very serious, lightweight, dependency-free Python library (and command-line utility) for downloading YouTube Videos.
17
 
18
  ## Description
19
  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*.
pytube/__init__.py CHANGED
@@ -2,14 +2,10 @@
2
  # flake8: noqa
3
  # noreorder
4
  """
5
- Pytube is a Python library for downloading YouTube Videos.
6
-
7
- Pytube aims to be lightweight, dependency-free, extensively documented and
8
- follows best practice patterns.
9
-
10
  """
11
  __title__ = 'pytube'
12
- __version__ = '9.1.1'
13
  __author__ = 'Nick Ficano'
14
  __license__ = 'MIT License'
15
  __copyright__ = 'Copyright 2017 Nick Ficano'
 
2
  # flake8: noqa
3
  # noreorder
4
  """
5
+ Pytube: a very serious Python library for downloading YouTube Videos.
 
 
 
 
6
  """
7
  __title__ = 'pytube'
8
+ __version__ = '9.2.3'
9
  __author__ = 'Nick Ficano'
10
  __license__ = 'MIT License'
11
  __copyright__ = 'Copyright 2017 Nick Ficano'
pytube/__main__.py CHANGED
@@ -19,10 +19,11 @@ from pytube import mixins
19
  from pytube import request
20
  from pytube import Stream
21
  from pytube import StreamQuery
 
22
  from pytube.compat import parse_qsl
 
23
  from pytube.helpers import apply_mixin
24
 
25
-
26
  logger = logging.getLogger(__name__)
27
 
28
 
@@ -31,7 +32,7 @@ class YouTube(object):
31
 
32
  def __init__(
33
  self, url=None, defer_prefetch_init=False, on_progress_callback=None,
34
- on_complete_callback=None,
35
  ):
36
  """Construct a :class:`YouTube <YouTube>`.
37
 
@@ -80,6 +81,9 @@ class YouTube(object):
80
  'on_complete': on_complete_callback,
81
  }
82
 
 
 
 
83
  if not defer_prefetch_init:
84
  self.prefetch_init()
85
 
@@ -154,6 +158,8 @@ class YouTube(object):
154
 
155
  """
156
  self.watch_html = request.get(url=self.watch_url)
 
 
157
  self.embed_html = request.get(url=self.embed_url)
158
  self.age_restricted = extract.is_age_restricted(self.watch_html)
159
  self.vid_info_url = extract.video_info_url(
 
19
  from pytube import request
20
  from pytube import Stream
21
  from pytube import StreamQuery
22
+ from pytube.compat import install_proxy
23
  from pytube.compat import parse_qsl
24
+ from pytube.exceptions import VideoUnavailable
25
  from pytube.helpers import apply_mixin
26
 
 
27
  logger = logging.getLogger(__name__)
28
 
29
 
 
32
 
33
  def __init__(
34
  self, url=None, defer_prefetch_init=False, on_progress_callback=None,
35
+ on_complete_callback=None, proxies=None,
36
  ):
37
  """Construct a :class:`YouTube <YouTube>`.
38
 
 
81
  'on_complete': on_complete_callback,
82
  }
83
 
84
+ if proxies:
85
+ install_proxy(proxies)
86
+
87
  if not defer_prefetch_init:
88
  self.prefetch_init()
89
 
 
158
 
159
  """
160
  self.watch_html = request.get(url=self.watch_url)
161
+ if '<img class="icon meh" src="/yts/img' not in self.watch_html:
162
+ raise VideoUnavailable('This video is unavailable.')
163
  self.embed_html = request.get(url=self.embed_url)
164
  self.age_restricted = extract.is_age_restricted(self.watch_html)
165
  self.vid_info_url = extract.video_info_url(
pytube/compat.py CHANGED
@@ -10,6 +10,7 @@ PY33 = sys.version_info[0:2] >= (3, 3)
10
 
11
 
12
  if PY2:
 
13
  from urllib import urlencode
14
  from urllib2 import URLError
15
  from urllib2 import quote
@@ -18,6 +19,17 @@ if PY2:
18
  from urlparse import parse_qsl
19
  from HTMLParser import HTMLParser
20
 
 
 
 
 
 
 
 
 
 
 
 
21
  def unescape(s):
22
  """Strip HTML entries from a string."""
23
  html_parser = HTMLParser()
@@ -34,6 +46,12 @@ elif PY3:
34
  from urllib.parse import unquote
35
  from urllib.parse import urlencode
36
  from urllib.request import urlopen
 
 
 
 
 
 
37
 
38
  def unicode(s):
39
  """No-op."""
 
10
 
11
 
12
  if PY2:
13
+ import urllib2
14
  from urllib import urlencode
15
  from urllib2 import URLError
16
  from urllib2 import quote
 
19
  from urlparse import parse_qsl
20
  from HTMLParser import HTMLParser
21
 
22
+ def install_proxy(proxy_handler):
23
+ """
24
+ install global proxy.
25
+ :param proxy_handler:
26
+ :samp:`{"http":"http://my.proxy.com:1234", "https":"https://my.proxy.com:1234"}`
27
+ :return:
28
+ """
29
+ proxy_support = urllib2.ProxyHandler(proxy_handler)
30
+ opener = urllib2.build_opener(proxy_support)
31
+ urllib2.install_opener(opener)
32
+
33
  def unescape(s):
34
  """Strip HTML entries from a string."""
35
  html_parser = HTMLParser()
 
46
  from urllib.parse import unquote
47
  from urllib.parse import urlencode
48
  from urllib.request import urlopen
49
+ from urllib import request
50
+
51
+ def install_proxy(proxy_handler):
52
+ proxy_support = request.ProxyHandler(proxy_handler)
53
+ opener = request.build_opener(proxy_support)
54
+ request.install_opener(opener)
55
 
56
  def unicode(s):
57
  """No-op."""
pytube/contrib/playlist.py CHANGED
@@ -66,26 +66,67 @@ class Playlist(object):
66
  complete_url = base_url + video_id
67
  self.video_urls.append(complete_url)
68
 
69
- def download_all(self, download_path=None):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  """Download all the videos in the the playlist. Initially, download
71
  resolution is 720p (or highest available), later more option
72
  should be added to download resolution of choice
73
 
74
  TODO(nficano): Add option to download resolution of user's choice
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  """
76
 
77
  self.populate_video_urls()
78
- logger.debug('total videos found: ', len(self.video_urls))
79
  logger.debug('starting download')
80
 
 
 
81
  for link in self.video_urls:
82
  yt = YouTube(link)
83
-
84
  # TODO: this should not be hardcoded to a single user's preference
85
  dl_stream = yt.streams.filter(
86
  progressive=True, subtype='mp4',
87
  ).order_by('resolution').desc().first()
88
 
89
  logger.debug('download path: %s', download_path)
90
- dl_stream.download(download_path)
 
 
 
 
 
91
  logger.debug('download complete')
 
66
  complete_url = base_url + video_id
67
  self.video_urls.append(complete_url)
68
 
69
+ def _path_num_prefix_generator(self, reverse=False):
70
+ """
71
+ This generator function generates number prefixes, for the items
72
+ in the playlist.
73
+ If the number of digits required to name a file,is less than is
74
+ required to name the last file,it prepends 0s.
75
+ So if you have a playlist of 100 videos it will number them like:
76
+ 001, 002, 003 ect, up to 100.
77
+ It also adds a space after the number.
78
+ :return: prefix string generator : generator
79
+ """
80
+ digits = len(str(len(self.video_urls)))
81
+ if reverse:
82
+ start, stop, step = (len(self.video_urls), 0, -1)
83
+ else:
84
+ start, stop, step = (1, len(self.video_urls) + 1, 1)
85
+ return (str(i).zfill(digits) for i in range(start, stop, step))
86
+
87
+ def download_all(
88
+ self, download_path=None, prefix_number=True,
89
+ reverse_numbering=False,
90
+ ):
91
  """Download all the videos in the the playlist. Initially, download
92
  resolution is 720p (or highest available), later more option
93
  should be added to download resolution of choice
94
 
95
  TODO(nficano): Add option to download resolution of user's choice
96
+
97
+ :param download_path:
98
+ (optional) Output path for the playlist If one is not
99
+ specified, defaults to the current working directory.
100
+ This is passed along to the Stream objects.
101
+ :type download_path: str or None
102
+ :param prefix_number:
103
+ (optional) Automatically numbers playlists using the
104
+ _path_num_prefix_generator function.
105
+ :type prefix_number: bool
106
+ :param reverse_numbering:
107
+ (optional) Lets you number playlists in reverse, since some
108
+ playlists are ordered newest -> oldests.
109
+ :type reverse_numbering: bool
110
  """
111
 
112
  self.populate_video_urls()
113
+ logger.debug('total videos found: %d', len(self.video_urls))
114
  logger.debug('starting download')
115
 
116
+ prefix_gen = self._path_num_prefix_generator(reverse_numbering)
117
+
118
  for link in self.video_urls:
119
  yt = YouTube(link)
 
120
  # TODO: this should not be hardcoded to a single user's preference
121
  dl_stream = yt.streams.filter(
122
  progressive=True, subtype='mp4',
123
  ).order_by('resolution').desc().first()
124
 
125
  logger.debug('download path: %s', download_path)
126
+ if prefix_number:
127
+ prefix = next(prefix_gen)
128
+ logger.debug('file prefix is: %s', prefix)
129
+ dl_stream.download(download_path, filename_prefix=prefix)
130
+ else:
131
+ dl_stream.download(download_path)
132
  logger.debug('download complete')
pytube/exceptions.py CHANGED
@@ -34,3 +34,7 @@ class ExtractError(PytubeError):
34
 
35
  class RegexMatchError(ExtractError):
36
  """Regex pattern did not return any matches."""
 
 
 
 
 
34
 
35
  class RegexMatchError(ExtractError):
36
  """Regex pattern did not return any matches."""
37
+
38
+
39
+ class VideoUnavailable(PytubeError):
40
+ """Video is unavailable."""
pytube/itags.py CHANGED
@@ -57,9 +57,9 @@ ITAGS = {
57
  246: ('480p', None),
58
  247: ('720p', None),
59
  248: ('1080p', None),
60
- 264: ('144p', None),
61
  266: ('2160p', None),
62
- 271: ('144p', None),
63
  272: ('2160p', None),
64
  278: ('144p', None),
65
  298: ('720p', None),
 
57
  246: ('480p', None),
58
  247: ('720p', None),
59
  248: ('1080p', None),
60
+ 264: ('1440p', None),
61
  266: ('2160p', None),
62
+ 271: ('1440p', None),
63
  272: ('2160p', None),
64
  278: ('144p', None),
65
  298: ('720p', None),
pytube/query.py CHANGED
@@ -187,7 +187,7 @@ class StreamQuery:
187
  def get_by_itag(self, itag):
188
  """Get the corresponding :class:`Stream <Stream>` for a given itag.
189
 
190
- :param str itag:
191
  YouTube format identifier code.
192
  :rtype: :class:`Stream <Stream>` or None
193
  :returns:
@@ -196,7 +196,7 @@ class StreamQuery:
196
 
197
  """
198
  try:
199
- return self.itag_index[itag]
200
  except KeyError:
201
  pass
202
 
 
187
  def get_by_itag(self, itag):
188
  """Get the corresponding :class:`Stream <Stream>` for a given itag.
189
 
190
+ :param str int itag:
191
  YouTube format identifier code.
192
  :rtype: :class:`Stream <Stream>` or None
193
  :returns:
 
196
 
197
  """
198
  try:
199
+ return self.itag_index[int(itag)]
200
  except KeyError:
201
  pass
202
 
pytube/streams.py CHANGED
@@ -9,6 +9,7 @@ separately).
9
  """
10
  from __future__ import absolute_import
11
 
 
12
  import logging
13
  import os
14
  import pprint
@@ -173,7 +174,7 @@ class Stream(object):
173
  filename = safe_filename(title)
174
  return '{filename}.{s.subtype}'.format(filename=filename, s=self)
175
 
176
- def download(self, output_path=None, filename=None):
177
  """Write the media stream to disk.
178
 
179
  :param output_path:
@@ -184,8 +185,15 @@ class Stream(object):
184
  (optional) Output filename (stem only) for writing media file.
185
  If one is not specified, the default filename is used.
186
  :type filename: str or None
 
 
 
 
 
 
 
187
 
188
- :rtype: None
189
 
190
  """
191
  output_path = output_path or os.getcwd()
@@ -194,6 +202,13 @@ class Stream(object):
194
  filename = '{filename}.{s.subtype}'.format(filename=safe, s=self)
195
  filename = filename or self.default_filename
196
 
 
 
 
 
 
 
 
197
  # file path
198
  fp = os.path.join(output_path, filename)
199
  bytes_remaining = self.filesize
@@ -209,6 +224,27 @@ class Stream(object):
209
  # send to the on_progress callback.
210
  self.on_progress(chunk, fh, bytes_remaining)
211
  self.on_complete(fh)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
  def on_progress(self, chunk, file_handler, bytes_remaining):
214
  """On progress callback function.
 
9
  """
10
  from __future__ import absolute_import
11
 
12
+ import io
13
  import logging
14
  import os
15
  import pprint
 
174
  filename = safe_filename(title)
175
  return '{filename}.{s.subtype}'.format(filename=filename, s=self)
176
 
177
+ def download(self, output_path=None, filename=None, filename_prefix=None):
178
  """Write the media stream to disk.
179
 
180
  :param output_path:
 
185
  (optional) Output filename (stem only) for writing media file.
186
  If one is not specified, the default filename is used.
187
  :type filename: str or None
188
+ :param filename_prefix:
189
+ (optional) A string that will be prepended to the filename.
190
+ For example a number in a playlist or the name of a series.
191
+ If one is not specified, nothing will be prepended
192
+ This is seperate from filename so you can use the default
193
+ filename but still add a prefix.
194
+ :type filename_prefix: str or None
195
 
196
+ :rtype: str
197
 
198
  """
199
  output_path = output_path or os.getcwd()
 
202
  filename = '{filename}.{s.subtype}'.format(filename=safe, s=self)
203
  filename = filename or self.default_filename
204
 
205
+ if filename_prefix:
206
+ filename = '{prefix}{filename}'\
207
+ .format(
208
+ prefix=safe_filename(filename_prefix),
209
+ filename=filename,
210
+ )
211
+
212
  # file path
213
  fp = os.path.join(output_path, filename)
214
  bytes_remaining = self.filesize
 
224
  # send to the on_progress callback.
225
  self.on_progress(chunk, fh, bytes_remaining)
226
  self.on_complete(fh)
227
+ return fp
228
+
229
+ def stream_to_buffer(self):
230
+ """Write the media stream to buffer
231
+
232
+ :rtype: io.BytesIO buffer
233
+ """
234
+ buffer = io.BytesIO()
235
+ bytes_remaining = self.filesize
236
+ logger.debug(
237
+ 'downloading (%s total bytes) file to BytesIO buffer',
238
+ self.filesize,
239
+ )
240
+
241
+ for chunk in request.get(self.url, streaming=True):
242
+ # reduce the (bytes) remainder by the length of the chunk.
243
+ bytes_remaining -= len(chunk)
244
+ # send to the on_progress callback.
245
+ self.on_progress(chunk, buffer, bytes_remaining)
246
+ self.on_complete(buffer)
247
+ return buffer
248
 
249
  def on_progress(self, chunk, file_handler, bytes_remaining):
250
  """On progress callback function.
setup.cfg CHANGED
@@ -1,9 +1,9 @@
1
  [bumpversion]
2
  commit = True
3
  tag = True
4
- current_version = 9.1.1
5
  parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?
6
- serialize =
7
  {major}.{minor}.{patch}
8
 
9
  [metadata]
@@ -15,6 +15,5 @@ description-file = README.md
15
 
16
  [coverage:run]
17
  source = pytube
18
- omit =
19
  pytube/compat.py
20
-
 
1
  [bumpversion]
2
  commit = True
3
  tag = True
4
+ current_version = 9.2.3
5
  parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?
6
+ serialize =
7
  {major}.{minor}.{patch}
8
 
9
  [metadata]
 
15
 
16
  [coverage:run]
17
  source = pytube
18
+ omit =
19
  pytube/compat.py
 
setup.py CHANGED
@@ -14,7 +14,7 @@ with open('LICENSE') as readme_file:
14
 
15
  setup(
16
  name='pytube',
17
- version='9.1.1',
18
  author='Nick Ficano',
19
  author_email='nficano@gmail.com',
20
  packages=['pytube', 'pytube.contrib'],
 
14
 
15
  setup(
16
  name='pytube',
17
+ version='9.2.3',
18
  author='Nick Ficano',
19
  author_email='nficano@gmail.com',
20
  packages=['pytube', 'pytube.contrib'],
tests/test_playlist.py CHANGED
@@ -1,12 +1,14 @@
1
  # -*- coding: utf-8 -*-
2
  from pytube import Playlist
3
 
 
 
 
 
 
4
 
5
  def test_construct():
6
- ob = Playlist(
7
- 'https://www.youtube.com/watch?v=m5q2GCsteQs&list='
8
- 'PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw',
9
- )
10
  expected = 'https://www.youtube.com/' \
11
  'playlist?list=' \
12
  'PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw'
@@ -14,25 +16,8 @@ def test_construct():
14
  assert ob.construct_playlist_url() == expected
15
 
16
 
17
- def test_link_parse():
18
- ob = Playlist(
19
- 'https://www.youtube.com/watch?v=m5q2GCsteQs&list='
20
- 'PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw',
21
- )
22
-
23
- expected = [
24
- '/watch?v=m5q2GCsteQs',
25
- '/watch?v=5YK63cXyJ2Q',
26
- '/watch?v=Rzt4rUPFYD4',
27
- ]
28
- assert ob.parse_links() == expected
29
-
30
-
31
  def test_populate():
32
- ob = Playlist(
33
- 'https://www.youtube.com/watch?v=m5q2GCsteQs&list='
34
- 'PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw',
35
- )
36
  expected = [
37
  'https://www.youtube.com/watch?v=m5q2GCsteQs',
38
  'https://www.youtube.com/watch?v=5YK63cXyJ2Q',
@@ -43,10 +28,50 @@ def test_populate():
43
  assert ob.video_urls == expected
44
 
45
 
 
 
 
 
 
 
 
 
 
 
 
46
  def test_download():
47
- ob = Playlist(
48
- 'https://www.youtube.com/watch?v=lByG_AgKS9k&list='
49
- 'PL525f8ds9RvuerPZ3bZygmNiYw2sP4BDk',
50
- )
51
  ob.download_all()
52
  ob.download_all('.')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # -*- coding: utf-8 -*-
2
  from pytube import Playlist
3
 
4
+ short_test_pl = 'https://www.youtube.com/watch?v=' \
5
+ 'm5q2GCsteQs&list=PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw'
6
+ long_test_pl = 'https://www.youtube.com/watch?v=' \
7
+ '9CHDoAsX1yo&list=UUXuqSBlHAE6Xw-yeJA0Tunw'
8
+
9
 
10
  def test_construct():
11
+ ob = Playlist(short_test_pl)
 
 
 
12
  expected = 'https://www.youtube.com/' \
13
  'playlist?list=' \
14
  'PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw'
 
16
  assert ob.construct_playlist_url() == expected
17
 
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  def test_populate():
20
+ ob = Playlist(short_test_pl)
 
 
 
21
  expected = [
22
  'https://www.youtube.com/watch?v=m5q2GCsteQs',
23
  'https://www.youtube.com/watch?v=5YK63cXyJ2Q',
 
28
  assert ob.video_urls == expected
29
 
30
 
31
+ def test_link_parse():
32
+ ob = Playlist(short_test_pl)
33
+
34
+ expected = [
35
+ '/watch?v=m5q2GCsteQs',
36
+ '/watch?v=5YK63cXyJ2Q',
37
+ '/watch?v=Rzt4rUPFYD4',
38
+ ]
39
+ assert ob.parse_links() == expected
40
+
41
+
42
  def test_download():
43
+ ob = Playlist(short_test_pl)
 
 
 
44
  ob.download_all()
45
  ob.download_all('.')
46
+ ob.download_all(prefix_number=False)
47
+ ob.download_all('.', prefix_number=False)
48
+
49
+
50
+ def test_numbering():
51
+ ob = Playlist(short_test_pl)
52
+ ob.populate_video_urls()
53
+ gen = ob._path_num_prefix_generator(reverse=False)
54
+ assert '1' in next(gen)
55
+ assert '2' in next(gen)
56
+
57
+ ob = Playlist(short_test_pl)
58
+ ob.populate_video_urls()
59
+ gen = ob._path_num_prefix_generator(reverse=True)
60
+ assert str(len(ob.video_urls)) in next(gen)
61
+ assert str(len(ob.video_urls) - 1) in next(gen)
62
+
63
+ ob = Playlist(long_test_pl)
64
+ ob.populate_video_urls()
65
+ gen = ob._path_num_prefix_generator(reverse=False)
66
+ nxt = next(gen)
67
+ assert len(nxt) > 1
68
+ assert '1' in nxt
69
+ nxt = next(gen)
70
+ assert len(nxt) > 1
71
+ assert '2' in nxt
72
+
73
+ ob = Playlist(long_test_pl)
74
+ ob.populate_video_urls()
75
+ gen = ob._path_num_prefix_generator(reverse=True)
76
+ assert str(len(ob.video_urls)) in next(gen)
77
+ assert str(len(ob.video_urls) - 1) in next(gen)
tests/test_query.py CHANGED
@@ -111,6 +111,7 @@ def test_get_by_itag(cipher_signature):
111
  :class:`Stream <Stream>`.
112
  """
113
  assert cipher_signature.streams.get_by_itag(22).itag == '22'
 
114
 
115
 
116
  def test_get_by_non_existent_itag(cipher_signature):
 
111
  :class:`Stream <Stream>`.
112
  """
113
  assert cipher_signature.streams.get_by_itag(22).itag == '22'
114
+ assert cipher_signature.streams.get_by_itag('22').itag == '22'
115
 
116
 
117
  def test_get_by_non_existent_itag(cipher_signature):