mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2025-12-08 15:12:47 +01:00
Compare commits
1373 Commits
2021.04.11
...
2022.02.03
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cea9ec2eb | ||
|
|
28469edd7d | ||
|
|
d5a398988b | ||
|
|
455a15e2dc | ||
|
|
460a1c08b9 | ||
|
|
4918522735 | ||
|
|
65662dffb1 | ||
|
|
5e51f4a8ad | ||
|
|
54bb39065c | ||
|
|
c5332d7fbb | ||
|
|
35cd4c4d88 | ||
|
|
67fb99f193 | ||
|
|
85553414ae | ||
|
|
d16df59db5 | ||
|
|
63c3ee4f63 | ||
|
|
182bda88e8 | ||
|
|
16aa9ea41d | ||
|
|
d6bc443bde | ||
|
|
046cab3915 | ||
|
|
7df07a3b55 | ||
|
|
2d49720f89 | ||
|
|
48416bc4a8 | ||
|
|
6a0546e313 | ||
|
|
dbcea0585f | ||
|
|
f7d4854131 | ||
|
|
403be2eefb | ||
|
|
63bac931c2 | ||
|
|
7c74a01584 | ||
|
|
1d3586d0d5 | ||
|
|
c533c89ce1 | ||
|
|
b8b3f4562a | ||
|
|
1c6f480160 | ||
|
|
f8580bf02f | ||
|
|
19afd9ea51 | ||
|
|
b72270d27e | ||
|
|
706dfe441b | ||
|
|
c4da5ff971 | ||
|
|
e26f9cc1e5 | ||
|
|
fa8fd95118 | ||
|
|
05b23b4156 | ||
|
|
8f028b5f40 | ||
|
|
013322a95e | ||
|
|
fb62afd6f0 | ||
|
|
50600e833d | ||
|
|
fc08bdd6ab | ||
|
|
2568d41f70 | ||
|
|
88f23a18e0 | ||
|
|
bb66c24797 | ||
|
|
2edb38e8ca | ||
|
|
af6793f804 | ||
|
|
b695e3f9bd | ||
|
|
6a5a30f9e2 | ||
|
|
d37707bda4 | ||
|
|
f40ee5e9a0 | ||
|
|
1f13021eca | ||
|
|
e612f66c7c | ||
|
|
87e8e8a7d0 | ||
|
|
e600a5c908 | ||
|
|
50ce204cc2 | ||
|
|
144a3588b4 | ||
|
|
ed40877833 | ||
|
|
935f5a4209 | ||
|
|
6970b6005e | ||
|
|
fc5fa964c7 | ||
|
|
e0ddbd02bd | ||
|
|
0bfc53d05c | ||
|
|
78ab4f447c | ||
|
|
85fee22152 | ||
|
|
ad9158d5f4 | ||
|
|
f81c62a6a4 | ||
|
|
6c73052c0a | ||
|
|
593e43c030 | ||
|
|
8fe514d382 | ||
|
|
b1156c1e59 | ||
|
|
311b6615d8 | ||
|
|
396a76f7bf | ||
|
|
301d07fc4b | ||
|
|
d14cbdd92d | ||
|
|
19b4c74d40 | ||
|
|
135dfa2c7e | ||
|
|
e0585e6562 | ||
|
|
426764371f | ||
|
|
64f36541c9 | ||
|
|
0ff1e0fba3 | ||
|
|
1a20d29552 | ||
|
|
f7085283e1 | ||
|
|
e25ca9b017 | ||
|
|
4259402c56 | ||
|
|
dfb7f2a25d | ||
|
|
42c5458a02 | ||
|
|
ba1c671d2e | ||
|
|
b143e83ec9 | ||
|
|
4a77fb1d6b | ||
|
|
66f7c6a3e0 | ||
|
|
baf599effa | ||
|
|
8bd1c00bf3 | ||
|
|
596379e260 | ||
|
|
b6ce9bb038 | ||
|
|
eea1b0358e | ||
|
|
32b95bb643 | ||
|
|
fdf80059d9 | ||
|
|
aa062713c1 | ||
|
|
71738b1451 | ||
|
|
0bb5ac1ac4 | ||
|
|
77b28f000a | ||
|
|
d57576b9d9 | ||
|
|
11c861702d | ||
|
|
a4a426023d | ||
|
|
3b603dbdf1 | ||
|
|
5df1ac92bd | ||
|
|
b2db8102dc | ||
|
|
e9a6a65a55 | ||
|
|
ed8d87f911 | ||
|
|
397235c52b | ||
|
|
4636548463 | ||
|
|
cb3c5682ae | ||
|
|
7d449fff53 | ||
|
|
80fa6e5327 | ||
|
|
fabb27fcea | ||
|
|
e04938ab88 | ||
|
|
8bcd404818 | ||
|
|
0df11dafdd | ||
|
|
dc5f409cdc | ||
|
|
99d6f9461d | ||
|
|
8130779db6 | ||
|
|
ed5835b451 | ||
|
|
e88e1febd8 | ||
|
|
faca674510 | ||
|
|
0931ba94ab | ||
|
|
b31874334d | ||
|
|
f1150b9e1e | ||
|
|
d6579d532b | ||
|
|
2be56f2242 | ||
|
|
f95a7b93e6 | ||
|
|
62c955efc9 | ||
|
|
0254f16274 | ||
|
|
a70b71e85a | ||
|
|
4c968755fc | ||
|
|
be1f331f21 | ||
|
|
3cf5429a21 | ||
|
|
bfa0e270cf | ||
|
|
f76ca2dd56 | ||
|
|
5f969a78b0 | ||
|
|
443f8de820 | ||
|
|
768145d48a | ||
|
|
976ae3eabb | ||
|
|
f0d785d3ed | ||
|
|
97a6b117d9 | ||
|
|
6f32a0b5b7 | ||
|
|
e8736539f3 | ||
|
|
9c634ef857 | ||
|
|
9f517bb1f3 | ||
|
|
b8eeced286 | ||
|
|
db47787024 | ||
|
|
fdeab99eab | ||
|
|
9e907ebddf | ||
|
|
21df2117e4 | ||
|
|
06e57990f7 | ||
|
|
b62fa6d75f | ||
|
|
be72c62480 | ||
|
|
61e9d9268c | ||
|
|
a13e684813 | ||
|
|
f46e2f9d92 | ||
|
|
9c906919ae | ||
|
|
6020e05d23 | ||
|
|
ebed8b3732 | ||
|
|
1e43a6f733 | ||
|
|
ca30f449a1 | ||
|
|
af3cbd8782 | ||
|
|
7141ced57d | ||
|
|
18c7683d27 | ||
|
|
f5c2c2c9b0 | ||
|
|
8896899216 | ||
|
|
1797b073ed | ||
|
|
4c922dd3fc | ||
|
|
b8e976a445 | ||
|
|
a9f5f5d6eb | ||
|
|
f522573787 | ||
|
|
7592749cbe | ||
|
|
767f999b53 | ||
|
|
8efffafa53 | ||
|
|
26f2aa3db9 | ||
|
|
3464a2727b | ||
|
|
497d77e1aa | ||
|
|
9040e2d6e3 | ||
|
|
6134fbeb65 | ||
|
|
cfcf60ea99 | ||
|
|
4afa3ec4b6 | ||
|
|
11aa91a12f | ||
|
|
abbeeebc4c | ||
|
|
2c539d493a | ||
|
|
042931a507 | ||
|
|
96f13f01a6 | ||
|
|
4b9353239e | ||
|
|
dd5e60b15d | ||
|
|
e540c56f39 | ||
|
|
45d86abeb4 | ||
|
|
f02d24d8d2 | ||
|
|
ceb98323f2 | ||
|
|
7537e35b64 | ||
|
|
1e5c83b26b | ||
|
|
6223f67a8c | ||
|
|
6a34813a0d | ||
|
|
f59f5ef8b6 | ||
|
|
f44afb54ef | ||
|
|
77cee0f188 | ||
|
|
6a17677577 | ||
|
|
ee7b9bdf5d | ||
|
|
185bf31070 | ||
|
|
0b77924a38 | ||
|
|
8126298c1b | ||
|
|
6da22e7d4f | ||
|
|
c62ecf0d90 | ||
|
|
3774f4f427 | ||
|
|
9980d3d213 | ||
|
|
8eb4b1bb8e | ||
|
|
332da56f52 | ||
|
|
459aea84c3 | ||
|
|
87e0499624 | ||
|
|
0f86a1cd59 | ||
|
|
d80d98e7d4 | ||
|
|
352d5da812 | ||
|
|
d43de6821c | ||
|
|
070f6a85ea | ||
|
|
4b4b7f746c | ||
|
|
e9efb99f66 | ||
|
|
a709d87335 | ||
|
|
774a46c53d | ||
|
|
c8b80b9643 | ||
|
|
4e260d1a56 | ||
|
|
4f3fa23e5a | ||
|
|
b28bac93ab | ||
|
|
37893bb0c9 | ||
|
|
c25de59cf7 | ||
|
|
205a0654c0 | ||
|
|
663949f825 | ||
|
|
b69fd25c25 | ||
|
|
e0fd95737d | ||
|
|
4ac5b94807 | ||
|
|
4273cc776d | ||
|
|
fa9f30b802 | ||
|
|
1cefca9e44 | ||
|
|
5edb8dfec2 | ||
|
|
0fcba15d57 | ||
|
|
adbc4ec4bb | ||
|
|
c031b0414c | ||
|
|
f3aa3c3f98 | ||
|
|
ae43a4b986 | ||
|
|
ca5db158ae | ||
|
|
5f549d4959 | ||
|
|
6839d02cb6 | ||
|
|
2aae2c91ff | ||
|
|
c2dedf12e8 | ||
|
|
e75bb0d6c3 | ||
|
|
dd0228ce1f | ||
|
|
37e57a9fd4 | ||
|
|
940a67a3e2 | ||
|
|
e6ae51c123 | ||
|
|
75ad33572b | ||
|
|
aab41cdd33 | ||
|
|
b3a5115ff1 | ||
|
|
d76d15a669 | ||
|
|
e978789f0f | ||
|
|
ec2e44fc57 | ||
|
|
375d9360bf | ||
|
|
d5c3254889 | ||
|
|
fed1309651 | ||
|
|
fe69f52e5c | ||
|
|
3116be32b4 | ||
|
|
a8549f19e7 | ||
|
|
39ca3b5c7f | ||
|
|
46383212b3 | ||
|
|
0bb322b9c0 | ||
|
|
ff9f925b63 | ||
|
|
5bfc8bee5a | ||
|
|
19188702ef | ||
|
|
d984a98def | ||
|
|
069c6ccf02 | ||
|
|
53dad39e30 | ||
|
|
db77c49c84 | ||
|
|
abc07b554c | ||
|
|
86f3d52f8c | ||
|
|
8b688881ba | ||
|
|
13debc86e7 | ||
|
|
b5f94e4fa1 | ||
|
|
61882afdc5 | ||
|
|
aa4b054512 | ||
|
|
487c5b3389 | ||
|
|
8157a09d22 | ||
|
|
b1aaf1c07f | ||
|
|
5f9aaac8c2 | ||
|
|
54c2521ca6 | ||
|
|
2814f12ba4 | ||
|
|
1619836cb7 | ||
|
|
e3c7d49571 | ||
|
|
ddd24c9949 | ||
|
|
443b21dc4e | ||
|
|
66f4c04e50 | ||
|
|
93864403ea | ||
|
|
b5475f1145 | ||
|
|
38d79fd16c | ||
|
|
acc0d6a411 | ||
|
|
146cc4114a | ||
|
|
818faa3a86 | ||
|
|
aa5ecf082c | ||
|
|
d2b2fca53f | ||
|
|
63ccf4ff1a | ||
|
|
43b2290658 | ||
|
|
99148c6a33 | ||
|
|
9bdd99cf39 | ||
|
|
2c4aaaddc9 | ||
|
|
5f7cb91ae9 | ||
|
|
3efb96a6d1 | ||
|
|
3262f8abf2 | ||
|
|
bdbafb3913 | ||
|
|
a804f6d89c | ||
|
|
814dfb7e25 | ||
|
|
91f071af60 | ||
|
|
2aa5e2cc01 | ||
|
|
1bad50eced | ||
|
|
ac0efabf12 | ||
|
|
73f035e1fe | ||
|
|
0cbed930c8 | ||
|
|
5118d2ec58 | ||
|
|
717216b093 | ||
|
|
5c22c63da3 | ||
|
|
ee8dd27a73 | ||
|
|
f304da8a29 | ||
|
|
06dfe0a0a2 | ||
|
|
75b725a7cc | ||
|
|
13ab5fa586 | ||
|
|
36eaf3039a | ||
|
|
f2ebc5c7be | ||
|
|
b222c27145 | ||
|
|
5e5be0c0b2 | ||
|
|
7578d77d8c | ||
|
|
b29165267f | ||
|
|
bc104778d6 | ||
|
|
d298d33fe6 | ||
|
|
bf57cfa8b7 | ||
|
|
3c2208f82d | ||
|
|
93e597ba28 | ||
|
|
b28cdcc0e4 | ||
|
|
a33c0d9c5d | ||
|
|
75689fe59b | ||
|
|
5ce1d13eba | ||
|
|
e04b003e64 | ||
|
|
909b0d66f4 | ||
|
|
dfd78699f5 | ||
|
|
639f80c1f9 | ||
|
|
896a88c5c6 | ||
|
|
4e4ba1d75f | ||
|
|
2abf081554 | ||
|
|
359df0fc42 | ||
|
|
3938a9212c | ||
|
|
cf1f13b817 | ||
|
|
18d6dd4e01 | ||
|
|
883ecd5494 | ||
|
|
eb56d132d2 | ||
|
|
17b4540662 | ||
|
|
da27aeea5c | ||
|
|
fec41d17a5 | ||
|
|
a61fd4cf6f | ||
|
|
a6213a4925 | ||
|
|
9941a1e127 | ||
|
|
ff51ed588f | ||
|
|
57dbe8077f | ||
|
|
e5d731f35d | ||
|
|
d52cd2f5cd | ||
|
|
bc8ab44ea0 | ||
|
|
8f122fa070 | ||
|
|
14a086058a | ||
|
|
0e6b018a10 | ||
|
|
f7b558df4d | ||
|
|
1ee34c76bb | ||
|
|
234416e4bf | ||
|
|
c98d4df23b | ||
|
|
849d699a8b | ||
|
|
77fcc65158 | ||
|
|
545ad64988 | ||
|
|
d76991ab07 | ||
|
|
282f570918 | ||
|
|
c07a39ae8e | ||
|
|
c5e3f84972 | ||
|
|
c45b87419f | ||
|
|
7333296ff5 | ||
|
|
a04e005521 | ||
|
|
6b993ca765 | ||
|
|
dd2a987d3f | ||
|
|
9222c38182 | ||
|
|
467b6b8387 | ||
|
|
8863c8f09e | ||
|
|
e16fefd869 | ||
|
|
c6118ca2cc | ||
|
|
764f5de2f4 | ||
|
|
cfcaf64a4b | ||
|
|
402cd603a4 | ||
|
|
22a510ff44 | ||
|
|
61be785a67 | ||
|
|
11852843e7 | ||
|
|
525d9e0c7d | ||
|
|
9d63137eac | ||
|
|
266a1b5d52 | ||
|
|
450bdf69bc | ||
|
|
720c309932 | ||
|
|
d8cf8d97a8 | ||
|
|
d0d012d4e7 | ||
|
|
013b50b794 | ||
|
|
dac5df5a98 | ||
|
|
f279aaee8e | ||
|
|
d0e6121adf | ||
|
|
9ac24e235e | ||
|
|
7c7f7161fc | ||
|
|
e339d25a0d | ||
|
|
39c04074e7 | ||
|
|
92775d8a40 | ||
|
|
df03de2c02 | ||
|
|
48e9310660 | ||
|
|
c1dc0ee56e | ||
|
|
bf5f605e76 | ||
|
|
e08a85d865 | ||
|
|
093a17107e | ||
|
|
44bcb8d122 | ||
|
|
013ae2e503 | ||
|
|
b47d236d72 | ||
|
|
9ebf3c6ab9 | ||
|
|
7144b697fc | ||
|
|
2e9a445bc3 | ||
|
|
86c1a8aae4 | ||
|
|
ebfab36fca | ||
|
|
c15de6ffe6 | ||
|
|
56bb56f3cf | ||
|
|
c0599d4fe4 | ||
|
|
3f771f75d7 | ||
|
|
ed76230b3f | ||
|
|
89fcdff5d8 | ||
|
|
f98709af31 | ||
|
|
c586f9e8de | ||
|
|
59a7a13ef9 | ||
|
|
4476d2c764 | ||
|
|
aa9369a2d8 | ||
|
|
d54c6003ab | ||
|
|
1ee316a34a | ||
|
|
358247ed2a | ||
|
|
9b12e9a573 | ||
|
|
a109acbf82 | ||
|
|
a49891c761 | ||
|
|
582fad70f5 | ||
|
|
aeec0e44e2 | ||
|
|
d9190e4467 | ||
|
|
e1b7c54d78 | ||
|
|
244644c02c | ||
|
|
34921b4345 | ||
|
|
a331949df3 | ||
|
|
2c5e8a961e | ||
|
|
b515b37cc4 | ||
|
|
3c4eebf772 | ||
|
|
fb2d1ee6cc | ||
|
|
9cb070f9c0 | ||
|
|
2a6f8475ac | ||
|
|
73673ccff3 | ||
|
|
aeb2a9ad27 | ||
|
|
df6c409d1f | ||
|
|
a9d4da606d | ||
|
|
c18d4482b1 | ||
|
|
0f6518938d | ||
|
|
22cd06c452 | ||
|
|
a4211baff5 | ||
|
|
8913ef74d7 | ||
|
|
832e9000c7 | ||
|
|
673c0057e8 | ||
|
|
9af98e17bd | ||
|
|
31c49255bf | ||
|
|
bd93fd5d45 | ||
|
|
d89257f398 | ||
|
|
9bd979ca40 | ||
|
|
a1fc7ca074 | ||
|
|
c588b602d3 | ||
|
|
f0ffaa1621 | ||
|
|
0930b11fda | ||
|
|
a0bb6ce58d | ||
|
|
da48320075 | ||
|
|
5b6cb56207 | ||
|
|
b2f25dc242 | ||
|
|
2f9e021299 | ||
|
|
8dcf65c92e | ||
|
|
92592bd305 | ||
|
|
404f611f1c | ||
|
|
cd9ea4104b | ||
|
|
652fb0d446 | ||
|
|
6b301aaa34 | ||
|
|
fa0b816e37 | ||
|
|
5e7bbac305 | ||
|
|
10beccc980 | ||
|
|
e6ff66efc0 | ||
|
|
aeaf3b2b92 | ||
|
|
7b5f3f7c3d | ||
|
|
3783b5f1d1 | ||
|
|
ab630a57b9 | ||
|
|
16b0d7e621 | ||
|
|
5be76d1ab7 | ||
|
|
b7b186e7de | ||
|
|
bd1c792327 | ||
|
|
dc88e9be03 | ||
|
|
673944b001 | ||
|
|
0c873df3a8 | ||
|
|
c35ada3360 | ||
|
|
0db3bae879 | ||
|
|
48f796874d | ||
|
|
abad800058 | ||
|
|
08438d2ca5 | ||
|
|
7de837a5e3 | ||
|
|
7e59ca440a | ||
|
|
8e7ab2cf08 | ||
|
|
ad64a2323f | ||
|
|
f2fe69c7b0 | ||
|
|
fccf502118 | ||
|
|
9f1a1c36e6 | ||
|
|
96565c7e55 | ||
|
|
ec11a9f4a2 | ||
|
|
93c7f3398d | ||
|
|
1117579b94 | ||
|
|
0676afb126 | ||
|
|
49a57e70a9 | ||
|
|
457f6d6866 | ||
|
|
ad0090d0d2 | ||
|
|
d183af3cc1 | ||
|
|
3c239332b0 | ||
|
|
ab2ffab22d | ||
|
|
f656a23cb1 | ||
|
|
58ab5cbc58 | ||
|
|
17ec8bcfa9 | ||
|
|
0f6e60bb57 | ||
|
|
ef58c47637 | ||
|
|
19b824f693 | ||
|
|
f0ded3dad3 | ||
|
|
733d8e8f99 | ||
|
|
386cdfdb5b | ||
|
|
6e21fdd279 | ||
|
|
0e5927eebf | ||
|
|
27f817a84b | ||
|
|
d3c93ec2b7 | ||
|
|
b4b855ebc7 | ||
|
|
2cda6b401d | ||
|
|
aa7785f860 | ||
|
|
9fab498fbf | ||
|
|
e619d8a752 | ||
|
|
1e520b5535 | ||
|
|
176f1866cb | ||
|
|
17bddf3e95 | ||
|
|
2d9ec70423 | ||
|
|
e820fbaa6f | ||
|
|
b11d210156 | ||
|
|
24b0a72b30 | ||
|
|
aae16f6ed9 | ||
|
|
373475f035 | ||
|
|
920134b2e5 | ||
|
|
72ab768719 | ||
|
|
01b052b2b1 | ||
|
|
019a94f7d6 | ||
|
|
e69585f8c6 | ||
|
|
693ec74401 | ||
|
|
239df02103 | ||
|
|
18f96d129b | ||
|
|
ec3f6640c1 | ||
|
|
dd078970ba | ||
|
|
71ce444a3f | ||
|
|
580d3274e5 | ||
|
|
03b4de722a | ||
|
|
48ee10ee8a | ||
|
|
6ff34542d2 | ||
|
|
e3950399e4 | ||
|
|
974208e151 | ||
|
|
883d4b1eec | ||
|
|
a0c716bb61 | ||
|
|
d5a39f0bad | ||
|
|
a64907d0ac | ||
|
|
6993f78d1b | ||
|
|
993191c0d5 | ||
|
|
fc5c8b6492 | ||
|
|
b836dc94f2 | ||
|
|
c111cefa5d | ||
|
|
975a0d0df9 | ||
|
|
a387b69a7c | ||
|
|
ecdc9049c0 | ||
|
|
7b38649845 | ||
|
|
e88d44c6ee | ||
|
|
a2160aa45f | ||
|
|
cc16383ff3 | ||
|
|
a903d8285c | ||
|
|
9dda99f2fc | ||
|
|
ba10757412 | ||
|
|
e6faf2be36 | ||
|
|
ed39cac53d | ||
|
|
a169858f24 | ||
|
|
0481e266f5 | ||
|
|
2c4bba96ac | ||
|
|
e8f726a57f | ||
|
|
8063de5109 | ||
|
|
dec0d56fa9 | ||
|
|
21186af70a | ||
|
|
84999521c8 | ||
|
|
d1d5c08f29 | ||
|
|
2e01ba6218 | ||
|
|
c9652aa418 | ||
|
|
91b6c884c9 | ||
|
|
28fe35b4e3 | ||
|
|
aa9a92fdbb | ||
|
|
a170527e1f | ||
|
|
90d55df330 | ||
|
|
81bcd43a03 | ||
|
|
b5ae35ee6d | ||
|
|
4e3b637d5b | ||
|
|
8cd69fc407 | ||
|
|
2614f64600 | ||
|
|
b922db9fe5 | ||
|
|
f2cad2e496 | ||
|
|
d6124e191e | ||
|
|
8c6f4daa4c | ||
|
|
ac56cf38a4 | ||
|
|
c08b8873ea | ||
|
|
819e05319b | ||
|
|
fee3f44f5f | ||
|
|
705e7c2005 | ||
|
|
49e7e9c3ce | ||
|
|
8472674399 | ||
|
|
1276a43a77 | ||
|
|
519804a92f | ||
|
|
1b6bb4a85a | ||
|
|
644149afec | ||
|
|
4e3d1898a8 | ||
|
|
f85e6be42e | ||
|
|
762e509d91 | ||
|
|
d92125aeba | ||
|
|
0f0ac87be3 | ||
|
|
755203fc3f | ||
|
|
943d5ab133 | ||
|
|
3001a84dca | ||
|
|
ebf2fb4d61 | ||
|
|
efc947fb3e | ||
|
|
b11c04a8ae | ||
|
|
5d535b4a55 | ||
|
|
a1c3967307 | ||
|
|
e919569e67 | ||
|
|
ff1dec819a | ||
|
|
9359f3d4f0 | ||
|
|
0eaec13ba6 | ||
|
|
ad095c4283 | ||
|
|
e6f21b3d92 | ||
|
|
d710cc6d36 | ||
|
|
3ae5e79774 | ||
|
|
8e3fd7e034 | ||
|
|
80c03fa98f | ||
|
|
1f2a268bd3 | ||
|
|
804ca01cc7 | ||
|
|
851876095b | ||
|
|
2d997542ca | ||
|
|
7756277882 | ||
|
|
7687c8ac6e | ||
|
|
80c360d7aa | ||
|
|
250a938de8 | ||
|
|
f1d42a83ab | ||
|
|
3cf4b91dc5 | ||
|
|
fecb20a503 | ||
|
|
360167b9fc | ||
|
|
28234287f1 | ||
|
|
91dd88b90f | ||
|
|
d31dab7084 | ||
|
|
c470901ccf | ||
|
|
2333ea1029 | ||
|
|
9a13345439 | ||
|
|
524e2e4fda | ||
|
|
f440b14f87 | ||
|
|
8dc831f715 | ||
|
|
e99b2d2771 | ||
|
|
1fed277349 | ||
|
|
0ef787d773 | ||
|
|
a5de4099cb | ||
|
|
ff1c7fc9d3 | ||
|
|
600e900300 | ||
|
|
20b91b9b63 | ||
|
|
4c88ff87fc | ||
|
|
e27cc5d864 | ||
|
|
eb6d4ad1ca | ||
|
|
99e9e001de | ||
|
|
51ff9ca0b0 | ||
|
|
b19404591a | ||
|
|
1f8471e22c | ||
|
|
77c4a9ef68 | ||
|
|
8f70b0b82f | ||
|
|
be867b03f5 | ||
|
|
1813a6ccd4 | ||
|
|
8100c77223 | ||
|
|
9ada988bfc | ||
|
|
d1a7768432 | ||
|
|
49fa4d9af7 | ||
|
|
ee2b3563f3 | ||
|
|
bdc196a444 | ||
|
|
388bc4a640 | ||
|
|
50eff38c1c | ||
|
|
4be9dbdc24 | ||
|
|
a21e0ab1a1 | ||
|
|
a76e2e0f88 | ||
|
|
bd50a52b0d | ||
|
|
c12977bdc4 | ||
|
|
f6d8776d34 | ||
|
|
d806c9fd97 | ||
|
|
5e3f2f8fc4 | ||
|
|
1009f67c2a | ||
|
|
bd6f722de8 | ||
|
|
d9d8b85747 | ||
|
|
daf7ac2b92 | ||
|
|
96933fc1b6 | ||
|
|
0d32e124c6 | ||
|
|
cb2ec90e91 | ||
|
|
3cd786dbd7 | ||
|
|
1b629e1b4c | ||
|
|
8f8e8eba24 | ||
|
|
09906f554d | ||
|
|
a63d9bd0b0 | ||
|
|
f137e4c27c | ||
|
|
4762621925 | ||
|
|
57aa7b8511 | ||
|
|
9c1c3ec016 | ||
|
|
f9cc0161e6 | ||
|
|
c6af2dd8e5 | ||
|
|
7738bd3272 | ||
|
|
7c37ff97d3 | ||
|
|
d47f46e17e | ||
|
|
298bf1d275 | ||
|
|
d1b39ad844 | ||
|
|
edf65256aa | ||
|
|
7303f84abe | ||
|
|
f5aa5cfbff | ||
|
|
f1f6ca78b4 | ||
|
|
2fac2e9136 | ||
|
|
23dd2d9a32 | ||
|
|
b89378a69a | ||
|
|
0001fcb586 | ||
|
|
c589c1d395 | ||
|
|
f7590d4764 | ||
|
|
dbf7eca917 | ||
|
|
d21bba7853 | ||
|
|
a8cb7eca61 | ||
|
|
92790da2bb | ||
|
|
b5a39ed43b | ||
|
|
cc33cc4395 | ||
|
|
1722099ded | ||
|
|
40b18348e7 | ||
|
|
e9a30b181e | ||
|
|
9c95ac677e | ||
|
|
ea706726d6 | ||
|
|
f60990ddfc | ||
|
|
ad226b1dc9 | ||
|
|
ca46b94134 | ||
|
|
67ad7759af | ||
|
|
d5fe04f5c7 | ||
|
|
03c862794f | ||
|
|
0fd6661edb | ||
|
|
02c7ae8104 | ||
|
|
16f7e6be3a | ||
|
|
ffecd3034b | ||
|
|
1c5ce74c04 | ||
|
|
81a136b80f | ||
|
|
eab3f867e2 | ||
|
|
a7e999beec | ||
|
|
71407b3eca | ||
|
|
dc9de9cbd2 | ||
|
|
92ddaa415e | ||
|
|
b6de707d13 | ||
|
|
bccdbd22d5 | ||
|
|
bd9ff55bcd | ||
|
|
526d74ec5a | ||
|
|
e04a1ff92e | ||
|
|
aa6c25309a | ||
|
|
d98b006b85 | ||
|
|
265a7a8ee5 | ||
|
|
826446bd82 | ||
|
|
bc79491368 | ||
|
|
421ddcb8b4 | ||
|
|
c0ac49bcca | ||
|
|
02def2714c | ||
|
|
f9be9cb9fd | ||
|
|
4614bc22c1 | ||
|
|
8e5fecc88c | ||
|
|
165efb823b | ||
|
|
dd594deb2a | ||
|
|
409e18286e | ||
|
|
8113999995 | ||
|
|
8026e50152 | ||
|
|
9ee4f0bb5b | ||
|
|
be4d9f4cd9 | ||
|
|
347182a0cd | ||
|
|
a7429aa9fa | ||
|
|
7a340e0df3 | ||
|
|
f0e5366335 | ||
|
|
49ca8db06b | ||
|
|
ee57a19d84 | ||
|
|
908b56eaf7 | ||
|
|
1461d7bef2 | ||
|
|
8a2d992389 | ||
|
|
8e25d624df | ||
|
|
e88dabb35e | ||
|
|
8eb7ba82ca | ||
|
|
b2eeee0ce0 | ||
|
|
875cfb8cbc | ||
|
|
b8773e63f0 | ||
|
|
05664a2f7b | ||
|
|
2ee6389bef | ||
|
|
62cdaaf0e2 | ||
|
|
419508eabb | ||
|
|
54153fb71b | ||
|
|
1dd6d9ca9d | ||
|
|
356ac009d3 | ||
|
|
9a292a620c | ||
|
|
7e55872286 | ||
|
|
2fc14b9925 | ||
|
|
58f68fe703 | ||
|
|
abafce59a1 | ||
|
|
2e7781a93c | ||
|
|
bc36bc36a1 | ||
|
|
d75201a873 | ||
|
|
691d5823d6 | ||
|
|
c311988d19 | ||
|
|
26e8e04454 | ||
|
|
198e3a04c9 | ||
|
|
61bfacb233 | ||
|
|
85a0021fb3 | ||
|
|
7a45a1590b | ||
|
|
1c36c1f320 | ||
|
|
e0493e90fc | ||
|
|
1931a55ee8 | ||
|
|
63b1ad0f05 | ||
|
|
0bb1bc1b10 | ||
|
|
45842107b9 | ||
|
|
6251555f1c | ||
|
|
330690a214 | ||
|
|
91d4b32bb6 | ||
|
|
a181cd0c60 | ||
|
|
ea81966e64 | ||
|
|
2acf2ce5cb | ||
|
|
f7f18f905c | ||
|
|
4f8b70b593 | ||
|
|
e43e9f3c2c | ||
|
|
71dd5d4a00 | ||
|
|
52a2f994c9 | ||
|
|
8b7491c8d1 | ||
|
|
251ae04e6a | ||
|
|
5bc4a65eea | ||
|
|
1151c4079a | ||
|
|
88acdbc269 | ||
|
|
9b5fa9ee7c | ||
|
|
aca5774e68 | ||
|
|
3fb4e21b38 | ||
|
|
4dfbf8696b | ||
|
|
8fc54b1230 | ||
|
|
da33e35b05 | ||
|
|
5ad28e7ffd | ||
|
|
f79ec47d71 | ||
|
|
45b0596290 | ||
|
|
96c23f3be8 | ||
|
|
6e7dfe4959 | ||
|
|
c34f505b04 | ||
|
|
14183d1f80 | ||
|
|
58adec4677 | ||
|
|
9e598870dd | ||
|
|
8f18aca871 | ||
|
|
3ad56b4236 | ||
|
|
5d62709bc7 | ||
|
|
7581d2467a | ||
|
|
5fa206fb54 | ||
|
|
df2a5633da | ||
|
|
7a6742b5f9 | ||
|
|
e040bb0a41 | ||
|
|
f8fabc9930 | ||
|
|
d967c68e4c | ||
|
|
3dd39c5f9a | ||
|
|
be44eefd5e | ||
|
|
f775c83110 | ||
|
|
b714b41f81 | ||
|
|
31654882e9 | ||
|
|
86c66b2d3e | ||
|
|
37242e56f2 | ||
|
|
6c7274ecd2 | ||
|
|
5c333d7496 | ||
|
|
641ad5d813 | ||
|
|
0715f7e19b | ||
|
|
a8731fcc1d | ||
|
|
5a64127f94 | ||
|
|
ade6dc5e9e | ||
|
|
418964fa91 | ||
|
|
c196640ff1 | ||
|
|
60c8fc73c6 | ||
|
|
bc8745480e | ||
|
|
ff5e16f2f6 | ||
|
|
be2fc5b212 | ||
|
|
7be9ccff0b | ||
|
|
245d43cacf | ||
|
|
246fb276e0 | ||
|
|
6e6e0d95b3 | ||
|
|
25a3f4f5d6 | ||
|
|
ad3dc496bb | ||
|
|
2831b4686c | ||
|
|
8c0ae192a4 | ||
|
|
e9f4ccd19e | ||
|
|
a38bd1defa | ||
|
|
476febeb3a | ||
|
|
b6a35ad83b | ||
|
|
bfd56b74b9 | ||
|
|
858a65ecc1 | ||
|
|
3b34e38813 | ||
|
|
3448870205 | ||
|
|
b868936cd6 | ||
|
|
c681cb5d93 | ||
|
|
379e44ed3c | ||
|
|
243c57cfe8 | ||
|
|
28f436bad0 | ||
|
|
2b8a2973bd | ||
|
|
b7b04c782e | ||
|
|
6e84b21559 | ||
|
|
575e17a1b9 | ||
|
|
57015a4a3f | ||
|
|
9cc1a3130a | ||
|
|
b51d2ae3ca | ||
|
|
fee5f0c909 | ||
|
|
7bb6434767 | ||
|
|
124bc071ee | ||
|
|
a047eeb6d2 | ||
|
|
77b87f0519 | ||
|
|
678da2f21b | ||
|
|
cc3fa8d39d | ||
|
|
89efdc15dd | ||
|
|
8012d892bd | ||
|
|
9d65e7bd6d | ||
|
|
36576d7c4c | ||
|
|
bb36a55c41 | ||
|
|
3dbb2a9dcb | ||
|
|
9997eee4af | ||
|
|
3e376d183e | ||
|
|
888299e6ca | ||
|
|
c31be5b009 | ||
|
|
e5611e8eda | ||
|
|
8e6cc12c80 | ||
|
|
e980017ac8 | ||
|
|
e9d9efc0f2 | ||
|
|
6ccf351a87 | ||
|
|
28dff70b51 | ||
|
|
1aebc0f79e | ||
|
|
cf87314d4e | ||
|
|
1bd3639f69 | ||
|
|
68f5867cf0 | ||
|
|
605cad0be7 | ||
|
|
0855702f3f | ||
|
|
e8384376c0 | ||
|
|
e7e94f2a5c | ||
|
|
a46a815b05 | ||
|
|
96fccc101f | ||
|
|
dbf5416a20 | ||
|
|
d74a58a186 | ||
|
|
f5510afef0 | ||
|
|
e4f0275711 | ||
|
|
e0f2b4b47d | ||
|
|
eca330cb88 | ||
|
|
d24734daea | ||
|
|
d9e6e9481e | ||
|
|
3619f78d2c | ||
|
|
65c2fde23f | ||
|
|
000c15a4ca | ||
|
|
9275f62cf8 | ||
|
|
6552469433 | ||
|
|
11cc45718c | ||
|
|
fe07e2c69f | ||
|
|
89ce723edd | ||
|
|
45d1f15725 | ||
|
|
a318f59d14 | ||
|
|
7d1eb38af1 | ||
|
|
901130bbcf | ||
|
|
c0bc527bca | ||
|
|
2a9c6dcd22 | ||
|
|
5a1fc62b41 | ||
|
|
b4c055bac2 | ||
|
|
ea05b3020d | ||
|
|
9536bc072d | ||
|
|
8242bf220d | ||
|
|
4bfa401d40 | ||
|
|
0222620725 | ||
|
|
1fe3c4c27e | ||
|
|
f703a88055 | ||
|
|
a353beba83 | ||
|
|
052e135029 | ||
|
|
cb89cfc14b | ||
|
|
060ac76257 | ||
|
|
063c409dfb | ||
|
|
767b02a99b | ||
|
|
f45e6c1126 | ||
|
|
3944e7af92 | ||
|
|
ad34b2951e | ||
|
|
c8fa48fd94 | ||
|
|
2fd226f6a7 | ||
|
|
3ba7740dd8 | ||
|
|
29b208f6f9 | ||
|
|
e4d666d27b | ||
|
|
245524e6a3 | ||
|
|
9c0d7f4951 | ||
|
|
e37d0efbd9 | ||
|
|
c926c9541f | ||
|
|
982ee69a74 | ||
|
|
7ea6541124 | ||
|
|
ae30b84072 | ||
|
|
cc9d1493c6 | ||
|
|
f6755419d1 | ||
|
|
145bd631c5 | ||
|
|
b35496d825 | ||
|
|
352d63fdb5 | ||
|
|
11f9be0912 | ||
|
|
c84aeac6b5 | ||
|
|
50fed816dd | ||
|
|
a1a7907bc0 | ||
|
|
d61fc64618 | ||
|
|
6586bca9b9 | ||
|
|
da503b7a52 | ||
|
|
7c365c2109 | ||
|
|
3f698246b2 | ||
|
|
cca80fe611 | ||
|
|
c634ad2a3c | ||
|
|
8f3343809e | ||
|
|
0ba692acc8 | ||
|
|
d9488f69c1 | ||
|
|
dce8743677 | ||
|
|
5520aa2dc9 | ||
|
|
8d9b902243 | ||
|
|
fe93e2c4cf | ||
|
|
314ee30548 | ||
|
|
34917076ad | ||
|
|
ccc7795ca3 | ||
|
|
da1c94ee45 | ||
|
|
3b297919e0 | ||
|
|
47193e0298 | ||
|
|
49bd8c66d3 | ||
|
|
182b6ae8a6 | ||
|
|
c843e68588 | ||
|
|
198f7ea89e | ||
|
|
c888ffb95a | ||
|
|
9752433221 | ||
|
|
f0ff9979c6 | ||
|
|
501dd1ad55 | ||
|
|
75722b037d | ||
|
|
2d6659b9ea | ||
|
|
c5370857b3 | ||
|
|
00034c146a | ||
|
|
325ebc1703 | ||
|
|
7dde84f3c9 | ||
|
|
6606817a86 | ||
|
|
73d829c144 | ||
|
|
60bdb7bd9e | ||
|
|
4bb6b02f93 | ||
|
|
b5ac45b197 | ||
|
|
38a40c9e16 | ||
|
|
a8bf9b4dc1 | ||
|
|
51f8a31d65 | ||
|
|
be05d5cff1 | ||
|
|
30d569d2ac | ||
|
|
08625e4125 | ||
|
|
3acf6d3856 | ||
|
|
46890374f7 | ||
|
|
60755938b3 | ||
|
|
723d44b92b | ||
|
|
bc97cdae67 | ||
|
|
e010672ab5 | ||
|
|
169dbde946 | ||
|
|
17f0eb66b8 | ||
|
|
981052c9c6 | ||
|
|
b1e60d1806 | ||
|
|
6b6c16ca6c | ||
|
|
f6745c4980 | ||
|
|
109dd3b237 | ||
|
|
c2603313b1 | ||
|
|
1e79316e20 | ||
|
|
45261e063b | ||
|
|
49c258e18d | ||
|
|
d3f62c1967 | ||
|
|
5d3a0e794b | ||
|
|
125728b038 | ||
|
|
15a4fd53d3 | ||
|
|
4513a41a72 | ||
|
|
6033d9808d | ||
|
|
bd4d1ea398 | ||
|
|
8e897ed283 | ||
|
|
412cce82b0 | ||
|
|
d534c4520b | ||
|
|
2b18a8c590 | ||
|
|
dac8b87b0c | ||
|
|
6aecd87106 | ||
|
|
ed807c1837 | ||
|
|
29f63c9672 | ||
|
|
9fc0de5796 | ||
|
|
c60ee3a218 | ||
|
|
8a77e5e6bc | ||
|
|
51d9739f80 | ||
|
|
4c7853de14 | ||
|
|
e6779b9400 | ||
|
|
e36d50c5dd | ||
|
|
ff0f78e1fe | ||
|
|
7e067091e8 | ||
|
|
f89b3e2d7a | ||
|
|
fd7cfb6444 | ||
|
|
4e6767b5f2 | ||
|
|
9fea350f0d | ||
|
|
e858a9d6d3 | ||
|
|
7e87e27c52 | ||
|
|
d0fb4bd16f | ||
|
|
3fd4c2a543 | ||
|
|
cdb19aa4c2 | ||
|
|
4d85fbbdbb | ||
|
|
551f93885e | ||
|
|
8326b00aab | ||
|
|
b0249bcaf0 | ||
|
|
21cd8fae49 | ||
|
|
45db527fa6 | ||
|
|
28419ca2c8 | ||
|
|
8ba8714880 | ||
|
|
187986a857 | ||
|
|
4ba001080f | ||
|
|
1974e99f4b | ||
|
|
0181adefc6 | ||
|
|
fd3c633d26 | ||
|
|
0d47c278d1 | ||
|
|
385a27fad1 | ||
|
|
5c6542ce69 | ||
|
|
639f1cea92 | ||
|
|
b5c5d84f60 | ||
|
|
aa75e51f99 | ||
|
|
884ce9d05d | ||
|
|
3b1fe47d84 | ||
|
|
ed64ce5905 | ||
|
|
76a264ac9e | ||
|
|
324ad82006 | ||
|
|
beb982bead | ||
|
|
e88396f123 | ||
|
|
46358f647d | ||
|
|
bd99f6e648 | ||
|
|
ecb5419149 | ||
|
|
cf59cd4dcd | ||
|
|
56ce9eb832 | ||
|
|
89ee4cf8ae | ||
|
|
87ea7dfc04 | ||
|
|
eb0f9d6838 | ||
|
|
d3d8d8184a | ||
|
|
e85a39717a | ||
|
|
f2cd7060fc | ||
|
|
752cda3880 | ||
|
|
9d83ad93d0 | ||
|
|
cc52de4356 | ||
|
|
14b17a551f | ||
|
|
2ec1759f9d | ||
|
|
e2efe599aa | ||
|
|
5e1dba8ed6 | ||
|
|
bea742222f | ||
|
|
e06ca6ddac | ||
|
|
eb03899192 | ||
|
|
3de7c2ce9a | ||
|
|
bc6b9bcd65 | ||
|
|
6e6390321c | ||
|
|
4040428efc | ||
|
|
cc1dfc9373 | ||
|
|
14eb1ee1cb | ||
|
|
879e7199bb | ||
|
|
d89da64b1d | ||
|
|
5dcd8e1d88 | ||
|
|
10bb7e51e8 | ||
|
|
b0089e8992 | ||
|
|
a3ed14cbaf | ||
|
|
9dee4df559 | ||
|
|
adddc50cbf | ||
|
|
46c43ffc9d | ||
|
|
37a3bb66a7 | ||
|
|
337e0c62f8 | ||
|
|
885cc0b75c | ||
|
|
46953e7e6e | ||
|
|
ae8f99e648 | ||
|
|
077c476276 | ||
|
|
835a1478b4 | ||
|
|
120fe5134a | ||
|
|
56a8fb4f77 | ||
|
|
55575225b4 | ||
|
|
483336e79e | ||
|
|
c77495e3a4 | ||
|
|
65af1839c6 | ||
|
|
177877c544 | ||
|
|
b25522ba52 | ||
|
|
c19bc311cb | ||
|
|
5435dcf96e | ||
|
|
f17c702270 | ||
|
|
3907333c5d | ||
|
|
acdecdfaef | ||
|
|
09d18ad07e | ||
|
|
bc516a3f3c | ||
|
|
9572eaaa11 | ||
|
|
18e674b4f6 | ||
|
|
8d68ab98a7 | ||
|
|
135e6b93f4 | ||
|
|
13a49340ed | ||
|
|
81a23040eb | ||
|
|
857f63136d | ||
|
|
a927acb1ec | ||
|
|
09f1580e2d | ||
|
|
cd59e22191 | ||
|
|
7237fdc6ce | ||
|
|
0fdf490d33 | ||
|
|
b73612a254 | ||
|
|
5014558ab9 | ||
|
|
28b0eb0f65 | ||
|
|
95131b2176 | ||
|
|
2305e2e5c9 | ||
|
|
00ae27690d | ||
|
|
9d5d4d64f8 | ||
|
|
98784ef8d6 | ||
|
|
d3fc8074a4 | ||
|
|
9c2b75b561 | ||
|
|
856bb8f99d | ||
|
|
af32f40bf5 | ||
|
|
4ec82a72bb | ||
|
|
07cce701de | ||
|
|
74e001af1d | ||
|
|
ff2751ac9c | ||
|
|
abcdd12b26 | ||
|
|
18db754858 | ||
|
|
fe03a6cdc8 | ||
|
|
cd684175ad | ||
|
|
da692b7920 | ||
|
|
95c01b6c16 | ||
|
|
6911e11edd | ||
|
|
5112f26a60 | ||
|
|
a06916d98e | ||
|
|
681de68e9d | ||
|
|
7aee40c13c | ||
|
|
9297939ec3 | ||
|
|
774d79cc4c | ||
|
|
2412044c90 | ||
|
|
120916dac2 | ||
|
|
fe346461ff | ||
|
|
d2a1fad968 | ||
|
|
0fb983f62d | ||
|
|
53c18592d3 | ||
|
|
e632bce2e4 | ||
|
|
0760b0a7e2 | ||
|
|
d908aa636a | ||
|
|
3d89341b47 | ||
|
|
d8ec40b39f | ||
|
|
4171221823 | ||
|
|
eaeca38fc4 | ||
|
|
fac988053f | ||
|
|
61241abbb0 | ||
|
|
53ed7066ab | ||
|
|
a61f4b287b | ||
|
|
486fb17975 | ||
|
|
2f567473c6 | ||
|
|
000ee7ef34 | ||
|
|
41d1cca328 | ||
|
|
717297545b | ||
|
|
e8e738406a | ||
|
|
e625be0d10 | ||
|
|
12e73423f1 | ||
|
|
7700b37f39 | ||
|
|
c28cfda81f | ||
|
|
848887eb7a | ||
|
|
3158150cb7 | ||
|
|
6ef6bcbd6b | ||
|
|
06425e9621 | ||
|
|
4d224a3022 | ||
|
|
f59ae58163 | ||
|
|
0d1bb027aa | ||
|
|
4cd0a709aa | ||
|
|
1815d1028b | ||
|
|
0fa9a1e236 | ||
|
|
eb55bad5a0 | ||
|
|
cc0ec3e161 | ||
|
|
80185155a1 | ||
|
|
c755f1901f | ||
|
|
68b91dc905 | ||
|
|
88f06afc0c | ||
|
|
40078a55e2 | ||
|
|
d2558234cf | ||
|
|
f5fa042c82 | ||
|
|
07e4a40a9a | ||
|
|
e28f1c0ae8 | ||
|
|
ef39f8600a | ||
|
|
2291dbce2a | ||
|
|
58f197b76c | ||
|
|
895b0931e5 | ||
|
|
1ad047d0f7 | ||
|
|
be6202f12b | ||
|
|
e8f834cd8d | ||
|
|
e0e624ca7f | ||
|
|
ec4f374c05 | ||
|
|
c811e8d8bd | ||
|
|
b2cd5da460 | ||
|
|
2de3b21e05 | ||
|
|
4bed436371 | ||
|
|
efe9dba595 | ||
|
|
47f4203dd3 | ||
|
|
015c10aeec | ||
|
|
a00d781b73 | ||
|
|
0c541b563f | ||
|
|
64a5cf7929 | ||
|
|
7a450a3b1c | ||
|
|
7de27caf16 | ||
|
|
c26326c1be | ||
|
|
66a1b8643a | ||
|
|
15828bcf25 | ||
|
|
333217f43e | ||
|
|
4a2f19abbd | ||
|
|
5fbcebed8c | ||
|
|
becdc7f82c | ||
|
|
73b9088a1c | ||
|
|
f6a1d69a87 | ||
|
|
fd76a14259 | ||
|
|
171e59edd4 | ||
|
|
a0c3b2d5cf | ||
|
|
19bb39202d | ||
|
|
d4553567d2 | ||
|
|
4d49884c58 | ||
|
|
5873d4ccdd | ||
|
|
db9a564b6a | ||
|
|
c72967d5de | ||
|
|
598d185db1 | ||
|
|
b982cbdd0e | ||
|
|
6a04a74e8b | ||
|
|
88728713c8 | ||
|
|
6b1d8c1e30 | ||
|
|
87c3d06271 | ||
|
|
915f911e36 | ||
|
|
cf9d6cfb0c | ||
|
|
bbed5763f1 | ||
|
|
ca0b91b39e | ||
|
|
0cf0571560 | ||
|
|
e58c22a0f6 | ||
|
|
e4bdd3377d | ||
|
|
0b2e9d2c30 | ||
|
|
1bdae7d312 | ||
|
|
a471f21da6 | ||
|
|
6efb071135 | ||
|
|
f4536226c1 | ||
|
|
a439a3a45c | ||
|
|
26e2805c3f | ||
|
|
3b4775e021 | ||
|
|
ab406a1c0e | ||
|
|
a3faeb7de4 | ||
|
|
8c54a3051d | ||
|
|
c32b0aab8a | ||
|
|
3097d9e512 | ||
|
|
c1df120eda | ||
|
|
2cff495997 | ||
|
|
d0491a1ebe | ||
|
|
b9d68c199b | ||
|
|
155510fe81 | ||
|
|
201c145953 | ||
|
|
5d34200268 | ||
|
|
b7da73eb19 | ||
|
|
6a39ee13f7 | ||
|
|
33245766ab | ||
|
|
358de58c4d | ||
|
|
a7191c6f57 | ||
|
|
baa5873942 | ||
|
|
c6ce815461 | ||
|
|
79360d99d3 | ||
|
|
46fff7105e | ||
|
|
72e1fe969f | ||
|
|
b5be6dd504 | ||
|
|
8ea3f7b909 | ||
|
|
921b76cab8 | ||
|
|
a31953b0e6 | ||
|
|
54670cf084 |
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -1 +1,4 @@
|
|||||||
|
* text=auto
|
||||||
|
|
||||||
Makefile* text whitespace=-tab-in-indent
|
Makefile* text whitespace=-tab-in-indent
|
||||||
|
*.sh text eol=lf
|
||||||
|
|||||||
13
.github/FUNDING.yml
vendored
Normal file
13
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
|
||||||
|
custom: ['https://github.com/yt-dlp/yt-dlp/blob/master/Collaborators.md#collaborators']
|
||||||
70
.github/ISSUE_TEMPLATE/1_broken_site.md
vendored
70
.github/ISSUE_TEMPLATE/1_broken_site.md
vendored
@@ -1,70 +0,0 @@
|
|||||||
---
|
|
||||||
name: Broken site support
|
|
||||||
about: Report broken or misfunctioning site
|
|
||||||
title: "[Broken]"
|
|
||||||
labels: Broken
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
WARNING!
|
|
||||||
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
|
||||||
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.04.03. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
|
|
||||||
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
|
||||||
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/yt-dlp/yt-dlp.
|
|
||||||
- Search the bugtracker for similar issues: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
|
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
|
||||||
-->
|
|
||||||
|
|
||||||
- [ ] I'm reporting a broken site support
|
|
||||||
- [ ] I've verified that I'm running yt-dlp version **2021.04.03**
|
|
||||||
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
|
||||||
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
|
||||||
- [ ] I've searched the bugtracker for similar issues including closed ones
|
|
||||||
|
|
||||||
|
|
||||||
## Verbose log
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide the complete verbose output of yt-dlp that clearly demonstrates the problem.
|
|
||||||
Add the `-v` flag to your command line you run yt-dlp with (`yt-dlp -v <your command line>`), copy the WHOLE output and insert it below. It should look similar to this:
|
|
||||||
[debug] System config: []
|
|
||||||
[debug] User config: []
|
|
||||||
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
|
||||||
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
|
||||||
[debug] yt-dlp version 2021.04.03
|
|
||||||
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
|
||||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
|
||||||
[debug] Proxy map: {}
|
|
||||||
<more lines>
|
|
||||||
-->
|
|
||||||
|
|
||||||
```
|
|
||||||
PASTE VERBOSE LOG HERE
|
|
||||||
|
|
||||||
```
|
|
||||||
<!--
|
|
||||||
Do not remove the above ```
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide an explanation of your issue in an arbitrary form. Provide any additional information, suggested solution and as much context and examples as possible.
|
|
||||||
If work on your issue requires account credentials please provide them or explain how one can obtain them.
|
|
||||||
-->
|
|
||||||
|
|
||||||
WRITE DESCRIPTION HERE
|
|
||||||
63
.github/ISSUE_TEMPLATE/1_broken_site.yml
vendored
Normal file
63
.github/ISSUE_TEMPLATE/1_broken_site.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
name: Broken site
|
||||||
|
description: Report broken or misfunctioning site
|
||||||
|
labels: [triage, site-bug]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: |
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
||||||
|
options:
|
||||||
|
- label: I'm reporting a broken site
|
||||||
|
required: true
|
||||||
|
- label: I've verified that I'm running yt-dlp version **2022.02.03**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
||||||
|
required: true
|
||||||
|
- label: I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
required: true
|
||||||
|
- label: I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/ytdl-org/youtube-dl#video-url-contains-an-ampersand-and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
|
||||||
|
required: true
|
||||||
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
||||||
|
required: true
|
||||||
|
- label: I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
|
||||||
|
required: true
|
||||||
|
- label: I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required
|
||||||
|
- type: input
|
||||||
|
id: region
|
||||||
|
attributes:
|
||||||
|
label: Region
|
||||||
|
description: "Enter the region the site is accessible from"
|
||||||
|
placeholder: "India"
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Provide an explanation of your issue in an arbitrary form.
|
||||||
|
Provide any additional information, any suggested solutions, and as much context and examples as possible
|
||||||
|
placeholder: WRITE DESCRIPTION HERE
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: log
|
||||||
|
attributes:
|
||||||
|
label: Verbose log
|
||||||
|
description: |
|
||||||
|
Provide the complete verbose output of yt-dlp **that clearly demonstrates the problem**.
|
||||||
|
Add the `-vU` flag to your command line you run yt-dlp with (`yt-dlp -vU <your command line>`), copy the WHOLE output and insert it below.
|
||||||
|
It should look similar to this:
|
||||||
|
placeholder: |
|
||||||
|
[debug] Command-line config: ['-vU', 'http://www.youtube.com/watch?v=BaW_jenozKc']
|
||||||
|
[debug] Portable config file: yt-dlp.conf
|
||||||
|
[debug] Portable config: ['-i']
|
||||||
|
[debug] Encodings: locale cp1252, fs utf-8, stdout utf-8, stderr utf-8, pref cp1252
|
||||||
|
[debug] yt-dlp version 2022.02.03 (exe)
|
||||||
|
[debug] Python version 3.8.8 (CPython 64bit) - Windows-10-10.0.19041-SP0
|
||||||
|
[debug] exe versions: ffmpeg 3.0.1, ffprobe 3.0.1
|
||||||
|
[debug] Optional libraries: Cryptodome, keyring, mutagen, sqlite, websockets
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
yt-dlp is up to date (2022.02.03)
|
||||||
|
<more lines>
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
56
.github/ISSUE_TEMPLATE/2_site_support_request.md
vendored
56
.github/ISSUE_TEMPLATE/2_site_support_request.md
vendored
@@ -1,56 +0,0 @@
|
|||||||
---
|
|
||||||
name: Site support request
|
|
||||||
about: Request support for a new site
|
|
||||||
title: "[Site Request]"
|
|
||||||
labels: Request
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
WARNING!
|
|
||||||
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
|
||||||
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.04.03. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
|
|
||||||
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
|
||||||
- Make sure that site you are requesting is not dedicated to copyright infringement, see https://github.com/yt-dlp/yt-dlp. yt-dlp does not support such sites. In order for site support request to be accepted all provided example URLs should not violate any copyrights.
|
|
||||||
- Search the bugtracker for similar site support requests: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
|
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
|
||||||
-->
|
|
||||||
|
|
||||||
- [ ] I'm reporting a new site support request
|
|
||||||
- [ ] I've verified that I'm running yt-dlp version **2021.04.03**
|
|
||||||
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
|
||||||
- [ ] I've checked that none of provided URLs violate any copyrights
|
|
||||||
- [ ] I've searched the bugtracker for similar site support requests including closed ones
|
|
||||||
|
|
||||||
|
|
||||||
## Example URLs
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide all kinds of example URLs support for which should be included. Replace following example URLs by yours.
|
|
||||||
-->
|
|
||||||
|
|
||||||
- Single video: https://www.youtube.com/watch?v=BaW_jenozKc
|
|
||||||
- Single video: https://youtu.be/BaW_jenozKc
|
|
||||||
- Playlist: https://www.youtube.com/playlist?list=PL4lCao7KL_QFVb7Iudeipvc2BCavECqzc
|
|
||||||
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide any additional information.
|
|
||||||
If work on your issue requires account credentials please provide them or explain how one can obtain them.
|
|
||||||
-->
|
|
||||||
|
|
||||||
WRITE DESCRIPTION HERE
|
|
||||||
74
.github/ISSUE_TEMPLATE/2_site_support_request.yml
vendored
Normal file
74
.github/ISSUE_TEMPLATE/2_site_support_request.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
name: Site support request
|
||||||
|
description: Request support for a new site
|
||||||
|
labels: [triage, site-request]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: |
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
||||||
|
options:
|
||||||
|
- label: I'm reporting a new site support request
|
||||||
|
required: true
|
||||||
|
- label: I've verified that I'm running yt-dlp version **2022.02.03**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
||||||
|
required: true
|
||||||
|
- label: I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
required: true
|
||||||
|
- label: I've checked that none of provided URLs [violate any copyrights](https://github.com/ytdl-org/youtube-dl#can-you-add-support-for-this-anime-video-site-or-site-which-shows-current-movies-for-free) or contain any [DRM](https://en.wikipedia.org/wiki/Digital_rights_management) to the best of my knowledge
|
||||||
|
required: true
|
||||||
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
||||||
|
required: true
|
||||||
|
- label: I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
|
||||||
|
required: true
|
||||||
|
- label: I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and am willing to share it if required
|
||||||
|
- type: input
|
||||||
|
id: region
|
||||||
|
attributes:
|
||||||
|
label: Region
|
||||||
|
description: "Enter the region the site is accessible from"
|
||||||
|
placeholder: "India"
|
||||||
|
- type: textarea
|
||||||
|
id: example-urls
|
||||||
|
attributes:
|
||||||
|
label: Example URLs
|
||||||
|
description: |
|
||||||
|
Provide all kinds of example URLs for which support should be added
|
||||||
|
placeholder: |
|
||||||
|
- Single video: https://www.youtube.com/watch?v=BaW_jenozKc
|
||||||
|
- Single video: https://youtu.be/BaW_jenozKc
|
||||||
|
- Playlist: https://www.youtube.com/playlist?list=PL4lCao7KL_QFVb7Iudeipvc2BCavECqzc
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Provide any additional information
|
||||||
|
placeholder: WRITE DESCRIPTION HERE
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: log
|
||||||
|
attributes:
|
||||||
|
label: Verbose log
|
||||||
|
description: |
|
||||||
|
Provide the complete verbose output **using one of the example URLs provided above**.
|
||||||
|
Add the `-vU` flag to your command line you run yt-dlp with (`yt-dlp -vU <your command line>`), copy the WHOLE output and insert it below.
|
||||||
|
It should look similar to this:
|
||||||
|
placeholder: |
|
||||||
|
[debug] Command-line config: ['-vU', 'http://www.youtube.com/watch?v=BaW_jenozKc']
|
||||||
|
[debug] Portable config file: yt-dlp.conf
|
||||||
|
[debug] Portable config: ['-i']
|
||||||
|
[debug] Encodings: locale cp1252, fs utf-8, stdout utf-8, stderr utf-8, pref cp1252
|
||||||
|
[debug] yt-dlp version 2022.02.03 (exe)
|
||||||
|
[debug] Python version 3.8.8 (CPython 64bit) - Windows-10-10.0.19041-SP0
|
||||||
|
[debug] exe versions: ffmpeg 3.0.1, ffprobe 3.0.1
|
||||||
|
[debug] Optional libraries: Cryptodome, keyring, mutagen, sqlite, websockets
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
yt-dlp is up to date (2022.02.03)
|
||||||
|
<more lines>
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
40
.github/ISSUE_TEMPLATE/3_site_feature_request.md
vendored
40
.github/ISSUE_TEMPLATE/3_site_feature_request.md
vendored
@@ -1,40 +0,0 @@
|
|||||||
---
|
|
||||||
name: Site feature request
|
|
||||||
about: Request a new functionality for a site
|
|
||||||
title: "[Site Request]"
|
|
||||||
labels: Request
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
WARNING!
|
|
||||||
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
|
||||||
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.04.03. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
|
|
||||||
- Search the bugtracker for similar site feature requests: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
|
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
|
||||||
-->
|
|
||||||
|
|
||||||
- [ ] I'm reporting a site feature request
|
|
||||||
- [ ] I've verified that I'm running yt-dlp version **2021.04.03**
|
|
||||||
- [ ] I've searched the bugtracker for similar site feature requests including closed ones
|
|
||||||
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide an explanation of your site feature request in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
|
|
||||||
-->
|
|
||||||
|
|
||||||
WRITE DESCRIPTION HERE
|
|
||||||
72
.github/ISSUE_TEMPLATE/3_site_feature_request.yml
vendored
Normal file
72
.github/ISSUE_TEMPLATE/3_site_feature_request.yml
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
name: Site feature request
|
||||||
|
description: Request a new functionality for a supported site
|
||||||
|
labels: [triage, site-enhancement]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: |
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
||||||
|
options:
|
||||||
|
- label: I'm reporting a site feature request
|
||||||
|
required: true
|
||||||
|
- label: I've verified that I'm running yt-dlp version **2022.02.03**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
||||||
|
required: true
|
||||||
|
- label: I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
required: true
|
||||||
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
||||||
|
required: true
|
||||||
|
- label: I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
|
||||||
|
required: true
|
||||||
|
- label: I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required
|
||||||
|
- type: input
|
||||||
|
id: region
|
||||||
|
attributes:
|
||||||
|
label: Region
|
||||||
|
description: "Enter the region the site is accessible from"
|
||||||
|
placeholder: "India"
|
||||||
|
- type: textarea
|
||||||
|
id: example-urls
|
||||||
|
attributes:
|
||||||
|
label: Example URLs
|
||||||
|
description: |
|
||||||
|
Example URLs that can be used to demonstrate the requested feature
|
||||||
|
placeholder: |
|
||||||
|
https://www.youtube.com/watch?v=BaW_jenozKc
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Provide an explanation of your site feature request in an arbitrary form.
|
||||||
|
Please make sure the description is worded well enough to be understood, see [is-the-description-of-the-issue-itself-sufficient](https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient).
|
||||||
|
Provide any additional information, any suggested solutions, and as much context and examples as possible
|
||||||
|
placeholder: WRITE DESCRIPTION HERE
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: log
|
||||||
|
attributes:
|
||||||
|
label: Verbose log
|
||||||
|
description: |
|
||||||
|
Provide the complete verbose output of yt-dlp that demonstrates the need for the enhancement.
|
||||||
|
Add the `-vU` flag to your command line you run yt-dlp with (`yt-dlp -vU <your command line>`), copy the WHOLE output and insert it below.
|
||||||
|
It should look similar to this:
|
||||||
|
placeholder: |
|
||||||
|
[debug] Command-line config: ['-vU', 'http://www.youtube.com/watch?v=BaW_jenozKc']
|
||||||
|
[debug] Portable config file: yt-dlp.conf
|
||||||
|
[debug] Portable config: ['-i']
|
||||||
|
[debug] Encodings: locale cp1252, fs utf-8, stdout utf-8, stderr utf-8, pref cp1252
|
||||||
|
[debug] yt-dlp version 2022.02.03 (exe)
|
||||||
|
[debug] Python version 3.8.8 (CPython 64bit) - Windows-10-10.0.19041-SP0
|
||||||
|
[debug] exe versions: ffmpeg 3.0.1, ffprobe 3.0.1
|
||||||
|
[debug] Optional libraries: Cryptodome, keyring, mutagen, sqlite, websockets
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
yt-dlp is up to date (2022.02.03)
|
||||||
|
<more lines>
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
72
.github/ISSUE_TEMPLATE/4_bug_report.md
vendored
72
.github/ISSUE_TEMPLATE/4_bug_report.md
vendored
@@ -1,72 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Report a bug unrelated to any particular site or extractor
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
WARNING!
|
|
||||||
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
|
||||||
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.04.03. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
|
|
||||||
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
|
||||||
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/yt-dlp/yt-dlp.
|
|
||||||
- Search the bugtracker for similar issues: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
|
|
||||||
- Read bugs section in FAQ: https://github.com/yt-dlp/yt-dlp
|
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
|
||||||
-->
|
|
||||||
|
|
||||||
- [ ] I'm reporting a broken site support issue
|
|
||||||
- [ ] I've verified that I'm running yt-dlp version **2021.04.03**
|
|
||||||
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
|
||||||
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
|
||||||
- [ ] I've searched the bugtracker for similar bug reports including closed ones
|
|
||||||
- [ ] I've read bugs section in FAQ
|
|
||||||
|
|
||||||
|
|
||||||
## Verbose log
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide the complete verbose output of yt-dlp that clearly demonstrates the problem.
|
|
||||||
Add the `-v` flag to your command line you run yt-dlp with (`yt-dlp -v <your command line>`), copy the WHOLE output and insert it below. It should look similar to this:
|
|
||||||
[debug] System config: []
|
|
||||||
[debug] User config: []
|
|
||||||
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
|
||||||
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
|
||||||
[debug] yt-dlp version 2021.04.03
|
|
||||||
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
|
||||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
|
||||||
[debug] Proxy map: {}
|
|
||||||
<more lines>
|
|
||||||
-->
|
|
||||||
|
|
||||||
```
|
|
||||||
PASTE VERBOSE LOG HERE
|
|
||||||
|
|
||||||
```
|
|
||||||
<!--
|
|
||||||
Do not remove the above ```
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide an explanation of your issue in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
|
|
||||||
If work on your issue requires account credentials please provide them or explain how one can obtain them.
|
|
||||||
-->
|
|
||||||
|
|
||||||
WRITE DESCRIPTION HERE
|
|
||||||
57
.github/ISSUE_TEMPLATE/4_bug_report.yml
vendored
Normal file
57
.github/ISSUE_TEMPLATE/4_bug_report.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
name: Bug report
|
||||||
|
description: Report a bug unrelated to any particular site or extractor
|
||||||
|
labels: [triage, bug]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: |
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
||||||
|
options:
|
||||||
|
- label: I'm reporting a bug unrelated to a specific site
|
||||||
|
required: true
|
||||||
|
- label: I've verified that I'm running yt-dlp version **2022.02.03**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
||||||
|
required: true
|
||||||
|
- label: I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
required: true
|
||||||
|
- label: I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/ytdl-org/youtube-dl#video-url-contains-an-ampersand-and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
|
||||||
|
required: true
|
||||||
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
||||||
|
required: true
|
||||||
|
- label: I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Provide an explanation of your issue in an arbitrary form.
|
||||||
|
Please make sure the description is worded well enough to be understood, see [is-the-description-of-the-issue-itself-sufficient](https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient).
|
||||||
|
Provide any additional information, any suggested solutions, and as much context and examples as possible
|
||||||
|
placeholder: WRITE DESCRIPTION HERE
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: log
|
||||||
|
attributes:
|
||||||
|
label: Verbose log
|
||||||
|
description: |
|
||||||
|
Provide the complete verbose output of yt-dlp **that clearly demonstrates the problem**.
|
||||||
|
Add the `-vU` flag to **your** command line you run yt-dlp with (`yt-dlp -vU <your command line>`), copy the WHOLE output and insert it below.
|
||||||
|
It should look similar to this:
|
||||||
|
placeholder: |
|
||||||
|
[debug] Command-line config: ['-vU', 'http://www.youtube.com/watch?v=BaW_jenozKc']
|
||||||
|
[debug] Portable config file: yt-dlp.conf
|
||||||
|
[debug] Portable config: ['-i']
|
||||||
|
[debug] Encodings: locale cp1252, fs utf-8, stdout utf-8, stderr utf-8, pref cp1252
|
||||||
|
[debug] yt-dlp version 2022.02.03 (exe)
|
||||||
|
[debug] Python version 3.8.8 (CPython 64bit) - Windows-10-10.0.19041-SP0
|
||||||
|
[debug] exe versions: ffmpeg 3.0.1, ffprobe 3.0.1
|
||||||
|
[debug] Optional libraries: Cryptodome, keyring, mutagen, sqlite, websockets
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
yt-dlp is up to date (2022.02.03)
|
||||||
|
<more lines>
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
40
.github/ISSUE_TEMPLATE/5_feature_request.md
vendored
40
.github/ISSUE_TEMPLATE/5_feature_request.md
vendored
@@ -1,40 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Request a new functionality unrelated to any particular site or extractor
|
|
||||||
title: "[Feature Request]"
|
|
||||||
labels: Request
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
WARNING!
|
|
||||||
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
|
||||||
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.04.03. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
|
|
||||||
- Search the bugtracker for similar feature requests: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
|
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
|
||||||
-->
|
|
||||||
|
|
||||||
- [ ] I'm reporting a feature request
|
|
||||||
- [ ] I've verified that I'm running yt-dlp version **2021.04.03**
|
|
||||||
- [ ] I've searched the bugtracker for similar feature requests including closed ones
|
|
||||||
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide an explanation of your issue in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
|
|
||||||
-->
|
|
||||||
|
|
||||||
WRITE DESCRIPTION HERE
|
|
||||||
32
.github/ISSUE_TEMPLATE/5_feature_request.yml
vendored
Normal file
32
.github/ISSUE_TEMPLATE/5_feature_request.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Feature request
|
||||||
|
description: Request a new functionality unrelated to any particular site or extractor
|
||||||
|
labels: [triage, enhancement]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: |
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
||||||
|
options:
|
||||||
|
- label: I'm reporting a feature request
|
||||||
|
required: true
|
||||||
|
- label: I've looked through the [README](https://github.com/yt-dlp/yt-dlp#readme)
|
||||||
|
required: true
|
||||||
|
- label: I've verified that I'm running yt-dlp version **2022.02.03**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
||||||
|
required: true
|
||||||
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
||||||
|
required: true
|
||||||
|
- label: I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Provide an explanation of your site feature request in an arbitrary form.
|
||||||
|
Please make sure the description is worded well enough to be understood, see [is-the-description-of-the-issue-itself-sufficient](https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient).
|
||||||
|
Provide any additional information, any suggested solutions, and as much context and examples as possible
|
||||||
|
placeholder: WRITE DESCRIPTION HERE
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
40
.github/ISSUE_TEMPLATE/6_question.md
vendored
40
.github/ISSUE_TEMPLATE/6_question.md
vendored
@@ -1,40 +0,0 @@
|
|||||||
---
|
|
||||||
name: Ask question
|
|
||||||
about: Ask youtube-dl related question
|
|
||||||
title: "[Question]"
|
|
||||||
labels: question
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
WARNING!
|
|
||||||
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
|
||||||
- Look through the README (https://github.com/yt-dlp/yt-dlp) and FAQ (https://github.com/yt-dlp/yt-dlp) for similar questions
|
|
||||||
- Search the bugtracker for similar questions: https://github.com/yt-dlp/yt-dlp
|
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
|
||||||
-->
|
|
||||||
|
|
||||||
- [ ] I'm asking a question
|
|
||||||
- [ ] I've looked through the README and FAQ for similar questions
|
|
||||||
- [ ] I've searched the bugtracker for similar questions including closed ones
|
|
||||||
|
|
||||||
|
|
||||||
## Question
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Ask your question in an arbitrary form. Please make sure it's worded well enough to be understood, see https://github.com/yt-dlp/yt-dlp.
|
|
||||||
-->
|
|
||||||
|
|
||||||
WRITE QUESTION HERE
|
|
||||||
53
.github/ISSUE_TEMPLATE/6_question.yml
vendored
Normal file
53
.github/ISSUE_TEMPLATE/6_question.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
name: Ask question
|
||||||
|
description: Ask yt-dlp related question
|
||||||
|
labels: [question]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: |
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
||||||
|
options:
|
||||||
|
- label: I'm asking a question and **not** reporting a bug/feature request
|
||||||
|
required: true
|
||||||
|
- label: I've looked through the [README](https://github.com/yt-dlp/yt-dlp#readme)
|
||||||
|
required: true
|
||||||
|
- label: I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
|
||||||
|
required: true
|
||||||
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar questions including closed ones
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: question
|
||||||
|
attributes:
|
||||||
|
label: Question
|
||||||
|
description: |
|
||||||
|
Ask your question in an arbitrary form.
|
||||||
|
Please make sure it's worded well enough to be understood, see [is-the-description-of-the-issue-itself-sufficient](https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient).
|
||||||
|
Provide any additional information and as much context and examples as possible.
|
||||||
|
If your question contains "isn't working" or "can you add", this is most likely the wrong template.
|
||||||
|
If you are in doubt if this is the right template, use another template!
|
||||||
|
placeholder: WRITE QUESTION HERE
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: log
|
||||||
|
attributes:
|
||||||
|
label: Verbose log
|
||||||
|
description: |
|
||||||
|
If your question involes a yt-dlp command, provide the complete verbose output of that command.
|
||||||
|
Add the `-vU` flag to **your** command line you run yt-dlp with (`yt-dlp -vU <your command line>`), copy the WHOLE output and insert it below.
|
||||||
|
It should look similar to this:
|
||||||
|
placeholder: |
|
||||||
|
[debug] Command-line config: ['-vU', 'http://www.youtube.com/watch?v=BaW_jenozKc']
|
||||||
|
[debug] Portable config file: yt-dlp.conf
|
||||||
|
[debug] Portable config: ['-i']
|
||||||
|
[debug] Encodings: locale cp1252, fs utf-8, stdout utf-8, stderr utf-8, pref cp1252
|
||||||
|
[debug] yt-dlp version 2021.12.01 (exe)
|
||||||
|
[debug] Python version 3.8.8 (CPython 64bit) - Windows-10-10.0.19041-SP0
|
||||||
|
[debug] exe versions: ffmpeg 3.0.1, ffprobe 3.0.1
|
||||||
|
[debug] Optional libraries: Cryptodome, keyring, mutagen, sqlite, websockets
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
yt-dlp is up to date (2021.12.01)
|
||||||
|
<more lines>
|
||||||
|
render: shell
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Get help from the community on Discord
|
||||||
|
url: https://discord.gg/H5MNcFW63r
|
||||||
|
about: Join the yt-dlp Discord for community-powered support!
|
||||||
|
- name: Matrix Bridge to the Discord server
|
||||||
|
url: https://matrix.to/#/#yt-dlp:matrix.org
|
||||||
|
about: For those who do not want to use Discord
|
||||||
70
.github/ISSUE_TEMPLATE_tmpl/1_broken_site.md
vendored
70
.github/ISSUE_TEMPLATE_tmpl/1_broken_site.md
vendored
@@ -1,70 +0,0 @@
|
|||||||
---
|
|
||||||
name: Broken site support
|
|
||||||
about: Report broken or misfunctioning site
|
|
||||||
title: "[Broken]"
|
|
||||||
labels: Broken
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
WARNING!
|
|
||||||
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
|
||||||
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is %(version)s. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
|
|
||||||
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
|
||||||
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/yt-dlp/yt-dlp.
|
|
||||||
- Search the bugtracker for similar issues: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
|
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
|
||||||
-->
|
|
||||||
|
|
||||||
- [ ] I'm reporting a broken site support
|
|
||||||
- [ ] I've verified that I'm running yt-dlp version **%(version)s**
|
|
||||||
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
|
||||||
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
|
||||||
- [ ] I've searched the bugtracker for similar issues including closed ones
|
|
||||||
|
|
||||||
|
|
||||||
## Verbose log
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide the complete verbose output of yt-dlp that clearly demonstrates the problem.
|
|
||||||
Add the `-v` flag to your command line you run yt-dlp with (`yt-dlp -v <your command line>`), copy the WHOLE output and insert it below. It should look similar to this:
|
|
||||||
[debug] System config: []
|
|
||||||
[debug] User config: []
|
|
||||||
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
|
||||||
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
|
||||||
[debug] yt-dlp version %(version)s
|
|
||||||
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
|
||||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
|
||||||
[debug] Proxy map: {}
|
|
||||||
<more lines>
|
|
||||||
-->
|
|
||||||
|
|
||||||
```
|
|
||||||
PASTE VERBOSE LOG HERE
|
|
||||||
|
|
||||||
```
|
|
||||||
<!--
|
|
||||||
Do not remove the above ```
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide an explanation of your issue in an arbitrary form. Provide any additional information, suggested solution and as much context and examples as possible.
|
|
||||||
If work on your issue requires account credentials please provide them or explain how one can obtain them.
|
|
||||||
-->
|
|
||||||
|
|
||||||
WRITE DESCRIPTION HERE
|
|
||||||
63
.github/ISSUE_TEMPLATE_tmpl/1_broken_site.yml
vendored
Normal file
63
.github/ISSUE_TEMPLATE_tmpl/1_broken_site.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
name: Broken site
|
||||||
|
description: Report broken or misfunctioning site
|
||||||
|
labels: [triage, site-bug]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: |
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
||||||
|
options:
|
||||||
|
- label: I'm reporting a broken site
|
||||||
|
required: true
|
||||||
|
- label: I've verified that I'm running yt-dlp version **%(version)s**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
||||||
|
required: true
|
||||||
|
- label: I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
required: true
|
||||||
|
- label: I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/ytdl-org/youtube-dl#video-url-contains-an-ampersand-and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
|
||||||
|
required: true
|
||||||
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
||||||
|
required: true
|
||||||
|
- label: I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
|
||||||
|
required: true
|
||||||
|
- label: I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required
|
||||||
|
- type: input
|
||||||
|
id: region
|
||||||
|
attributes:
|
||||||
|
label: Region
|
||||||
|
description: "Enter the region the site is accessible from"
|
||||||
|
placeholder: "India"
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Provide an explanation of your issue in an arbitrary form.
|
||||||
|
Provide any additional information, any suggested solutions, and as much context and examples as possible
|
||||||
|
placeholder: WRITE DESCRIPTION HERE
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: log
|
||||||
|
attributes:
|
||||||
|
label: Verbose log
|
||||||
|
description: |
|
||||||
|
Provide the complete verbose output of yt-dlp **that clearly demonstrates the problem**.
|
||||||
|
Add the `-vU` flag to your command line you run yt-dlp with (`yt-dlp -vU <your command line>`), copy the WHOLE output and insert it below.
|
||||||
|
It should look similar to this:
|
||||||
|
placeholder: |
|
||||||
|
[debug] Command-line config: ['-vU', 'http://www.youtube.com/watch?v=BaW_jenozKc']
|
||||||
|
[debug] Portable config file: yt-dlp.conf
|
||||||
|
[debug] Portable config: ['-i']
|
||||||
|
[debug] Encodings: locale cp1252, fs utf-8, stdout utf-8, stderr utf-8, pref cp1252
|
||||||
|
[debug] yt-dlp version %(version)s (exe)
|
||||||
|
[debug] Python version 3.8.8 (CPython 64bit) - Windows-10-10.0.19041-SP0
|
||||||
|
[debug] exe versions: ffmpeg 3.0.1, ffprobe 3.0.1
|
||||||
|
[debug] Optional libraries: Cryptodome, keyring, mutagen, sqlite, websockets
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
yt-dlp is up to date (%(version)s)
|
||||||
|
<more lines>
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
---
|
|
||||||
name: Site support request
|
|
||||||
about: Request support for a new site
|
|
||||||
title: "[Site Request]"
|
|
||||||
labels: Request
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
WARNING!
|
|
||||||
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
|
||||||
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is %(version)s. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
|
|
||||||
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
|
||||||
- Make sure that site you are requesting is not dedicated to copyright infringement, see https://github.com/yt-dlp/yt-dlp. yt-dlp does not support such sites. In order for site support request to be accepted all provided example URLs should not violate any copyrights.
|
|
||||||
- Search the bugtracker for similar site support requests: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
|
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
|
||||||
-->
|
|
||||||
|
|
||||||
- [ ] I'm reporting a new site support request
|
|
||||||
- [ ] I've verified that I'm running yt-dlp version **%(version)s**
|
|
||||||
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
|
||||||
- [ ] I've checked that none of provided URLs violate any copyrights
|
|
||||||
- [ ] I've searched the bugtracker for similar site support requests including closed ones
|
|
||||||
|
|
||||||
|
|
||||||
## Example URLs
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide all kinds of example URLs support for which should be included. Replace following example URLs by yours.
|
|
||||||
-->
|
|
||||||
|
|
||||||
- Single video: https://www.youtube.com/watch?v=BaW_jenozKc
|
|
||||||
- Single video: https://youtu.be/BaW_jenozKc
|
|
||||||
- Playlist: https://www.youtube.com/playlist?list=PL4lCao7KL_QFVb7Iudeipvc2BCavECqzc
|
|
||||||
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide any additional information.
|
|
||||||
If work on your issue requires account credentials please provide them or explain how one can obtain them.
|
|
||||||
-->
|
|
||||||
|
|
||||||
WRITE DESCRIPTION HERE
|
|
||||||
74
.github/ISSUE_TEMPLATE_tmpl/2_site_support_request.yml
vendored
Normal file
74
.github/ISSUE_TEMPLATE_tmpl/2_site_support_request.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
name: Site support request
|
||||||
|
description: Request support for a new site
|
||||||
|
labels: [triage, site-request]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: |
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
||||||
|
options:
|
||||||
|
- label: I'm reporting a new site support request
|
||||||
|
required: true
|
||||||
|
- label: I've verified that I'm running yt-dlp version **%(version)s**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
||||||
|
required: true
|
||||||
|
- label: I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
required: true
|
||||||
|
- label: I've checked that none of provided URLs [violate any copyrights](https://github.com/ytdl-org/youtube-dl#can-you-add-support-for-this-anime-video-site-or-site-which-shows-current-movies-for-free) or contain any [DRM](https://en.wikipedia.org/wiki/Digital_rights_management) to the best of my knowledge
|
||||||
|
required: true
|
||||||
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
||||||
|
required: true
|
||||||
|
- label: I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
|
||||||
|
required: true
|
||||||
|
- label: I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and am willing to share it if required
|
||||||
|
- type: input
|
||||||
|
id: region
|
||||||
|
attributes:
|
||||||
|
label: Region
|
||||||
|
description: "Enter the region the site is accessible from"
|
||||||
|
placeholder: "India"
|
||||||
|
- type: textarea
|
||||||
|
id: example-urls
|
||||||
|
attributes:
|
||||||
|
label: Example URLs
|
||||||
|
description: |
|
||||||
|
Provide all kinds of example URLs for which support should be added
|
||||||
|
placeholder: |
|
||||||
|
- Single video: https://www.youtube.com/watch?v=BaW_jenozKc
|
||||||
|
- Single video: https://youtu.be/BaW_jenozKc
|
||||||
|
- Playlist: https://www.youtube.com/playlist?list=PL4lCao7KL_QFVb7Iudeipvc2BCavECqzc
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Provide any additional information
|
||||||
|
placeholder: WRITE DESCRIPTION HERE
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: log
|
||||||
|
attributes:
|
||||||
|
label: Verbose log
|
||||||
|
description: |
|
||||||
|
Provide the complete verbose output **using one of the example URLs provided above**.
|
||||||
|
Add the `-vU` flag to your command line you run yt-dlp with (`yt-dlp -vU <your command line>`), copy the WHOLE output and insert it below.
|
||||||
|
It should look similar to this:
|
||||||
|
placeholder: |
|
||||||
|
[debug] Command-line config: ['-vU', 'http://www.youtube.com/watch?v=BaW_jenozKc']
|
||||||
|
[debug] Portable config file: yt-dlp.conf
|
||||||
|
[debug] Portable config: ['-i']
|
||||||
|
[debug] Encodings: locale cp1252, fs utf-8, stdout utf-8, stderr utf-8, pref cp1252
|
||||||
|
[debug] yt-dlp version %(version)s (exe)
|
||||||
|
[debug] Python version 3.8.8 (CPython 64bit) - Windows-10-10.0.19041-SP0
|
||||||
|
[debug] exe versions: ffmpeg 3.0.1, ffprobe 3.0.1
|
||||||
|
[debug] Optional libraries: Cryptodome, keyring, mutagen, sqlite, websockets
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
yt-dlp is up to date (%(version)s)
|
||||||
|
<more lines>
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
---
|
|
||||||
name: Site feature request
|
|
||||||
about: Request a new functionality for a site
|
|
||||||
title: "[Site Request]"
|
|
||||||
labels: Request
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
WARNING!
|
|
||||||
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
|
||||||
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is %(version)s. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
|
|
||||||
- Search the bugtracker for similar site feature requests: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
|
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
|
||||||
-->
|
|
||||||
|
|
||||||
- [ ] I'm reporting a site feature request
|
|
||||||
- [ ] I've verified that I'm running yt-dlp version **%(version)s**
|
|
||||||
- [ ] I've searched the bugtracker for similar site feature requests including closed ones
|
|
||||||
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide an explanation of your site feature request in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
|
|
||||||
-->
|
|
||||||
|
|
||||||
WRITE DESCRIPTION HERE
|
|
||||||
72
.github/ISSUE_TEMPLATE_tmpl/3_site_feature_request.yml
vendored
Normal file
72
.github/ISSUE_TEMPLATE_tmpl/3_site_feature_request.yml
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
name: Site feature request
|
||||||
|
description: Request a new functionality for a supported site
|
||||||
|
labels: [triage, site-enhancement]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: |
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
||||||
|
options:
|
||||||
|
- label: I'm reporting a site feature request
|
||||||
|
required: true
|
||||||
|
- label: I've verified that I'm running yt-dlp version **%(version)s**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
||||||
|
required: true
|
||||||
|
- label: I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
required: true
|
||||||
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
||||||
|
required: true
|
||||||
|
- label: I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
|
||||||
|
required: true
|
||||||
|
- label: I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required
|
||||||
|
- type: input
|
||||||
|
id: region
|
||||||
|
attributes:
|
||||||
|
label: Region
|
||||||
|
description: "Enter the region the site is accessible from"
|
||||||
|
placeholder: "India"
|
||||||
|
- type: textarea
|
||||||
|
id: example-urls
|
||||||
|
attributes:
|
||||||
|
label: Example URLs
|
||||||
|
description: |
|
||||||
|
Example URLs that can be used to demonstrate the requested feature
|
||||||
|
placeholder: |
|
||||||
|
https://www.youtube.com/watch?v=BaW_jenozKc
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Provide an explanation of your site feature request in an arbitrary form.
|
||||||
|
Please make sure the description is worded well enough to be understood, see [is-the-description-of-the-issue-itself-sufficient](https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient).
|
||||||
|
Provide any additional information, any suggested solutions, and as much context and examples as possible
|
||||||
|
placeholder: WRITE DESCRIPTION HERE
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: log
|
||||||
|
attributes:
|
||||||
|
label: Verbose log
|
||||||
|
description: |
|
||||||
|
Provide the complete verbose output of yt-dlp that demonstrates the need for the enhancement.
|
||||||
|
Add the `-vU` flag to your command line you run yt-dlp with (`yt-dlp -vU <your command line>`), copy the WHOLE output and insert it below.
|
||||||
|
It should look similar to this:
|
||||||
|
placeholder: |
|
||||||
|
[debug] Command-line config: ['-vU', 'http://www.youtube.com/watch?v=BaW_jenozKc']
|
||||||
|
[debug] Portable config file: yt-dlp.conf
|
||||||
|
[debug] Portable config: ['-i']
|
||||||
|
[debug] Encodings: locale cp1252, fs utf-8, stdout utf-8, stderr utf-8, pref cp1252
|
||||||
|
[debug] yt-dlp version %(version)s (exe)
|
||||||
|
[debug] Python version 3.8.8 (CPython 64bit) - Windows-10-10.0.19041-SP0
|
||||||
|
[debug] exe versions: ffmpeg 3.0.1, ffprobe 3.0.1
|
||||||
|
[debug] Optional libraries: Cryptodome, keyring, mutagen, sqlite, websockets
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
yt-dlp is up to date (%(version)s)
|
||||||
|
<more lines>
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
72
.github/ISSUE_TEMPLATE_tmpl/4_bug_report.md
vendored
72
.github/ISSUE_TEMPLATE_tmpl/4_bug_report.md
vendored
@@ -1,72 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Report a bug unrelated to any particular site or extractor
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
WARNING!
|
|
||||||
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
|
||||||
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is %(version)s. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
|
|
||||||
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
|
||||||
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/yt-dlp/yt-dlp.
|
|
||||||
- Search the bugtracker for similar issues: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
|
|
||||||
- Read bugs section in FAQ: https://github.com/yt-dlp/yt-dlp
|
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
|
||||||
-->
|
|
||||||
|
|
||||||
- [ ] I'm reporting a broken site support issue
|
|
||||||
- [ ] I've verified that I'm running yt-dlp version **%(version)s**
|
|
||||||
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
|
||||||
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
|
||||||
- [ ] I've searched the bugtracker for similar bug reports including closed ones
|
|
||||||
- [ ] I've read bugs section in FAQ
|
|
||||||
|
|
||||||
|
|
||||||
## Verbose log
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide the complete verbose output of yt-dlp that clearly demonstrates the problem.
|
|
||||||
Add the `-v` flag to your command line you run yt-dlp with (`yt-dlp -v <your command line>`), copy the WHOLE output and insert it below. It should look similar to this:
|
|
||||||
[debug] System config: []
|
|
||||||
[debug] User config: []
|
|
||||||
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
|
||||||
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
|
||||||
[debug] yt-dlp version %(version)s
|
|
||||||
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
|
||||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
|
||||||
[debug] Proxy map: {}
|
|
||||||
<more lines>
|
|
||||||
-->
|
|
||||||
|
|
||||||
```
|
|
||||||
PASTE VERBOSE LOG HERE
|
|
||||||
|
|
||||||
```
|
|
||||||
<!--
|
|
||||||
Do not remove the above ```
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide an explanation of your issue in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
|
|
||||||
If work on your issue requires account credentials please provide them or explain how one can obtain them.
|
|
||||||
-->
|
|
||||||
|
|
||||||
WRITE DESCRIPTION HERE
|
|
||||||
57
.github/ISSUE_TEMPLATE_tmpl/4_bug_report.yml
vendored
Normal file
57
.github/ISSUE_TEMPLATE_tmpl/4_bug_report.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
name: Bug report
|
||||||
|
description: Report a bug unrelated to any particular site or extractor
|
||||||
|
labels: [triage, bug]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: |
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
||||||
|
options:
|
||||||
|
- label: I'm reporting a bug unrelated to a specific site
|
||||||
|
required: true
|
||||||
|
- label: I've verified that I'm running yt-dlp version **%(version)s**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
||||||
|
required: true
|
||||||
|
- label: I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
required: true
|
||||||
|
- label: I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/ytdl-org/youtube-dl#video-url-contains-an-ampersand-and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
|
||||||
|
required: true
|
||||||
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
||||||
|
required: true
|
||||||
|
- label: I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Provide an explanation of your issue in an arbitrary form.
|
||||||
|
Please make sure the description is worded well enough to be understood, see [is-the-description-of-the-issue-itself-sufficient](https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient).
|
||||||
|
Provide any additional information, any suggested solutions, and as much context and examples as possible
|
||||||
|
placeholder: WRITE DESCRIPTION HERE
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: log
|
||||||
|
attributes:
|
||||||
|
label: Verbose log
|
||||||
|
description: |
|
||||||
|
Provide the complete verbose output of yt-dlp **that clearly demonstrates the problem**.
|
||||||
|
Add the `-vU` flag to **your** command line you run yt-dlp with (`yt-dlp -vU <your command line>`), copy the WHOLE output and insert it below.
|
||||||
|
It should look similar to this:
|
||||||
|
placeholder: |
|
||||||
|
[debug] Command-line config: ['-vU', 'http://www.youtube.com/watch?v=BaW_jenozKc']
|
||||||
|
[debug] Portable config file: yt-dlp.conf
|
||||||
|
[debug] Portable config: ['-i']
|
||||||
|
[debug] Encodings: locale cp1252, fs utf-8, stdout utf-8, stderr utf-8, pref cp1252
|
||||||
|
[debug] yt-dlp version %(version)s (exe)
|
||||||
|
[debug] Python version 3.8.8 (CPython 64bit) - Windows-10-10.0.19041-SP0
|
||||||
|
[debug] exe versions: ffmpeg 3.0.1, ffprobe 3.0.1
|
||||||
|
[debug] Optional libraries: Cryptodome, keyring, mutagen, sqlite, websockets
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
yt-dlp is up to date (%(version)s)
|
||||||
|
<more lines>
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
40
.github/ISSUE_TEMPLATE_tmpl/5_feature_request.md
vendored
40
.github/ISSUE_TEMPLATE_tmpl/5_feature_request.md
vendored
@@ -1,40 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Request a new functionality unrelated to any particular site or extractor
|
|
||||||
title: "[Feature Request]"
|
|
||||||
labels: Request
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
WARNING!
|
|
||||||
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
|
||||||
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is %(version)s. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
|
|
||||||
- Search the bugtracker for similar feature requests: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
|
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
|
||||||
-->
|
|
||||||
|
|
||||||
- [ ] I'm reporting a feature request
|
|
||||||
- [ ] I've verified that I'm running yt-dlp version **%(version)s**
|
|
||||||
- [ ] I've searched the bugtracker for similar feature requests including closed ones
|
|
||||||
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide an explanation of your issue in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
|
|
||||||
-->
|
|
||||||
|
|
||||||
WRITE DESCRIPTION HERE
|
|
||||||
32
.github/ISSUE_TEMPLATE_tmpl/5_feature_request.yml
vendored
Normal file
32
.github/ISSUE_TEMPLATE_tmpl/5_feature_request.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Feature request
|
||||||
|
description: Request a new functionality unrelated to any particular site or extractor
|
||||||
|
labels: [triage, enhancement]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: |
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
||||||
|
options:
|
||||||
|
- label: I'm reporting a feature request
|
||||||
|
required: true
|
||||||
|
- label: I've looked through the [README](https://github.com/yt-dlp/yt-dlp#readme)
|
||||||
|
required: true
|
||||||
|
- label: I've verified that I'm running yt-dlp version **%(version)s**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
||||||
|
required: true
|
||||||
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
||||||
|
required: true
|
||||||
|
- label: I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Provide an explanation of your site feature request in an arbitrary form.
|
||||||
|
Please make sure the description is worded well enough to be understood, see [is-the-description-of-the-issue-itself-sufficient](https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient).
|
||||||
|
Provide any additional information, any suggested solutions, and as much context and examples as possible
|
||||||
|
placeholder: WRITE DESCRIPTION HERE
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
53
.github/ISSUE_TEMPLATE_tmpl/6_question.yml
vendored
Normal file
53
.github/ISSUE_TEMPLATE_tmpl/6_question.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
name: Ask question
|
||||||
|
description: Ask yt-dlp related question
|
||||||
|
labels: [question]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: |
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
|
||||||
|
options:
|
||||||
|
- label: I'm asking a question and **not** reporting a bug/feature request
|
||||||
|
required: true
|
||||||
|
- label: I've looked through the [README](https://github.com/yt-dlp/yt-dlp#readme)
|
||||||
|
required: true
|
||||||
|
- label: I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
|
||||||
|
required: true
|
||||||
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar questions including closed ones
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: question
|
||||||
|
attributes:
|
||||||
|
label: Question
|
||||||
|
description: |
|
||||||
|
Ask your question in an arbitrary form.
|
||||||
|
Please make sure it's worded well enough to be understood, see [is-the-description-of-the-issue-itself-sufficient](https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient).
|
||||||
|
Provide any additional information and as much context and examples as possible.
|
||||||
|
If your question contains "isn't working" or "can you add", this is most likely the wrong template.
|
||||||
|
If you are in doubt if this is the right template, use another template!
|
||||||
|
placeholder: WRITE QUESTION HERE
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: log
|
||||||
|
attributes:
|
||||||
|
label: Verbose log
|
||||||
|
description: |
|
||||||
|
If your question involes a yt-dlp command, provide the complete verbose output of that command.
|
||||||
|
Add the `-vU` flag to **your** command line you run yt-dlp with (`yt-dlp -vU <your command line>`), copy the WHOLE output and insert it below.
|
||||||
|
It should look similar to this:
|
||||||
|
placeholder: |
|
||||||
|
[debug] Command-line config: ['-vU', 'http://www.youtube.com/watch?v=BaW_jenozKc']
|
||||||
|
[debug] Portable config file: yt-dlp.conf
|
||||||
|
[debug] Portable config: ['-i']
|
||||||
|
[debug] Encodings: locale cp1252, fs utf-8, stdout utf-8, stderr utf-8, pref cp1252
|
||||||
|
[debug] yt-dlp version 2021.12.01 (exe)
|
||||||
|
[debug] Python version 3.8.8 (CPython 64bit) - Windows-10-10.0.19041-SP0
|
||||||
|
[debug] exe versions: ffmpeg 3.0.1, ffprobe 3.0.1
|
||||||
|
[debug] Optional libraries: Cryptodome, keyring, mutagen, sqlite, websockets
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
yt-dlp is up to date (2021.12.01)
|
||||||
|
<more lines>
|
||||||
|
render: shell
|
||||||
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -7,11 +7,11 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
### Before submitting a *pull request* make sure you have:
|
### Before submitting a *pull request* make sure you have:
|
||||||
- [ ] At least skimmed through [adding new extractor tutorial](https://github.com/ytdl-org/youtube-dl#adding-support-for-a-new-site) and [youtube-dl coding conventions](https://github.com/ytdl-org/youtube-dl#youtube-dl-coding-conventions) sections
|
- [ ] At least skimmed through [contributing guidelines](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#developer-instructions) including [yt-dlp coding conventions](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#yt-dlp-coding-conventions)
|
||||||
- [ ] [Searched](https://github.com/yt-dlp/yt-dlp/search?q=is%3Apr&type=Issues) the bugtracker for similar pull requests
|
- [ ] [Searched](https://github.com/yt-dlp/yt-dlp/search?q=is%3Apr&type=Issues) the bugtracker for similar pull requests
|
||||||
- [ ] Checked the code with [flake8](https://pypi.python.org/pypi/flake8)
|
- [ ] Checked the code with [flake8](https://pypi.python.org/pypi/flake8)
|
||||||
|
|
||||||
### In order to be accepted and merged into youtube-dl each piece of code must be in public domain or released under [Unlicense](http://unlicense.org/). Check one of the following options:
|
### In order to be accepted and merged into yt-dlp each piece of code must be in public domain or released under [Unlicense](http://unlicense.org/). Check one of the following options:
|
||||||
- [ ] I am the original author of this code and I am willing to release it under [Unlicense](http://unlicense.org/)
|
- [ ] I am the original author of this code and I am willing to release it under [Unlicense](http://unlicense.org/)
|
||||||
- [ ] I am not the original author of this code but it is in public domain or released under [Unlicense](http://unlicense.org/) (provide reliable evidence)
|
- [ ] I am not the original author of this code but it is in public domain or released under [Unlicense](http://unlicense.org/) (provide reliable evidence)
|
||||||
|
|
||||||
|
|||||||
31
.github/banner.svg
vendored
Normal file
31
.github/banner.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 24 KiB |
389
.github/workflows/build.yml
vendored
389
.github/workflows/build.yml
vendored
@@ -1,61 +1,80 @@
|
|||||||
name: Build
|
name: Build
|
||||||
|
on: workflow_dispatch
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- release
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_unix:
|
build_unix:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
|
version_suffix: ${{ steps.version_suffix.outputs.version_suffix }}
|
||||||
ytdlp_version: ${{ steps.bump_version.outputs.ytdlp_version }}
|
ytdlp_version: ${{ steps.bump_version.outputs.ytdlp_version }}
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
sha2_unix: ${{ steps.sha2_file.outputs.sha2_unix }}
|
sha256_bin: ${{ steps.sha256_bin.outputs.sha256_bin }}
|
||||||
|
sha512_bin: ${{ steps.sha512_bin.outputs.sha512_bin }}
|
||||||
|
sha256_tar: ${{ steps.sha256_tar.outputs.sha256_tar }}
|
||||||
|
sha512_tar: ${{ steps.sha512_tar.outputs.sha512_tar }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: '3.8'
|
python-version: '3.8'
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: sudo apt-get -y install zip pandoc man
|
run: sudo apt-get -y install zip pandoc man
|
||||||
|
- name: Set version suffix
|
||||||
|
id: version_suffix
|
||||||
|
env:
|
||||||
|
PUSH_VERSION_COMMIT: ${{ secrets.PUSH_VERSION_COMMIT }}
|
||||||
|
if: "env.PUSH_VERSION_COMMIT == ''"
|
||||||
|
run: echo ::set-output name=version_suffix::$(date -u +"%H%M%S")
|
||||||
- name: Bump version
|
- name: Bump version
|
||||||
id: bump_version
|
id: bump_version
|
||||||
run: python devscripts/update-version.py
|
run: |
|
||||||
- name: Print version
|
python devscripts/update-version.py ${{ steps.version_suffix.outputs.version_suffix }}
|
||||||
run: echo "${{ steps.bump_version.outputs.ytdlp_version }}"
|
make issuetemplates
|
||||||
|
- name: Push to release
|
||||||
|
id: push_release
|
||||||
|
run: |
|
||||||
|
git config --global user.name github-actions
|
||||||
|
git config --global user.email github-actions@example.com
|
||||||
|
git add -u
|
||||||
|
git commit -m "[version] update" -m "Created by: ${{ github.event.sender.login }}" -m ":ci skip all"
|
||||||
|
git push origin --force ${{ github.event.ref }}:release
|
||||||
|
echo ::set-output name=head_sha::$(git rev-parse HEAD)
|
||||||
|
- name: Update master
|
||||||
|
id: push_master
|
||||||
|
env:
|
||||||
|
PUSH_VERSION_COMMIT: ${{ secrets.PUSH_VERSION_COMMIT }}
|
||||||
|
if: "env.PUSH_VERSION_COMMIT != ''"
|
||||||
|
run: git push origin ${{ github.event.ref }}
|
||||||
|
- name: Get Changelog
|
||||||
|
id: get_changelog
|
||||||
|
run: |
|
||||||
|
changelog=$(cat Changelog.md | grep -oPz '(?s)(?<=### ${{ steps.bump_version.outputs.ytdlp_version }}\n{2}).+?(?=\n{2,3}###)') || true
|
||||||
|
echo "changelog<<EOF" >> $GITHUB_ENV
|
||||||
|
echo "$changelog" >> $GITHUB_ENV
|
||||||
|
echo "EOF" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build lazy extractors
|
||||||
|
id: lazy_extractors
|
||||||
|
run: python devscripts/make_lazy_extractors.py
|
||||||
- name: Run Make
|
- name: Run Make
|
||||||
run: make
|
run: make all tar
|
||||||
- name: Create Release
|
|
||||||
id: create_release
|
|
||||||
uses: actions/create-release@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
tag_name: ${{ steps.bump_version.outputs.ytdlp_version }}
|
|
||||||
release_name: yt-dlp ${{ steps.bump_version.outputs.ytdlp_version }}
|
|
||||||
body: |
|
|
||||||
Changelog:
|
|
||||||
PLACEHOLDER
|
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
- name: Upload yt-dlp Unix binary
|
|
||||||
id: upload-release-asset
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
asset_path: ./yt-dlp
|
|
||||||
asset_name: yt-dlp
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
- name: Get SHA2-256SUMS for yt-dlp
|
- name: Get SHA2-256SUMS for yt-dlp
|
||||||
id: sha2_file
|
id: sha256_bin
|
||||||
run: echo "::set-output name=sha2_unix::$(sha256sum yt-dlp | awk '{print $1}')"
|
run: echo "::set-output name=sha256_bin::$(sha256sum yt-dlp | awk '{print $1}')"
|
||||||
|
- name: Get SHA2-256SUMS for yt-dlp.tar.gz
|
||||||
|
id: sha256_tar
|
||||||
|
run: echo "::set-output name=sha256_tar::$(sha256sum yt-dlp.tar.gz | awk '{print $1}')"
|
||||||
|
- name: Get SHA2-512SUMS for yt-dlp
|
||||||
|
id: sha512_bin
|
||||||
|
run: echo "::set-output name=sha512_bin::$(sha512sum yt-dlp | awk '{print $1}')"
|
||||||
|
- name: Get SHA2-512SUMS for yt-dlp.tar.gz
|
||||||
|
id: sha512_tar
|
||||||
|
run: echo "::set-output name=sha512_tar::$(sha512sum yt-dlp.tar.gz | awk '{print $1}')"
|
||||||
|
|
||||||
- name: Install dependencies for pypi
|
- name: Install dependencies for pypi
|
||||||
env:
|
env:
|
||||||
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
|
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
|
||||||
@@ -73,32 +92,159 @@ jobs:
|
|||||||
python setup.py sdist bdist_wheel
|
python setup.py sdist bdist_wheel
|
||||||
twine upload dist/*
|
twine upload dist/*
|
||||||
|
|
||||||
build_windows:
|
- name: Install SSH private key
|
||||||
|
env:
|
||||||
|
BREW_TOKEN: ${{ secrets.BREW_TOKEN }}
|
||||||
|
if: "env.BREW_TOKEN != ''"
|
||||||
|
uses: yt-dlp/ssh-agent@v0.5.3
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ env.BREW_TOKEN }}
|
||||||
|
- name: Update Homebrew Formulae
|
||||||
|
env:
|
||||||
|
BREW_TOKEN: ${{ secrets.BREW_TOKEN }}
|
||||||
|
if: "env.BREW_TOKEN != ''"
|
||||||
|
run: |
|
||||||
|
git clone git@github.com:yt-dlp/homebrew-taps taps/
|
||||||
|
python3 devscripts/update-formulae.py taps/Formula/yt-dlp.rb "${{ steps.bump_version.outputs.ytdlp_version }}"
|
||||||
|
git -C taps/ config user.name github-actions
|
||||||
|
git -C taps/ config user.email github-actions@example.com
|
||||||
|
git -C taps/ commit -am 'yt-dlp: ${{ steps.bump_version.outputs.ytdlp_version }}'
|
||||||
|
git -C taps/ push
|
||||||
|
|
||||||
runs-on: windows-latest
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ steps.bump_version.outputs.ytdlp_version }}
|
||||||
|
release_name: yt-dlp ${{ steps.bump_version.outputs.ytdlp_version }}
|
||||||
|
commitish: ${{ steps.push_release.outputs.head_sha }}
|
||||||
|
body: |
|
||||||
|
#### [A description of the various files]((https://github.com/yt-dlp/yt-dlp#release-files)) are in the README
|
||||||
|
|
||||||
outputs:
|
---
|
||||||
sha2_windows: ${{ steps.sha2_file_win.outputs.sha2_windows }}
|
|
||||||
|
|
||||||
|
### Changelog:
|
||||||
|
${{ env.changelog }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
- name: Upload yt-dlp Unix binary
|
||||||
|
id: upload-release-asset
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: ./yt-dlp
|
||||||
|
asset_name: yt-dlp
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
- name: Upload Source tar
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: ./yt-dlp.tar.gz
|
||||||
|
asset_name: yt-dlp.tar.gz
|
||||||
|
asset_content_type: application/gzip
|
||||||
|
|
||||||
|
build_macos:
|
||||||
|
runs-on: macos-11
|
||||||
needs: build_unix
|
needs: build_unix
|
||||||
|
outputs:
|
||||||
|
sha256_macos: ${{ steps.sha256_macos.outputs.sha256_macos }}
|
||||||
|
sha512_macos: ${{ steps.sha512_macos.outputs.sha512_macos }}
|
||||||
|
sha256_macos_zip: ${{ steps.sha256_macos_zip.outputs.sha256_macos_zip }}
|
||||||
|
sha512_macos_zip: ${{ steps.sha512_macos_zip.outputs.sha512_macos_zip }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python
|
# In order to create a universal2 application, the version of python3 in /usr/bin has to be used
|
||||||
|
# Pyinstaller is pinned to 4.5.1 because the builds are failing in 4.6, 4.7
|
||||||
|
- name: Install Requirements
|
||||||
|
run: |
|
||||||
|
brew install coreutils
|
||||||
|
/usr/bin/python3 -m pip install -U --user pip Pyinstaller==4.5.1 -r requirements.txt
|
||||||
|
- name: Bump version
|
||||||
|
id: bump_version
|
||||||
|
run: /usr/bin/python3 devscripts/update-version.py
|
||||||
|
- name: Build lazy extractors
|
||||||
|
id: lazy_extractors
|
||||||
|
run: /usr/bin/python3 devscripts/make_lazy_extractors.py
|
||||||
|
- name: Run PyInstaller Script
|
||||||
|
run: /usr/bin/python3 pyinst.py --target-architecture universal2 --onefile
|
||||||
|
- name: Upload yt-dlp MacOS binary
|
||||||
|
id: upload-release-macos
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ needs.build_unix.outputs.upload_url }}
|
||||||
|
asset_path: ./dist/yt-dlp_macos
|
||||||
|
asset_name: yt-dlp_macos
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
- name: Get SHA2-256SUMS for yt-dlp_macos
|
||||||
|
id: sha256_macos
|
||||||
|
run: echo "::set-output name=sha256_macos::$(sha256sum dist/yt-dlp_macos | awk '{print $1}')"
|
||||||
|
- name: Get SHA2-512SUMS for yt-dlp_macos
|
||||||
|
id: sha512_macos
|
||||||
|
run: echo "::set-output name=sha512_macos::$(sha512sum dist/yt-dlp_macos | awk '{print $1}')"
|
||||||
|
|
||||||
|
- name: Run PyInstaller Script with --onedir
|
||||||
|
run: |
|
||||||
|
/usr/bin/python3 pyinst.py --target-architecture universal2 --onedir
|
||||||
|
zip ./dist/yt-dlp_macos.zip ./dist/yt-dlp_macos
|
||||||
|
- name: Upload yt-dlp MacOS onedir
|
||||||
|
id: upload-release-macos-zip
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ needs.build_unix.outputs.upload_url }}
|
||||||
|
asset_path: ./dist/yt-dlp_macos.zip
|
||||||
|
asset_name: yt-dlp_macos.zip
|
||||||
|
asset_content_type: application/zip
|
||||||
|
- name: Get SHA2-256SUMS for yt-dlp_macos.zip
|
||||||
|
id: sha256_macos_zip
|
||||||
|
run: echo "::set-output name=sha256_macos_zip::$(sha256sum dist/yt-dlp_macos.zip | awk '{print $1}')"
|
||||||
|
- name: Get SHA2-512SUMS for yt-dlp_macos.zip
|
||||||
|
id: sha512_macos_zip
|
||||||
|
run: echo "::set-output name=sha512_macos_zip::$(sha512sum dist/yt-dlp_macos.zip | awk '{print $1}')"
|
||||||
|
|
||||||
|
build_windows:
|
||||||
|
runs-on: windows-latest
|
||||||
|
needs: build_unix
|
||||||
|
outputs:
|
||||||
|
sha256_win: ${{ steps.sha256_win.outputs.sha256_win }}
|
||||||
|
sha512_win: ${{ steps.sha512_win.outputs.sha512_win }}
|
||||||
|
sha256_py2exe: ${{ steps.sha256_py2exe.outputs.sha256_py2exe }}
|
||||||
|
sha512_py2exe: ${{ steps.sha512_py2exe.outputs.sha512_py2exe }}
|
||||||
|
sha256_win_zip: ${{ steps.sha256_win_zip.outputs.sha256_win_zip }}
|
||||||
|
sha512_win_zip: ${{ steps.sha512_win_zip.outputs.sha512_win_zip }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
# 3.8 is used for Win7 support
|
||||||
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: '3.8'
|
python-version: '3.8'
|
||||||
- name: Upgrade pip and enable wheel support
|
|
||||||
run: python -m pip install --upgrade pip setuptools wheel
|
|
||||||
- name: Install Requirements
|
- name: Install Requirements
|
||||||
run: pip install pyinstaller mutagen pycryptodome
|
# Custom pyinstaller built with https://github.com/yt-dlp/pyinstaller-builds
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip setuptools wheel py2exe
|
||||||
|
pip install "https://yt-dlp.github.io/Pyinstaller-Builds/x86_64/pyinstaller-4.5.1-py3-none-any.whl" -r requirements.txt
|
||||||
- name: Bump version
|
- name: Bump version
|
||||||
id: bump_version
|
id: bump_version
|
||||||
run: python devscripts/update-version.py
|
env:
|
||||||
- name: Print version
|
version_suffix: ${{ needs.build_unix.outputs.version_suffix }}
|
||||||
run: echo "${{ steps.bump_version.outputs.ytdlp_version }}"
|
run: python devscripts/update-version.py ${{ env.version_suffix }}
|
||||||
|
- name: Build lazy extractors
|
||||||
|
id: lazy_extractors
|
||||||
|
run: python devscripts/make_lazy_extractors.py
|
||||||
- name: Run PyInstaller Script
|
- name: Run PyInstaller Script
|
||||||
run: python pyinst.py 64
|
run: python pyinst.py
|
||||||
- name: Upload yt-dlp.exe Windows binary
|
- name: Upload yt-dlp.exe Windows binary
|
||||||
id: upload-release-windows
|
id: upload-release-windows
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
@@ -110,36 +256,82 @@ jobs:
|
|||||||
asset_name: yt-dlp.exe
|
asset_name: yt-dlp.exe
|
||||||
asset_content_type: application/vnd.microsoft.portable-executable
|
asset_content_type: application/vnd.microsoft.portable-executable
|
||||||
- name: Get SHA2-256SUMS for yt-dlp.exe
|
- name: Get SHA2-256SUMS for yt-dlp.exe
|
||||||
id: sha2_file_win
|
id: sha256_win
|
||||||
run: echo "::set-output name=sha2_windows::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA256).Hash.ToLower())"
|
run: echo "::set-output name=sha256_win::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA256).Hash.ToLower())"
|
||||||
|
- name: Get SHA2-512SUMS for yt-dlp.exe
|
||||||
|
id: sha512_win
|
||||||
|
run: echo "::set-output name=sha512_win::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA512).Hash.ToLower())"
|
||||||
|
|
||||||
|
- name: Run PyInstaller Script with --onedir
|
||||||
|
run: |
|
||||||
|
python pyinst.py --onedir
|
||||||
|
Compress-Archive -LiteralPath ./dist/yt-dlp -DestinationPath ./dist/yt-dlp_win.zip
|
||||||
|
- name: Upload yt-dlp Windows onedir
|
||||||
|
id: upload-release-windows-zip
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ needs.build_unix.outputs.upload_url }}
|
||||||
|
asset_path: ./dist/yt-dlp_win.zip
|
||||||
|
asset_name: yt-dlp_win.zip
|
||||||
|
asset_content_type: application/zip
|
||||||
|
- name: Get SHA2-256SUMS for yt-dlp_win.zip
|
||||||
|
id: sha256_win_zip
|
||||||
|
run: echo "::set-output name=sha256_win_zip::$((Get-FileHash dist\yt-dlp_win.zip -Algorithm SHA256).Hash.ToLower())"
|
||||||
|
- name: Get SHA2-512SUMS for yt-dlp_win.zip
|
||||||
|
id: sha512_win_zip
|
||||||
|
run: echo "::set-output name=sha512_win_zip::$((Get-FileHash dist\yt-dlp_win.zip -Algorithm SHA512).Hash.ToLower())"
|
||||||
|
|
||||||
|
- name: Run py2exe Script
|
||||||
|
run: python setup.py py2exe
|
||||||
|
- name: Upload yt-dlp_min.exe Windows binary
|
||||||
|
id: upload-release-windows-py2exe
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ needs.build_unix.outputs.upload_url }}
|
||||||
|
asset_path: ./dist/yt-dlp.exe
|
||||||
|
asset_name: yt-dlp_min.exe
|
||||||
|
asset_content_type: application/vnd.microsoft.portable-executable
|
||||||
|
- name: Get SHA2-256SUMS for yt-dlp_min.exe
|
||||||
|
id: sha256_py2exe
|
||||||
|
run: echo "::set-output name=sha256_py2exe::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA256).Hash.ToLower())"
|
||||||
|
- name: Get SHA2-512SUMS for yt-dlp_min.exe
|
||||||
|
id: sha512_py2exe
|
||||||
|
run: echo "::set-output name=sha512_py2exe::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA512).Hash.ToLower())"
|
||||||
|
|
||||||
build_windows32:
|
build_windows32:
|
||||||
|
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
needs: build_unix
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
sha2_windows32: ${{ steps.sha2_file_win32.outputs.sha2_windows32 }}
|
sha256_win32: ${{ steps.sha256_win32.outputs.sha256_win32 }}
|
||||||
|
sha512_win32: ${{ steps.sha512_win32.outputs.sha512_win32 }}
|
||||||
needs: [build_unix, build_windows]
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.4.4 32-Bit
|
# 3.7 is used for Vista support. See https://github.com/yt-dlp/yt-dlp/issues/390
|
||||||
|
- name: Set up Python 3.7 32-Bit
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: '3.4.4'
|
python-version: '3.7'
|
||||||
architecture: 'x86'
|
architecture: 'x86'
|
||||||
- name: Upgrade pip and enable wheel support
|
- name: Install Requirements
|
||||||
run: python -m pip install pip==19.1.1 setuptools==43.0.0 wheel==0.33.6
|
run: |
|
||||||
- name: Install Requirements for 32 Bit
|
python -m pip install --upgrade pip setuptools wheel
|
||||||
run: pip install pyinstaller==3.5 mutagen==1.42.0 pycryptodome==3.9.4
|
pip install "https://yt-dlp.github.io/Pyinstaller-Builds/i686/pyinstaller-4.5.1-py3-none-any.whl" -r requirements.txt
|
||||||
- name: Bump version
|
- name: Bump version
|
||||||
id: bump_version
|
id: bump_version
|
||||||
run: python devscripts/update-version.py
|
env:
|
||||||
- name: Print version
|
version_suffix: ${{ needs.build_unix.outputs.version_suffix }}
|
||||||
run: echo "${{ steps.bump_version.outputs.ytdlp_version }}"
|
run: python devscripts/update-version.py ${{ env.version_suffix }}
|
||||||
|
- name: Build lazy extractors
|
||||||
|
id: lazy_extractors
|
||||||
|
run: python devscripts/make_lazy_extractors.py
|
||||||
- name: Run PyInstaller Script for 32 Bit
|
- name: Run PyInstaller Script for 32 Bit
|
||||||
run: python pyinst.py 32
|
run: python pyinst.py
|
||||||
- name: Upload Executable yt-dlp_x86.exe
|
- name: Upload Executable yt-dlp_x86.exe
|
||||||
id: upload-release-windows32
|
id: upload-release-windows32
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
@@ -151,20 +343,36 @@ jobs:
|
|||||||
asset_name: yt-dlp_x86.exe
|
asset_name: yt-dlp_x86.exe
|
||||||
asset_content_type: application/vnd.microsoft.portable-executable
|
asset_content_type: application/vnd.microsoft.portable-executable
|
||||||
- name: Get SHA2-256SUMS for yt-dlp_x86.exe
|
- name: Get SHA2-256SUMS for yt-dlp_x86.exe
|
||||||
id: sha2_file_win32
|
id: sha256_win32
|
||||||
run: echo "::set-output name=sha2_windows32::$((Get-FileHash dist\yt-dlp_x86.exe -Algorithm SHA256).Hash.ToLower())"
|
run: echo "::set-output name=sha256_win32::$((Get-FileHash dist\yt-dlp_x86.exe -Algorithm SHA256).Hash.ToLower())"
|
||||||
|
- name: Get SHA2-512SUMS for yt-dlp_x86.exe
|
||||||
|
id: sha512_win32
|
||||||
|
run: echo "::set-output name=sha512_win32::$((Get-FileHash dist\yt-dlp_x86.exe -Algorithm SHA512).Hash.ToLower())"
|
||||||
|
|
||||||
|
finish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [build_unix, build_windows, build_windows32, build_macos]
|
||||||
|
|
||||||
|
steps:
|
||||||
- name: Make SHA2-256SUMS file
|
- name: Make SHA2-256SUMS file
|
||||||
env:
|
env:
|
||||||
SHA2_WINDOWS: ${{ needs.build_windows.outputs.sha2_windows }}
|
SHA256_BIN: ${{ needs.build_unix.outputs.sha256_bin }}
|
||||||
SHA2_WINDOWS32: ${{ steps.sha2_file_win32.outputs.sha2_windows32 }}
|
SHA256_TAR: ${{ needs.build_unix.outputs.sha256_tar }}
|
||||||
SHA2_UNIX: ${{ needs.build_unix.outputs.sha2_unix }}
|
SHA256_WIN: ${{ needs.build_windows.outputs.sha256_win }}
|
||||||
YTDLP_VERSION: ${{ needs.build_unix.outputs.ytdlp_version }}
|
SHA256_PY2EXE: ${{ needs.build_windows.outputs.sha256_py2exe }}
|
||||||
|
SHA256_WIN_ZIP: ${{ needs.build_windows.outputs.sha256_win_zip }}
|
||||||
|
SHA256_WIN32: ${{ needs.build_windows32.outputs.sha256_win32 }}
|
||||||
|
SHA256_MACOS: ${{ needs.build_macos.outputs.sha256_macos }}
|
||||||
|
SHA256_MACOS_ZIP: ${{ needs.build_macos.outputs.sha256_macos_zip }}
|
||||||
run: |
|
run: |
|
||||||
echo "version:${env:YTDLP_VERSION}" >> SHA2-256SUMS
|
echo "${{ env.SHA256_BIN }} yt-dlp" >> SHA2-256SUMS
|
||||||
echo "yt-dlp.exe:${env:SHA2_WINDOWS}" >> SHA2-256SUMS
|
echo "${{ env.SHA256_TAR }} yt-dlp.tar.gz" >> SHA2-256SUMS
|
||||||
echo "yt-dlp_x86.exe:${env:SHA2_WINDOWS32}" >> SHA2-256SUMS
|
echo "${{ env.SHA256_WIN }} yt-dlp.exe" >> SHA2-256SUMS
|
||||||
echo "yt-dlp:${env:SHA2_UNIX}" >> SHA2-256SUMS
|
echo "${{ env.SHA256_PY2EXE }} yt-dlp_min.exe" >> SHA2-256SUMS
|
||||||
|
echo "${{ env.SHA256_WIN32 }} yt-dlp_x86.exe" >> SHA2-256SUMS
|
||||||
|
echo "${{ env.SHA256_WIN_ZIP }} yt-dlp_win.zip" >> SHA2-256SUMS
|
||||||
|
echo "${{ env.SHA256_MACOS }} yt-dlp_macos" >> SHA2-256SUMS
|
||||||
|
echo "${{ env.SHA256_MACOS_ZIP }} yt-dlp_macos.zip" >> SHA2-256SUMS
|
||||||
- name: Upload 256SUMS file
|
- name: Upload 256SUMS file
|
||||||
id: upload-sums
|
id: upload-sums
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
@@ -175,3 +383,32 @@ jobs:
|
|||||||
asset_path: ./SHA2-256SUMS
|
asset_path: ./SHA2-256SUMS
|
||||||
asset_name: SHA2-256SUMS
|
asset_name: SHA2-256SUMS
|
||||||
asset_content_type: text/plain
|
asset_content_type: text/plain
|
||||||
|
- name: Make SHA2-512SUMS file
|
||||||
|
env:
|
||||||
|
SHA512_BIN: ${{ needs.build_unix.outputs.sha512_bin }}
|
||||||
|
SHA512_TAR: ${{ needs.build_unix.outputs.sha512_tar }}
|
||||||
|
SHA512_WIN: ${{ needs.build_windows.outputs.sha512_win }}
|
||||||
|
SHA512_PY2EXE: ${{ needs.build_windows.outputs.sha512_py2exe }}
|
||||||
|
SHA512_WIN_ZIP: ${{ needs.build_windows.outputs.sha512_win_zip }}
|
||||||
|
SHA512_WIN32: ${{ needs.build_windows32.outputs.sha512_win32 }}
|
||||||
|
SHA512_MACOS: ${{ needs.build_macos.outputs.sha512_macos }}
|
||||||
|
SHA512_MACOS_ZIP: ${{ needs.build_macos.outputs.sha512_macos_zip }}
|
||||||
|
run: |
|
||||||
|
echo "${{ env.SHA512_BIN }} yt-dlp" >> SHA2-512SUMS
|
||||||
|
echo "${{ env.SHA512_TAR }} yt-dlp.tar.gz" >> SHA2-512SUMS
|
||||||
|
echo "${{ env.SHA512_WIN }} yt-dlp.exe" >> SHA2-512SUMS
|
||||||
|
echo "${{ env.SHA512_WIN_ZIP }} yt-dlp_win.zip" >> SHA2-512SUMS
|
||||||
|
echo "${{ env.SHA512_PY2EXE }} yt-dlp_min.exe" >> SHA2-512SUMS
|
||||||
|
echo "${{ env.SHA512_WIN32 }} yt-dlp_x86.exe" >> SHA2-512SUMS
|
||||||
|
echo "${{ env.SHA512_MACOS }} yt-dlp_macos" >> SHA2-512SUMS
|
||||||
|
echo "${{ env.SHA512_MACOS_ZIP }} yt-dlp_macos.zip" >> SHA2-512SUMS
|
||||||
|
- name: Upload 512SUMS file
|
||||||
|
id: upload-512sums
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ needs.build_unix.outputs.upload_url }}
|
||||||
|
asset_path: ./SHA2-512SUMS
|
||||||
|
asset_name: SHA2-512SUMS
|
||||||
|
asset_content_type: text/plain
|
||||||
|
|||||||
41
.github/workflows/core.yml
vendored
41
.github/workflows/core.yml
vendored
@@ -6,49 +6,26 @@ jobs:
|
|||||||
if: "!contains(github.event.head_commit.message, 'ci skip')"
|
if: "!contains(github.event.head_commit.message, 'ci skip')"
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-18.04]
|
os: [ubuntu-18.04]
|
||||||
# TODO: python 2.6
|
# py3.9 is in quick-test
|
||||||
python-version: [2.7, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, pypy-2.7, pypy-3.6, pypy-3.7]
|
python-version: [3.7, 3.8, 3.10-dev, pypy-3.6, pypy-3.7]
|
||||||
python-impl: [cpython]
|
|
||||||
ytdl-test-set: [core]
|
|
||||||
run-tests-ext: [sh]
|
run-tests-ext: [sh]
|
||||||
include:
|
include:
|
||||||
# python 3.2 is only available on windows via setup-python
|
# atleast one of the tests must be in windows
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: 3.2
|
python-version: 3.6
|
||||||
python-impl: cpython
|
|
||||||
ytdl-test-set: core
|
|
||||||
run-tests-ext: bat
|
run-tests-ext: bat
|
||||||
# jython
|
|
||||||
- os: ubuntu-latest
|
|
||||||
python-impl: jython
|
|
||||||
ytdl-test-set: core
|
|
||||||
run-tests-ext: sh
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
if: ${{ matrix.python-impl == 'cpython' }}
|
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
- name: Set up Java 8
|
- name: Install pytest
|
||||||
if: ${{ matrix.python-impl == 'jython' }}
|
run: pip install pytest
|
||||||
uses: actions/setup-java@v1
|
|
||||||
with:
|
|
||||||
java-version: 8
|
|
||||||
- name: Install Jython
|
|
||||||
if: ${{ matrix.python-impl == 'jython' }}
|
|
||||||
run: |
|
|
||||||
wget http://search.maven.org/remotecontent?filepath=org/python/jython-installer/2.7.1/jython-installer-2.7.1.jar -O jython-installer.jar
|
|
||||||
java -jar jython-installer.jar -s -d "$HOME/jython"
|
|
||||||
echo "$HOME/jython/bin" >> $GITHUB_PATH
|
|
||||||
- name: Install nose
|
|
||||||
run: pip install nose
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
continue-on-error: ${{ matrix.ytdl-test-set == 'download' || matrix.python-impl == 'jython' }}
|
continue-on-error: False
|
||||||
env:
|
run: ./devscripts/run_tests.${{ matrix.run-tests-ext }} core
|
||||||
YTDL_TEST_SET: ${{ matrix.ytdl-test-set }}
|
|
||||||
run: ./devscripts/run_tests.${{ matrix.run-tests-ext }}
|
|
||||||
# Linter is in quick-test
|
# Linter is in quick-test
|
||||||
|
|||||||
37
.github/workflows/download.yml
vendored
37
.github/workflows/download.yml
vendored
@@ -9,45 +9,20 @@ jobs:
|
|||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-18.04]
|
os: [ubuntu-18.04]
|
||||||
# TODO: python 2.6
|
python-version: [3.7, 3.8, 3.9, 3.10-dev, pypy-3.6, pypy-3.7]
|
||||||
python-version: [2.7, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, pypy-2.7, pypy-3.6, pypy-3.7]
|
|
||||||
python-impl: [cpython]
|
|
||||||
ytdl-test-set: [download]
|
|
||||||
run-tests-ext: [sh]
|
run-tests-ext: [sh]
|
||||||
include:
|
include:
|
||||||
# python 3.2 is only available on windows via setup-python
|
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: 3.2
|
python-version: 3.6
|
||||||
python-impl: cpython
|
|
||||||
ytdl-test-set: download
|
|
||||||
run-tests-ext: bat
|
run-tests-ext: bat
|
||||||
# jython - disable for now since it takes too long to complete
|
|
||||||
# - os: ubuntu-latest
|
|
||||||
# python-impl: jython
|
|
||||||
# ytdl-test-set: download
|
|
||||||
# run-tests-ext: sh
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
if: ${{ matrix.python-impl == 'cpython' }}
|
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
- name: Set up Java 8
|
- name: Install pytest
|
||||||
if: ${{ matrix.python-impl == 'jython' }}
|
run: pip install pytest
|
||||||
uses: actions/setup-java@v1
|
|
||||||
with:
|
|
||||||
java-version: 8
|
|
||||||
- name: Install Jython
|
|
||||||
if: ${{ matrix.python-impl == 'jython' }}
|
|
||||||
run: |
|
|
||||||
wget http://search.maven.org/remotecontent?filepath=org/python/jython-installer/2.7.1/jython-installer-2.7.1.jar -O jython-installer.jar
|
|
||||||
java -jar jython-installer.jar -s -d "$HOME/jython"
|
|
||||||
echo "$HOME/jython/bin" >> $GITHUB_PATH
|
|
||||||
- name: Install nose
|
|
||||||
run: pip install nose
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
continue-on-error: ${{ matrix.ytdl-test-set == 'download' || matrix.python-impl == 'jython' }}
|
continue-on-error: true
|
||||||
env:
|
run: ./devscripts/run_tests.${{ matrix.run-tests-ext }} download
|
||||||
YTDL_TEST_SET: ${{ matrix.ytdl-test-set }}
|
|
||||||
run: ./devscripts/run_tests.${{ matrix.run-tests-ext }}
|
|
||||||
|
|||||||
10
.github/workflows/quick-test.yml
vendored
10
.github/workflows/quick-test.yml
vendored
@@ -11,12 +11,10 @@ jobs:
|
|||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.9
|
python-version: 3.9
|
||||||
- name: Install nose
|
- name: Install test requirements
|
||||||
run: pip install nose
|
run: pip install pytest pycryptodomex
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
env:
|
run: ./devscripts/run_tests.sh core
|
||||||
YTDL_TEST_SET: core
|
|
||||||
run: ./devscripts/run_tests.sh
|
|
||||||
flake8:
|
flake8:
|
||||||
name: Linter
|
name: Linter
|
||||||
if: "!contains(github.event.head_commit.message, 'ci skip all')"
|
if: "!contains(github.event.head_commit.message, 'ci skip all')"
|
||||||
@@ -29,5 +27,7 @@ jobs:
|
|||||||
python-version: 3.9
|
python-version: 3.9
|
||||||
- name: Install flake8
|
- name: Install flake8
|
||||||
run: pip install flake8
|
run: pip install flake8
|
||||||
|
- name: Make lazy extractors
|
||||||
|
run: python devscripts/make_lazy_extractors.py
|
||||||
- name: Run flake8
|
- name: Run flake8
|
||||||
run: flake8 .
|
run: flake8 .
|
||||||
102
.gitignore
vendored
102
.gitignore
vendored
@@ -1,6 +1,64 @@
|
|||||||
|
# Config
|
||||||
|
*.conf
|
||||||
|
cookies
|
||||||
|
*cookies.txt
|
||||||
|
.netrc
|
||||||
|
|
||||||
|
# Downloaded
|
||||||
|
*.annotations.xml
|
||||||
|
*.aria2
|
||||||
|
*.description
|
||||||
|
*.dump
|
||||||
|
*.frag
|
||||||
|
*.frag.aria2
|
||||||
|
*.frag.urls
|
||||||
|
*.info.json
|
||||||
|
*.live_chat.json
|
||||||
|
*.meta
|
||||||
|
*.part*
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
*.unknown_video
|
||||||
|
*.ytdl
|
||||||
|
.cache/
|
||||||
|
|
||||||
|
*.3gp
|
||||||
|
*.ape
|
||||||
|
*.avi
|
||||||
|
*.desktop
|
||||||
|
*.flac
|
||||||
|
*.flv
|
||||||
|
*.jpeg
|
||||||
|
*.jpg
|
||||||
|
*.m4a
|
||||||
|
*.m4v
|
||||||
|
*.mhtml
|
||||||
|
*.mkv
|
||||||
|
*.mov
|
||||||
|
*.mp3
|
||||||
|
*.mp4
|
||||||
|
*.ogg
|
||||||
|
*.opus
|
||||||
|
*.png
|
||||||
|
*.sbv
|
||||||
|
*.srt
|
||||||
|
*.swf
|
||||||
|
*.swp
|
||||||
|
*.ttml
|
||||||
|
*.url
|
||||||
|
*.vtt
|
||||||
|
*.wav
|
||||||
|
*.webloc
|
||||||
|
*.webm
|
||||||
|
*.webp
|
||||||
|
|
||||||
|
# Allow config/media files in testdata
|
||||||
|
!test/**
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
|
.pytest_cache
|
||||||
wine-py2exe/
|
wine-py2exe/
|
||||||
py2exe.log
|
py2exe.log
|
||||||
build/
|
build/
|
||||||
@@ -31,10 +89,10 @@ README.txt
|
|||||||
*.1
|
*.1
|
||||||
*.bash-completion
|
*.bash-completion
|
||||||
*.fish
|
*.fish
|
||||||
*.exe
|
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
*.zsh
|
*.zsh
|
||||||
*.spec
|
*.spec
|
||||||
|
test/testdata/sigs/player-*.js
|
||||||
|
|
||||||
# Binary
|
# Binary
|
||||||
/youtube-dl
|
/youtube-dl
|
||||||
@@ -43,48 +101,6 @@ README.txt
|
|||||||
yt-dlp.zip
|
yt-dlp.zip
|
||||||
*.exe
|
*.exe
|
||||||
|
|
||||||
# Downloaded
|
|
||||||
*.srt
|
|
||||||
*.ttml
|
|
||||||
*.sbv
|
|
||||||
*.vtt
|
|
||||||
*.flv
|
|
||||||
*.mp4
|
|
||||||
*.m4a
|
|
||||||
*.m4v
|
|
||||||
*.mp3
|
|
||||||
*.3gp
|
|
||||||
*.webm
|
|
||||||
*.wav
|
|
||||||
*.ape
|
|
||||||
*.mkv
|
|
||||||
*.swf
|
|
||||||
*.part
|
|
||||||
*.part-*
|
|
||||||
*.ytdl
|
|
||||||
*.dump
|
|
||||||
*.frag
|
|
||||||
*.frag.urls
|
|
||||||
*.aria2
|
|
||||||
*.swp
|
|
||||||
*.ogg
|
|
||||||
*.opus
|
|
||||||
*.info.json
|
|
||||||
*.live_chat.json
|
|
||||||
*.jpg
|
|
||||||
*.png
|
|
||||||
*.webp
|
|
||||||
*.annotations.xml
|
|
||||||
*.description
|
|
||||||
|
|
||||||
# Config
|
|
||||||
*.conf
|
|
||||||
*.spec
|
|
||||||
cookies
|
|
||||||
cookies.txt
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Text Editor / IDE
|
# Text Editor / IDE
|
||||||
.idea
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
|
|||||||
375
CONTRIBUTING.md
375
CONTRIBUTING.md
@@ -1,26 +1,61 @@
|
|||||||
**Please include the full output of youtube-dl when run with `-v`**, i.e. **add** `-v` flag to **your command line**, copy the **whole** output and post it in the issue body wrapped in \`\`\` for better formatting. It should look similar to this:
|
# CONTRIBUTING TO YT-DLP
|
||||||
|
|
||||||
|
- [OPENING AN ISSUE](#opening-an-issue)
|
||||||
|
- [Is the description of the issue itself sufficient?](#is-the-description-of-the-issue-itself-sufficient)
|
||||||
|
- [Are you using the latest version?](#are-you-using-the-latest-version)
|
||||||
|
- [Is the issue already documented?](#is-the-issue-already-documented)
|
||||||
|
- [Why are existing options not enough?](#why-are-existing-options-not-enough)
|
||||||
|
- [Have you read and understood the changes, between youtube-dl and yt-dlp](#have-you-read-and-understood-the-changes-between-youtube-dl-and-yt-dlp)
|
||||||
|
- [Is there enough context in your bug report?](#is-there-enough-context-in-your-bug-report)
|
||||||
|
- [Does the issue involve one problem, and one problem only?](#does-the-issue-involve-one-problem-and-one-problem-only)
|
||||||
|
- [Is anyone going to need the feature?](#is-anyone-going-to-need-the-feature)
|
||||||
|
- [Is your question about yt-dlp?](#is-your-question-about-yt-dlp)
|
||||||
|
- [Are you willing to share account details if needed?](#are-you-willing-to-share-account-details-if-needed)
|
||||||
|
- [DEVELOPER INSTRUCTIONS](#developer-instructions)
|
||||||
|
- [Adding new feature or making overarching changes](#adding-new-feature-or-making-overarching-changes)
|
||||||
|
- [Adding support for a new site](#adding-support-for-a-new-site)
|
||||||
|
- [yt-dlp coding conventions](#yt-dlp-coding-conventions)
|
||||||
|
- [Mandatory and optional metafields](#mandatory-and-optional-metafields)
|
||||||
|
- [Provide fallbacks](#provide-fallbacks)
|
||||||
|
- [Regular expressions](#regular-expressions)
|
||||||
|
- [Long lines policy](#long-lines-policy)
|
||||||
|
- [Quotes](#quotes)
|
||||||
|
- [Inline values](#inline-values)
|
||||||
|
- [Collapse fallbacks](#collapse-fallbacks)
|
||||||
|
- [Trailing parentheses](#trailing-parentheses)
|
||||||
|
- [Use convenience conversion and parsing functions](#use-convenience-conversion-and-parsing-functions)
|
||||||
|
- [EMBEDDING YT-DLP](README.md#embedding-yt-dlp)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# OPENING AN ISSUE
|
||||||
|
|
||||||
|
Bugs and suggestions should be reported at: [yt-dlp/yt-dlp/issues](https://github.com/yt-dlp/yt-dlp/issues). Unless you were prompted to or there is another pertinent reason (e.g. GitHub fails to accept the bug report), please do not send bug reports via personal email. For discussions, join us in our [discord server](https://discord.gg/H5MNcFW63r).
|
||||||
|
|
||||||
|
**Please include the full output of yt-dlp when run with `-vU`**, i.e. **add** `-vU` flag to **your command line**, copy the **whole** output and post it in the issue body wrapped in \`\`\` for better formatting. It should look similar to this:
|
||||||
```
|
```
|
||||||
$ youtube-dl -v <your command line>
|
$ yt-dlp -vU <your command line>
|
||||||
[debug] System config: []
|
[debug] Command-line config: ['-v', 'demo.com']
|
||||||
[debug] User config: []
|
[debug] Encodings: locale UTF-8, fs utf-8, out utf-8, pref UTF-8
|
||||||
[debug] Command-line args: [u'-v', u'https://www.youtube.com/watch?v=BaW_jenozKcj']
|
[debug] yt-dlp version 2021.09.25 (zip)
|
||||||
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
[debug] Python version 3.8.10 (CPython 64bit) - Linux-5.4.0-74-generic-x86_64-with-glibc2.29
|
||||||
[debug] youtube-dl version 2015.12.06
|
[debug] exe versions: ffmpeg 4.2.4, ffprobe 4.2.4
|
||||||
[debug] Git HEAD: 135392e
|
|
||||||
[debug] Python version 2.6.6 - Windows-2003Server-5.2.3790-SP2
|
|
||||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
|
||||||
[debug] Proxy map: {}
|
[debug] Proxy map: {}
|
||||||
|
Current Build Hash 25cc412d1d3c0725a1f2f5b7e4682f6fb40e6d15f7024e96f7afd572e9919535
|
||||||
|
yt-dlp is up to date (2021.09.25)
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
**Do not post screenshots of verbose logs; only plain text is acceptable.**
|
**Do not post screenshots of verbose logs; only plain text is acceptable.**
|
||||||
|
|
||||||
The output (including the first lines) contains important debugging information. Issues without the full output are often not reproducible and therefore do not get solved in short order, if ever.
|
The output (including the first lines) contains important debugging information. Issues without the full output are often not reproducible and therefore will be closed as `incomplete`.
|
||||||
|
|
||||||
|
The templates provided for the Issues, should be completed and **not removed**, this helps aide the resolution of the issue.
|
||||||
|
|
||||||
Please re-read your issue once again to avoid a couple of common mistakes (you can and should use this as a checklist):
|
Please re-read your issue once again to avoid a couple of common mistakes (you can and should use this as a checklist):
|
||||||
|
|
||||||
### Is the description of the issue itself sufficient?
|
### Is the description of the issue itself sufficient?
|
||||||
|
|
||||||
We often get issue reports that we cannot really decipher. While in most cases we eventually get the required information after asking back multiple times, this poses an unnecessary drain on our resources. Many contributors, including myself, are also not native speakers, so we may misread some parts.
|
We often get issue reports that we cannot really decipher. While in most cases we eventually get the required information after asking back multiple times, this poses an unnecessary drain on our resources.
|
||||||
|
|
||||||
So please elaborate on what feature you are requesting, or what bug you want to be fixed. Make sure that it's obvious
|
So please elaborate on what feature you are requesting, or what bug you want to be fixed. Make sure that it's obvious
|
||||||
|
|
||||||
@@ -28,25 +63,31 @@ So please elaborate on what feature you are requesting, or what bug you want to
|
|||||||
- How it could be fixed
|
- How it could be fixed
|
||||||
- How your proposed solution would look like
|
- How your proposed solution would look like
|
||||||
|
|
||||||
If your report is shorter than two lines, it is almost certainly missing some of these, which makes it hard for us to respond to it. We're often too polite to close the issue outright, but the missing info makes misinterpretation likely. As a committer myself, I often get frustrated by these issues, since the only possible way for me to move forward on them is to ask for clarification over and over.
|
If your report is shorter than two lines, it is almost certainly missing some of these, which makes it hard for us to respond to it. We're often too polite to close the issue outright, but the missing info makes misinterpretation likely. We often get frustrated by these issues, since the only possible way for us to move forward on them is to ask for clarification over and over.
|
||||||
|
|
||||||
For bug reports, this means that your report should contain the *complete* output of youtube-dl when called with the `-v` flag. The error message you get for (most) bugs even says so, but you would not believe how many of our bug reports do not contain this information.
|
For bug reports, this means that your report should contain the **complete** output of yt-dlp when called with the `-vU` flag. The error message you get for (most) bugs even says so, but you would not believe how many of our bug reports do not contain this information.
|
||||||
|
|
||||||
If your server has multiple IPs or you suspect censorship, adding `--call-home` may be a good idea to get more diagnostics. If the error is `ERROR: Unable to extract ...` and you cannot reproduce it from multiple countries, add `--dump-pages` (warning: this will yield a rather large output, redirect it to the file `log.txt` by adding `>log.txt 2>&1` to your command-line) or upload the `.dump` files you get when you add `--write-pages` [somewhere](https://gist.github.com/).
|
If the error is `ERROR: Unable to extract ...` and you cannot reproduce it from multiple countries, add `--write-pages` and upload the `.dump` files you get [somewhere](https://gist.github.com).
|
||||||
|
|
||||||
**Site support requests must contain an example URL**. An example URL is a URL you might want to download, like `https://www.youtube.com/watch?v=BaW_jenozKc`. There should be an obvious video present. Except under very special circumstances, the main page of a video service (e.g. `https://www.youtube.com/`) is *not* an example URL.
|
**Site support requests must contain an example URL**. An example URL is a URL you might want to download, like `https://www.youtube.com/watch?v=BaW_jenozKc`. There should be an obvious video present. Except under very special circumstances, the main page of a video service (e.g. `https://www.youtube.com/`) is *not* an example URL.
|
||||||
|
|
||||||
### Are you using the latest version?
|
### Are you using the latest version?
|
||||||
|
|
||||||
Before reporting any issue, type `youtube-dl -U`. This should report that you're up-to-date. About 20% of the reports we receive are already fixed, but people are using outdated versions. This goes for feature requests as well.
|
Before reporting any issue, type `yt-dlp -U`. This should report that you're up-to-date. This goes for feature requests as well.
|
||||||
|
|
||||||
### Is the issue already documented?
|
### Is the issue already documented?
|
||||||
|
|
||||||
Make sure that someone has not already opened the issue you're trying to open. Search at the top of the window or browse the [GitHub Issues](https://github.com/ytdl-org/youtube-dl/search?type=Issues) of this repository. If there is an issue, feel free to write something along the lines of "This affects me as well, with version 2015.01.01. Here is some more information on the issue: ...". While some issues may be old, a new post into them often spurs rapid activity.
|
Make sure that someone has not already opened the issue you're trying to open. Search at the top of the window or browse the [GitHub Issues](https://github.com/yt-dlp/yt-dlp/search?type=Issues) of this repository. If there is an issue, feel free to write something along the lines of "This affects me as well, with version 2021.01.01. Here is some more information on the issue: ...". While some issues may be old, a new post into them often spurs rapid activity.
|
||||||
|
|
||||||
|
Additionally, it is also helpful to see if the issue has already been documented in the [youtube-dl issue tracker](https://github.com/ytdl-org/youtube-dl/issues). If similar issues have already been reported in youtube-dl (but not in our issue tracker), links to them can be included in your issue report here.
|
||||||
|
|
||||||
### Why are existing options not enough?
|
### Why are existing options not enough?
|
||||||
|
|
||||||
Before requesting a new feature, please have a quick peek at [the list of supported options](https://github.com/ytdl-org/youtube-dl/blob/master/README.md#options). Many feature requests are for features that actually exist already! Please, absolutely do show off your work in the issue report and detail how the existing similar options do *not* solve your problem.
|
Before requesting a new feature, please have a quick peek at [the list of supported options](README.md#usage-and-options). Many feature requests are for features that actually exist already! Please, absolutely do show off your work in the issue report and detail how the existing similar options do *not* solve your problem.
|
||||||
|
|
||||||
|
### Have you read and understood the changes, between youtube-dl and yt-dlp
|
||||||
|
|
||||||
|
There are many changes between youtube-dl and yt-dlp [(changes to default behavior)](README.md#differences-in-default-behavior), and some of the options available have a different behaviour in yt-dlp, or have been removed all together [(list of changes to options)](README.md#deprecated-options). Make sure you have read and understand the differences in the options and how this may impact your downloads before opening an issue.
|
||||||
|
|
||||||
### Is there enough context in your bug report?
|
### Is there enough context in your bug report?
|
||||||
|
|
||||||
@@ -58,68 +99,86 @@ We are then presented with a very complicated request when the original problem
|
|||||||
|
|
||||||
Some of our users seem to think there is a limit of issues they can or should open. There is no limit of issues they can or should open. While it may seem appealing to be able to dump all your issues into one ticket, that means that someone who solves one of your issues cannot mark the issue as closed. Typically, reporting a bunch of issues leads to the ticket lingering since nobody wants to attack that behemoth, until someone mercifully splits the issue into multiple ones.
|
Some of our users seem to think there is a limit of issues they can or should open. There is no limit of issues they can or should open. While it may seem appealing to be able to dump all your issues into one ticket, that means that someone who solves one of your issues cannot mark the issue as closed. Typically, reporting a bunch of issues leads to the ticket lingering since nobody wants to attack that behemoth, until someone mercifully splits the issue into multiple ones.
|
||||||
|
|
||||||
In particular, every site support request issue should only pertain to services at one site (generally under a common domain, but always using the same backend technology). Do not request support for vimeo user videos, White house podcasts, and Google Plus pages in the same issue. Also, make sure that you don't post bug reports alongside feature requests. As a rule of thumb, a feature request does not include outputs of youtube-dl that are not immediately related to the feature at hand. Do not post reports of a network error alongside the request for a new video service.
|
In particular, every site support request issue should only pertain to services at one site (generally under a common domain, but always using the same backend technology). Do not request support for vimeo user videos, White house podcasts, and Google Plus pages in the same issue. Also, make sure that you don't post bug reports alongside feature requests. As a rule of thumb, a feature request does not include outputs of yt-dlp that are not immediately related to the feature at hand. Do not post reports of a network error alongside the request for a new video service.
|
||||||
|
|
||||||
### Is anyone going to need the feature?
|
### Is anyone going to need the feature?
|
||||||
|
|
||||||
Only post features that you (or an incapacitated friend you can personally talk to) require. Do not post features because they seem like a good idea. If they are really useful, they will be requested by someone who requires them.
|
Only post features that you (or an incapacitated friend you can personally talk to) require. Do not post features because they seem like a good idea. If they are really useful, they will be requested by someone who requires them.
|
||||||
|
|
||||||
### Is your question about youtube-dl?
|
### Is your question about yt-dlp?
|
||||||
|
|
||||||
|
Some bug reports are completely unrelated to yt-dlp and relate to a different, or even the reporter's own, application. Please make sure that you are actually using yt-dlp. If you are using a UI for yt-dlp, report the bug to the maintainer of the actual application providing the UI. In general, if you are unable to provide the verbose log, you should not be opening the issue here.
|
||||||
|
|
||||||
|
If the issue is with `youtube-dl` (the upstream fork of yt-dlp) and not with yt-dlp, the issue should be raised in the youtube-dl project.
|
||||||
|
|
||||||
|
### Are you willing to share account details if needed?
|
||||||
|
|
||||||
|
The maintainers and potential contributors of the project often do not have an account for the website you are asking support for. So any developer interested in solving your issue may ask you for account details. It is your personal discretion whether you are willing to share the account in order for the developer to try and solve your issue. However, if you are unwilling or unable to provide details, they obviously cannot work on the issue and it cannot be solved unless some developer who both has an account and is willing/able to contribute decides to solve it.
|
||||||
|
|
||||||
|
By sharing an account with anyone, you agree to bear all risks associated with it. The maintainers and yt-dlp can't be held responsible for any misuse of the credentials.
|
||||||
|
|
||||||
|
While these steps won't necessarily ensure that no misuse of the account takes place, these are still some good practices to follow.
|
||||||
|
|
||||||
|
- Look for people with `Member` (maintainers of the project) or `Contributor` (people who have previously contributed code) tag on their messages.
|
||||||
|
- Change the password before sharing the account to something random (use [this](https://passwordsgenerator.net/) if you don't have a random password generator).
|
||||||
|
- Change the password after receiving the account back.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
It may sound strange, but some bug reports we receive are completely unrelated to youtube-dl and relate to a different, or even the reporter's own, application. Please make sure that you are actually using youtube-dl. If you are using a UI for youtube-dl, report the bug to the maintainer of the actual application providing the UI. On the other hand, if your UI for youtube-dl fails in some way you believe is related to youtube-dl, by all means, go ahead and report the bug.
|
|
||||||
|
|
||||||
# DEVELOPER INSTRUCTIONS
|
# DEVELOPER INSTRUCTIONS
|
||||||
|
|
||||||
Most users do not need to build youtube-dl and can [download the builds](https://ytdl-org.github.io/youtube-dl/download.html) or get them from their distribution.
|
Most users do not need to build yt-dlp and can [download the builds](https://github.com/yt-dlp/yt-dlp/releases) or get them via [the other installation methods](README.md#installation).
|
||||||
|
|
||||||
To run youtube-dl as a developer, you don't need to build anything either. Simply execute
|
To run yt-dlp as a developer, you don't need to build anything either. Simply execute
|
||||||
|
|
||||||
python -m youtube_dl
|
python -m yt_dlp
|
||||||
|
|
||||||
To run the test, simply invoke your favorite test runner, or execute a test file directly; any of the following work:
|
To run the test, simply invoke your favorite test runner, or execute a test file directly; any of the following work:
|
||||||
|
|
||||||
python -m unittest discover
|
python -m unittest discover
|
||||||
python test/test_download.py
|
python test/test_download.py
|
||||||
nosetests
|
nosetests
|
||||||
|
pytest
|
||||||
|
|
||||||
See item 6 of [new extractor tutorial](#adding-support-for-a-new-site) for how to run extractor specific test cases.
|
See item 6 of [new extractor tutorial](#adding-support-for-a-new-site) for how to run extractor specific test cases.
|
||||||
|
|
||||||
If you want to create a build of youtube-dl yourself, you'll need
|
If you want to create a build of yt-dlp yourself, you can follow the instructions [here](README.md#compile).
|
||||||
|
|
||||||
* python
|
|
||||||
* make (only GNU make is supported)
|
|
||||||
* pandoc
|
|
||||||
* zip
|
|
||||||
* nosetests
|
|
||||||
|
|
||||||
### Adding support for a new site
|
## Adding new feature or making overarching changes
|
||||||
|
|
||||||
If you want to add support for a new site, first of all **make sure** this site is **not dedicated to [copyright infringement](README.md#can-you-add-support-for-this-anime-video-site-or-site-which-shows-current-movies-for-free)**. youtube-dl does **not support** such sites thus pull requests adding support for them **will be rejected**.
|
Before you start writing code for implementing a new feature, open an issue explaining your feature request and atleast one use case. This allows the maintainers to decide whether such a feature is desired for the project in the first place, and will provide an avenue to discuss some implementation details. If you open a pull request for a new feature without discussing with us first, do not be surprised when we ask for large changes to the code, or even reject it outright.
|
||||||
|
|
||||||
|
The same applies for changes to the documentation, code style, or overarching changes to the architecture
|
||||||
|
|
||||||
|
|
||||||
|
## Adding support for a new site
|
||||||
|
|
||||||
|
If you want to add support for a new site, first of all **make sure** this site is **not dedicated to [copyright infringement](https://www.github.com/ytdl-org/youtube-dl#can-you-add-support-for-this-anime-video-site-or-site-which-shows-current-movies-for-free)**. yt-dlp does **not support** such sites thus pull requests adding support for them **will be rejected**.
|
||||||
|
|
||||||
After you have ensured this site is distributing its content legally, you can follow this quick list (assuming your service is called `yourextractor`):
|
After you have ensured this site is distributing its content legally, you can follow this quick list (assuming your service is called `yourextractor`):
|
||||||
|
|
||||||
1. [Fork this repository](https://github.com/ytdl-org/youtube-dl/fork)
|
1. [Fork this repository](https://github.com/yt-dlp/yt-dlp/fork)
|
||||||
2. Check out the source code with:
|
1. Check out the source code with:
|
||||||
|
|
||||||
git clone git@github.com:YOUR_GITHUB_USERNAME/youtube-dl.git
|
git clone git@github.com:YOUR_GITHUB_USERNAME/yt-dlp.git
|
||||||
|
|
||||||
3. Start a new git branch with
|
1. Start a new git branch with
|
||||||
|
|
||||||
cd youtube-dl
|
cd yt-dlp
|
||||||
git checkout -b yourextractor
|
git checkout -b yourextractor
|
||||||
|
|
||||||
4. Start with this simple template and save it to `youtube_dl/extractor/yourextractor.py`:
|
1. Start with this simple template and save it to `yt_dlp/extractor/yourextractor.py`:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
|
|
||||||
|
|
||||||
class YourExtractorIE(InfoExtractor):
|
class YourExtractorIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://(?:www\.)?yourextractor\.com/watch/(?P<id>[0-9]+)'
|
_VALID_URL = r'https?://(?:www\.)?yourextractor\.com/watch/(?P<id>[0-9]+)'
|
||||||
_TEST = {
|
_TESTS = [{
|
||||||
'url': 'https://yourextractor.com/watch/42',
|
'url': 'https://yourextractor.com/watch/42',
|
||||||
'md5': 'TODO: md5 sum of the first 10241 bytes of the video file (use --test)',
|
'md5': 'TODO: md5 sum of the first 10241 bytes of the video file (use --test)',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
@@ -133,7 +192,7 @@ After you have ensured this site is distributing its content legally, you can fo
|
|||||||
# * A regular expression; start the string with re:
|
# * A regular expression; start the string with re:
|
||||||
# * Any Python type (for example int or float)
|
# * Any Python type (for example int or float)
|
||||||
}
|
}
|
||||||
}
|
}]
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
video_id = self._match_id(url)
|
video_id = self._match_id(url)
|
||||||
@@ -147,45 +206,59 @@ After you have ensured this site is distributing its content legally, you can fo
|
|||||||
'title': title,
|
'title': title,
|
||||||
'description': self._og_search_description(webpage),
|
'description': self._og_search_description(webpage),
|
||||||
'uploader': self._search_regex(r'<div[^>]+id="uploader"[^>]*>([^<]+)<', webpage, 'uploader', fatal=False),
|
'uploader': self._search_regex(r'<div[^>]+id="uploader"[^>]*>([^<]+)<', webpage, 'uploader', fatal=False),
|
||||||
# TODO more properties (see youtube_dl/extractor/common.py)
|
# TODO more properties (see yt_dlp/extractor/common.py)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
5. Add an import in [`youtube_dl/extractor/extractors.py`](https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/extractor/extractors.py).
|
1. Add an import in [`yt_dlp/extractor/extractors.py`](yt_dlp/extractor/extractors.py).
|
||||||
6. Run `python test/test_download.py TestDownload.test_YourExtractor`. This *should fail* at first, but you can continually re-run it until you're done. If you decide to add more than one test, then rename ``_TEST`` to ``_TESTS`` and make it into a list of dictionaries. The tests will then be named `TestDownload.test_YourExtractor`, `TestDownload.test_YourExtractor_1`, `TestDownload.test_YourExtractor_2`, etc. Note that tests with `only_matching` key in test's dict are not counted in.
|
1. Run `python test/test_download.py TestDownload.test_YourExtractor`. This *should fail* at first, but you can continually re-run it until you're done. If you decide to add more than one test, the tests will then be named `TestDownload.test_YourExtractor`, `TestDownload.test_YourExtractor_1`, `TestDownload.test_YourExtractor_2`, etc. Note that tests with `only_matching` key in test's dict are not counted in. You can also run all the tests in one go with `TestDownload.test_YourExtractor_all`
|
||||||
7. Have a look at [`youtube_dl/extractor/common.py`](https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/extractor/common.py) for possible helper methods and a [detailed description of what your extractor should and may return](https://github.com/ytdl-org/youtube-dl/blob/7f41a598b3fba1bcab2817de64a08941200aa3c8/youtube_dl/extractor/common.py#L94-L303). Add tests and code for as many as you want.
|
1. Make sure you have atleast one test for your extractor. Even if all videos covered by the extractor are expected to be inaccessible for automated testing, tests should still be added with a `skip` parameter indicating why the particular test is disabled from running.
|
||||||
8. Make sure your code follows [youtube-dl coding conventions](#youtube-dl-coding-conventions) and check the code with [flake8](https://flake8.pycqa.org/en/latest/index.html#quickstart):
|
1. Have a look at [`yt_dlp/extractor/common.py`](yt_dlp/extractor/common.py) for possible helper methods and a [detailed description of what your extractor should and may return](yt_dlp/extractor/common.py#L91-L426). Add tests and code for as many as you want.
|
||||||
|
1. Make sure your code follows [yt-dlp coding conventions](#yt-dlp-coding-conventions) and check the code with [flake8](https://flake8.pycqa.org/en/latest/index.html#quickstart):
|
||||||
|
|
||||||
$ flake8 youtube_dl/extractor/yourextractor.py
|
$ flake8 yt_dlp/extractor/yourextractor.py
|
||||||
|
|
||||||
9. Make sure your code works under all [Python](https://www.python.org/) versions claimed supported by youtube-dl, namely 2.6, 2.7, and 3.2+.
|
1. Make sure your code works under all [Python](https://www.python.org/) versions supported by yt-dlp, namely CPython and PyPy for Python 3.6 and above. Backward compatibility is not required for even older versions of Python.
|
||||||
10. When the tests pass, [add](https://git-scm.com/docs/git-add) the new files and [commit](https://git-scm.com/docs/git-commit) them and [push](https://git-scm.com/docs/git-push) the result, like this:
|
1. When the tests pass, [add](https://git-scm.com/docs/git-add) the new files, [commit](https://git-scm.com/docs/git-commit) them and [push](https://git-scm.com/docs/git-push) the result, like this:
|
||||||
|
|
||||||
$ git add youtube_dl/extractor/extractors.py
|
$ git add yt_dlp/extractor/extractors.py
|
||||||
$ git add youtube_dl/extractor/yourextractor.py
|
$ git add yt_dlp/extractor/yourextractor.py
|
||||||
$ git commit -m '[yourextractor] Add new extractor'
|
$ git commit -m '[yourextractor] Add extractor'
|
||||||
$ git push origin yourextractor
|
$ git push origin yourextractor
|
||||||
|
|
||||||
11. Finally, [create a pull request](https://help.github.com/articles/creating-a-pull-request). We'll then review and merge it.
|
1. Finally, [create a pull request](https://help.github.com/articles/creating-a-pull-request). We'll then review and merge it.
|
||||||
|
|
||||||
In any case, thank you very much for your contributions!
|
In any case, thank you very much for your contributions!
|
||||||
|
|
||||||
## youtube-dl coding conventions
|
**Tip:** To test extractors that require login information, create a file `test/local_parameters.json` and add `"usenetrc": true` or your username and password in it:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"username": "your user name",
|
||||||
|
"password": "your password"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## yt-dlp coding conventions
|
||||||
|
|
||||||
This section introduces a guide lines for writing idiomatic, robust and future-proof extractor code.
|
This section introduces a guide lines for writing idiomatic, robust and future-proof extractor code.
|
||||||
|
|
||||||
Extractors are very fragile by nature since they depend on the layout of the source data provided by 3rd party media hosters out of your control and this layout tends to change. As an extractor implementer your task is not only to write code that will extract media links and metadata correctly but also to minimize dependency on the source's layout and even to make the code foresee potential future changes and be ready for that. This is important because it will allow the extractor not to break on minor layout changes thus keeping old youtube-dl versions working. Even though this breakage issue is easily fixed by emitting a new version of youtube-dl with a fix incorporated, all the previous versions become broken in all repositories and distros' packages that may not be so prompt in fetching the update from us. Needless to say, some non rolling release distros may never receive an update at all.
|
Extractors are very fragile by nature since they depend on the layout of the source data provided by 3rd party media hosters out of your control and this layout tends to change. As an extractor implementer your task is not only to write code that will extract media links and metadata correctly but also to minimize dependency on the source's layout and even to make the code foresee potential future changes and be ready for that. This is important because it will allow the extractor not to break on minor layout changes thus keeping old yt-dlp versions working. Even though this breakage issue may be easily fixed by a new version of yt-dlp, this could take some time, during which the the extractor will remain broken.
|
||||||
|
|
||||||
|
|
||||||
### Mandatory and optional metafields
|
### Mandatory and optional metafields
|
||||||
|
|
||||||
For extraction to work youtube-dl relies on metadata your extractor extracts and provides to youtube-dl expressed by an [information dictionary](https://github.com/ytdl-org/youtube-dl/blob/7f41a598b3fba1bcab2817de64a08941200aa3c8/youtube_dl/extractor/common.py#L94-L303) or simply *info dict*. Only the following meta fields in the *info dict* are considered mandatory for a successful extraction process by youtube-dl:
|
For extraction to work yt-dlp relies on metadata your extractor extracts and provides to yt-dlp expressed by an [information dictionary](yt_dlp/extractor/common.py#L91-L426) or simply *info dict*. Only the following meta fields in the *info dict* are considered mandatory for a successful extraction process by yt-dlp:
|
||||||
|
|
||||||
- `id` (media identifier)
|
- `id` (media identifier)
|
||||||
- `title` (media title)
|
- `title` (media title)
|
||||||
- `url` (media download URL) or `formats`
|
- `url` (media download URL) or `formats`
|
||||||
|
|
||||||
In fact only the last option is technically mandatory (i.e. if you can't figure out the download location of the media the extraction does not make any sense). But by convention youtube-dl also treats `id` and `title` as mandatory. Thus the aforementioned metafields are the critical data that the extraction does not make any sense without and if any of them fail to be extracted then the extractor is considered completely broken.
|
The aforementioned metafields are the critical data that the extraction does not make any sense without and if any of them fail to be extracted then the extractor is considered completely broken. While all extractors must return a `title`, they must also allow it's extraction to be non-fatal.
|
||||||
|
|
||||||
[Any field](https://github.com/ytdl-org/youtube-dl/blob/7f41a598b3fba1bcab2817de64a08941200aa3c8/youtube_dl/extractor/common.py#L188-L303) apart from the aforementioned ones are considered **optional**. That means that extraction should be **tolerant** to situations when sources for these fields can potentially be unavailable (even if they are always available at the moment) and **future-proof** in order not to break the extraction of general purpose mandatory fields.
|
For pornographic sites, appropriate `age_limit` must also be returned.
|
||||||
|
|
||||||
|
The extractor is allowed to return the info dict without url or formats in some special cases if it allows the user to extract usefull information with `--ignore-no-formats-error` - Eg: when the video is a live stream that has not started yet.
|
||||||
|
|
||||||
|
[Any field](yt_dlp/extractor/common.py#219-L426) apart from the aforementioned ones are considered **optional**. That means that extraction should be **tolerant** to situations when sources for these fields can potentially be unavailable (even if they are always available at the moment) and **future-proof** in order not to break the extraction of general purpose mandatory fields.
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
@@ -199,8 +272,10 @@ Assume at this point `meta`'s layout is:
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
{
|
{
|
||||||
...
|
|
||||||
"summary": "some fancy summary text",
|
"summary": "some fancy summary text",
|
||||||
|
"user": {
|
||||||
|
"name": "uploader name"
|
||||||
|
},
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -219,6 +294,30 @@ description = meta['summary'] # incorrect
|
|||||||
|
|
||||||
The latter will break extraction process with `KeyError` if `summary` disappears from `meta` at some later time but with the former approach extraction will just go ahead with `description` set to `None` which is perfectly fine (remember `None` is equivalent to the absence of data).
|
The latter will break extraction process with `KeyError` if `summary` disappears from `meta` at some later time but with the former approach extraction will just go ahead with `description` set to `None` which is perfectly fine (remember `None` is equivalent to the absence of data).
|
||||||
|
|
||||||
|
|
||||||
|
If the data is nested, do not use `.get` chains, but instead make use of the utility functions `try_get` or `traverse_obj`
|
||||||
|
|
||||||
|
Considering the above `meta` again, assume you want to extract `["user"]["name"]` and put it in the resulting info dict as `uploader`
|
||||||
|
|
||||||
|
```python
|
||||||
|
uploader = try_get(meta, lambda x: x['user']['name']) # correct
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```python
|
||||||
|
uploader = traverse_obj(meta, ('user', 'name')) # correct
|
||||||
|
```
|
||||||
|
|
||||||
|
and not like:
|
||||||
|
|
||||||
|
```python
|
||||||
|
uploader = meta['user']['name'] # incorrect
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```python
|
||||||
|
uploader = meta.get('user', {}).get('name') # incorrect
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Similarly, you should pass `fatal=False` when extracting optional data from a webpage with `_search_regex`, `_html_search_regex` or similar methods, for instance:
|
Similarly, you should pass `fatal=False` when extracting optional data from a webpage with `_search_regex`, `_html_search_regex` or similar methods, for instance:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -239,10 +338,35 @@ description = self._search_regex(
|
|||||||
|
|
||||||
On failure this code will silently continue the extraction with `description` set to `None`. That is useful for metafields that may or may not be present.
|
On failure this code will silently continue the extraction with `description` set to `None`. That is useful for metafields that may or may not be present.
|
||||||
|
|
||||||
|
|
||||||
|
Another thing to remember is not to try to iterate over `None`
|
||||||
|
|
||||||
|
Say you extracted a list of thumbnails into `thumbnail_data` using `try_get` and now want to iterate over them
|
||||||
|
|
||||||
|
```python
|
||||||
|
thumbnail_data = try_get(...)
|
||||||
|
thumbnails = [{
|
||||||
|
'url': item['url']
|
||||||
|
} for item in thumbnail_data or []] # correct
|
||||||
|
```
|
||||||
|
|
||||||
|
and not like:
|
||||||
|
|
||||||
|
```python
|
||||||
|
thumbnail_data = try_get(...)
|
||||||
|
thumbnails = [{
|
||||||
|
'url': item['url']
|
||||||
|
} for item in thumbnail_data] # incorrect
|
||||||
|
```
|
||||||
|
|
||||||
|
In the later case, `thumbnail_data` will be `None` if the field was not found and this will cause the loop `for item in thumbnail_data` to raise a fatal error. Using `for item in thumbnail_data or []` avoids this error and results in setting an empty list in `thumbnails` instead.
|
||||||
|
|
||||||
|
|
||||||
### Provide fallbacks
|
### Provide fallbacks
|
||||||
|
|
||||||
When extracting metadata try to do so from multiple sources. For example if `title` is present in several places, try extracting from at least some of them. This makes it more future-proof in case some of the sources become unavailable.
|
When extracting metadata try to do so from multiple sources. For example if `title` is present in several places, try extracting from at least some of them. This makes it more future-proof in case some of the sources become unavailable.
|
||||||
|
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
Say `meta` from the previous example has a `title` and you are about to extract it. Since `title` is a mandatory meta field you should end up with something like:
|
Say `meta` from the previous example has a `title` and you are about to extract it. Since `title` is a mandatory meta field you should end up with something like:
|
||||||
@@ -261,6 +385,7 @@ title = meta.get('title') or self._og_search_title(webpage)
|
|||||||
|
|
||||||
This code will try to extract from `meta` first and if it fails it will try extracting `og:title` from a `webpage`.
|
This code will try to extract from `meta` first and if it fails it will try extracting `og:title` from a `webpage`.
|
||||||
|
|
||||||
|
|
||||||
### Regular expressions
|
### Regular expressions
|
||||||
|
|
||||||
#### Don't capture groups you don't use
|
#### Don't capture groups you don't use
|
||||||
@@ -282,7 +407,6 @@ Incorrect:
|
|||||||
r'(id|ID)=(?P<id>\d+)'
|
r'(id|ID)=(?P<id>\d+)'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#### Make regular expressions relaxed and flexible
|
#### Make regular expressions relaxed and flexible
|
||||||
|
|
||||||
When using regular expressions try to write them fuzzy, relaxed and flexible, skipping insignificant parts that are more likely to change, allowing both single and double quotes for quoted values and so on.
|
When using regular expressions try to write them fuzzy, relaxed and flexible, skipping insignificant parts that are more likely to change, allowing both single and double quotes for quoted values and so on.
|
||||||
@@ -298,14 +422,14 @@ Say you need to extract `title` from the following HTML code:
|
|||||||
The code for that task should look similar to:
|
The code for that task should look similar to:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
title = self._search_regex(
|
title = self._search_regex( # correct
|
||||||
r'<span[^>]+class="title"[^>]*>([^<]+)', webpage, 'title')
|
r'<span[^>]+class="title"[^>]*>([^<]+)', webpage, 'title')
|
||||||
```
|
```
|
||||||
|
|
||||||
Or even better:
|
Or even better:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
title = self._search_regex(
|
title = self._search_regex( # correct
|
||||||
r'<span[^>]+class=(["\'])title\1[^>]*>(?P<title>[^<]+)',
|
r'<span[^>]+class=(["\'])title\1[^>]*>(?P<title>[^<]+)',
|
||||||
webpage, 'title', group='title')
|
webpage, 'title', group='title')
|
||||||
```
|
```
|
||||||
@@ -315,17 +439,32 @@ Note how you tolerate potential changes in the `style` attribute's value or swit
|
|||||||
The code definitely should not look like:
|
The code definitely should not look like:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
title = self._search_regex(
|
title = self._search_regex( # incorrect
|
||||||
r'<span style="position: absolute; left: 910px; width: 90px; float: right; z-index: 9999;" class="title">(.*?)</span>',
|
r'<span style="position: absolute; left: 910px; width: 90px; float: right; z-index: 9999;" class="title">(.*?)</span>',
|
||||||
webpage, 'title', group='title')
|
webpage, 'title', group='title')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
or even
|
||||||
|
|
||||||
|
```python
|
||||||
|
title = self._search_regex( # incorrect
|
||||||
|
r'<span style=".*?" class="title">(.*?)</span>',
|
||||||
|
webpage, 'title', group='title')
|
||||||
|
```
|
||||||
|
|
||||||
|
Here the presence or absence of other attributes including `style` is irrelevent for the data we need, and so the regex must not depend on it
|
||||||
|
|
||||||
|
|
||||||
### Long lines policy
|
### Long lines policy
|
||||||
|
|
||||||
There is a soft limit to keep lines of code under 80 characters long. This means it should be respected if possible and if it does not make readability and code maintenance worse.
|
There is a soft limit to keep lines of code under 100 characters long. This means it should be respected if possible and if it does not make readability and code maintenance worse. Sometimes, it may be reasonable to go upto 120 characters and sometimes even 80 can be unreadable. Keep in mind that this is not a hard limit and is just one of many tools to make the code more readable.
|
||||||
|
|
||||||
For example, you should **never** split long string literals like URLs or some other often copied entities over multiple lines to fit this limit:
|
For example, you should **never** split long string literals like URLs or some other often copied entities over multiple lines to fit this limit:
|
||||||
|
|
||||||
|
Conversely, don't unecessarily split small lines further. As a rule of thumb, if removing the line split keeps the code under 80 characters, it should be a single line.
|
||||||
|
|
||||||
|
##### Examples
|
||||||
|
|
||||||
Correct:
|
Correct:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -339,6 +478,47 @@ Incorrect:
|
|||||||
'PLMYEtVRpaqY00V9W81Cwmzp6N6vZqfUKD4'
|
'PLMYEtVRpaqY00V9W81Cwmzp6N6vZqfUKD4'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Correct:
|
||||||
|
|
||||||
|
```python
|
||||||
|
uploader = traverse_obj(info, ('uploader', 'name'), ('author', 'fullname'))
|
||||||
|
```
|
||||||
|
|
||||||
|
Incorrect:
|
||||||
|
|
||||||
|
```python
|
||||||
|
uploader = traverse_obj(
|
||||||
|
info,
|
||||||
|
('uploader', 'name'),
|
||||||
|
('author', 'fullname'))
|
||||||
|
```
|
||||||
|
|
||||||
|
Correct:
|
||||||
|
|
||||||
|
```python
|
||||||
|
formats = self._extract_m3u8_formats(
|
||||||
|
m3u8_url, video_id, 'mp4', 'm3u8_native', m3u8_id='hls',
|
||||||
|
note='Downloading HD m3u8 information', errnote='Unable to download HD m3u8 information')
|
||||||
|
```
|
||||||
|
|
||||||
|
Incorrect:
|
||||||
|
|
||||||
|
```python
|
||||||
|
formats = self._extract_m3u8_formats(m3u8_url,
|
||||||
|
video_id,
|
||||||
|
'mp4',
|
||||||
|
'm3u8_native',
|
||||||
|
m3u8_id='hls',
|
||||||
|
note='Downloading HD m3u8 information',
|
||||||
|
errnote='Unable to download HD m3u8 information')
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Quotes
|
||||||
|
|
||||||
|
Always use single quotes for strings (even if the string has `'`) and double quotes for docstrings. Use `'''` only for multi-line strings. An exception can be made if a string has multiple single quotes in it and escaping makes it significantly harder to read. For f-strings, use you can use double quotes on the inside. But avoid f-strings that have too many quotes inside.
|
||||||
|
|
||||||
|
|
||||||
### Inline values
|
### Inline values
|
||||||
|
|
||||||
Extracting variables is acceptable for reducing code duplication and improving readability of complex expressions. However, you should avoid extracting variables used only once and moving them to opposite parts of the extractor file, which makes reading the linear flow difficult.
|
Extracting variables is acceptable for reducing code duplication and improving readability of complex expressions. However, you should avoid extracting variables used only once and moving them to opposite parts of the extractor file, which makes reading the linear flow difficult.
|
||||||
@@ -359,6 +539,7 @@ TITLE_RE = r'<title>([^<]+)</title>'
|
|||||||
title = self._html_search_regex(TITLE_RE, webpage, 'title')
|
title = self._html_search_regex(TITLE_RE, webpage, 'title')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Collapse fallbacks
|
### Collapse fallbacks
|
||||||
|
|
||||||
Multiple fallback values can quickly become unwieldy. Collapse multiple fallback values into a single expression via a list of patterns.
|
Multiple fallback values can quickly become unwieldy. Collapse multiple fallback values into a single expression via a list of patterns.
|
||||||
@@ -384,15 +565,25 @@ description = (
|
|||||||
|
|
||||||
Methods supporting list of patterns are: `_search_regex`, `_html_search_regex`, `_og_search_property`, `_html_search_meta`.
|
Methods supporting list of patterns are: `_search_regex`, `_html_search_regex`, `_og_search_property`, `_html_search_meta`.
|
||||||
|
|
||||||
|
|
||||||
### Trailing parentheses
|
### Trailing parentheses
|
||||||
|
|
||||||
Always move trailing parentheses after the last argument.
|
Always move trailing parentheses used for grouping/functions after the last argument. On the other hand, literal list/tuple/dict/set should closed be in a new line. Generators and list/dict comprehensions may use either style
|
||||||
|
|
||||||
#### Example
|
#### Examples
|
||||||
|
|
||||||
Correct:
|
Correct:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
url = try_get(
|
||||||
|
info,
|
||||||
|
lambda x: x['ResultSet']['Result'][0]['VideoUrlSet']['VideoUrl'],
|
||||||
|
list)
|
||||||
|
```
|
||||||
|
Correct:
|
||||||
|
|
||||||
|
```python
|
||||||
|
url = try_get(info,
|
||||||
lambda x: x['ResultSet']['Result'][0]['VideoUrlSet']['VideoUrl'],
|
lambda x: x['ResultSet']['Result'][0]['VideoUrlSet']['VideoUrl'],
|
||||||
list)
|
list)
|
||||||
```
|
```
|
||||||
@@ -400,35 +591,75 @@ Correct:
|
|||||||
Incorrect:
|
Incorrect:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
url = try_get(
|
||||||
|
info,
|
||||||
lambda x: x['ResultSet']['Result'][0]['VideoUrlSet']['VideoUrl'],
|
lambda x: x['ResultSet']['Result'][0]['VideoUrlSet']['VideoUrl'],
|
||||||
list,
|
list,
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Correct:
|
||||||
|
|
||||||
|
```python
|
||||||
|
f = {
|
||||||
|
'url': url,
|
||||||
|
'format_id': format_id,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Incorrect:
|
||||||
|
|
||||||
|
```python
|
||||||
|
f = {'url': url,
|
||||||
|
'format_id': format_id}
|
||||||
|
```
|
||||||
|
|
||||||
|
Correct:
|
||||||
|
|
||||||
|
```python
|
||||||
|
formats = [process_formats(f) for f in format_data
|
||||||
|
if f.get('type') in ('hls', 'dash', 'direct') and f.get('downloadable')]
|
||||||
|
```
|
||||||
|
|
||||||
|
Correct:
|
||||||
|
|
||||||
|
```python
|
||||||
|
formats = [
|
||||||
|
process_formats(f) for f in format_data
|
||||||
|
if f.get('type') in ('hls', 'dash', 'direct') and f.get('downloadable')
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Use convenience conversion and parsing functions
|
### Use convenience conversion and parsing functions
|
||||||
|
|
||||||
Wrap all extracted numeric data into safe functions from [`youtube_dl/utils.py`](https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/utils.py): `int_or_none`, `float_or_none`. Use them for string to number conversions as well.
|
Wrap all extracted numeric data into safe functions from [`yt_dlp/utils.py`](yt_dlp/utils.py): `int_or_none`, `float_or_none`. Use them for string to number conversions as well.
|
||||||
|
|
||||||
Use `url_or_none` for safe URL processing.
|
Use `url_or_none` for safe URL processing.
|
||||||
|
|
||||||
Use `try_get` for safe metadata extraction from parsed JSON.
|
Use `try_get`, `dict_get` and `traverse_obj` for safe metadata extraction from parsed JSON.
|
||||||
|
|
||||||
Use `unified_strdate` for uniform `upload_date` or any `YYYYMMDD` meta field extraction, `unified_timestamp` for uniform `timestamp` extraction, `parse_filesize` for `filesize` extraction, `parse_count` for count meta fields extraction, `parse_resolution`, `parse_duration` for `duration` extraction, `parse_age_limit` for `age_limit` extraction.
|
Use `unified_strdate` for uniform `upload_date` or any `YYYYMMDD` meta field extraction, `unified_timestamp` for uniform `timestamp` extraction, `parse_filesize` for `filesize` extraction, `parse_count` for count meta fields extraction, `parse_resolution`, `parse_duration` for `duration` extraction, `parse_age_limit` for `age_limit` extraction.
|
||||||
|
|
||||||
Explore [`youtube_dl/utils.py`](https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/utils.py) for more useful convenience functions.
|
Explore [`yt_dlp/utils.py`](yt_dlp/utils.py) for more useful convenience functions.
|
||||||
|
|
||||||
#### More examples
|
#### More examples
|
||||||
|
|
||||||
##### Safely extract optional description from parsed JSON
|
##### Safely extract optional description from parsed JSON
|
||||||
```python
|
```python
|
||||||
description = try_get(response, lambda x: x['result']['video'][0]['summary'], compat_str)
|
description = traverse_obj(response, ('result', 'video', 'summary'), expected_type=str)
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Safely extract more optional metadata
|
##### Safely extract more optional metadata
|
||||||
```python
|
```python
|
||||||
video = try_get(response, lambda x: x['result']['video'][0], dict) or {}
|
video = traverse_obj(response, ('result', 'video', 0), default={}, expected_type=dict)
|
||||||
description = video.get('summary')
|
description = video.get('summary')
|
||||||
duration = float_or_none(video.get('durationMs'), scale=1000)
|
duration = float_or_none(video.get('durationMs'), scale=1000)
|
||||||
view_count = int_or_none(video.get('views'))
|
view_count = int_or_none(video.get('views'))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# EMBEDDING YT-DLP
|
||||||
|
See [README.md#embedding-yt-dlp](README.md#embedding-yt-dlp) for instructions on how to embed yt-dlp in another Python program
|
||||||
|
|||||||
166
CONTRIBUTORS
166
CONTRIBUTORS
@@ -1,6 +1,8 @@
|
|||||||
pukkandan (owner)
|
pukkandan (owner)
|
||||||
shirt-dev (collaborator)
|
shirt-dev (collaborator)
|
||||||
colethedj (collaborator)
|
coletdjnz/colethedj (collaborator)
|
||||||
|
Ashish0804 (collaborator)
|
||||||
|
nao20010128nao/Lesmiscore (collaborator)
|
||||||
h-h-h-h
|
h-h-h-h
|
||||||
pauldubois98
|
pauldubois98
|
||||||
nixxo
|
nixxo
|
||||||
@@ -18,13 +20,10 @@ samiksome
|
|||||||
alxnull
|
alxnull
|
||||||
FelixFrog
|
FelixFrog
|
||||||
Zocker1999NET
|
Zocker1999NET
|
||||||
nao20010128nao
|
|
||||||
kurumigi
|
kurumigi
|
||||||
tsukumi
|
|
||||||
bbepis
|
bbepis
|
||||||
animelover1984
|
animelover1984/horahoradev
|
||||||
Pccode66
|
Pccode66
|
||||||
Ashish0804
|
|
||||||
RobinD42
|
RobinD42
|
||||||
hseg
|
hseg
|
||||||
DennyDai
|
DennyDai
|
||||||
@@ -38,3 +37,160 @@ xtkoba
|
|||||||
llacb47
|
llacb47
|
||||||
hheimbuerger
|
hheimbuerger
|
||||||
B0pol
|
B0pol
|
||||||
|
lkho
|
||||||
|
fstirlitz
|
||||||
|
Lamieur
|
||||||
|
tsukumijima
|
||||||
|
Hadi0609
|
||||||
|
b5eff52
|
||||||
|
craftingmod
|
||||||
|
tpikonen
|
||||||
|
tripulse
|
||||||
|
king-millez
|
||||||
|
alex-gedeon
|
||||||
|
hhirtz
|
||||||
|
louie-github
|
||||||
|
MinePlayersPE
|
||||||
|
olifre
|
||||||
|
rhsmachine/zenerdi0de
|
||||||
|
nihil-admirari
|
||||||
|
krichbanana
|
||||||
|
ohmybahgosh
|
||||||
|
nyuszika7h
|
||||||
|
blackjack4494
|
||||||
|
pyx
|
||||||
|
TpmKranz
|
||||||
|
mzbaulhaque
|
||||||
|
zackmark29
|
||||||
|
mbway
|
||||||
|
zerodytrash
|
||||||
|
wesnm
|
||||||
|
pento
|
||||||
|
rigstot
|
||||||
|
dirkf
|
||||||
|
funniray
|
||||||
|
Jessecar96
|
||||||
|
jhwgh1968
|
||||||
|
kikuyan
|
||||||
|
max-te
|
||||||
|
nchilada
|
||||||
|
pgaig
|
||||||
|
PSlava
|
||||||
|
stdedos
|
||||||
|
u-spec-png
|
||||||
|
Sipherdrakon
|
||||||
|
kidonng
|
||||||
|
smege1001
|
||||||
|
tandy1000
|
||||||
|
IONECarter
|
||||||
|
capntrips
|
||||||
|
mrfade
|
||||||
|
ParadoxGBB
|
||||||
|
wlritchi
|
||||||
|
NeroBurner
|
||||||
|
mahanstreamer
|
||||||
|
alerikaisattera
|
||||||
|
Derkades
|
||||||
|
BunnyHelp
|
||||||
|
i6t
|
||||||
|
std-move
|
||||||
|
Chocobozzz
|
||||||
|
ouwou
|
||||||
|
korli
|
||||||
|
octotherp
|
||||||
|
CeruleanSky
|
||||||
|
zootedb0t
|
||||||
|
chao813
|
||||||
|
ChillingPepper
|
||||||
|
ConquerorDopy
|
||||||
|
dalanmiller
|
||||||
|
DigitalDJ
|
||||||
|
f4pp3rk1ng
|
||||||
|
gesa
|
||||||
|
Jules-A
|
||||||
|
makeworld-the-better-one
|
||||||
|
MKSherbini
|
||||||
|
mrx23dot
|
||||||
|
poschi3
|
||||||
|
raphaeldore
|
||||||
|
renalid
|
||||||
|
sleaux-meaux
|
||||||
|
sulyi
|
||||||
|
tmarki
|
||||||
|
Vangelis66
|
||||||
|
AjaxGb
|
||||||
|
ajj8
|
||||||
|
jakubadamw
|
||||||
|
jfogelman
|
||||||
|
timethrow
|
||||||
|
sarnoud
|
||||||
|
Bojidarist
|
||||||
|
18928172992817182/gustaf
|
||||||
|
nixklai
|
||||||
|
smplayer-dev
|
||||||
|
Zirro
|
||||||
|
CrypticSignal
|
||||||
|
flashdagger
|
||||||
|
fractalf
|
||||||
|
frafra
|
||||||
|
kaz-us
|
||||||
|
ozburo
|
||||||
|
rhendric
|
||||||
|
sdomi
|
||||||
|
selfisekai
|
||||||
|
stanoarn
|
||||||
|
0xA7404A/Aurora
|
||||||
|
4a1e2y5
|
||||||
|
aarubui
|
||||||
|
chio0hai
|
||||||
|
cntrl-s
|
||||||
|
Deer-Spangle
|
||||||
|
DEvmIb
|
||||||
|
Grabien
|
||||||
|
j54vc1bk
|
||||||
|
mpeter50
|
||||||
|
mrpapersonic
|
||||||
|
pabs3
|
||||||
|
staubichsauger
|
||||||
|
xenova
|
||||||
|
Yakabuff
|
||||||
|
zulaport
|
||||||
|
ehoogeveen-medweb
|
||||||
|
PilzAdam
|
||||||
|
zmousm
|
||||||
|
iw0nderhow
|
||||||
|
unit193
|
||||||
|
TwoThousandHedgehogs
|
||||||
|
Jertzukka
|
||||||
|
cypheron
|
||||||
|
Hyeeji
|
||||||
|
bwildenhain
|
||||||
|
C0D3D3V
|
||||||
|
kebianizao
|
||||||
|
Lapin0t
|
||||||
|
abdullah-if
|
||||||
|
DavidSkrundz
|
||||||
|
mkubecek
|
||||||
|
raleeper
|
||||||
|
YuenSzeHong
|
||||||
|
Sematre
|
||||||
|
jaller94
|
||||||
|
r5d
|
||||||
|
julien-hadleyjack
|
||||||
|
git-anony-mouse
|
||||||
|
mdawar
|
||||||
|
trassshhub
|
||||||
|
foghawk
|
||||||
|
k3ns1n
|
||||||
|
teridon
|
||||||
|
mozlima
|
||||||
|
timendum
|
||||||
|
ischmidt20
|
||||||
|
CreaValix
|
||||||
|
sian1468
|
||||||
|
arkamar
|
||||||
|
hyano
|
||||||
|
KiberInfinity
|
||||||
|
tejing1
|
||||||
|
Bricio
|
||||||
|
lazypete365
|
||||||
|
|||||||
1499
Changelog.md
1499
Changelog.md
File diff suppressed because it is too large
Load Diff
50
Collaborators.md
Normal file
50
Collaborators.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Collaborators
|
||||||
|
|
||||||
|
This is a list of the collaborators of the project and their major contributions. See the [Changelog](Changelog.md) for more details.
|
||||||
|
|
||||||
|
You can also find lists of all [contributors of yt-dlp](CONTRIBUTORS) and [authors of youtube-dl](https://github.com/ytdl-org/youtube-dl/blob/master/AUTHORS)
|
||||||
|
|
||||||
|
|
||||||
|
## [pukkandan](https://github.com/pukkandan)
|
||||||
|
|
||||||
|
[](https://ko-fi.com/pukkandan)
|
||||||
|
|
||||||
|
* Owner of the fork
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [shirt](https://github.com/shirt-dev)
|
||||||
|
|
||||||
|
[](https://ko-fi.com/shirt)
|
||||||
|
|
||||||
|
* Multithreading (`-N`) and aria2c support for fragment downloads
|
||||||
|
* Support for media initialization and discontinuity in HLS
|
||||||
|
* The self-updater (`-U`)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [coletdjnz](https://github.com/coletdjnz)
|
||||||
|
|
||||||
|
[](https://github.com/sponsors/coletdjnz)
|
||||||
|
|
||||||
|
* YouTube improvements including: age-gate bypass, private playlists, multiple-clients (to avoid throttling) and a lot of under-the-hood improvements
|
||||||
|
* Added support for downloading YoutubeWebArchive videos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [Ashish0804](https://github.com/Ashish0804)
|
||||||
|
|
||||||
|
[](https://ko-fi.com/ashish0804)
|
||||||
|
|
||||||
|
* Added support for new websites BiliIntl, DiscoveryPlusIndia, OlympicsReplay, PlanetMarathi, ShemarooMe, Utreon, Zee5 etc
|
||||||
|
* Added playlist/series downloads for Hotstar, ParamountPlus, Rumble, SonyLIV, Trovo, TubiTv, Voot etc
|
||||||
|
* Improved/fixed support for HiDive, HotStar, Hungama, LBRY, LinkedInLearning, Mxplayer, SonyLiv, TV2, Vimeo, VLive etc
|
||||||
|
|
||||||
|
|
||||||
|
## [Lesmiscore](https://github.com/Lesmiscore) (nao20010128nao)
|
||||||
|
|
||||||
|
**Bitcoin**: bc1qfd02r007cutfdjwjmyy9w23rjvtls6ncve7r3s
|
||||||
|
**Monacoin**: mona1q3tf7dzvshrhfe3md379xtvt2n22duhglv5dskr
|
||||||
|
|
||||||
|
* Download live from start to end for YouTube
|
||||||
|
* Added support for new websites mildom, PixivSketch, skeb, radiko, voicy, mirrativ, openrec, whowatch, damtomo, 17.live, mixch etc
|
||||||
64
Makefile
64
Makefile
@@ -1,5 +1,6 @@
|
|||||||
all: yt-dlp doc pypi-files
|
all: lazy-extractors yt-dlp doc pypi-files
|
||||||
clean: clean-test clean-dist clean-cache
|
clean: clean-test clean-dist
|
||||||
|
clean-all: clean clean-cache
|
||||||
completions: completion-bash completion-fish completion-zsh
|
completions: completion-bash completion-fish completion-zsh
|
||||||
doc: README.md CONTRIBUTING.md issuetemplates supportedsites
|
doc: README.md CONTRIBUTING.md issuetemplates supportedsites
|
||||||
ot: offlinetest
|
ot: offlinetest
|
||||||
@@ -13,11 +14,15 @@ pypi-files: AUTHORS Changelog.md LICENSE README.md README.txt supportedsites com
|
|||||||
.PHONY: all clean install test tar pypi-files completions ot offlinetest codetest supportedsites
|
.PHONY: all clean install test tar pypi-files completions ot offlinetest codetest supportedsites
|
||||||
|
|
||||||
clean-test:
|
clean-test:
|
||||||
rm -rf *.dump *.part* *.ytdl *.info.json *.mp4 *.m4a *.flv *.mp3 *.avi *.mkv *.webm *.3gp *.wav *.ape *.swf *.jpg *.png *.frag *.frag.urls *.frag.aria2
|
rm -rf test/testdata/sigs/player-*.js tmp/ *.annotations.xml *.aria2 *.description *.dump *.frag \
|
||||||
|
*.frag.aria2 *.frag.urls *.info.json *.live_chat.json *.meta *.part* *.tmp *.temp *.unknown_video *.ytdl \
|
||||||
|
*.3gp *.ape *.avi *.desktop *.flac *.flv *.jpeg *.jpg *.m4a *.m4v *.mhtml *.mkv *.mov *.mp3 \
|
||||||
|
*.mp4 *.ogg *.opus *.png *.sbv *.srt *.swf *.swp *.ttml *.url *.vtt *.wav *.webloc *.webm *.webp
|
||||||
clean-dist:
|
clean-dist:
|
||||||
rm -rf yt-dlp.1.temp.md yt-dlp.1 README.txt MANIFEST build/ dist/ .coverage cover/ yt-dlp.tar.gz completions/ yt_dlp/extractor/lazy_extractors.py *.spec CONTRIBUTING.md.tmp yt-dlp yt-dlp.exe yt_dlp.egg-info/ AUTHORS .mailmap
|
rm -rf yt-dlp.1.temp.md yt-dlp.1 README.txt MANIFEST build/ dist/ .coverage cover/ yt-dlp.tar.gz completions/ \
|
||||||
|
yt_dlp/extractor/lazy_extractors.py *.spec CONTRIBUTING.md.tmp yt-dlp yt-dlp.exe yt_dlp.egg-info/ AUTHORS .mailmap
|
||||||
clean-cache:
|
clean-cache:
|
||||||
find . -name "*.pyc" -o -name "*.class" -delete
|
find . \( -name "*.pyc" -o -name "*.class" \) -delete
|
||||||
|
|
||||||
completion-bash: completions/bash/yt-dlp
|
completion-bash: completions/bash/yt-dlp
|
||||||
completion-fish: completions/fish/yt-dlp.fish
|
completion-fish: completions/fish/yt-dlp.fish
|
||||||
@@ -25,10 +30,10 @@ completion-zsh: completions/zsh/_yt-dlp
|
|||||||
lazy-extractors: yt_dlp/extractor/lazy_extractors.py
|
lazy-extractors: yt_dlp/extractor/lazy_extractors.py
|
||||||
|
|
||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
|
DESTDIR ?= .
|
||||||
BINDIR ?= $(PREFIX)/bin
|
BINDIR ?= $(PREFIX)/bin
|
||||||
MANDIR ?= $(PREFIX)/man
|
MANDIR ?= $(PREFIX)/man
|
||||||
SHAREDIR ?= $(PREFIX)/share
|
SHAREDIR ?= $(PREFIX)/share
|
||||||
# make_supportedsites.py doesnot work correctly in python2
|
|
||||||
PYTHON ?= /usr/bin/env python3
|
PYTHON ?= /usr/bin/env python3
|
||||||
|
|
||||||
# set SYSCONFDIR to /etc if PREFIX=/usr or PREFIX=/usr/local
|
# set SYSCONFDIR to /etc if PREFIX=/usr or PREFIX=/usr/local
|
||||||
@@ -37,9 +42,9 @@ SYSCONFDIR = $(shell if [ $(PREFIX) = /usr -o $(PREFIX) = /usr/local ]; then ech
|
|||||||
# set markdown input format to "markdown-smart" for pandoc version 2 and to "markdown" for pandoc prior to version 2
|
# set markdown input format to "markdown-smart" for pandoc version 2 and to "markdown" for pandoc prior to version 2
|
||||||
MARKDOWN = $(shell if [ `pandoc -v | head -n1 | cut -d" " -f2 | head -c1` = "2" ]; then echo markdown-smart; else echo markdown; fi)
|
MARKDOWN = $(shell if [ `pandoc -v | head -n1 | cut -d" " -f2 | head -c1` = "2" ]; then echo markdown-smart; else echo markdown; fi)
|
||||||
|
|
||||||
install: yt-dlp yt-dlp.1 completions
|
install: lazy-extractors yt-dlp yt-dlp.1 completions
|
||||||
install -Dm755 yt-dlp $(DESTDIR)$(BINDIR)
|
install -Dm755 yt-dlp $(DESTDIR)$(BINDIR)/yt-dlp
|
||||||
install -Dm644 yt-dlp.1 $(DESTDIR)$(MANDIR)/man1
|
install -Dm644 yt-dlp.1 $(DESTDIR)$(MANDIR)/man1/yt-dlp.1
|
||||||
install -Dm644 completions/bash/yt-dlp $(DESTDIR)$(SHAREDIR)/bash-completion/completions/yt-dlp
|
install -Dm644 completions/bash/yt-dlp $(DESTDIR)$(SHAREDIR)/bash-completion/completions/yt-dlp
|
||||||
install -Dm644 completions/zsh/_yt-dlp $(DESTDIR)$(SHAREDIR)/zsh/site-functions/_yt-dlp
|
install -Dm644 completions/zsh/_yt-dlp $(DESTDIR)$(SHAREDIR)/zsh/site-functions/_yt-dlp
|
||||||
install -Dm644 completions/fish/yt-dlp.fish $(DESTDIR)$(SHAREDIR)/fish/vendor_completions.d/yt-dlp.fish
|
install -Dm644 completions/fish/yt-dlp.fish $(DESTDIR)$(SHAREDIR)/fish/vendor_completions.d/yt-dlp.fish
|
||||||
@@ -48,23 +53,11 @@ codetest:
|
|||||||
flake8 .
|
flake8 .
|
||||||
|
|
||||||
test:
|
test:
|
||||||
#nosetests --with-coverage --cover-package=yt_dlp --cover-html --verbose --processes 4 test
|
$(PYTHON) -m pytest
|
||||||
nosetests --verbose test
|
|
||||||
$(MAKE) codetest
|
$(MAKE) codetest
|
||||||
|
|
||||||
# Keep this list in sync with devscripts/run_tests.sh
|
|
||||||
offlinetest: codetest
|
offlinetest: codetest
|
||||||
$(PYTHON) -m nose --verbose test \
|
$(PYTHON) -m pytest -k "not download"
|
||||||
--exclude test_age_restriction.py \
|
|
||||||
--exclude test_download.py \
|
|
||||||
--exclude test_iqiyi_sdk_interpreter.py \
|
|
||||||
--exclude test_overwrites.py \
|
|
||||||
--exclude test_socks.py \
|
|
||||||
--exclude test_subtitles.py \
|
|
||||||
--exclude test_write_annotations.py \
|
|
||||||
--exclude test_youtube_lists.py \
|
|
||||||
--exclude test_youtube_signature.py \
|
|
||||||
--exclude test_post_hooks.py
|
|
||||||
|
|
||||||
yt-dlp: yt_dlp/*.py yt_dlp/*/*.py
|
yt-dlp: yt_dlp/*.py yt_dlp/*/*.py
|
||||||
mkdir -p zip
|
mkdir -p zip
|
||||||
@@ -87,12 +80,13 @@ README.md: yt_dlp/*.py yt_dlp/*/*.py
|
|||||||
CONTRIBUTING.md: README.md
|
CONTRIBUTING.md: README.md
|
||||||
$(PYTHON) devscripts/make_contributing.py README.md CONTRIBUTING.md
|
$(PYTHON) devscripts/make_contributing.py README.md CONTRIBUTING.md
|
||||||
|
|
||||||
issuetemplates: devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/1_broken_site.md .github/ISSUE_TEMPLATE_tmpl/2_site_support_request.md .github/ISSUE_TEMPLATE_tmpl/3_site_feature_request.md .github/ISSUE_TEMPLATE_tmpl/4_bug_report.md .github/ISSUE_TEMPLATE_tmpl/5_feature_request.md yt_dlp/version.py
|
issuetemplates: devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/1_broken_site.yml .github/ISSUE_TEMPLATE_tmpl/2_site_support_request.yml .github/ISSUE_TEMPLATE_tmpl/3_site_feature_request.yml .github/ISSUE_TEMPLATE_tmpl/4_bug_report.yml .github/ISSUE_TEMPLATE_tmpl/5_feature_request.yml yt_dlp/version.py
|
||||||
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/1_broken_site.md .github/ISSUE_TEMPLATE/1_broken_site.md
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/1_broken_site.yml .github/ISSUE_TEMPLATE/1_broken_site.yml
|
||||||
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/2_site_support_request.md .github/ISSUE_TEMPLATE/2_site_support_request.md
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/2_site_support_request.yml .github/ISSUE_TEMPLATE/2_site_support_request.yml
|
||||||
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/3_site_feature_request.md .github/ISSUE_TEMPLATE/3_site_feature_request.md
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/3_site_feature_request.yml .github/ISSUE_TEMPLATE/3_site_feature_request.yml
|
||||||
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/4_bug_report.md .github/ISSUE_TEMPLATE/4_bug_report.md
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/4_bug_report.yml .github/ISSUE_TEMPLATE/4_bug_report.yml
|
||||||
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/5_feature_request.md .github/ISSUE_TEMPLATE/5_feature_request.md
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/5_feature_request.yml .github/ISSUE_TEMPLATE/5_feature_request.yml
|
||||||
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/6_question.yml .github/ISSUE_TEMPLATE/6_question.yml
|
||||||
|
|
||||||
supportedsites:
|
supportedsites:
|
||||||
$(PYTHON) devscripts/make_supportedsites.py supportedsites.md
|
$(PYTHON) devscripts/make_supportedsites.py supportedsites.md
|
||||||
@@ -121,7 +115,7 @@ _EXTRACTOR_FILES = $(shell find yt_dlp/extractor -iname '*.py' -and -not -iname
|
|||||||
yt_dlp/extractor/lazy_extractors.py: devscripts/make_lazy_extractors.py devscripts/lazy_load_template.py $(_EXTRACTOR_FILES)
|
yt_dlp/extractor/lazy_extractors.py: devscripts/make_lazy_extractors.py devscripts/lazy_load_template.py $(_EXTRACTOR_FILES)
|
||||||
$(PYTHON) devscripts/make_lazy_extractors.py $@
|
$(PYTHON) devscripts/make_lazy_extractors.py $@
|
||||||
|
|
||||||
yt-dlp.tar.gz: README.md yt-dlp.1 completions Changelog.md AUTHORS
|
yt-dlp.tar.gz: all
|
||||||
@tar -czf $(DESTDIR)/yt-dlp.tar.gz --transform "s|^|yt-dlp/|" --owner 0 --group 0 \
|
@tar -czf $(DESTDIR)/yt-dlp.tar.gz --transform "s|^|yt-dlp/|" --owner 0 --group 0 \
|
||||||
--exclude '*.DS_Store' \
|
--exclude '*.DS_Store' \
|
||||||
--exclude '*.kate-swp' \
|
--exclude '*.kate-swp' \
|
||||||
@@ -130,12 +124,12 @@ yt-dlp.tar.gz: README.md yt-dlp.1 completions Changelog.md AUTHORS
|
|||||||
--exclude '*~' \
|
--exclude '*~' \
|
||||||
--exclude '__pycache__' \
|
--exclude '__pycache__' \
|
||||||
--exclude '.git' \
|
--exclude '.git' \
|
||||||
--exclude 'docs/_build' \
|
|
||||||
-- \
|
-- \
|
||||||
devscripts test \
|
README.md supportedsites.md Changelog.md LICENSE \
|
||||||
Changelog.md AUTHORS LICENSE README.md supportedsites.md \
|
CONTRIBUTING.md Collaborators.md CONTRIBUTORS AUTHORS \
|
||||||
Makefile MANIFEST.in yt-dlp.1 completions \
|
Makefile MANIFEST.in yt-dlp.1 README.txt completions \
|
||||||
setup.py setup.cfg yt-dlp
|
setup.py setup.cfg yt-dlp yt_dlp requirements.txt \
|
||||||
|
devscripts test tox.ini pytest.ini
|
||||||
|
|
||||||
AUTHORS: .mailmap
|
AUTHORS: .mailmap
|
||||||
git shortlog -s -n | cut -f2 | sort > AUTHORS
|
git shortlog -s -n | cut -f2 | sort > AUTHORS
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# UNUSED
|
||||||
|
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,6 +1,6 @@
|
|||||||
# Unused
|
# Unused
|
||||||
|
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import io
|
import io
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import optparse
|
import optparse
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import codecs
|
import codecs
|
||||||
|
|||||||
0
devscripts/gh-pages/add-version.py → devscripts/gh-pages.unused/add-version.py
Executable file → Normal file
0
devscripts/gh-pages/add-version.py → devscripts/gh-pages.unused/add-version.py
Executable file → Normal file
0
devscripts/gh-pages/generate-download.py → devscripts/gh-pages.unused/generate-download.py
Executable file → Normal file
0
devscripts/gh-pages/generate-download.py → devscripts/gh-pages.unused/generate-download.py
Executable file → Normal file
0
devscripts/gh-pages/sign-versions.py → devscripts/gh-pages.unused/sign-versions.py
Executable file → Normal file
0
devscripts/gh-pages/sign-versions.py → devscripts/gh-pages.unused/sign-versions.py
Executable file → Normal file
2
devscripts/gh-pages/update-copyright.py → devscripts/gh-pages.unused/update-copyright.py
Executable file → Normal file
2
devscripts/gh-pages/update-copyright.py → devscripts/gh-pages.unused/update-copyright.py
Executable file → Normal file
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
from __future__ import with_statement, unicode_literals
|
from __future__ import with_statement, unicode_literals
|
||||||
0
devscripts/gh-pages/update-feed.py → devscripts/gh-pages.unused/update-feed.py
Executable file → Normal file
0
devscripts/gh-pages/update-feed.py → devscripts/gh-pages.unused/update-feed.py
Executable file → Normal file
0
devscripts/gh-pages/update-sites.py → devscripts/gh-pages.unused/update-sites.py
Executable file → Normal file
0
devscripts/gh-pages/update-sites.py → devscripts/gh-pages.unused/update-sites.py
Executable file → Normal file
@@ -1,19 +1,31 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from ..utils import bug_reports_message, write_string
|
||||||
|
|
||||||
class LazyLoadExtractor(object):
|
|
||||||
|
class LazyLoadMetaClass(type):
|
||||||
|
def __getattr__(cls, name):
|
||||||
|
if '_real_class' not in cls.__dict__:
|
||||||
|
write_string(
|
||||||
|
f'WARNING: Falling back to normal extractor since lazy extractor '
|
||||||
|
f'{cls.__name__} does not have attribute {name}{bug_reports_message()}')
|
||||||
|
return getattr(cls._get_real_class(), name)
|
||||||
|
|
||||||
|
|
||||||
|
class LazyLoadExtractor(metaclass=LazyLoadMetaClass):
|
||||||
_module = None
|
_module = None
|
||||||
|
_WORKING = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def ie_key(cls):
|
def _get_real_class(cls):
|
||||||
return cls.__name__[:-2]
|
if '_real_class' not in cls.__dict__:
|
||||||
|
mod = __import__(cls._module, fromlist=(cls.__name__,))
|
||||||
|
cls._real_class = getattr(mod, cls.__name__)
|
||||||
|
return cls._real_class
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
def __new__(cls, *args, **kwargs):
|
||||||
mod = __import__(cls._module, fromlist=(cls.__name__,))
|
real_cls = cls._get_real_class()
|
||||||
real_cls = getattr(mod, cls.__name__)
|
|
||||||
instance = real_cls.__new__(real_cls)
|
instance = real_cls.__new__(real_cls)
|
||||||
instance.__init__(*args, **kwargs)
|
instance.__init__(*args, **kwargs)
|
||||||
return instance
|
return instance
|
||||||
|
|||||||
BIN
devscripts/logo.ico
Normal file
BIN
devscripts/logo.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -1,33 +1,34 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
# import io
|
import io
|
||||||
import optparse
|
import optparse
|
||||||
# import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
return # This is unused in yt-dlp
|
||||||
|
|
||||||
parser = optparse.OptionParser(usage='%prog INFILE OUTFILE')
|
parser = optparse.OptionParser(usage='%prog INFILE OUTFILE')
|
||||||
options, args = parser.parse_args()
|
options, args = parser.parse_args()
|
||||||
if len(args) != 2:
|
if len(args) != 2:
|
||||||
parser.error('Expected an input and an output filename')
|
parser.error('Expected an input and an output filename')
|
||||||
|
|
||||||
|
infile, outfile = args
|
||||||
""" infile, outfile = args
|
|
||||||
|
|
||||||
with io.open(infile, encoding='utf-8') as inf:
|
with io.open(infile, encoding='utf-8') as inf:
|
||||||
readme = inf.read()
|
readme = inf.read()
|
||||||
|
|
||||||
bug_text = re.search( """
|
bug_text = re.search(
|
||||||
# r'(?s)#\s*BUGS\s*[^\n]*\s*(.*?)#\s*COPYRIGHT', readme).group(1)
|
r'(?s)#\s*BUGS\s*[^\n]*\s*(.*?)#\s*COPYRIGHT', readme).group(1)
|
||||||
# dev_text = re.search(
|
dev_text = re.search(
|
||||||
# r'(?s)(#\s*DEVELOPER INSTRUCTIONS.*?)#\s*EMBEDDING yt-dlp',
|
r'(?s)(#\s*DEVELOPER INSTRUCTIONS.*?)#\s*EMBEDDING yt-dlp', readme).group(1)
|
||||||
""" readme).group(1)
|
|
||||||
|
|
||||||
out = bug_text + dev_text
|
out = bug_text + dev_text
|
||||||
|
|
||||||
with io.open(outfile, 'w', encoding='utf-8') as outf:
|
with io.open(outfile, 'w', encoding='utf-8') as outf:
|
||||||
outf.write(out) """
|
outf.write(out)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import io
|
import io
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals, print_function
|
from __future__ import unicode_literals, print_function
|
||||||
|
|
||||||
from inspect import getsource
|
from inspect import getsource
|
||||||
@@ -6,36 +7,38 @@ import os
|
|||||||
from os.path import dirname as dirn
|
from os.path import dirname as dirn
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
print('WARNING: Lazy loading extractors is an experimental feature that may not always work', file=sys.stderr)
|
|
||||||
|
|
||||||
sys.path.insert(0, dirn(dirn((os.path.abspath(__file__)))))
|
sys.path.insert(0, dirn(dirn((os.path.abspath(__file__)))))
|
||||||
|
|
||||||
lazy_extractors_filename = sys.argv[1]
|
lazy_extractors_filename = sys.argv[1] if len(sys.argv) > 1 else 'yt_dlp/extractor/lazy_extractors.py'
|
||||||
if os.path.exists(lazy_extractors_filename):
|
if os.path.exists(lazy_extractors_filename):
|
||||||
os.remove(lazy_extractors_filename)
|
os.remove(lazy_extractors_filename)
|
||||||
|
|
||||||
|
# Block plugins from loading
|
||||||
|
plugins_dirname = 'ytdlp_plugins'
|
||||||
|
plugins_blocked_dirname = 'ytdlp_plugins_blocked'
|
||||||
|
if os.path.exists(plugins_dirname):
|
||||||
|
os.rename(plugins_dirname, plugins_blocked_dirname)
|
||||||
|
|
||||||
from yt_dlp.extractor import _ALL_CLASSES
|
from yt_dlp.extractor import _ALL_CLASSES
|
||||||
from yt_dlp.extractor.common import InfoExtractor, SearchInfoExtractor
|
from yt_dlp.extractor.common import InfoExtractor, SearchInfoExtractor
|
||||||
|
|
||||||
|
if os.path.exists(plugins_blocked_dirname):
|
||||||
|
os.rename(plugins_blocked_dirname, plugins_dirname)
|
||||||
|
|
||||||
with open('devscripts/lazy_load_template.py', 'rt') as f:
|
with open('devscripts/lazy_load_template.py', 'rt') as f:
|
||||||
module_template = f.read()
|
module_template = f.read()
|
||||||
|
|
||||||
|
CLASS_PROPERTIES = ['ie_key', 'working', '_match_valid_url', 'suitable', '_match_id', 'get_temp_id']
|
||||||
module_contents = [
|
module_contents = [
|
||||||
module_template + '\n' + getsource(InfoExtractor.suitable) + '\n',
|
module_template,
|
||||||
'class LazyLoadSearchExtractor(LazyLoadExtractor):\n pass\n']
|
*[getsource(getattr(InfoExtractor, k)) for k in CLASS_PROPERTIES],
|
||||||
|
'\nclass LazyLoadSearchExtractor(LazyLoadExtractor):\n pass\n']
|
||||||
|
|
||||||
ie_template = '''
|
ie_template = '''
|
||||||
class {name}({bases}):
|
class {name}({bases}):
|
||||||
_VALID_URL = {valid_url!r}
|
|
||||||
_module = '{module}'
|
_module = '{module}'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
make_valid_template = '''
|
|
||||||
@classmethod
|
|
||||||
def _make_valid_url(cls):
|
|
||||||
return {valid_url!r}
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
def get_base_name(base):
|
def get_base_name(base):
|
||||||
if base is InfoExtractor:
|
if base is InfoExtractor:
|
||||||
@@ -47,17 +50,19 @@ def get_base_name(base):
|
|||||||
|
|
||||||
|
|
||||||
def build_lazy_ie(ie, name):
|
def build_lazy_ie(ie, name):
|
||||||
valid_url = getattr(ie, '_VALID_URL', None)
|
|
||||||
s = ie_template.format(
|
s = ie_template.format(
|
||||||
name=name,
|
name=name,
|
||||||
bases=', '.join(map(get_base_name, ie.__bases__)),
|
bases=', '.join(map(get_base_name, ie.__bases__)),
|
||||||
valid_url=valid_url,
|
|
||||||
module=ie.__module__)
|
module=ie.__module__)
|
||||||
|
valid_url = getattr(ie, '_VALID_URL', None)
|
||||||
|
if not valid_url and hasattr(ie, '_make_valid_url'):
|
||||||
|
valid_url = ie._make_valid_url()
|
||||||
|
if valid_url:
|
||||||
|
s += f' _VALID_URL = {valid_url!r}\n'
|
||||||
|
if not ie._WORKING:
|
||||||
|
s += ' _WORKING = False\n'
|
||||||
if ie.suitable.__func__ is not InfoExtractor.suitable.__func__:
|
if ie.suitable.__func__ is not InfoExtractor.suitable.__func__:
|
||||||
s += '\n' + getsource(ie.suitable)
|
s += f'\n{getsource(ie.suitable)}'
|
||||||
if hasattr(ie, '_make_valid_url'):
|
|
||||||
# search extractors
|
|
||||||
s += make_valid_template.format(valid_url=ie._make_valid_url())
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
@@ -92,7 +97,7 @@ for ie in ordered_cls:
|
|||||||
names.append(name)
|
names.append(name)
|
||||||
|
|
||||||
module_contents.append(
|
module_contents.append(
|
||||||
'_ALL_CLASSES = [{0}]'.format(', '.join(names)))
|
'\n_ALL_CLASSES = [{0}]'.format(', '.join(names)))
|
||||||
|
|
||||||
module_src = '\n'.join(module_contents) + '\n'
|
module_src = '\n'.join(module_contents) + '\n'
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# yt-dlp --help | make_readme.py
|
||||||
|
# This must be run in a console of correct width
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import io
|
import io
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import io
|
import io
|
||||||
@@ -29,6 +29,9 @@ def main():
|
|||||||
continue
|
continue
|
||||||
if ie_desc is not None:
|
if ie_desc is not None:
|
||||||
ie_md += ': {0}'.format(ie.IE_DESC)
|
ie_md += ': {0}'.format(ie.IE_DESC)
|
||||||
|
search_key = getattr(ie, 'SEARCH_KEY', None)
|
||||||
|
if search_key is not None:
|
||||||
|
ie_md += f'; "{ie.SEARCH_KEY}:" prefix'
|
||||||
if not ie.working():
|
if not ie.working():
|
||||||
ie_md += ' (Currently broken)'
|
ie_md += ' (Currently broken)'
|
||||||
yield ie_md
|
yield ie_md
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import io
|
import io
|
||||||
@@ -12,12 +13,14 @@ PREFIX = r'''%yt-dlp(1)
|
|||||||
|
|
||||||
# NAME
|
# NAME
|
||||||
|
|
||||||
youtube\-dl \- download videos from youtube.com or other video platforms
|
yt\-dlp \- A youtube-dl fork with additional features and patches
|
||||||
|
|
||||||
# SYNOPSIS
|
# SYNOPSIS
|
||||||
|
|
||||||
**yt-dlp** \[OPTIONS\] URL [URL...]
|
**yt-dlp** \[OPTIONS\] URL [URL...]
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
@@ -32,27 +35,46 @@ def main():
|
|||||||
with io.open(README_FILE, encoding='utf-8') as f:
|
with io.open(README_FILE, encoding='utf-8') as f:
|
||||||
readme = f.read()
|
readme = f.read()
|
||||||
|
|
||||||
readme = re.sub(r'(?s)^.*?(?=# DESCRIPTION)', '', readme)
|
readme = filter_excluded_sections(readme)
|
||||||
readme = re.sub(r'\s+yt-dlp \[OPTIONS\] URL \[URL\.\.\.\]', '', readme)
|
readme = move_sections(readme)
|
||||||
readme = PREFIX + readme
|
|
||||||
|
|
||||||
readme = filter_options(readme)
|
readme = filter_options(readme)
|
||||||
|
|
||||||
with io.open(outfile, 'w', encoding='utf-8') as outf:
|
with io.open(outfile, 'w', encoding='utf-8') as outf:
|
||||||
outf.write(readme)
|
outf.write(PREFIX + readme)
|
||||||
|
|
||||||
|
|
||||||
|
def filter_excluded_sections(readme):
|
||||||
|
EXCLUDED_SECTION_BEGIN_STRING = re.escape('<!-- MANPAGE: BEGIN EXCLUDED SECTION -->')
|
||||||
|
EXCLUDED_SECTION_END_STRING = re.escape('<!-- MANPAGE: END EXCLUDED SECTION -->')
|
||||||
|
return re.sub(
|
||||||
|
rf'(?s){EXCLUDED_SECTION_BEGIN_STRING}.+?{EXCLUDED_SECTION_END_STRING}\n',
|
||||||
|
'', readme)
|
||||||
|
|
||||||
|
|
||||||
|
def move_sections(readme):
|
||||||
|
MOVE_TAG_TEMPLATE = '<!-- MANPAGE: MOVE "%s" SECTION HERE -->'
|
||||||
|
sections = re.findall(r'(?m)^%s$' % (
|
||||||
|
re.escape(MOVE_TAG_TEMPLATE).replace(r'\%', '%') % '(.+)'), readme)
|
||||||
|
|
||||||
|
for section_name in sections:
|
||||||
|
move_tag = MOVE_TAG_TEMPLATE % section_name
|
||||||
|
if readme.count(move_tag) > 1:
|
||||||
|
raise Exception(f'There is more than one occurrence of "{move_tag}". This is unexpected')
|
||||||
|
|
||||||
|
sections = re.findall(rf'(?sm)(^# {re.escape(section_name)}.+?)(?=^# )', readme)
|
||||||
|
if len(sections) < 1:
|
||||||
|
raise Exception(f'The section {section_name} does not exist')
|
||||||
|
elif len(sections) > 1:
|
||||||
|
raise Exception(f'There are multiple occurrences of section {section_name}, this is unhandled')
|
||||||
|
|
||||||
|
readme = readme.replace(sections[0], '', 1).replace(move_tag, sections[0], 1)
|
||||||
|
return readme
|
||||||
|
|
||||||
|
|
||||||
def filter_options(readme):
|
def filter_options(readme):
|
||||||
ret = ''
|
section = re.search(r'(?sm)^# USAGE AND OPTIONS\n.+?(?=^# )', readme).group(0)
|
||||||
in_options = False
|
options = '# OPTIONS\n'
|
||||||
for line in readme.split('\n'):
|
for line in section.split('\n')[1:]:
|
||||||
if line.startswith('# '):
|
|
||||||
if line[2:].startswith('OPTIONS'):
|
|
||||||
in_options = True
|
|
||||||
else:
|
|
||||||
in_options = False
|
|
||||||
|
|
||||||
if in_options:
|
|
||||||
if line.lstrip().startswith('-'):
|
if line.lstrip().startswith('-'):
|
||||||
split = re.split(r'\s{2,}', line.lstrip())
|
split = re.split(r'\s{2,}', line.lstrip())
|
||||||
# Description string may start with `-` as well. If there is
|
# Description string may start with `-` as well. If there is
|
||||||
@@ -62,17 +84,14 @@ def filter_options(readme):
|
|||||||
split_option = option.split(' ')
|
split_option = option.split(' ')
|
||||||
|
|
||||||
if not split_option[-1].startswith('-'): # metavar
|
if not split_option[-1].startswith('-'): # metavar
|
||||||
option = ' '.join(split_option[:-1] + ['*%s*' % split_option[-1]])
|
option = ' '.join(split_option[:-1] + [f'*{split_option[-1]}*'])
|
||||||
|
|
||||||
# Pandoc's definition_lists. See http://pandoc.org/README.html
|
# Pandoc's definition_lists. See http://pandoc.org/README.html
|
||||||
# for more information.
|
options += f'\n{option}\n: {description}\n'
|
||||||
ret += '\n%s\n: %s\n' % (option, description)
|
|
||||||
continue
|
continue
|
||||||
ret += line.lstrip() + '\n'
|
options += line.lstrip() + '\n'
|
||||||
else:
|
|
||||||
ret += line + '\n'
|
|
||||||
|
|
||||||
return ret
|
return readme.replace(section, options, 1)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Unused
|
# Unused
|
||||||
|
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# IMPORTANT: the following assumptions are made
|
# IMPORTANT: the following assumptions are made
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
|
@setlocal
|
||||||
@echo off
|
@echo off
|
||||||
|
cd /d %~dp0..
|
||||||
|
|
||||||
rem Keep this list in sync with the `offlinetest` target in Makefile
|
if ["%~1"]==[""] (
|
||||||
set DOWNLOAD_TESTS="age_restriction^|download^|iqiyi_sdk_interpreter^|socks^|subtitles^|write_annotations^|youtube_lists^|youtube_signature^|post_hooks"
|
set "test_set="test""
|
||||||
|
) else if ["%~1"]==["core"] (
|
||||||
if "%YTDL_TEST_SET%" == "core" (
|
set "test_set="-m not download""
|
||||||
set test_set="-I test_("%DOWNLOAD_TESTS%")\.py"
|
) else if ["%~1"]==["download"] (
|
||||||
set multiprocess_args=""
|
set "test_set="-m "download""
|
||||||
) else if "%YTDL_TEST_SET%" == "download" (
|
|
||||||
set test_set="-I test_(?!"%DOWNLOAD_TESTS%").+\.py"
|
|
||||||
set multiprocess_args="--processes=4 --process-timeout=540"
|
|
||||||
) else (
|
) else (
|
||||||
echo YTDL_TEST_SET is not set or invalid
|
echo.Invalid test type "%~1". Use "core" ^| "download"
|
||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
nosetests test --verbose %test_set:"=% %multiprocess_args:"=%
|
pytest %test_set%
|
||||||
|
|||||||
@@ -1,22 +1,14 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
# Keep this list in sync with the `offlinetest` target in Makefile
|
if [ -z $1 ]; then
|
||||||
DOWNLOAD_TESTS="age_restriction|download|iqiyi_sdk_interpreter|overwrites|socks|subtitles|write_annotations|youtube_lists|youtube_signature|post_hooks"
|
test_set='test'
|
||||||
|
elif [ $1 = 'core' ]; then
|
||||||
|
test_set="-m not download"
|
||||||
|
elif [ $1 = 'download' ]; then
|
||||||
|
test_set="-m download"
|
||||||
|
else
|
||||||
|
echo 'Invalid test type "'$1'". Use "core" | "download"'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
test_set=""
|
python3 -m pytest "$test_set"
|
||||||
multiprocess_args=""
|
|
||||||
|
|
||||||
case "$YTDL_TEST_SET" in
|
|
||||||
core)
|
|
||||||
test_set="-I test_($DOWNLOAD_TESTS)\.py"
|
|
||||||
;;
|
|
||||||
download)
|
|
||||||
test_set="-I test_(?!$DOWNLOAD_TESTS).+\.py"
|
|
||||||
multiprocess_args="--processes=4 --process-timeout=540"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
nosetests test --verbose $test_set $multiprocess_args
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Unused
|
# Unused
|
||||||
|
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
|
|||||||
37
devscripts/update-formulae.py
Normal file
37
devscripts/update-formulae.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
|
from yt_dlp.compat import compat_urllib_request
|
||||||
|
|
||||||
|
|
||||||
|
# usage: python3 ./devscripts/update-formulae.py <path-to-formulae-rb> <version>
|
||||||
|
# version can be either 0-aligned (yt-dlp version) or normalized (PyPl version)
|
||||||
|
|
||||||
|
filename, version = sys.argv[1:]
|
||||||
|
|
||||||
|
normalized_version = '.'.join(str(int(x)) for x in version.split('.'))
|
||||||
|
|
||||||
|
pypi_release = json.loads(compat_urllib_request.urlopen(
|
||||||
|
'https://pypi.org/pypi/yt-dlp/%s/json' % normalized_version
|
||||||
|
).read().decode('utf-8'))
|
||||||
|
|
||||||
|
tarball_file = next(x for x in pypi_release['urls'] if x['filename'].endswith('.tar.gz'))
|
||||||
|
|
||||||
|
sha256sum = tarball_file['digests']['sha256']
|
||||||
|
url = tarball_file['url']
|
||||||
|
|
||||||
|
with open(filename, 'r') as r:
|
||||||
|
formulae_text = r.read()
|
||||||
|
|
||||||
|
formulae_text = re.sub(r'sha256 "[0-9a-f]*?"', 'sha256 "%s"' % sha256sum, formulae_text)
|
||||||
|
formulae_text = re.sub(r'url "[^"]*?"', 'url "%s"' % url, formulae_text)
|
||||||
|
|
||||||
|
with open(filename, 'w') as w:
|
||||||
|
w.write(formulae_text)
|
||||||
@@ -1,31 +1,42 @@
|
|||||||
from __future__ import unicode_literals
|
#!/usr/bin/env python3
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
# import urllib.request
|
import sys
|
||||||
|
import subprocess
|
||||||
|
|
||||||
# response = urllib.request.urlopen('https://blackjack4494.github.io/youtube-dlc/update/LATEST_VERSION')
|
|
||||||
# old_version = response.read().decode('utf-8')
|
|
||||||
|
|
||||||
exec(compile(open('yt_dlp/version.py').read(), 'yt_dlp/version.py', 'exec'))
|
with open('yt_dlp/version.py', 'rt') as f:
|
||||||
|
exec(compile(f.read(), 'yt_dlp/version.py', 'exec'))
|
||||||
old_version = locals()['__version__']
|
old_version = locals()['__version__']
|
||||||
|
|
||||||
old_version_list = old_version.split(".", 4)
|
old_version_list = old_version.split('.')
|
||||||
|
|
||||||
old_ver = '.'.join(old_version_list[:3])
|
old_ver = '.'.join(old_version_list[:3])
|
||||||
old_rev = old_version_list[3] if len(old_version_list) > 3 else ''
|
old_rev = old_version_list[3] if len(old_version_list) > 3 else ''
|
||||||
|
|
||||||
ver = datetime.utcnow().strftime("%Y.%m.%d")
|
ver = datetime.utcnow().strftime("%Y.%m.%d")
|
||||||
rev = str(int(old_rev or 0) + 1) if old_ver == ver else ''
|
|
||||||
|
rev = (sys.argv[1:] or [''])[0] # Use first argument, if present as revision number
|
||||||
|
if not rev:
|
||||||
|
rev = str(int(old_rev or 0) + 1) if old_ver == ver else ''
|
||||||
|
|
||||||
VERSION = '.'.join((ver, rev)) if rev else ver
|
VERSION = '.'.join((ver, rev)) if rev else ver
|
||||||
# VERSION_LIST = [(int(v) for v in ver.split(".") + [rev or 0])]
|
|
||||||
|
try:
|
||||||
|
sp = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'], stdout=subprocess.PIPE)
|
||||||
|
GIT_HEAD = sp.communicate()[0].decode().strip() or None
|
||||||
|
except Exception:
|
||||||
|
GIT_HEAD = None
|
||||||
|
|
||||||
|
VERSION_FILE = f'''\
|
||||||
|
# Autogenerated by devscripts/update-version.py
|
||||||
|
|
||||||
|
__version__ = {VERSION!r}
|
||||||
|
|
||||||
|
RELEASE_GIT_HEAD = {GIT_HEAD!r}
|
||||||
|
'''
|
||||||
|
|
||||||
|
with open('yt_dlp/version.py', 'wt') as f:
|
||||||
|
f.write(VERSION_FILE)
|
||||||
|
|
||||||
print('::set-output name=ytdlp_version::' + VERSION)
|
print('::set-output name=ytdlp_version::' + VERSION)
|
||||||
|
print(f'\nVersion = {VERSION}, Git HEAD = {GIT_HEAD}')
|
||||||
file_version_py = open('yt_dlp/version.py', 'rt')
|
|
||||||
data = file_version_py.read()
|
|
||||||
data = data.replace(old_version, VERSION)
|
|
||||||
file_version_py.close()
|
|
||||||
|
|
||||||
file_version_py = open('yt_dlp/version.py', 'wt')
|
|
||||||
file_version_py.write(data)
|
|
||||||
file_version_py.close()
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# UNUSED
|
||||||
|
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Run with as parameter a setup.py that works in the current directory
|
# Run with as parameter a setup.py that works in the current directory
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|||||||
5
docs/Collaborators.md
Normal file
5
docs/Collaborators.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
orphan: true
|
||||||
|
---
|
||||||
|
```{include} ../Collaborators.md
|
||||||
|
```
|
||||||
5
docs/Contributing.md
Normal file
5
docs/Contributing.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
orphan: true
|
||||||
|
---
|
||||||
|
```{include} ../Contributing.md
|
||||||
|
```
|
||||||
164
pyinst.py
164
pyinst.py
@@ -1,41 +1,112 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
import os
|
||||||
from __future__ import unicode_literals
|
|
||||||
import sys
|
|
||||||
# import os
|
|
||||||
import platform
|
import platform
|
||||||
|
import sys
|
||||||
|
from PyInstaller.utils.hooks import collect_submodules
|
||||||
|
|
||||||
from PyInstaller.utils.win32.versioninfo import (
|
|
||||||
|
OS_NAME = platform.system()
|
||||||
|
if OS_NAME == 'Windows':
|
||||||
|
from PyInstaller.utils.win32.versioninfo import (
|
||||||
VarStruct, VarFileInfo, StringStruct, StringTable,
|
VarStruct, VarFileInfo, StringStruct, StringTable,
|
||||||
StringFileInfo, FixedFileInfo, VSVersionInfo, SetVersion,
|
StringFileInfo, FixedFileInfo, VSVersionInfo, SetVersion,
|
||||||
)
|
)
|
||||||
import PyInstaller.__main__
|
elif OS_NAME == 'Darwin':
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise Exception('{OS_NAME} is not supported')
|
||||||
|
|
||||||
arch = sys.argv[1] if len(sys.argv) > 1 else platform.architecture()[0][:2]
|
ARCH = platform.architecture()[0][:2]
|
||||||
assert arch in ('32', '64')
|
|
||||||
print('Building %sbit version' % arch)
|
|
||||||
_x86 = '_x86' if arch == '32' else ''
|
|
||||||
|
|
||||||
FILE_DESCRIPTION = 'Media Downloader%s' % (' (32 Bit)' if _x86 else '')
|
|
||||||
|
|
||||||
# root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
def main():
|
||||||
# print('Changing working directory to %s' % root_dir)
|
opts = parse_options()
|
||||||
# os.chdir(root_dir)
|
version = read_version()
|
||||||
|
|
||||||
exec(compile(open('yt_dlp/version.py').read(), 'yt_dlp/version.py', 'exec'))
|
suffix = '_macos' if OS_NAME == 'Darwin' else '_x86' if ARCH == '32' else ''
|
||||||
VERSION = locals()['__version__']
|
final_file = 'dist/%syt-dlp%s%s' % (
|
||||||
|
'yt-dlp/' if '--onedir' in opts else '', suffix, '.exe' if OS_NAME == 'Windows' else '')
|
||||||
|
|
||||||
VERSION_LIST = VERSION.split('.')
|
print(f'Building yt-dlp v{version} {ARCH}bit for {OS_NAME} with options {opts}')
|
||||||
VERSION_LIST = list(map(int, VERSION_LIST)) + [0] * (4 - len(VERSION_LIST))
|
print('Remember to update the version using "devscripts/update-version.py"')
|
||||||
|
if not os.path.isfile('yt_dlp/extractor/lazy_extractors.py'):
|
||||||
|
print('WARNING: Building without lazy_extractors. Run '
|
||||||
|
'"devscripts/make_lazy_extractors.py" to build lazy extractors', file=sys.stderr)
|
||||||
|
print(f'Destination: {final_file}\n')
|
||||||
|
|
||||||
print('Version: %s%s' % (VERSION, _x86))
|
opts = [
|
||||||
print('Remember to update the version using devscipts\\update-version.py')
|
f'--name=yt-dlp{suffix}',
|
||||||
|
'--icon=devscripts/logo.ico',
|
||||||
|
'--upx-exclude=vcruntime140.dll',
|
||||||
|
'--noconfirm',
|
||||||
|
*dependency_options(),
|
||||||
|
*opts,
|
||||||
|
'yt_dlp/__main__.py',
|
||||||
|
]
|
||||||
|
print(f'Running PyInstaller with {opts}')
|
||||||
|
|
||||||
VERSION_FILE = VSVersionInfo(
|
import PyInstaller.__main__
|
||||||
|
|
||||||
|
PyInstaller.__main__.run(opts)
|
||||||
|
|
||||||
|
set_version_info(final_file, version)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_options():
|
||||||
|
# Compatability with older arguments
|
||||||
|
opts = sys.argv[1:]
|
||||||
|
if opts[0:1] in (['32'], ['64']):
|
||||||
|
if ARCH != opts[0]:
|
||||||
|
raise Exception(f'{opts[0]}bit executable cannot be built on a {ARCH}bit system')
|
||||||
|
opts = opts[1:]
|
||||||
|
return opts or ['--onefile']
|
||||||
|
|
||||||
|
|
||||||
|
def read_version():
|
||||||
|
exec(compile(open('yt_dlp/version.py').read(), 'yt_dlp/version.py', 'exec'))
|
||||||
|
return locals()['__version__']
|
||||||
|
|
||||||
|
|
||||||
|
def version_to_list(version):
|
||||||
|
version_list = version.split('.')
|
||||||
|
return list(map(int, version_list)) + [0] * (4 - len(version_list))
|
||||||
|
|
||||||
|
|
||||||
|
def dependency_options():
|
||||||
|
dependencies = [pycryptodome_module(), 'mutagen'] + collect_submodules('websockets')
|
||||||
|
excluded_modules = ['test', 'ytdlp_plugins', 'youtube-dl', 'youtube-dlc']
|
||||||
|
|
||||||
|
yield from (f'--hidden-import={module}' for module in dependencies)
|
||||||
|
yield from (f'--exclude-module={module}' for module in excluded_modules)
|
||||||
|
|
||||||
|
|
||||||
|
def pycryptodome_module():
|
||||||
|
try:
|
||||||
|
import Cryptodome # noqa: F401
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
import Crypto # noqa: F401
|
||||||
|
print('WARNING: Using Crypto since Cryptodome is not available. '
|
||||||
|
'Install with: pip install pycryptodomex', file=sys.stderr)
|
||||||
|
return 'Crypto'
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
return 'Cryptodome'
|
||||||
|
|
||||||
|
|
||||||
|
def set_version_info(exe, version):
|
||||||
|
if OS_NAME == 'Windows':
|
||||||
|
windows_set_version(exe, version)
|
||||||
|
|
||||||
|
|
||||||
|
def windows_set_version(exe, version):
|
||||||
|
version_list = version_to_list(version)
|
||||||
|
suffix = '_x86' if ARCH == '32' else ''
|
||||||
|
SetVersion(exe, VSVersionInfo(
|
||||||
ffi=FixedFileInfo(
|
ffi=FixedFileInfo(
|
||||||
filevers=VERSION_LIST,
|
filevers=version_list,
|
||||||
prodvers=VERSION_LIST,
|
prodvers=version_list,
|
||||||
mask=0x3F,
|
mask=0x3F,
|
||||||
flags=0x0,
|
flags=0x0,
|
||||||
OS=0x4,
|
OS=0x4,
|
||||||
@@ -44,36 +115,21 @@ VERSION_FILE = VSVersionInfo(
|
|||||||
date=(0, 0),
|
date=(0, 0),
|
||||||
),
|
),
|
||||||
kids=[
|
kids=[
|
||||||
StringFileInfo([
|
StringFileInfo([StringTable('040904B0', [
|
||||||
StringTable(
|
StringStruct('Comments', 'yt-dlp%s Command Line Interface.' % suffix),
|
||||||
'040904B0', [
|
|
||||||
StringStruct('Comments', 'yt-dlp%s Command Line Interface.' % _x86),
|
|
||||||
StringStruct('CompanyName', 'https://github.com/yt-dlp'),
|
StringStruct('CompanyName', 'https://github.com/yt-dlp'),
|
||||||
StringStruct('FileDescription', FILE_DESCRIPTION),
|
StringStruct('FileDescription', 'yt-dlp%s' % (' (32 Bit)' if ARCH == '32' else '')),
|
||||||
StringStruct('FileVersion', VERSION),
|
StringStruct('FileVersion', version),
|
||||||
StringStruct('InternalName', 'yt-dlp%s' % _x86),
|
StringStruct('InternalName', f'yt-dlp{suffix}'),
|
||||||
|
StringStruct('LegalCopyright', 'pukkandan.ytdlp@gmail.com | UNLICENSE'),
|
||||||
|
StringStruct('OriginalFilename', f'yt-dlp{suffix}.exe'),
|
||||||
|
StringStruct('ProductName', f'yt-dlp{suffix}'),
|
||||||
StringStruct(
|
StringStruct(
|
||||||
'LegalCopyright',
|
'ProductVersion', f'{version}{suffix} on Python {platform.python_version()}'),
|
||||||
'pukkandan.ytdlp@gmail.com | UNLICENSE',
|
])]), VarFileInfo([VarStruct('Translation', [0, 1200])])
|
||||||
),
|
|
||||||
StringStruct('OriginalFilename', 'yt-dlp%s.exe' % _x86),
|
|
||||||
StringStruct('ProductName', 'yt-dlp%s' % _x86),
|
|
||||||
StringStruct('ProductVersion', '%s%s' % (VERSION, _x86)),
|
|
||||||
])]),
|
|
||||||
VarFileInfo([VarStruct('Translation', [0, 1200])])
|
|
||||||
]
|
]
|
||||||
)
|
))
|
||||||
|
|
||||||
PyInstaller.__main__.run([
|
|
||||||
'--name=yt-dlp%s' % _x86,
|
if __name__ == '__main__':
|
||||||
'--onefile',
|
main()
|
||||||
'--icon=devscripts/cloud.ico',
|
|
||||||
'--exclude-module=youtube_dl',
|
|
||||||
'--exclude-module=test',
|
|
||||||
'--exclude-module=ytdlp_plugins',
|
|
||||||
'--hidden-import=mutagen',
|
|
||||||
'--hidden-import=Crypto',
|
|
||||||
'--upx-exclude=vcruntime140.dll',
|
|
||||||
'yt_dlp/__main__.py',
|
|
||||||
])
|
|
||||||
SetVersion('dist/yt-dlp%s.exe' % _x86, VERSION_FILE)
|
|
||||||
|
|||||||
4
pytest.ini
Normal file
4
pytest.ini
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[pytest]
|
||||||
|
addopts = -ra -v --strict-markers
|
||||||
|
markers =
|
||||||
|
download
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
mutagen
|
mutagen
|
||||||
pycryptodome
|
pycryptodomex
|
||||||
|
websockets
|
||||||
|
|||||||
119
setup.py
119
setup.py
@@ -1,30 +1,59 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
from setuptools import setup, Command, find_packages
|
|
||||||
import os.path
|
import os.path
|
||||||
import warnings
|
import warnings
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
from setuptools import setup, Command, find_packages
|
||||||
|
setuptools_available = True
|
||||||
|
except ImportError:
|
||||||
|
from distutils.core import setup, Command
|
||||||
|
setuptools_available = False
|
||||||
from distutils.spawn import spawn
|
from distutils.spawn import spawn
|
||||||
|
|
||||||
|
|
||||||
# Get the version from yt_dlp/version.py without importing the package
|
# Get the version from yt_dlp/version.py without importing the package
|
||||||
exec(compile(open('yt_dlp/version.py').read(),
|
exec(compile(open('yt_dlp/version.py').read(), 'yt_dlp/version.py', 'exec'))
|
||||||
'yt_dlp/version.py', 'exec'))
|
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION = 'Command-line program to download videos from YouTube.com and many other other video platforms.'
|
DESCRIPTION = 'A youtube-dl fork with additional features and patches'
|
||||||
|
|
||||||
LONG_DESCRIPTION = '\n\n'.join((
|
LONG_DESCRIPTION = '\n\n'.join((
|
||||||
'Official repository: <https://github.com/yt-dlp/yt-dlp>',
|
'Official repository: <https://github.com/yt-dlp/yt-dlp>',
|
||||||
'**PS**: Many links in this document will not work since this is a copy of the README.md from Github',
|
'**PS**: Some links in this document will not work since this is a copy of the README.md from Github',
|
||||||
open("README.md", "r", encoding="utf-8").read()))
|
open('README.md', 'r', encoding='utf-8').read()))
|
||||||
|
|
||||||
REQUIREMENTS = ['mutagen', 'pycryptodome']
|
REQUIREMENTS = ['mutagen', 'pycryptodomex', 'websockets']
|
||||||
|
|
||||||
|
|
||||||
if len(sys.argv) >= 2 and sys.argv[1] == 'py2exe':
|
if sys.argv[1:2] == ['py2exe']:
|
||||||
print("inv")
|
import py2exe
|
||||||
|
warnings.warn(
|
||||||
|
'py2exe builds do not support pycryptodomex and needs VC++14 to run. '
|
||||||
|
'The recommended way is to use "pyinst.py" to build using pyinstaller')
|
||||||
|
params = {
|
||||||
|
'console': [{
|
||||||
|
'script': './yt_dlp/__main__.py',
|
||||||
|
'dest_base': 'yt-dlp',
|
||||||
|
'version': __version__,
|
||||||
|
'description': DESCRIPTION,
|
||||||
|
'comments': LONG_DESCRIPTION.split('\n')[0],
|
||||||
|
'product_name': 'yt-dlp',
|
||||||
|
'product_version': __version__,
|
||||||
|
}],
|
||||||
|
'options': {
|
||||||
|
'py2exe': {
|
||||||
|
'bundle_files': 0,
|
||||||
|
'compressed': 1,
|
||||||
|
'optimize': 2,
|
||||||
|
'dist_dir': './dist',
|
||||||
|
'excludes': ['Crypto', 'Cryptodome'], # py2exe cannot import Crypto
|
||||||
|
'dll_excludes': ['w9xpopen.exe', 'crypt32.dll'],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'zipfile': None
|
||||||
|
}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
files_spec = [
|
files_spec = [
|
||||||
('share/bash-completion/completions', ['completions/bash/yt-dlp']),
|
('share/bash-completion/completions', ['completions/bash/yt-dlp']),
|
||||||
@@ -39,7 +68,7 @@ else:
|
|||||||
resfiles = []
|
resfiles = []
|
||||||
for fn in files:
|
for fn in files:
|
||||||
if not os.path.exists(fn):
|
if not os.path.exists(fn):
|
||||||
warnings.warn('Skipping file %s since it is not present. Try running `make pypi-files` first.' % fn)
|
warnings.warn('Skipping file %s since it is not present. Try running `make pypi-files` first' % fn)
|
||||||
else:
|
else:
|
||||||
resfiles.append(fn)
|
resfiles.append(fn)
|
||||||
data_files.append((dirname, resfiles))
|
data_files.append((dirname, resfiles))
|
||||||
@@ -47,7 +76,11 @@ else:
|
|||||||
params = {
|
params = {
|
||||||
'data_files': data_files,
|
'data_files': data_files,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if setuptools_available:
|
||||||
params['entry_points'] = {'console_scripts': ['yt-dlp = yt_dlp:main']}
|
params['entry_points'] = {'console_scripts': ['yt-dlp = yt_dlp:main']}
|
||||||
|
else:
|
||||||
|
params['scripts'] = ['yt-dlp']
|
||||||
|
|
||||||
|
|
||||||
class build_lazy_extractors(Command):
|
class build_lazy_extractors(Command):
|
||||||
@@ -61,56 +94,48 @@ class build_lazy_extractors(Command):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
spawn(
|
spawn([sys.executable, 'devscripts/make_lazy_extractors.py', 'yt_dlp/extractor/lazy_extractors.py'],
|
||||||
[sys.executable, 'devscripts/make_lazy_extractors.py', 'yt_dlp/extractor/lazy_extractors.py'],
|
dry_run=self.dry_run)
|
||||||
dry_run=self.dry_run,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
packages = find_packages(exclude=("youtube_dl", "test", "ytdlp_plugins"))
|
if setuptools_available:
|
||||||
|
packages = find_packages(exclude=('youtube_dl', 'youtube_dlc', 'test', 'ytdlp_plugins'))
|
||||||
|
else:
|
||||||
|
packages = ['yt_dlp', 'yt_dlp.downloader', 'yt_dlp.extractor', 'yt_dlp.postprocessor']
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="yt-dlp",
|
name='yt-dlp',
|
||||||
version=__version__,
|
version=__version__,
|
||||||
maintainer="pukkandan",
|
maintainer='pukkandan',
|
||||||
maintainer_email="pukkandan.ytdlp@gmail.com",
|
maintainer_email='pukkandan.ytdlp@gmail.com',
|
||||||
description=DESCRIPTION,
|
description=DESCRIPTION,
|
||||||
long_description=LONG_DESCRIPTION,
|
long_description=LONG_DESCRIPTION,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type='text/markdown',
|
||||||
url="https://github.com/yt-dlp/yt-dlp",
|
url='https://github.com/yt-dlp/yt-dlp',
|
||||||
packages=packages,
|
packages=packages,
|
||||||
install_requires=REQUIREMENTS,
|
install_requires=REQUIREMENTS,
|
||||||
project_urls={
|
project_urls={
|
||||||
'Documentation': 'https://yt-dlp.readthedocs.io',
|
'Documentation': 'https://yt-dlp.readthedocs.io',
|
||||||
'Source': 'https://github.com/yt-dlp/yt-dlp',
|
'Source': 'https://github.com/yt-dlp/yt-dlp',
|
||||||
'Tracker': 'https://github.com/yt-dlp/yt-dlp/issues',
|
'Tracker': 'https://github.com/yt-dlp/yt-dlp/issues',
|
||||||
#'Funding': 'https://donate.pypi.org',
|
'Funding': 'https://github.com/yt-dlp/yt-dlp/blob/master/Collaborators.md#collaborators',
|
||||||
},
|
},
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Topic :: Multimedia :: Video",
|
'Topic :: Multimedia :: Video',
|
||||||
"Development Status :: 5 - Production/Stable",
|
'Development Status :: 5 - Production/Stable',
|
||||||
"Environment :: Console",
|
'Environment :: Console',
|
||||||
"Programming Language :: Python",
|
'Programming Language :: Python',
|
||||||
"Programming Language :: Python :: 2",
|
'Programming Language :: Python :: 3.6',
|
||||||
"Programming Language :: Python :: 2.6",
|
'Programming Language :: Python :: 3.7',
|
||||||
"Programming Language :: Python :: 2.7",
|
'Programming Language :: Python :: 3.8',
|
||||||
"Programming Language :: Python :: 3",
|
'Programming Language :: Python :: Implementation',
|
||||||
"Programming Language :: Python :: 3.2",
|
'Programming Language :: Python :: Implementation :: CPython',
|
||||||
"Programming Language :: Python :: 3.3",
|
'Programming Language :: Python :: Implementation :: PyPy',
|
||||||
"Programming Language :: Python :: 3.4",
|
'License :: Public Domain',
|
||||||
"Programming Language :: Python :: 3.5",
|
'Operating System :: OS Independent',
|
||||||
"Programming Language :: Python :: 3.6",
|
|
||||||
"Programming Language :: Python :: 3.7",
|
|
||||||
"Programming Language :: Python :: 3.8",
|
|
||||||
"Programming Language :: Python :: Implementation",
|
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
|
||||||
"Programming Language :: Python :: Implementation :: IronPython",
|
|
||||||
"Programming Language :: Python :: Implementation :: Jython",
|
|
||||||
"Programming Language :: Python :: Implementation :: PyPy",
|
|
||||||
"License :: Public Domain",
|
|
||||||
"Operating System :: OS Independent",
|
|
||||||
],
|
],
|
||||||
python_requires='>=2.6',
|
python_requires='>=3.6',
|
||||||
|
|
||||||
cmdclass={'build_lazy_extractors': build_lazy_extractors},
|
cmdclass={'build_lazy_extractors': build_lazy_extractors},
|
||||||
**params
|
**params
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -22,11 +22,19 @@ from yt_dlp.utils import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if 'pytest' in sys.modules:
|
||||||
|
import pytest
|
||||||
|
is_download_test = pytest.mark.download
|
||||||
|
else:
|
||||||
|
def is_download_test(testClass):
|
||||||
|
return testClass
|
||||||
|
|
||||||
|
|
||||||
def get_params(override=None):
|
def get_params(override=None):
|
||||||
PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||||
"parameters.json")
|
'parameters.json')
|
||||||
LOCAL_PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
LOCAL_PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||||
"local_parameters.json")
|
'local_parameters.json')
|
||||||
with io.open(PARAMETERS_FILE, encoding='utf-8') as pf:
|
with io.open(PARAMETERS_FILE, encoding='utf-8') as pf:
|
||||||
parameters = json.load(pf)
|
parameters = json.load(pf)
|
||||||
if os.path.exists(LOCAL_PARAMETERS_FILE):
|
if os.path.exists(LOCAL_PARAMETERS_FILE):
|
||||||
@@ -186,25 +194,75 @@ def expect_dict(self, got_dict, expected_dict):
|
|||||||
expect_value(self, got, expected, info_field)
|
expect_value(self, got, expected, info_field)
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_got_info_dict(got_dict):
|
||||||
|
IGNORED_FIELDS = (
|
||||||
|
# Format keys
|
||||||
|
'url', 'manifest_url', 'format', 'format_id', 'format_note', 'width', 'height', 'resolution',
|
||||||
|
'dynamic_range', 'tbr', 'abr', 'acodec', 'asr', 'vbr', 'fps', 'vcodec', 'container', 'filesize',
|
||||||
|
'filesize_approx', 'player_url', 'protocol', 'fragment_base_url', 'fragments', 'preference',
|
||||||
|
'language', 'language_preference', 'quality', 'source_preference', 'http_headers',
|
||||||
|
'stretched_ratio', 'no_resume', 'has_drm', 'downloader_options',
|
||||||
|
|
||||||
|
# RTMP formats
|
||||||
|
'page_url', 'app', 'play_path', 'tc_url', 'flash_version', 'rtmp_live', 'rtmp_conn', 'rtmp_protocol', 'rtmp_real_time',
|
||||||
|
|
||||||
|
# Lists
|
||||||
|
'formats', 'thumbnails', 'subtitles', 'automatic_captions', 'comments', 'entries',
|
||||||
|
|
||||||
|
# Auto-generated
|
||||||
|
'autonumber', 'playlist', 'format_index', 'video_ext', 'audio_ext', 'duration_string', 'epoch',
|
||||||
|
'fulltitle', 'extractor', 'extractor_key', 'filepath', 'infojson_filename', 'original_url', 'n_entries',
|
||||||
|
|
||||||
|
# Only live_status needs to be checked
|
||||||
|
'is_live', 'was_live',
|
||||||
|
)
|
||||||
|
|
||||||
|
IGNORED_PREFIXES = ('', 'playlist', 'requested', 'webpage')
|
||||||
|
|
||||||
|
def sanitize(key, value):
|
||||||
|
if isinstance(value, str) and len(value) > 100 and key != 'thumbnail':
|
||||||
|
return f'md5:{md5(value)}'
|
||||||
|
elif isinstance(value, list) and len(value) > 10:
|
||||||
|
return f'count:{len(value)}'
|
||||||
|
elif key.endswith('_count') and isinstance(value, int):
|
||||||
|
return int
|
||||||
|
return value
|
||||||
|
|
||||||
|
test_info_dict = {
|
||||||
|
key: sanitize(key, value) for key, value in got_dict.items()
|
||||||
|
if value is not None and key not in IGNORED_FIELDS and not any(
|
||||||
|
key.startswith(f'{prefix}_') for prefix in IGNORED_PREFIXES)
|
||||||
|
}
|
||||||
|
|
||||||
|
# display_id may be generated from id
|
||||||
|
if test_info_dict.get('display_id') == test_info_dict.get('id'):
|
||||||
|
test_info_dict.pop('display_id')
|
||||||
|
|
||||||
|
return test_info_dict
|
||||||
|
|
||||||
|
|
||||||
def expect_info_dict(self, got_dict, expected_dict):
|
def expect_info_dict(self, got_dict, expected_dict):
|
||||||
expect_dict(self, got_dict, expected_dict)
|
expect_dict(self, got_dict, expected_dict)
|
||||||
# Check for the presence of mandatory fields
|
# Check for the presence of mandatory fields
|
||||||
if got_dict.get('_type') not in ('playlist', 'multi_video'):
|
if got_dict.get('_type') not in ('playlist', 'multi_video'):
|
||||||
for key in ('id', 'url', 'title', 'ext'):
|
mandatory_fields = ['id', 'title']
|
||||||
|
if expected_dict.get('ext'):
|
||||||
|
mandatory_fields.extend(('url', 'ext'))
|
||||||
|
for key in mandatory_fields:
|
||||||
self.assertTrue(got_dict.get(key), 'Missing mandatory field %s' % key)
|
self.assertTrue(got_dict.get(key), 'Missing mandatory field %s' % key)
|
||||||
# Check for mandatory fields that are automatically set by YoutubeDL
|
# Check for mandatory fields that are automatically set by YoutubeDL
|
||||||
for key in ['webpage_url', 'extractor', 'extractor_key']:
|
for key in ['webpage_url', 'extractor', 'extractor_key']:
|
||||||
self.assertTrue(got_dict.get(key), 'Missing field: %s' % key)
|
self.assertTrue(got_dict.get(key), 'Missing field: %s' % key)
|
||||||
|
|
||||||
# Are checkable fields missing from the test case definition?
|
test_info_dict = sanitize_got_info_dict(got_dict)
|
||||||
test_info_dict = dict((key, value if not isinstance(value, compat_str) or len(value) < 250 else 'md5:' + md5(value))
|
|
||||||
for key, value in got_dict.items()
|
|
||||||
if value and key in ('id', 'title', 'description', 'uploader', 'upload_date', 'timestamp', 'uploader_id', 'location', 'age_limit'))
|
|
||||||
missing_keys = set(test_info_dict.keys()) - set(expected_dict.keys())
|
missing_keys = set(test_info_dict.keys()) - set(expected_dict.keys())
|
||||||
if missing_keys:
|
if missing_keys:
|
||||||
def _repr(v):
|
def _repr(v):
|
||||||
if isinstance(v, compat_str):
|
if isinstance(v, compat_str):
|
||||||
return "'%s'" % v.replace('\\', '\\\\').replace("'", "\\'").replace('\n', '\\n')
|
return "'%s'" % v.replace('\\', '\\\\').replace("'", "\\'").replace('\n', '\\n')
|
||||||
|
elif isinstance(v, type):
|
||||||
|
return v.__name__
|
||||||
else:
|
else:
|
||||||
return repr(v)
|
return repr(v)
|
||||||
info_dict_str = ''
|
info_dict_str = ''
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"check_formats": false,
|
||||||
"consoletitle": false,
|
"consoletitle": false,
|
||||||
"continuedl": true,
|
"continuedl": true,
|
||||||
"forcedescription": false,
|
"forcedescription": false,
|
||||||
@@ -8,7 +9,7 @@
|
|||||||
"forcetitle": false,
|
"forcetitle": false,
|
||||||
"forceurl": false,
|
"forceurl": false,
|
||||||
"force_write_download_archive": false,
|
"force_write_download_archive": false,
|
||||||
"format": "best",
|
"format": "b/bv",
|
||||||
"ignoreerrors": false,
|
"ignoreerrors": false,
|
||||||
"listformats": null,
|
"listformats": null,
|
||||||
"logtostderr": false,
|
"logtostderr": false,
|
||||||
@@ -19,7 +20,6 @@
|
|||||||
"noprogress": false,
|
"noprogress": false,
|
||||||
"outtmpl": "%(id)s.%(ext)s",
|
"outtmpl": "%(id)s.%(ext)s",
|
||||||
"password": null,
|
"password": null,
|
||||||
"playlistend": -1,
|
|
||||||
"playliststart": 1,
|
"playliststart": 1,
|
||||||
"prefer_free_formats": false,
|
"prefer_free_formats": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
@@ -44,6 +44,5 @@
|
|||||||
"writesubtitles": false,
|
"writesubtitles": false,
|
||||||
"allsubtitles": false,
|
"allsubtitles": false,
|
||||||
"listsubtitles": false,
|
"listsubtitles": false,
|
||||||
"socket_timeout": 20,
|
|
||||||
"fixup": "never"
|
"fixup": "never"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
@@ -35,13 +35,13 @@ class InfoExtractorTestRequestHandler(compat_http_server.BaseHTTPRequestHandler)
|
|||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
||||||
class TestIE(InfoExtractor):
|
class DummyIE(InfoExtractor):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestInfoExtractor(unittest.TestCase):
|
class TestInfoExtractor(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.ie = TestIE(FakeYDL())
|
self.ie = DummyIE(FakeYDL())
|
||||||
|
|
||||||
def test_ie_key(self):
|
def test_ie_key(self):
|
||||||
self.assertEqual(get_info_extractor(YoutubeIE.ie_key()), YoutubeIE)
|
self.assertEqual(get_info_extractor(YoutubeIE.ie_key()), YoutubeIE)
|
||||||
@@ -99,10 +99,10 @@ class TestInfoExtractor(unittest.TestCase):
|
|||||||
self.assertRaises(RegexNotFoundError, ie._html_search_meta, ('z', 'x'), html, None, fatal=True)
|
self.assertRaises(RegexNotFoundError, ie._html_search_meta, ('z', 'x'), html, None, fatal=True)
|
||||||
|
|
||||||
def test_search_json_ld_realworld(self):
|
def test_search_json_ld_realworld(self):
|
||||||
|
_TESTS = [
|
||||||
# https://github.com/ytdl-org/youtube-dl/issues/23306
|
# https://github.com/ytdl-org/youtube-dl/issues/23306
|
||||||
expect_dict(
|
(
|
||||||
self,
|
r'''<script type="application/ld+json">
|
||||||
self.ie._search_json_ld(r'''<script type="application/ld+json">
|
|
||||||
{
|
{
|
||||||
"@context": "http://schema.org/",
|
"@context": "http://schema.org/",
|
||||||
"@type": "VideoObject",
|
"@type": "VideoObject",
|
||||||
@@ -135,7 +135,7 @@ class TestInfoExtractor(unittest.TestCase):
|
|||||||
"name": "Kleio Valentien",
|
"name": "Kleio Valentien",
|
||||||
"url": "https://www.eporner.com/pornstar/kleio-valentien/"
|
"url": "https://www.eporner.com/pornstar/kleio-valentien/"
|
||||||
}]}
|
}]}
|
||||||
</script>''', None),
|
</script>''',
|
||||||
{
|
{
|
||||||
'title': '1 On 1 With Kleio',
|
'title': '1 On 1 With Kleio',
|
||||||
'description': 'Kleio Valentien',
|
'description': 'Kleio Valentien',
|
||||||
@@ -145,7 +145,161 @@ class TestInfoExtractor(unittest.TestCase):
|
|||||||
'view_count': 1120958,
|
'view_count': 1120958,
|
||||||
'width': 1920,
|
'width': 1920,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
})
|
},
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
r'''<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"@type": "NewsArticle",
|
||||||
|
"mainEntityOfPage": {
|
||||||
|
"@type": "WebPage",
|
||||||
|
"@id": "https://www.ant1news.gr/Society/article/620286/symmoria-anilikon-dikigoros-thymaton-ithelan-na-toys-apoteleiosoyn"
|
||||||
|
},
|
||||||
|
"headline": "Συμμορία ανηλίκων – δικηγόρος θυμάτων: ήθελαν να τους αποτελειώσουν",
|
||||||
|
"name": "Συμμορία ανηλίκων – δικηγόρος θυμάτων: ήθελαν να τους αποτελειώσουν",
|
||||||
|
"description": "Τα παιδιά δέχθηκαν την επίθεση επειδή αρνήθηκαν να γίνουν μέλη της συμμορίας, ανέφερε ο Γ. Ζαχαρόπουλος.",
|
||||||
|
"image": {
|
||||||
|
"@type": "ImageObject",
|
||||||
|
"url": "https://ant1media.azureedge.net/imgHandler/1100/a635c968-be71-447c-bf9c-80d843ece21e.jpg",
|
||||||
|
"width": 1100,
|
||||||
|
"height": 756 },
|
||||||
|
"datePublished": "2021-11-10T08:50:00+03:00",
|
||||||
|
"dateModified": "2021-11-10T08:52:53+03:00",
|
||||||
|
"author": {
|
||||||
|
"@type": "Person",
|
||||||
|
"@id": "https://www.ant1news.gr/",
|
||||||
|
"name": "Ant1news",
|
||||||
|
"image": "https://www.ant1news.gr/images/logo-e5d7e4b3e714c88e8d2eca96130142f6.png",
|
||||||
|
"url": "https://www.ant1news.gr/"
|
||||||
|
},
|
||||||
|
"publisher": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"@id": "https://www.ant1news.gr#publisher",
|
||||||
|
"name": "Ant1news",
|
||||||
|
"url": "https://www.ant1news.gr",
|
||||||
|
"logo": {
|
||||||
|
"@type": "ImageObject",
|
||||||
|
"url": "https://www.ant1news.gr/images/logo-e5d7e4b3e714c88e8d2eca96130142f6.png",
|
||||||
|
"width": 400,
|
||||||
|
"height": 400 },
|
||||||
|
"sameAs": [
|
||||||
|
"https://www.facebook.com/Ant1news.gr",
|
||||||
|
"https://twitter.com/antennanews",
|
||||||
|
"https://www.youtube.com/channel/UC0smvAbfczoN75dP0Hw4Pzw",
|
||||||
|
"https://www.instagram.com/ant1news/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"keywords": "μαχαίρωμα,συμμορία ανηλίκων,ΕΙΔΗΣΕΙΣ,ΕΙΔΗΣΕΙΣ ΣΗΜΕΡΑ,ΝΕΑ,Κοινωνία - Ant1news",
|
||||||
|
|
||||||
|
|
||||||
|
"articleSection": "Κοινωνία"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</script>''',
|
||||||
|
{
|
||||||
|
'timestamp': 1636523400,
|
||||||
|
'title': 'md5:91fe569e952e4d146485740ae927662b',
|
||||||
|
},
|
||||||
|
{'expected_type': 'NewsArticle'},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
r'''<script type="application/ld+json">
|
||||||
|
{"url":"/vrtnu/a-z/het-journaal/2021/het-journaal-het-journaal-19u-20211231/",
|
||||||
|
"name":"Het journaal 19u",
|
||||||
|
"description":"Het journaal 19u van vrijdag 31 december 2021.",
|
||||||
|
"potentialAction":{"url":"https://vrtnu.page.link/pfVy6ihgCAJKgHqe8","@type":"ShareAction"},
|
||||||
|
"mainEntityOfPage":{"@id":"1640092242445","@type":"WebPage"},
|
||||||
|
"publication":[{
|
||||||
|
"startDate":"2021-12-31T19:00:00.000+01:00",
|
||||||
|
"endDate":"2022-01-30T23:55:00.000+01:00",
|
||||||
|
"publishedBy":{"name":"een","@type":"Organization"},
|
||||||
|
"publishedOn":{"url":"https://www.vrt.be/vrtnu/","name":"VRT NU","@type":"BroadcastService"},
|
||||||
|
"@id":"pbs-pub-3a7ec233-da95-4c1e-9b2b-cf5fdfebcbe8",
|
||||||
|
"@type":"BroadcastEvent"
|
||||||
|
}],
|
||||||
|
"video":{
|
||||||
|
"name":"Het journaal - Aflevering 365 (Seizoen 2021)",
|
||||||
|
"description":"Het journaal 19u van vrijdag 31 december 2021. Bekijk aflevering 365 van seizoen 2021 met VRT NU via de site of app.",
|
||||||
|
"thumbnailUrl":"//images.vrt.be/width1280/2021/12/31/80d5ed00-6a64-11ec-b07d-02b7b76bf47f.jpg",
|
||||||
|
"expires":"2022-01-30T23:55:00.000+01:00",
|
||||||
|
"hasPart":[
|
||||||
|
{"name":"Explosie Turnhout","startOffset":70,"@type":"Clip"},
|
||||||
|
{"name":"Jaarwisseling","startOffset":440,"@type":"Clip"},
|
||||||
|
{"name":"Natuurbranden Colorado","startOffset":1179,"@type":"Clip"},
|
||||||
|
{"name":"Klimaatverandering","startOffset":1263,"@type":"Clip"},
|
||||||
|
{"name":"Zacht weer","startOffset":1367,"@type":"Clip"},
|
||||||
|
{"name":"Financiële balans","startOffset":1383,"@type":"Clip"},
|
||||||
|
{"name":"Club Brugge","startOffset":1484,"@type":"Clip"},
|
||||||
|
{"name":"Mentale gezondheid bij topsporters","startOffset":1575,"@type":"Clip"},
|
||||||
|
{"name":"Olympische Winterspelen","startOffset":1728,"@type":"Clip"},
|
||||||
|
{"name":"Sober oudjaar in Nederland","startOffset":1873,"@type":"Clip"}
|
||||||
|
],
|
||||||
|
"duration":"PT34M39.23S",
|
||||||
|
"uploadDate":"2021-12-31T19:00:00.000+01:00",
|
||||||
|
"@id":"vid-9457d0c6-b8ac-4aba-b5e1-15aa3a3295b5",
|
||||||
|
"@type":"VideoObject"
|
||||||
|
},
|
||||||
|
"genre":["Nieuws en actua"],
|
||||||
|
"episodeNumber":365,
|
||||||
|
"partOfSeries":{"name":"Het journaal","@id":"222831405527","@type":"TVSeries"},
|
||||||
|
"partOfSeason":{"name":"Seizoen 2021","@id":"961809365527","@type":"TVSeason"},
|
||||||
|
"@context":"https://schema.org","@id":"961685295527","@type":"TVEpisode"}</script>
|
||||||
|
''',
|
||||||
|
{
|
||||||
|
'chapters': [
|
||||||
|
{"title": "Explosie Turnhout", "start_time": 70, "end_time": 440},
|
||||||
|
{"title": "Jaarwisseling", "start_time": 440, "end_time": 1179},
|
||||||
|
{"title": "Natuurbranden Colorado", "start_time": 1179, "end_time": 1263},
|
||||||
|
{"title": "Klimaatverandering", "start_time": 1263, "end_time": 1367},
|
||||||
|
{"title": "Zacht weer", "start_time": 1367, "end_time": 1383},
|
||||||
|
{"title": "Financiële balans", "start_time": 1383, "end_time": 1484},
|
||||||
|
{"title": "Club Brugge", "start_time": 1484, "end_time": 1575},
|
||||||
|
{"title": "Mentale gezondheid bij topsporters", "start_time": 1575, "end_time": 1728},
|
||||||
|
{"title": "Olympische Winterspelen", "start_time": 1728, "end_time": 1873},
|
||||||
|
{"title": "Sober oudjaar in Nederland", "start_time": 1873, "end_time": 2079.23}
|
||||||
|
],
|
||||||
|
'title': 'Het journaal - Aflevering 365 (Seizoen 2021)'
|
||||||
|
}, {}
|
||||||
|
),
|
||||||
|
(
|
||||||
|
# test multiple thumbnails in a list
|
||||||
|
r'''
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{"@context":"https://schema.org",
|
||||||
|
"@type":"VideoObject",
|
||||||
|
"thumbnailUrl":["https://www.rainews.it/cropgd/640x360/dl/img/2021/12/30/1640886376927_GettyImages.jpg"]}
|
||||||
|
</script>''',
|
||||||
|
{
|
||||||
|
'thumbnails': [{'url': 'https://www.rainews.it/cropgd/640x360/dl/img/2021/12/30/1640886376927_GettyImages.jpg'}],
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
# test single thumbnail
|
||||||
|
r'''
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{"@context":"https://schema.org",
|
||||||
|
"@type":"VideoObject",
|
||||||
|
"thumbnailUrl":"https://www.rainews.it/cropgd/640x360/dl/img/2021/12/30/1640886376927_GettyImages.jpg"}
|
||||||
|
</script>''',
|
||||||
|
{
|
||||||
|
'thumbnails': [{'url': 'https://www.rainews.it/cropgd/640x360/dl/img/2021/12/30/1640886376927_GettyImages.jpg'}],
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
]
|
||||||
|
for html, expected_dict, search_json_ld_kwargs in _TESTS:
|
||||||
|
expect_dict(
|
||||||
|
self,
|
||||||
|
self.ie._search_json_ld(html, None, **search_json_ld_kwargs),
|
||||||
|
expected_dict
|
||||||
|
)
|
||||||
|
|
||||||
def test_download_json(self):
|
def test_download_json(self):
|
||||||
uri = encode_data_uri(b'{"foo": "blah"}', 'application/json')
|
uri = encode_data_uri(b'{"foo": "blah"}', 'application/json')
|
||||||
@@ -450,7 +604,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'audio_ext': 'mp4',
|
'audio_ext': 'mp4',
|
||||||
}, {
|
}, {
|
||||||
'format_id': 'aud2-English',
|
'format_id': 'aud2-English',
|
||||||
@@ -458,7 +612,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'audio_ext': 'mp4',
|
'audio_ext': 'mp4',
|
||||||
}, {
|
}, {
|
||||||
'format_id': 'aud3-English',
|
'format_id': 'aud3-English',
|
||||||
@@ -466,14 +620,14 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'audio_ext': 'mp4',
|
'audio_ext': 'mp4',
|
||||||
}, {
|
}, {
|
||||||
'format_id': '530',
|
'format_id': '530',
|
||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v2/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v2/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 480,
|
'width': 480,
|
||||||
'height': 270,
|
'height': 270,
|
||||||
'vcodec': 'avc1.640015',
|
'vcodec': 'avc1.640015',
|
||||||
@@ -482,7 +636,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v2/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v2/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 480,
|
'width': 480,
|
||||||
'height': 270,
|
'height': 270,
|
||||||
'vcodec': 'avc1.640015',
|
'vcodec': 'avc1.640015',
|
||||||
@@ -491,7 +645,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v2/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v2/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 480,
|
'width': 480,
|
||||||
'height': 270,
|
'height': 270,
|
||||||
'vcodec': 'avc1.640015',
|
'vcodec': 'avc1.640015',
|
||||||
@@ -500,7 +654,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v3/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v3/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 640,
|
'width': 640,
|
||||||
'height': 360,
|
'height': 360,
|
||||||
'vcodec': 'avc1.64001e',
|
'vcodec': 'avc1.64001e',
|
||||||
@@ -509,7 +663,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v3/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v3/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 640,
|
'width': 640,
|
||||||
'height': 360,
|
'height': 360,
|
||||||
'vcodec': 'avc1.64001e',
|
'vcodec': 'avc1.64001e',
|
||||||
@@ -518,7 +672,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v3/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v3/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 640,
|
'width': 640,
|
||||||
'height': 360,
|
'height': 360,
|
||||||
'vcodec': 'avc1.64001e',
|
'vcodec': 'avc1.64001e',
|
||||||
@@ -527,7 +681,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v4/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v4/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 768,
|
'width': 768,
|
||||||
'height': 432,
|
'height': 432,
|
||||||
'vcodec': 'avc1.64001e',
|
'vcodec': 'avc1.64001e',
|
||||||
@@ -536,7 +690,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v4/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v4/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 768,
|
'width': 768,
|
||||||
'height': 432,
|
'height': 432,
|
||||||
'vcodec': 'avc1.64001e',
|
'vcodec': 'avc1.64001e',
|
||||||
@@ -545,7 +699,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v4/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v4/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 768,
|
'width': 768,
|
||||||
'height': 432,
|
'height': 432,
|
||||||
'vcodec': 'avc1.64001e',
|
'vcodec': 'avc1.64001e',
|
||||||
@@ -554,7 +708,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v5/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v5/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 960,
|
'width': 960,
|
||||||
'height': 540,
|
'height': 540,
|
||||||
'vcodec': 'avc1.640020',
|
'vcodec': 'avc1.640020',
|
||||||
@@ -563,7 +717,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v5/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v5/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 960,
|
'width': 960,
|
||||||
'height': 540,
|
'height': 540,
|
||||||
'vcodec': 'avc1.640020',
|
'vcodec': 'avc1.640020',
|
||||||
@@ -572,7 +726,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v5/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v5/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 960,
|
'width': 960,
|
||||||
'height': 540,
|
'height': 540,
|
||||||
'vcodec': 'avc1.640020',
|
'vcodec': 'avc1.640020',
|
||||||
@@ -581,7 +735,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v6/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v6/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 1280,
|
'width': 1280,
|
||||||
'height': 720,
|
'height': 720,
|
||||||
'vcodec': 'avc1.640020',
|
'vcodec': 'avc1.640020',
|
||||||
@@ -590,7 +744,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v6/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v6/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 1280,
|
'width': 1280,
|
||||||
'height': 720,
|
'height': 720,
|
||||||
'vcodec': 'avc1.640020',
|
'vcodec': 'avc1.640020',
|
||||||
@@ -599,7 +753,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v6/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v6/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 1280,
|
'width': 1280,
|
||||||
'height': 720,
|
'height': 720,
|
||||||
'vcodec': 'avc1.640020',
|
'vcodec': 'avc1.640020',
|
||||||
@@ -608,7 +762,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v7/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v7/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 1920,
|
'width': 1920,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
'vcodec': 'avc1.64002a',
|
'vcodec': 'avc1.64002a',
|
||||||
@@ -617,7 +771,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v7/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v7/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 1920,
|
'width': 1920,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
'vcodec': 'avc1.64002a',
|
'vcodec': 'avc1.64002a',
|
||||||
@@ -626,7 +780,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v7/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v7/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 1920,
|
'width': 1920,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
'vcodec': 'avc1.64002a',
|
'vcodec': 'avc1.64002a',
|
||||||
@@ -635,7 +789,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v8/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v8/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 1920,
|
'width': 1920,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
'vcodec': 'avc1.64002a',
|
'vcodec': 'avc1.64002a',
|
||||||
@@ -644,7 +798,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v8/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v8/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 1920,
|
'width': 1920,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
'vcodec': 'avc1.64002a',
|
'vcodec': 'avc1.64002a',
|
||||||
@@ -653,7 +807,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v8/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v8/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 1920,
|
'width': 1920,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
'vcodec': 'avc1.64002a',
|
'vcodec': 'avc1.64002a',
|
||||||
@@ -662,7 +816,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v9/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v9/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 1920,
|
'width': 1920,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
'vcodec': 'avc1.64002a',
|
'vcodec': 'avc1.64002a',
|
||||||
@@ -671,7 +825,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v9/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v9/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 1920,
|
'width': 1920,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
'vcodec': 'avc1.64002a',
|
'vcodec': 'avc1.64002a',
|
||||||
@@ -680,21 +834,190 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v9/prog_index.m3u8',
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v9/prog_index.m3u8',
|
||||||
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'protocol': 'm3u8',
|
'protocol': 'm3u8_native',
|
||||||
'width': 1920,
|
'width': 1920,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
'vcodec': 'avc1.64002a',
|
'vcodec': 'avc1.64002a',
|
||||||
}]
|
}],
|
||||||
|
{}
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'bipbop_16x9',
|
||||||
|
'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
|
||||||
|
[{
|
||||||
|
'format_id': 'bipbop_audio-BipBop Audio 2',
|
||||||
|
'format_index': None,
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/alternate_audio_aac/prog_index.m3u8',
|
||||||
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
|
||||||
|
'language': 'eng',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'protocol': 'm3u8_native',
|
||||||
|
'preference': None,
|
||||||
|
'quality': None,
|
||||||
|
'vcodec': 'none',
|
||||||
|
'audio_ext': 'mp4',
|
||||||
|
'video_ext': 'none',
|
||||||
|
}, {
|
||||||
|
'format_id': '41',
|
||||||
|
'format_index': None,
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/gear0/prog_index.m3u8',
|
||||||
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
|
||||||
|
'tbr': 41.457,
|
||||||
|
'ext': 'mp4',
|
||||||
|
'fps': None,
|
||||||
|
'protocol': 'm3u8_native',
|
||||||
|
'preference': None,
|
||||||
|
'quality': None,
|
||||||
|
'vcodec': 'none',
|
||||||
|
'acodec': 'mp4a.40.2',
|
||||||
|
'audio_ext': 'mp4',
|
||||||
|
'video_ext': 'none',
|
||||||
|
'abr': 41.457,
|
||||||
|
}, {
|
||||||
|
'format_id': '263',
|
||||||
|
'format_index': None,
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/gear1/prog_index.m3u8',
|
||||||
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
|
||||||
|
'tbr': 263.851,
|
||||||
|
'ext': 'mp4',
|
||||||
|
'fps': None,
|
||||||
|
'protocol': 'm3u8_native',
|
||||||
|
'preference': None,
|
||||||
|
'quality': None,
|
||||||
|
'width': 416,
|
||||||
|
'height': 234,
|
||||||
|
'vcodec': 'avc1.4d400d',
|
||||||
|
'acodec': 'mp4a.40.2',
|
||||||
|
'video_ext': 'mp4',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 263.851,
|
||||||
|
'abr': 0,
|
||||||
|
}, {
|
||||||
|
'format_id': '577',
|
||||||
|
'format_index': None,
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/gear2/prog_index.m3u8',
|
||||||
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
|
||||||
|
'tbr': 577.61,
|
||||||
|
'ext': 'mp4',
|
||||||
|
'fps': None,
|
||||||
|
'protocol': 'm3u8_native',
|
||||||
|
'preference': None,
|
||||||
|
'quality': None,
|
||||||
|
'width': 640,
|
||||||
|
'height': 360,
|
||||||
|
'vcodec': 'avc1.4d401e',
|
||||||
|
'acodec': 'mp4a.40.2',
|
||||||
|
'video_ext': 'mp4',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 577.61,
|
||||||
|
'abr': 0,
|
||||||
|
}, {
|
||||||
|
'format_id': '915',
|
||||||
|
'format_index': None,
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/gear3/prog_index.m3u8',
|
||||||
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
|
||||||
|
'tbr': 915.905,
|
||||||
|
'ext': 'mp4',
|
||||||
|
'fps': None,
|
||||||
|
'protocol': 'm3u8_native',
|
||||||
|
'preference': None,
|
||||||
|
'quality': None,
|
||||||
|
'width': 960,
|
||||||
|
'height': 540,
|
||||||
|
'vcodec': 'avc1.4d401f',
|
||||||
|
'acodec': 'mp4a.40.2',
|
||||||
|
'video_ext': 'mp4',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 915.905,
|
||||||
|
'abr': 0,
|
||||||
|
}, {
|
||||||
|
'format_id': '1030',
|
||||||
|
'format_index': None,
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/gear4/prog_index.m3u8',
|
||||||
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
|
||||||
|
'tbr': 1030.138,
|
||||||
|
'ext': 'mp4',
|
||||||
|
'fps': None,
|
||||||
|
'protocol': 'm3u8_native',
|
||||||
|
'preference': None,
|
||||||
|
'quality': None,
|
||||||
|
'width': 1280,
|
||||||
|
'height': 720,
|
||||||
|
'vcodec': 'avc1.4d401f',
|
||||||
|
'acodec': 'mp4a.40.2',
|
||||||
|
'video_ext': 'mp4',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 1030.138,
|
||||||
|
'abr': 0,
|
||||||
|
}, {
|
||||||
|
'format_id': '1924',
|
||||||
|
'format_index': None,
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/gear5/prog_index.m3u8',
|
||||||
|
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
|
||||||
|
'tbr': 1924.009,
|
||||||
|
'ext': 'mp4',
|
||||||
|
'fps': None,
|
||||||
|
'protocol': 'm3u8_native',
|
||||||
|
'preference': None,
|
||||||
|
'quality': None,
|
||||||
|
'width': 1920,
|
||||||
|
'height': 1080,
|
||||||
|
'vcodec': 'avc1.4d401f',
|
||||||
|
'acodec': 'mp4a.40.2',
|
||||||
|
'video_ext': 'mp4',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 1924.009,
|
||||||
|
'abr': 0,
|
||||||
|
}],
|
||||||
|
{
|
||||||
|
'en': [{
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/eng/prog_index.m3u8',
|
||||||
|
'ext': 'vtt',
|
||||||
|
'protocol': 'm3u8_native'
|
||||||
|
}, {
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/eng_forced/prog_index.m3u8',
|
||||||
|
'ext': 'vtt',
|
||||||
|
'protocol': 'm3u8_native'
|
||||||
|
}],
|
||||||
|
'fr': [{
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/fra/prog_index.m3u8',
|
||||||
|
'ext': 'vtt',
|
||||||
|
'protocol': 'm3u8_native'
|
||||||
|
}, {
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/fra_forced/prog_index.m3u8',
|
||||||
|
'ext': 'vtt',
|
||||||
|
'protocol': 'm3u8_native'
|
||||||
|
}],
|
||||||
|
'es': [{
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/spa/prog_index.m3u8',
|
||||||
|
'ext': 'vtt',
|
||||||
|
'protocol': 'm3u8_native'
|
||||||
|
}, {
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/spa_forced/prog_index.m3u8',
|
||||||
|
'ext': 'vtt',
|
||||||
|
'protocol': 'm3u8_native'
|
||||||
|
}],
|
||||||
|
'ja': [{
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/jpn/prog_index.m3u8',
|
||||||
|
'ext': 'vtt',
|
||||||
|
'protocol': 'm3u8_native'
|
||||||
|
}, {
|
||||||
|
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/jpn_forced/prog_index.m3u8',
|
||||||
|
'ext': 'vtt',
|
||||||
|
'protocol': 'm3u8_native'
|
||||||
|
}],
|
||||||
|
}
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
for m3u8_file, m3u8_url, expected_formats in _TEST_CASES:
|
for m3u8_file, m3u8_url, expected_formats, expected_subs in _TEST_CASES:
|
||||||
with io.open('./test/testdata/m3u8/%s.m3u8' % m3u8_file,
|
with io.open('./test/testdata/m3u8/%s.m3u8' % m3u8_file,
|
||||||
mode='r', encoding='utf-8') as f:
|
mode='r', encoding='utf-8') as f:
|
||||||
formats = self.ie._parse_m3u8_formats(
|
formats, subs = self.ie._parse_m3u8_formats_and_subtitles(
|
||||||
f.read(), m3u8_url, ext='mp4')
|
f.read(), m3u8_url, ext='mp4')
|
||||||
self.ie._sort_formats(formats)
|
self.ie._sort_formats(formats)
|
||||||
expect_value(self, formats, expected_formats, None)
|
expect_value(self, formats, expected_formats, None)
|
||||||
|
expect_value(self, subs, expected_subs, None)
|
||||||
|
|
||||||
def test_parse_mpd_formats(self):
|
def test_parse_mpd_formats(self):
|
||||||
_TEST_CASES = [
|
_TEST_CASES = [
|
||||||
@@ -780,7 +1103,8 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'tbr': 5997.485,
|
'tbr': 5997.485,
|
||||||
'width': 1920,
|
'width': 1920,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
}]
|
}],
|
||||||
|
{},
|
||||||
), (
|
), (
|
||||||
# https://github.com/ytdl-org/youtube-dl/pull/14844
|
# https://github.com/ytdl-org/youtube-dl/pull/14844
|
||||||
'urls_only',
|
'urls_only',
|
||||||
@@ -863,7 +1187,8 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'tbr': 4400,
|
'tbr': 4400,
|
||||||
'width': 1920,
|
'width': 1920,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
}]
|
}],
|
||||||
|
{},
|
||||||
), (
|
), (
|
||||||
# https://github.com/ytdl-org/youtube-dl/issues/20346
|
# https://github.com/ytdl-org/youtube-dl/issues/20346
|
||||||
# Media considered unfragmented even though it contains
|
# Media considered unfragmented even though it contains
|
||||||
@@ -909,18 +1234,328 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
|
|||||||
'width': 360,
|
'width': 360,
|
||||||
'height': 360,
|
'height': 360,
|
||||||
'fps': 30,
|
'fps': 30,
|
||||||
}]
|
}],
|
||||||
|
{},
|
||||||
|
), (
|
||||||
|
'subtitles',
|
||||||
|
'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/',
|
||||||
|
[{
|
||||||
|
'format_id': 'audio=128001',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'ext': 'm4a',
|
||||||
|
'tbr': 128.001,
|
||||||
|
'asr': 48000,
|
||||||
|
'format_note': 'DASH audio',
|
||||||
|
'container': 'm4a_dash',
|
||||||
|
'vcodec': 'none',
|
||||||
|
'acodec': 'mp4a.40.2',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
|
||||||
|
'protocol': 'http_dash_segments',
|
||||||
|
'audio_ext': 'm4a',
|
||||||
|
'video_ext': 'none',
|
||||||
|
'abr': 128.001,
|
||||||
|
}, {
|
||||||
|
'format_id': 'video=100000',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'width': 336,
|
||||||
|
'height': 144,
|
||||||
|
'tbr': 100,
|
||||||
|
'format_note': 'DASH video',
|
||||||
|
'container': 'mp4_dash',
|
||||||
|
'vcodec': 'avc1.4D401F',
|
||||||
|
'acodec': 'none',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
|
||||||
|
'protocol': 'http_dash_segments',
|
||||||
|
'video_ext': 'mp4',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 100,
|
||||||
|
}, {
|
||||||
|
'format_id': 'video=326000',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'width': 562,
|
||||||
|
'height': 240,
|
||||||
|
'tbr': 326,
|
||||||
|
'format_note': 'DASH video',
|
||||||
|
'container': 'mp4_dash',
|
||||||
|
'vcodec': 'avc1.4D401F',
|
||||||
|
'acodec': 'none',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
|
||||||
|
'protocol': 'http_dash_segments',
|
||||||
|
'video_ext': 'mp4',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 326,
|
||||||
|
}, {
|
||||||
|
'format_id': 'video=698000',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'width': 844,
|
||||||
|
'height': 360,
|
||||||
|
'tbr': 698,
|
||||||
|
'format_note': 'DASH video',
|
||||||
|
'container': 'mp4_dash',
|
||||||
|
'vcodec': 'avc1.4D401F',
|
||||||
|
'acodec': 'none',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
|
||||||
|
'protocol': 'http_dash_segments',
|
||||||
|
'video_ext': 'mp4',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 698,
|
||||||
|
}, {
|
||||||
|
'format_id': 'video=1493000',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'width': 1126,
|
||||||
|
'height': 480,
|
||||||
|
'tbr': 1493,
|
||||||
|
'format_note': 'DASH video',
|
||||||
|
'container': 'mp4_dash',
|
||||||
|
'vcodec': 'avc1.4D401F',
|
||||||
|
'acodec': 'none',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
|
||||||
|
'protocol': 'http_dash_segments',
|
||||||
|
'video_ext': 'mp4',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 1493,
|
||||||
|
}, {
|
||||||
|
'format_id': 'video=4482000',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'width': 1688,
|
||||||
|
'height': 720,
|
||||||
|
'tbr': 4482,
|
||||||
|
'format_note': 'DASH video',
|
||||||
|
'container': 'mp4_dash',
|
||||||
|
'vcodec': 'avc1.4D401F',
|
||||||
|
'acodec': 'none',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
|
||||||
|
'protocol': 'http_dash_segments',
|
||||||
|
'video_ext': 'mp4',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 4482,
|
||||||
|
}],
|
||||||
|
{
|
||||||
|
'en': [
|
||||||
|
{
|
||||||
|
'ext': 'mp4',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
|
||||||
|
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
|
||||||
|
'protocol': 'http_dash_segments',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
for mpd_file, mpd_url, mpd_base_url, expected_formats in _TEST_CASES:
|
for mpd_file, mpd_url, mpd_base_url, expected_formats, expected_subtitles in _TEST_CASES:
|
||||||
with io.open('./test/testdata/mpd/%s.mpd' % mpd_file,
|
with io.open('./test/testdata/mpd/%s.mpd' % mpd_file,
|
||||||
mode='r', encoding='utf-8') as f:
|
mode='r', encoding='utf-8') as f:
|
||||||
formats = self.ie._parse_mpd_formats(
|
formats, subtitles = self.ie._parse_mpd_formats_and_subtitles(
|
||||||
compat_etree_fromstring(f.read().encode('utf-8')),
|
compat_etree_fromstring(f.read().encode('utf-8')),
|
||||||
mpd_base_url=mpd_base_url, mpd_url=mpd_url)
|
mpd_base_url=mpd_base_url, mpd_url=mpd_url)
|
||||||
self.ie._sort_formats(formats)
|
self.ie._sort_formats(formats)
|
||||||
expect_value(self, formats, expected_formats, None)
|
expect_value(self, formats, expected_formats, None)
|
||||||
|
expect_value(self, subtitles, expected_subtitles, None)
|
||||||
|
|
||||||
|
def test_parse_ism_formats(self):
|
||||||
|
_TEST_CASES = [
|
||||||
|
(
|
||||||
|
'sintel',
|
||||||
|
'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
[{
|
||||||
|
'format_id': 'audio-128',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'ext': 'isma',
|
||||||
|
'tbr': 128,
|
||||||
|
'asr': 48000,
|
||||||
|
'vcodec': 'none',
|
||||||
|
'acodec': 'AACL',
|
||||||
|
'protocol': 'ism',
|
||||||
|
'_download_params': {
|
||||||
|
'stream_type': 'audio',
|
||||||
|
'duration': 8880746666,
|
||||||
|
'timescale': 10000000,
|
||||||
|
'width': 0,
|
||||||
|
'height': 0,
|
||||||
|
'fourcc': 'AACL',
|
||||||
|
'codec_private_data': '1190',
|
||||||
|
'sampling_rate': 48000,
|
||||||
|
'channels': 2,
|
||||||
|
'bits_per_sample': 16,
|
||||||
|
'nal_unit_length_field': 4
|
||||||
|
},
|
||||||
|
'audio_ext': 'isma',
|
||||||
|
'video_ext': 'none',
|
||||||
|
'abr': 128,
|
||||||
|
}, {
|
||||||
|
'format_id': 'video-100',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'ext': 'ismv',
|
||||||
|
'width': 336,
|
||||||
|
'height': 144,
|
||||||
|
'tbr': 100,
|
||||||
|
'vcodec': 'AVC1',
|
||||||
|
'acodec': 'none',
|
||||||
|
'protocol': 'ism',
|
||||||
|
'_download_params': {
|
||||||
|
'stream_type': 'video',
|
||||||
|
'duration': 8880746666,
|
||||||
|
'timescale': 10000000,
|
||||||
|
'width': 336,
|
||||||
|
'height': 144,
|
||||||
|
'fourcc': 'AVC1',
|
||||||
|
'codec_private_data': '00000001674D401FDA0544EFFC2D002CBC40000003004000000C03C60CA80000000168EF32C8',
|
||||||
|
'channels': 2,
|
||||||
|
'bits_per_sample': 16,
|
||||||
|
'nal_unit_length_field': 4
|
||||||
|
},
|
||||||
|
'video_ext': 'ismv',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 100,
|
||||||
|
}, {
|
||||||
|
'format_id': 'video-326',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'ext': 'ismv',
|
||||||
|
'width': 562,
|
||||||
|
'height': 240,
|
||||||
|
'tbr': 326,
|
||||||
|
'vcodec': 'AVC1',
|
||||||
|
'acodec': 'none',
|
||||||
|
'protocol': 'ism',
|
||||||
|
'_download_params': {
|
||||||
|
'stream_type': 'video',
|
||||||
|
'duration': 8880746666,
|
||||||
|
'timescale': 10000000,
|
||||||
|
'width': 562,
|
||||||
|
'height': 240,
|
||||||
|
'fourcc': 'AVC1',
|
||||||
|
'codec_private_data': '00000001674D401FDA0241FE23FFC3BC83BA44000003000400000300C03C60CA800000000168EF32C8',
|
||||||
|
'channels': 2,
|
||||||
|
'bits_per_sample': 16,
|
||||||
|
'nal_unit_length_field': 4
|
||||||
|
},
|
||||||
|
'video_ext': 'ismv',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 326,
|
||||||
|
}, {
|
||||||
|
'format_id': 'video-698',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'ext': 'ismv',
|
||||||
|
'width': 844,
|
||||||
|
'height': 360,
|
||||||
|
'tbr': 698,
|
||||||
|
'vcodec': 'AVC1',
|
||||||
|
'acodec': 'none',
|
||||||
|
'protocol': 'ism',
|
||||||
|
'_download_params': {
|
||||||
|
'stream_type': 'video',
|
||||||
|
'duration': 8880746666,
|
||||||
|
'timescale': 10000000,
|
||||||
|
'width': 844,
|
||||||
|
'height': 360,
|
||||||
|
'fourcc': 'AVC1',
|
||||||
|
'codec_private_data': '00000001674D401FDA0350BFB97FF06AF06AD1000003000100000300300F1832A00000000168EF32C8',
|
||||||
|
'channels': 2,
|
||||||
|
'bits_per_sample': 16,
|
||||||
|
'nal_unit_length_field': 4
|
||||||
|
},
|
||||||
|
'video_ext': 'ismv',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 698,
|
||||||
|
}, {
|
||||||
|
'format_id': 'video-1493',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'ext': 'ismv',
|
||||||
|
'width': 1126,
|
||||||
|
'height': 480,
|
||||||
|
'tbr': 1493,
|
||||||
|
'vcodec': 'AVC1',
|
||||||
|
'acodec': 'none',
|
||||||
|
'protocol': 'ism',
|
||||||
|
'_download_params': {
|
||||||
|
'stream_type': 'video',
|
||||||
|
'duration': 8880746666,
|
||||||
|
'timescale': 10000000,
|
||||||
|
'width': 1126,
|
||||||
|
'height': 480,
|
||||||
|
'fourcc': 'AVC1',
|
||||||
|
'codec_private_data': '00000001674D401FDA011C3DE6FFF0D890D871000003000100000300300F1832A00000000168EF32C8',
|
||||||
|
'channels': 2,
|
||||||
|
'bits_per_sample': 16,
|
||||||
|
'nal_unit_length_field': 4
|
||||||
|
},
|
||||||
|
'video_ext': 'ismv',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 1493,
|
||||||
|
}, {
|
||||||
|
'format_id': 'video-4482',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'ext': 'ismv',
|
||||||
|
'width': 1688,
|
||||||
|
'height': 720,
|
||||||
|
'tbr': 4482,
|
||||||
|
'vcodec': 'AVC1',
|
||||||
|
'acodec': 'none',
|
||||||
|
'protocol': 'ism',
|
||||||
|
'_download_params': {
|
||||||
|
'stream_type': 'video',
|
||||||
|
'duration': 8880746666,
|
||||||
|
'timescale': 10000000,
|
||||||
|
'width': 1688,
|
||||||
|
'height': 720,
|
||||||
|
'fourcc': 'AVC1',
|
||||||
|
'codec_private_data': '00000001674D401FDA01A816F97FFC1ABC1AB440000003004000000C03C60CA80000000168EF32C8',
|
||||||
|
'channels': 2,
|
||||||
|
'bits_per_sample': 16,
|
||||||
|
'nal_unit_length_field': 4
|
||||||
|
},
|
||||||
|
'video_ext': 'ismv',
|
||||||
|
'audio_ext': 'none',
|
||||||
|
'vbr': 4482,
|
||||||
|
}],
|
||||||
|
{
|
||||||
|
'eng': [
|
||||||
|
{
|
||||||
|
'ext': 'ismt',
|
||||||
|
'protocol': 'ism',
|
||||||
|
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
|
||||||
|
'_download_params': {
|
||||||
|
'stream_type': 'text',
|
||||||
|
'duration': 8880746666,
|
||||||
|
'timescale': 10000000,
|
||||||
|
'fourcc': 'TTML',
|
||||||
|
'codec_private_data': ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
for ism_file, ism_url, expected_formats, expected_subtitles in _TEST_CASES:
|
||||||
|
with io.open('./test/testdata/ism/%s.Manifest' % ism_file,
|
||||||
|
mode='r', encoding='utf-8') as f:
|
||||||
|
formats, subtitles = self.ie._parse_ism_formats_and_subtitles(
|
||||||
|
compat_etree_fromstring(f.read().encode('utf-8')), ism_url=ism_url)
|
||||||
|
self.ie._sort_formats(formats)
|
||||||
|
expect_value(self, formats, expected_formats, None)
|
||||||
|
expect_value(self, subtitles, expected_subtitles, None)
|
||||||
|
|
||||||
def test_parse_f4m_formats(self):
|
def test_parse_f4m_formats(self):
|
||||||
_TEST_CASES = [
|
_TEST_CASES = [
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
@@ -10,14 +10,15 @@ import unittest
|
|||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import json
|
||||||
|
|
||||||
from test.helper import FakeYDL, assertRegexpMatches
|
from test.helper import FakeYDL, assertRegexpMatches
|
||||||
from yt_dlp import YoutubeDL
|
from yt_dlp import YoutubeDL
|
||||||
from yt_dlp.compat import compat_str, compat_urllib_error
|
from yt_dlp.compat import compat_os_name, compat_setenv, compat_str, compat_urllib_error
|
||||||
from yt_dlp.extractor import YoutubeIE
|
from yt_dlp.extractor import YoutubeIE
|
||||||
from yt_dlp.extractor.common import InfoExtractor
|
from yt_dlp.extractor.common import InfoExtractor
|
||||||
from yt_dlp.postprocessor.common import PostProcessor
|
from yt_dlp.postprocessor.common import PostProcessor
|
||||||
from yt_dlp.utils import ExtractorError, match_filter_func
|
from yt_dlp.utils import ExtractorError, int_or_none, match_filter_func, LazyList
|
||||||
|
|
||||||
TEST_URL = 'http://localhost/sample.mp4'
|
TEST_URL = 'http://localhost/sample.mp4'
|
||||||
|
|
||||||
@@ -29,11 +30,16 @@ class YDL(FakeYDL):
|
|||||||
self.msgs = []
|
self.msgs = []
|
||||||
|
|
||||||
def process_info(self, info_dict):
|
def process_info(self, info_dict):
|
||||||
|
info_dict = info_dict.copy()
|
||||||
|
info_dict.pop('__original_infodict', None)
|
||||||
self.downloaded_info_dicts.append(info_dict)
|
self.downloaded_info_dicts.append(info_dict)
|
||||||
|
|
||||||
def to_screen(self, msg):
|
def to_screen(self, msg):
|
||||||
self.msgs.append(msg)
|
self.msgs.append(msg)
|
||||||
|
|
||||||
|
def dl(self, *args, **kwargs):
|
||||||
|
assert False, 'Downloader must not be invoked for test_YoutubeDL'
|
||||||
|
|
||||||
|
|
||||||
def _make_result(formats, **kwargs):
|
def _make_result(formats, **kwargs):
|
||||||
res = {
|
res = {
|
||||||
@@ -116,35 +122,24 @@ class TestFormatSelection(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
info_dict = _make_result(formats)
|
info_dict = _make_result(formats)
|
||||||
|
|
||||||
ydl = YDL({'format': '20/47'})
|
def test(inp, *expected, multi=False):
|
||||||
|
ydl = YDL({
|
||||||
|
'format': inp,
|
||||||
|
'allow_multiple_video_streams': multi,
|
||||||
|
'allow_multiple_audio_streams': multi,
|
||||||
|
})
|
||||||
ydl.process_ie_result(info_dict.copy())
|
ydl.process_ie_result(info_dict.copy())
|
||||||
downloaded = ydl.downloaded_info_dicts[0]
|
downloaded = map(lambda x: x['format_id'], ydl.downloaded_info_dicts)
|
||||||
self.assertEqual(downloaded['format_id'], '47')
|
self.assertEqual(list(downloaded), list(expected))
|
||||||
|
|
||||||
ydl = YDL({'format': '20/71/worst'})
|
test('20/47', '47')
|
||||||
ydl.process_ie_result(info_dict.copy())
|
test('20/71/worst', '35')
|
||||||
downloaded = ydl.downloaded_info_dicts[0]
|
test(None, '2')
|
||||||
self.assertEqual(downloaded['format_id'], '35')
|
test('webm/mp4', '47')
|
||||||
|
test('3gp/40/mp4', '35')
|
||||||
ydl = YDL()
|
test('example-with-dashes', 'example-with-dashes')
|
||||||
ydl.process_ie_result(info_dict.copy())
|
test('all', '2', '47', '45', 'example-with-dashes', '35')
|
||||||
downloaded = ydl.downloaded_info_dicts[0]
|
test('mergeall', '2+47+45+example-with-dashes+35', multi=True)
|
||||||
self.assertEqual(downloaded['format_id'], '2')
|
|
||||||
|
|
||||||
ydl = YDL({'format': 'webm/mp4'})
|
|
||||||
ydl.process_ie_result(info_dict.copy())
|
|
||||||
downloaded = ydl.downloaded_info_dicts[0]
|
|
||||||
self.assertEqual(downloaded['format_id'], '47')
|
|
||||||
|
|
||||||
ydl = YDL({'format': '3gp/40/mp4'})
|
|
||||||
ydl.process_ie_result(info_dict.copy())
|
|
||||||
downloaded = ydl.downloaded_info_dicts[0]
|
|
||||||
self.assertEqual(downloaded['format_id'], '35')
|
|
||||||
|
|
||||||
ydl = YDL({'format': 'example-with-dashes'})
|
|
||||||
ydl.process_ie_result(info_dict.copy())
|
|
||||||
downloaded = ydl.downloaded_info_dicts[0]
|
|
||||||
self.assertEqual(downloaded['format_id'], 'example-with-dashes')
|
|
||||||
|
|
||||||
def test_format_selection_audio(self):
|
def test_format_selection_audio(self):
|
||||||
formats = [
|
formats = [
|
||||||
@@ -311,8 +306,8 @@ class TestFormatSelection(unittest.TestCase):
|
|||||||
self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
|
self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
|
||||||
|
|
||||||
def test_youtube_format_selection(self):
|
def test_youtube_format_selection(self):
|
||||||
|
# FIXME: Rewrite in accordance with the new format sorting options
|
||||||
return
|
return
|
||||||
# disabled for now - this needs some changes
|
|
||||||
|
|
||||||
order = [
|
order = [
|
||||||
'38', '37', '46', '22', '45', '35', '44', '18', '34', '43', '6', '5', '17', '36', '13',
|
'38', '37', '46', '22', '45', '35', '44', '18', '34', '43', '6', '5', '17', '36', '13',
|
||||||
@@ -460,14 +455,13 @@ class TestFormatSelection(unittest.TestCase):
|
|||||||
|
|
||||||
def test_invalid_format_specs(self):
|
def test_invalid_format_specs(self):
|
||||||
def assert_syntax_error(format_spec):
|
def assert_syntax_error(format_spec):
|
||||||
ydl = YDL({'format': format_spec})
|
self.assertRaises(SyntaxError, YDL, {'format': format_spec})
|
||||||
info_dict = _make_result([{'format_id': 'foo', 'url': TEST_URL}])
|
|
||||||
self.assertRaises(SyntaxError, ydl.process_ie_result, info_dict)
|
|
||||||
|
|
||||||
assert_syntax_error('bestvideo,,best')
|
assert_syntax_error('bestvideo,,best')
|
||||||
assert_syntax_error('+bestaudio')
|
assert_syntax_error('+bestaudio')
|
||||||
assert_syntax_error('bestvideo+')
|
assert_syntax_error('bestvideo+')
|
||||||
assert_syntax_error('/')
|
assert_syntax_error('/')
|
||||||
|
assert_syntax_error('[720<height]')
|
||||||
|
|
||||||
def test_format_filtering(self):
|
def test_format_filtering(self):
|
||||||
formats = [
|
formats = [
|
||||||
@@ -527,7 +521,7 @@ class TestFormatSelection(unittest.TestCase):
|
|||||||
ydl = YDL({'format': 'all[width>=400][width<=600]'})
|
ydl = YDL({'format': 'all[width>=400][width<=600]'})
|
||||||
ydl.process_ie_result(info_dict)
|
ydl.process_ie_result(info_dict)
|
||||||
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
|
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
|
||||||
self.assertEqual(downloaded_ids, ['B', 'C', 'D'])
|
self.assertEqual(downloaded_ids, ['D', 'C', 'B'])
|
||||||
|
|
||||||
ydl = YDL({'format': 'best[height<40]'})
|
ydl = YDL({'format': 'best[height<40]'})
|
||||||
try:
|
try:
|
||||||
@@ -601,6 +595,26 @@ class TestYoutubeDL(unittest.TestCase):
|
|||||||
self.assertTrue(subs)
|
self.assertTrue(subs)
|
||||||
self.assertEqual(set(subs.keys()), set(['es', 'fr']))
|
self.assertEqual(set(subs.keys()), set(['es', 'fr']))
|
||||||
|
|
||||||
|
result = get_info({'writesubtitles': True, 'subtitleslangs': ['all', '-en']})
|
||||||
|
subs = result['requested_subtitles']
|
||||||
|
self.assertTrue(subs)
|
||||||
|
self.assertEqual(set(subs.keys()), set(['es', 'fr']))
|
||||||
|
|
||||||
|
result = get_info({'writesubtitles': True, 'subtitleslangs': ['en', 'fr', '-en']})
|
||||||
|
subs = result['requested_subtitles']
|
||||||
|
self.assertTrue(subs)
|
||||||
|
self.assertEqual(set(subs.keys()), set(['fr']))
|
||||||
|
|
||||||
|
result = get_info({'writesubtitles': True, 'subtitleslangs': ['-en', 'en']})
|
||||||
|
subs = result['requested_subtitles']
|
||||||
|
self.assertTrue(subs)
|
||||||
|
self.assertEqual(set(subs.keys()), set(['en']))
|
||||||
|
|
||||||
|
result = get_info({'writesubtitles': True, 'subtitleslangs': ['e.+']})
|
||||||
|
subs = result['requested_subtitles']
|
||||||
|
self.assertTrue(subs)
|
||||||
|
self.assertEqual(set(subs.keys()), set(['es', 'en']))
|
||||||
|
|
||||||
result = get_info({'writesubtitles': True, 'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
|
result = get_info({'writesubtitles': True, 'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
|
||||||
subs = result['requested_subtitles']
|
subs = result['requested_subtitles']
|
||||||
self.assertTrue(subs)
|
self.assertTrue(subs)
|
||||||
@@ -627,47 +641,213 @@ class TestYoutubeDL(unittest.TestCase):
|
|||||||
self.assertEqual(test_dict['extractor'], 'Foo')
|
self.assertEqual(test_dict['extractor'], 'Foo')
|
||||||
self.assertEqual(test_dict['playlist'], 'funny videos')
|
self.assertEqual(test_dict['playlist'], 'funny videos')
|
||||||
|
|
||||||
def test_prepare_filename(self):
|
outtmpl_info = {
|
||||||
info = {
|
|
||||||
'id': '1234',
|
'id': '1234',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'width': None,
|
'width': None,
|
||||||
'height': 1080,
|
'height': 1080,
|
||||||
|
'filesize': 1024,
|
||||||
'title1': '$PATH',
|
'title1': '$PATH',
|
||||||
'title2': '%PATH%',
|
'title2': '%PATH%',
|
||||||
|
'title3': 'foo/bar\\test',
|
||||||
|
'title4': 'foo "bar" test',
|
||||||
|
'title5': 'áéí 𝐀',
|
||||||
|
'timestamp': 1618488000,
|
||||||
|
'duration': 100000,
|
||||||
|
'playlist_index': 1,
|
||||||
|
'playlist_autonumber': 2,
|
||||||
|
'_last_playlist_index': 100,
|
||||||
|
'n_entries': 10,
|
||||||
|
'formats': [{'id': 'id 1'}, {'id': 'id 2'}, {'id': 'id 3'}]
|
||||||
}
|
}
|
||||||
|
|
||||||
def fname(templ, na_placeholder='NA'):
|
def test_prepare_outtmpl_and_filename(self):
|
||||||
params = {'outtmpl': templ}
|
def test(tmpl, expected, *, info=None, **params):
|
||||||
if na_placeholder != 'NA':
|
params['outtmpl'] = tmpl
|
||||||
params['outtmpl_na_placeholder'] = na_placeholder
|
|
||||||
ydl = YoutubeDL(params)
|
ydl = YoutubeDL(params)
|
||||||
return ydl.prepare_filename(info)
|
ydl._num_downloads = 1
|
||||||
self.assertEqual(fname('%(id)s.%(ext)s'), '1234.mp4')
|
self.assertEqual(ydl.validate_outtmpl(tmpl), None)
|
||||||
self.assertEqual(fname('%(id)s-%(width)s.%(ext)s'), '1234-NA.mp4')
|
|
||||||
NA_TEST_OUTTMPL = '%(uploader_date)s-%(width)d-%(id)s.%(ext)s'
|
out = ydl.evaluate_outtmpl(tmpl, info or self.outtmpl_info)
|
||||||
# Replace missing fields with 'NA' by default
|
fname = ydl.prepare_filename(info or self.outtmpl_info)
|
||||||
self.assertEqual(fname(NA_TEST_OUTTMPL), 'NA-NA-1234.mp4')
|
|
||||||
# Or by provided placeholder
|
if not isinstance(expected, (list, tuple)):
|
||||||
self.assertEqual(fname(NA_TEST_OUTTMPL, na_placeholder='none'), 'none-none-1234.mp4')
|
expected = (expected, expected)
|
||||||
self.assertEqual(fname(NA_TEST_OUTTMPL, na_placeholder=''), '--1234.mp4')
|
for (name, got), expect in zip((('outtmpl', out), ('filename', fname)), expected):
|
||||||
self.assertEqual(fname('%(height)d.%(ext)s'), '1080.mp4')
|
if callable(expect):
|
||||||
self.assertEqual(fname('%(height)6d.%(ext)s'), ' 1080.mp4')
|
self.assertTrue(expect(got), f'Wrong {name} from {tmpl}')
|
||||||
self.assertEqual(fname('%(height)-6d.%(ext)s'), '1080 .mp4')
|
else:
|
||||||
self.assertEqual(fname('%(height)06d.%(ext)s'), '001080.mp4')
|
self.assertEqual(got, expect, f'Wrong {name} from {tmpl}')
|
||||||
self.assertEqual(fname('%(height) 06d.%(ext)s'), ' 01080.mp4')
|
|
||||||
self.assertEqual(fname('%(height) 06d.%(ext)s'), ' 01080.mp4')
|
# Side-effects
|
||||||
self.assertEqual(fname('%(height)0 6d.%(ext)s'), ' 01080.mp4')
|
original_infodict = dict(self.outtmpl_info)
|
||||||
self.assertEqual(fname('%(height)0 6d.%(ext)s'), ' 01080.mp4')
|
test('foo.bar', 'foo.bar')
|
||||||
self.assertEqual(fname('%(height) 0 6d.%(ext)s'), ' 01080.mp4')
|
original_infodict['epoch'] = self.outtmpl_info.get('epoch')
|
||||||
self.assertEqual(fname('%%'), '%')
|
self.assertTrue(isinstance(original_infodict['epoch'], int))
|
||||||
self.assertEqual(fname('%%%%'), '%%')
|
test('%(epoch)d', int_or_none)
|
||||||
self.assertEqual(fname('%%(height)06d.%(ext)s'), '%(height)06d.mp4')
|
self.assertEqual(original_infodict, self.outtmpl_info)
|
||||||
self.assertEqual(fname('%(width)06d.%(ext)s'), 'NA.mp4')
|
|
||||||
self.assertEqual(fname('%(width)06d.%%(ext)s'), 'NA.%(ext)s')
|
# Auto-generated fields
|
||||||
self.assertEqual(fname('%%(width)06d.%(ext)s'), '%(width)06d.mp4')
|
test('%(id)s.%(ext)s', '1234.mp4')
|
||||||
self.assertEqual(fname('Hello %(title1)s'), 'Hello $PATH')
|
test('%(duration_string)s', ('27:46:40', '27-46-40'))
|
||||||
self.assertEqual(fname('Hello %(title2)s'), 'Hello %PATH%')
|
test('%(resolution)s', '1080p')
|
||||||
|
test('%(playlist_index)s', '001')
|
||||||
|
test('%(playlist_autonumber)s', '02')
|
||||||
|
test('%(autonumber)s', '00001')
|
||||||
|
test('%(autonumber+2)03d', '005', autonumber_start=3)
|
||||||
|
test('%(autonumber)s', '001', autonumber_size=3)
|
||||||
|
|
||||||
|
# Escaping %
|
||||||
|
test('%', '%')
|
||||||
|
test('%%', '%')
|
||||||
|
test('%%%%', '%%')
|
||||||
|
test('%s', '%s')
|
||||||
|
test('%%%s', '%%s')
|
||||||
|
test('%d', '%d')
|
||||||
|
test('%abc%', '%abc%')
|
||||||
|
test('%%(width)06d.%(ext)s', '%(width)06d.mp4')
|
||||||
|
test('%%%(height)s', '%1080')
|
||||||
|
test('%(width)06d.%(ext)s', 'NA.mp4')
|
||||||
|
test('%(width)06d.%%(ext)s', 'NA.%(ext)s')
|
||||||
|
test('%%(width)06d.%(ext)s', '%(width)06d.mp4')
|
||||||
|
|
||||||
|
# ID sanitization
|
||||||
|
test('%(id)s', '_abcd', info={'id': '_abcd'})
|
||||||
|
test('%(some_id)s', '_abcd', info={'some_id': '_abcd'})
|
||||||
|
test('%(formats.0.id)s', '_abcd', info={'formats': [{'id': '_abcd'}]})
|
||||||
|
test('%(id)s', '-abcd', info={'id': '-abcd'})
|
||||||
|
test('%(id)s', '.abcd', info={'id': '.abcd'})
|
||||||
|
test('%(id)s', 'ab__cd', info={'id': 'ab__cd'})
|
||||||
|
test('%(id)s', ('ab:cd', 'ab -cd'), info={'id': 'ab:cd'})
|
||||||
|
test('%(id.0)s', '-', info={'id': '--'})
|
||||||
|
|
||||||
|
# Invalid templates
|
||||||
|
self.assertTrue(isinstance(YoutubeDL.validate_outtmpl('%(title)'), ValueError))
|
||||||
|
test('%(invalid@tmpl|def)s', 'none', outtmpl_na_placeholder='none')
|
||||||
|
test('%(..)s', 'NA')
|
||||||
|
|
||||||
|
# Entire info_dict
|
||||||
|
def expect_same_infodict(out):
|
||||||
|
got_dict = json.loads(out)
|
||||||
|
for info_field, expected in self.outtmpl_info.items():
|
||||||
|
self.assertEqual(got_dict.get(info_field), expected, info_field)
|
||||||
|
return True
|
||||||
|
|
||||||
|
test('%()j', (expect_same_infodict, str))
|
||||||
|
|
||||||
|
# NA placeholder
|
||||||
|
NA_TEST_OUTTMPL = '%(uploader_date)s-%(width)d-%(x|def)s-%(id)s.%(ext)s'
|
||||||
|
test(NA_TEST_OUTTMPL, 'NA-NA-def-1234.mp4')
|
||||||
|
test(NA_TEST_OUTTMPL, 'none-none-def-1234.mp4', outtmpl_na_placeholder='none')
|
||||||
|
test(NA_TEST_OUTTMPL, '--def-1234.mp4', outtmpl_na_placeholder='')
|
||||||
|
test('%(non_existent.0)s', 'NA')
|
||||||
|
|
||||||
|
# String formatting
|
||||||
|
FMT_TEST_OUTTMPL = '%%(height)%s.%%(ext)s'
|
||||||
|
test(FMT_TEST_OUTTMPL % 's', '1080.mp4')
|
||||||
|
test(FMT_TEST_OUTTMPL % 'd', '1080.mp4')
|
||||||
|
test(FMT_TEST_OUTTMPL % '6d', ' 1080.mp4')
|
||||||
|
test(FMT_TEST_OUTTMPL % '-6d', '1080 .mp4')
|
||||||
|
test(FMT_TEST_OUTTMPL % '06d', '001080.mp4')
|
||||||
|
test(FMT_TEST_OUTTMPL % ' 06d', ' 01080.mp4')
|
||||||
|
test(FMT_TEST_OUTTMPL % ' 06d', ' 01080.mp4')
|
||||||
|
test(FMT_TEST_OUTTMPL % '0 6d', ' 01080.mp4')
|
||||||
|
test(FMT_TEST_OUTTMPL % '0 6d', ' 01080.mp4')
|
||||||
|
test(FMT_TEST_OUTTMPL % ' 0 6d', ' 01080.mp4')
|
||||||
|
|
||||||
|
# Type casting
|
||||||
|
test('%(id)d', '1234')
|
||||||
|
test('%(height)c', '1')
|
||||||
|
test('%(ext)c', 'm')
|
||||||
|
test('%(id)d %(id)r', "1234 '1234'")
|
||||||
|
test('%(id)r %(height)r', "'1234' 1080")
|
||||||
|
test('%(ext)s-%(ext|def)d', 'mp4-def')
|
||||||
|
test('%(width|0)04d', '0000')
|
||||||
|
test('a%(width|)d', 'a', outtmpl_na_placeholder='none')
|
||||||
|
|
||||||
|
FORMATS = self.outtmpl_info['formats']
|
||||||
|
sanitize = lambda x: x.replace(':', ' -').replace('"', "'").replace('\n', ' ')
|
||||||
|
|
||||||
|
# Custom type casting
|
||||||
|
test('%(formats.:.id)l', 'id 1, id 2, id 3')
|
||||||
|
test('%(formats.:.id)#l', ('id 1\nid 2\nid 3', 'id 1 id 2 id 3'))
|
||||||
|
test('%(ext)l', 'mp4')
|
||||||
|
test('%(formats.:.id) 18l', ' id 1, id 2, id 3')
|
||||||
|
test('%(formats)j', (json.dumps(FORMATS), sanitize(json.dumps(FORMATS))))
|
||||||
|
test('%(formats)#j', (json.dumps(FORMATS, indent=4), sanitize(json.dumps(FORMATS, indent=4))))
|
||||||
|
test('%(title5).3B', 'á')
|
||||||
|
test('%(title5)U', 'áéí 𝐀')
|
||||||
|
test('%(title5)#U', 'a\u0301e\u0301i\u0301 𝐀')
|
||||||
|
test('%(title5)+U', 'áéí A')
|
||||||
|
test('%(title5)+#U', 'a\u0301e\u0301i\u0301 A')
|
||||||
|
test('%(height)D', '1k')
|
||||||
|
test('%(filesize)#D', '1Ki')
|
||||||
|
test('%(height)5.2D', ' 1.08k')
|
||||||
|
test('%(title4)#S', 'foo_bar_test')
|
||||||
|
test('%(title4).10S', ('foo \'bar\' ', 'foo \'bar\'' + ('#' if compat_os_name == 'nt' else ' ')))
|
||||||
|
if compat_os_name == 'nt':
|
||||||
|
test('%(title4)q', ('"foo \\"bar\\" test"', "'foo _'bar_' test'"))
|
||||||
|
test('%(formats.:.id)#q', ('"id 1" "id 2" "id 3"', "'id 1' 'id 2' 'id 3'"))
|
||||||
|
test('%(formats.0.id)#q', ('"id 1"', "'id 1'"))
|
||||||
|
else:
|
||||||
|
test('%(title4)q', ('\'foo "bar" test\'', "'foo 'bar' test'"))
|
||||||
|
test('%(formats.:.id)#q', "'id 1' 'id 2' 'id 3'")
|
||||||
|
test('%(formats.0.id)#q', "'id 1'")
|
||||||
|
|
||||||
|
# Internal formatting
|
||||||
|
test('%(timestamp-1000>%H-%M-%S)s', '11-43-20')
|
||||||
|
test('%(title|%)s %(title|%%)s', '% %%')
|
||||||
|
test('%(id+1-height+3)05d', '00158')
|
||||||
|
test('%(width+100)05d', 'NA')
|
||||||
|
test('%(formats.0) 15s', ('% 15s' % FORMATS[0], '% 15s' % sanitize(str(FORMATS[0]))))
|
||||||
|
test('%(formats.0)r', (repr(FORMATS[0]), sanitize(repr(FORMATS[0]))))
|
||||||
|
test('%(height.0)03d', '001')
|
||||||
|
test('%(-height.0)04d', '-001')
|
||||||
|
test('%(formats.-1.id)s', FORMATS[-1]['id'])
|
||||||
|
test('%(formats.0.id.-1)d', FORMATS[0]['id'][-1])
|
||||||
|
test('%(formats.3)s', 'NA')
|
||||||
|
test('%(formats.:2:-1)r', repr(FORMATS[:2:-1]))
|
||||||
|
test('%(formats.0.id.-1+id)f', '1235.000000')
|
||||||
|
test('%(formats.0.id.-1+formats.1.id.-1)d', '3')
|
||||||
|
|
||||||
|
# Alternates
|
||||||
|
test('%(title,id)s', '1234')
|
||||||
|
test('%(width-100,height+20|def)d', '1100')
|
||||||
|
test('%(width-100,height+width|def)s', 'def')
|
||||||
|
test('%(timestamp-x>%H\\,%M\\,%S,timestamp>%H\\,%M\\,%S)s', '12,00,00')
|
||||||
|
|
||||||
|
# Replacement
|
||||||
|
test('%(id&foo)s.bar', 'foo.bar')
|
||||||
|
test('%(title&foo)s.bar', 'NA.bar')
|
||||||
|
test('%(title&foo|baz)s.bar', 'baz.bar')
|
||||||
|
|
||||||
|
# Laziness
|
||||||
|
def gen():
|
||||||
|
yield from range(5)
|
||||||
|
raise self.assertTrue(False, 'LazyList should not be evaluated till here')
|
||||||
|
test('%(key.4)s', '4', info={'key': LazyList(gen())})
|
||||||
|
|
||||||
|
# Empty filename
|
||||||
|
test('%(foo|)s-%(bar|)s.%(ext)s', '-.mp4')
|
||||||
|
# test('%(foo|)s.%(ext)s', ('.mp4', '_.mp4')) # fixme
|
||||||
|
# test('%(foo|)s', ('', '_')) # fixme
|
||||||
|
|
||||||
|
# Environment variable expansion for prepare_filename
|
||||||
|
compat_setenv('__yt_dlp_var', 'expanded')
|
||||||
|
envvar = '%__yt_dlp_var%' if compat_os_name == 'nt' else '$__yt_dlp_var'
|
||||||
|
test(envvar, (envvar, 'expanded'))
|
||||||
|
if compat_os_name == 'nt':
|
||||||
|
test('%s%', ('%s%', '%s%'))
|
||||||
|
compat_setenv('s', 'expanded')
|
||||||
|
test('%s%', ('%s%', 'expanded')) # %s% should be expanded before escaping %s
|
||||||
|
compat_setenv('(test)s', 'expanded')
|
||||||
|
test('%(test)s%', ('NA%', 'expanded')) # Environment should take priority over template
|
||||||
|
|
||||||
|
# Path expansion and escaping
|
||||||
|
test('Hello %(title1)s', 'Hello $PATH')
|
||||||
|
test('Hello %(title2)s', 'Hello %PATH%')
|
||||||
|
test('%(title3)s', ('foo/bar\\test', 'foo_bar_test'))
|
||||||
|
test('folder/%(title3)s', ('folder/foo/bar\\test', 'folder%sfoo_bar_test' % os.path.sep))
|
||||||
|
|
||||||
def test_format_note(self):
|
def test_format_note(self):
|
||||||
ydl = YoutubeDL()
|
ydl = YoutubeDL()
|
||||||
@@ -726,10 +906,10 @@ class TestYoutubeDL(unittest.TestCase):
|
|||||||
def process_info(self, info_dict):
|
def process_info(self, info_dict):
|
||||||
super(YDL, self).process_info(info_dict)
|
super(YDL, self).process_info(info_dict)
|
||||||
|
|
||||||
def _match_entry(self, info_dict, incomplete):
|
def _match_entry(self, info_dict, incomplete=False):
|
||||||
res = super(FilterYDL, self)._match_entry(info_dict, incomplete)
|
res = super(FilterYDL, self)._match_entry(info_dict, incomplete)
|
||||||
if res is None:
|
if res is None:
|
||||||
self.downloaded_info_dicts.append(info_dict)
|
self.downloaded_info_dicts.append(info_dict.copy())
|
||||||
return res
|
return res
|
||||||
|
|
||||||
first = {
|
first = {
|
||||||
@@ -837,54 +1017,32 @@ class TestYoutubeDL(unittest.TestCase):
|
|||||||
ydl.process_ie_result(copy.deepcopy(playlist))
|
ydl.process_ie_result(copy.deepcopy(playlist))
|
||||||
return ydl.downloaded_info_dicts
|
return ydl.downloaded_info_dicts
|
||||||
|
|
||||||
def get_ids(params):
|
def test_selection(params, expected_ids):
|
||||||
return [int(v['id']) for v in get_downloaded_info_dicts(params)]
|
results = [
|
||||||
|
(v['playlist_autonumber'] - 1, (int(v['id']), v['playlist_index']))
|
||||||
|
for v in get_downloaded_info_dicts(params)]
|
||||||
|
self.assertEqual(results, list(enumerate(zip(expected_ids, expected_ids))))
|
||||||
|
|
||||||
result = get_ids({})
|
test_selection({}, [1, 2, 3, 4])
|
||||||
self.assertEqual(result, [1, 2, 3, 4])
|
test_selection({'playlistend': 10}, [1, 2, 3, 4])
|
||||||
|
test_selection({'playlistend': 2}, [1, 2])
|
||||||
result = get_ids({'playlistend': 10})
|
test_selection({'playliststart': 10}, [])
|
||||||
self.assertEqual(result, [1, 2, 3, 4])
|
test_selection({'playliststart': 2}, [2, 3, 4])
|
||||||
|
test_selection({'playlist_items': '2-4'}, [2, 3, 4])
|
||||||
result = get_ids({'playlistend': 2})
|
test_selection({'playlist_items': '2,4'}, [2, 4])
|
||||||
self.assertEqual(result, [1, 2])
|
test_selection({'playlist_items': '10'}, [])
|
||||||
|
test_selection({'playlist_items': '0'}, [])
|
||||||
result = get_ids({'playliststart': 10})
|
|
||||||
self.assertEqual(result, [])
|
|
||||||
|
|
||||||
result = get_ids({'playliststart': 2})
|
|
||||||
self.assertEqual(result, [2, 3, 4])
|
|
||||||
|
|
||||||
result = get_ids({'playlist_items': '2-4'})
|
|
||||||
self.assertEqual(result, [2, 3, 4])
|
|
||||||
|
|
||||||
result = get_ids({'playlist_items': '2,4'})
|
|
||||||
self.assertEqual(result, [2, 4])
|
|
||||||
|
|
||||||
result = get_ids({'playlist_items': '10'})
|
|
||||||
self.assertEqual(result, [])
|
|
||||||
|
|
||||||
result = get_ids({'playlist_items': '3-10'})
|
|
||||||
self.assertEqual(result, [3, 4])
|
|
||||||
|
|
||||||
result = get_ids({'playlist_items': '2-4,3-4,3'})
|
|
||||||
self.assertEqual(result, [2, 3, 4])
|
|
||||||
|
|
||||||
# Tests for https://github.com/ytdl-org/youtube-dl/issues/10591
|
# Tests for https://github.com/ytdl-org/youtube-dl/issues/10591
|
||||||
# @{
|
test_selection({'playlist_items': '2-4,3-4,3'}, [2, 3, 4])
|
||||||
result = get_downloaded_info_dicts({'playlist_items': '2-4,3-4,3'})
|
test_selection({'playlist_items': '4,2'}, [4, 2])
|
||||||
self.assertEqual(result[0]['playlist_index'], 2)
|
|
||||||
self.assertEqual(result[1]['playlist_index'], 3)
|
|
||||||
|
|
||||||
result = get_downloaded_info_dicts({'playlist_items': '2-4,3-4,3'})
|
# Tests for https://github.com/yt-dlp/yt-dlp/issues/720
|
||||||
self.assertEqual(result[0]['playlist_index'], 2)
|
# https://github.com/yt-dlp/yt-dlp/issues/302
|
||||||
self.assertEqual(result[1]['playlist_index'], 3)
|
test_selection({'playlistreverse': True}, [4, 3, 2, 1])
|
||||||
self.assertEqual(result[2]['playlist_index'], 4)
|
test_selection({'playliststart': 2, 'playlistreverse': True}, [4, 3, 2])
|
||||||
|
test_selection({'playlist_items': '2,4', 'playlistreverse': True}, [4, 2])
|
||||||
result = get_downloaded_info_dicts({'playlist_items': '4,2'})
|
test_selection({'playlist_items': '4,2'}, [4, 2])
|
||||||
self.assertEqual(result[0]['playlist_index'], 4)
|
|
||||||
self.assertEqual(result[1]['playlist_index'], 2)
|
|
||||||
# @}
|
|
||||||
|
|
||||||
def test_urlopen_no_file_protocol(self):
|
def test_urlopen_no_file_protocol(self):
|
||||||
# see https://github.com/ytdl-org/youtube-dl/issues/8227
|
# see https://github.com/ytdl-org/youtube-dl/issues/8227
|
||||||
@@ -996,6 +1154,7 @@ class TestYoutubeDL(unittest.TestCase):
|
|||||||
self.assertTrue(entries[1] is None)
|
self.assertTrue(entries[1] is None)
|
||||||
self.assertEqual(len(ydl.downloaded_info_dicts), 1)
|
self.assertEqual(len(ydl.downloaded_info_dicts), 1)
|
||||||
downloaded = ydl.downloaded_info_dicts[0]
|
downloaded = ydl.downloaded_info_dicts[0]
|
||||||
|
entries[2].pop('requested_downloads', None)
|
||||||
self.assertEqual(entries[2], downloaded)
|
self.assertEqual(entries[2], downloaded)
|
||||||
self.assertEqual(downloaded['url'], TEST_URL)
|
self.assertEqual(downloaded['url'], TEST_URL)
|
||||||
self.assertEqual(downloaded['title'], 'Video Transparent 2')
|
self.assertEqual(downloaded['title'], 'Video Transparent 2')
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
# Allow direct execution
|
# Allow direct execution
|
||||||
@@ -8,7 +7,22 @@ import sys
|
|||||||
import unittest
|
import unittest
|
||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
from yt_dlp.aes import aes_decrypt, aes_encrypt, aes_cbc_decrypt, aes_cbc_encrypt, aes_decrypt_text
|
from yt_dlp.aes import (
|
||||||
|
aes_decrypt,
|
||||||
|
aes_encrypt,
|
||||||
|
aes_ecb_encrypt,
|
||||||
|
aes_ecb_decrypt,
|
||||||
|
aes_cbc_decrypt,
|
||||||
|
aes_cbc_decrypt_bytes,
|
||||||
|
aes_cbc_encrypt,
|
||||||
|
aes_ctr_decrypt,
|
||||||
|
aes_ctr_encrypt,
|
||||||
|
aes_gcm_decrypt_and_verify,
|
||||||
|
aes_gcm_decrypt_and_verify_bytes,
|
||||||
|
aes_decrypt_text,
|
||||||
|
BLOCK_SIZE_BYTES,
|
||||||
|
)
|
||||||
|
from yt_dlp.compat import compat_pycrypto_AES
|
||||||
from yt_dlp.utils import bytes_to_intlist, intlist_to_bytes
|
from yt_dlp.utils import bytes_to_intlist, intlist_to_bytes
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
@@ -28,10 +42,11 @@ class TestAES(unittest.TestCase):
|
|||||||
self.assertEqual(decrypted, msg)
|
self.assertEqual(decrypted, msg)
|
||||||
|
|
||||||
def test_cbc_decrypt(self):
|
def test_cbc_decrypt(self):
|
||||||
data = bytes_to_intlist(
|
data = b'\x97\x92+\xe5\x0b\xc3\x18\x91ky9m&\xb3\xb5@\xe6\x27\xc2\x96.\xc8u\x88\xab9-[\x9e|\xf1\xcd'
|
||||||
b"\x97\x92+\xe5\x0b\xc3\x18\x91ky9m&\xb3\xb5@\xe6'\xc2\x96.\xc8u\x88\xab9-[\x9e|\xf1\xcd"
|
decrypted = intlist_to_bytes(aes_cbc_decrypt(bytes_to_intlist(data), self.key, self.iv))
|
||||||
)
|
self.assertEqual(decrypted.rstrip(b'\x08'), self.secret_msg)
|
||||||
decrypted = intlist_to_bytes(aes_cbc_decrypt(data, self.key, self.iv))
|
if compat_pycrypto_AES:
|
||||||
|
decrypted = aes_cbc_decrypt_bytes(data, intlist_to_bytes(self.key), intlist_to_bytes(self.iv))
|
||||||
self.assertEqual(decrypted.rstrip(b'\x08'), self.secret_msg)
|
self.assertEqual(decrypted.rstrip(b'\x08'), self.secret_msg)
|
||||||
|
|
||||||
def test_cbc_encrypt(self):
|
def test_cbc_encrypt(self):
|
||||||
@@ -39,7 +54,31 @@ class TestAES(unittest.TestCase):
|
|||||||
encrypted = intlist_to_bytes(aes_cbc_encrypt(data, self.key, self.iv))
|
encrypted = intlist_to_bytes(aes_cbc_encrypt(data, self.key, self.iv))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
encrypted,
|
encrypted,
|
||||||
b"\x97\x92+\xe5\x0b\xc3\x18\x91ky9m&\xb3\xb5@\xe6'\xc2\x96.\xc8u\x88\xab9-[\x9e|\xf1\xcd")
|
b'\x97\x92+\xe5\x0b\xc3\x18\x91ky9m&\xb3\xb5@\xe6\'\xc2\x96.\xc8u\x88\xab9-[\x9e|\xf1\xcd')
|
||||||
|
|
||||||
|
def test_ctr_decrypt(self):
|
||||||
|
data = bytes_to_intlist(b'\x03\xc7\xdd\xd4\x8e\xb3\xbc\x1a*O\xdc1\x12+8Aio\xd1z\xb5#\xaf\x08')
|
||||||
|
decrypted = intlist_to_bytes(aes_ctr_decrypt(data, self.key, self.iv))
|
||||||
|
self.assertEqual(decrypted.rstrip(b'\x08'), self.secret_msg)
|
||||||
|
|
||||||
|
def test_ctr_encrypt(self):
|
||||||
|
data = bytes_to_intlist(self.secret_msg)
|
||||||
|
encrypted = intlist_to_bytes(aes_ctr_encrypt(data, self.key, self.iv))
|
||||||
|
self.assertEqual(
|
||||||
|
encrypted,
|
||||||
|
b'\x03\xc7\xdd\xd4\x8e\xb3\xbc\x1a*O\xdc1\x12+8Aio\xd1z\xb5#\xaf\x08')
|
||||||
|
|
||||||
|
def test_gcm_decrypt(self):
|
||||||
|
data = b'\x159Y\xcf5eud\x90\x9c\x85&]\x14\x1d\x0f.\x08\xb4T\xe4/\x17\xbd'
|
||||||
|
authentication_tag = b'\xe8&I\x80rI\x07\x9d}YWuU@:e'
|
||||||
|
|
||||||
|
decrypted = intlist_to_bytes(aes_gcm_decrypt_and_verify(
|
||||||
|
bytes_to_intlist(data), self.key, bytes_to_intlist(authentication_tag), self.iv[:12]))
|
||||||
|
self.assertEqual(decrypted.rstrip(b'\x08'), self.secret_msg)
|
||||||
|
if compat_pycrypto_AES:
|
||||||
|
decrypted = aes_gcm_decrypt_and_verify_bytes(
|
||||||
|
data, intlist_to_bytes(self.key), authentication_tag, intlist_to_bytes(self.iv[:12]))
|
||||||
|
self.assertEqual(decrypted.rstrip(b'\x08'), self.secret_msg)
|
||||||
|
|
||||||
def test_decrypt_text(self):
|
def test_decrypt_text(self):
|
||||||
password = intlist_to_bytes(self.key).decode('utf-8')
|
password = intlist_to_bytes(self.key).decode('utf-8')
|
||||||
@@ -58,6 +97,19 @@ class TestAES(unittest.TestCase):
|
|||||||
decrypted = (aes_decrypt_text(encrypted, password, 32))
|
decrypted = (aes_decrypt_text(encrypted, password, 32))
|
||||||
self.assertEqual(decrypted, self.secret_msg)
|
self.assertEqual(decrypted, self.secret_msg)
|
||||||
|
|
||||||
|
def test_ecb_encrypt(self):
|
||||||
|
data = bytes_to_intlist(self.secret_msg)
|
||||||
|
data += [0x08] * (BLOCK_SIZE_BYTES - len(data) % BLOCK_SIZE_BYTES)
|
||||||
|
encrypted = intlist_to_bytes(aes_ecb_encrypt(data, self.key, self.iv))
|
||||||
|
self.assertEqual(
|
||||||
|
encrypted,
|
||||||
|
b'\xaa\x86]\x81\x97>\x02\x92\x9d\x1bR[[L/u\xd3&\xd1(h\xde{\x81\x94\xba\x02\xae\xbd\xa6\xd0:')
|
||||||
|
|
||||||
|
def test_ecb_decrypt(self):
|
||||||
|
data = bytes_to_intlist(b'\xaa\x86]\x81\x97>\x02\x92\x9d\x1bR[[L/u\xd3&\xd1(h\xde{\x81\x94\xba\x02\xae\xbd\xa6\xd0:')
|
||||||
|
decrypted = intlist_to_bytes(aes_ecb_decrypt(data, self.key, self.iv))
|
||||||
|
self.assertEqual(decrypted.rstrip(b'\x08'), self.secret_msg)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
# Allow direct execution
|
# Allow direct execution
|
||||||
@@ -7,8 +7,7 @@ import sys
|
|||||||
import unittest
|
import unittest
|
||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
from test.helper import try_rm
|
from test.helper import try_rm, is_download_test
|
||||||
|
|
||||||
|
|
||||||
from yt_dlp import YoutubeDL
|
from yt_dlp import YoutubeDL
|
||||||
|
|
||||||
@@ -32,6 +31,7 @@ def _download_restricted(url, filename, age):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
@is_download_test
|
||||||
class TestAgeRestriction(unittest.TestCase):
|
class TestAgeRestriction(unittest.TestCase):
|
||||||
def _assert_restricted(self, url, filename, age, old_age=None):
|
def _assert_restricted(self, url, filename, age, old_age=None):
|
||||||
self.assertTrue(_download_restricted(url, filename, old_age))
|
self.assertTrue(_download_restricted(url, filename, old_age))
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user