Compare commits

...

1779 Commits

Author SHA1 Message Date
Mozi 351dc0bc33
[ie/eplus] Handle URLs without videos (#9855)
Authored by: pzhlkj6612
2 days ago
feederbox826 518c1afc15
[ie/pornhub] Fix login by email address (#9914)
Closes #9717
Authored by: feederbox826
2 days ago
WyohKnott 85ec2a337a
[ie/googledrive] Fix formats extraction (#9908)
Closes #8281
Authored by: WyohKnott
3 days ago
Jake Finley b207d26f83
[ie/xvideos:quickies] Fix extractor (#9834)
Closes #6356
Authored by: JakeFinley96
3 days ago
sepro 01395a3434
[cleanup] Remove questionable extractors (#9911)
Closes #6279, Closes #6799
Authored by: seproDev
3 days ago
Haxy cf212d0a33
[ie/youtube] Add `mediaconnect` client (#9546)
Authored by: clienthax
3 days ago
alard 6db96268c5
[ie/TV5Monde] Fix extractor (#9143)
Closes #9118
Authored by: alard, seproDev

Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
4 days ago
Eric Lam 800a43983e
[ie/EuroParlWebstream] Support new URL format (#9647)
Authored by: voidful, seproDev

Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
4 days ago
DaPotato69 7e4259dff0
Better warning when requested subs format not found (#9873)
Closes #9760
Authored by: DaPotato69
4 days ago
Stefan Lobbenmeier f1f158976e
[cookies] Get chrome session cookies with `--cookies-from-browser` (#9747)
Partially addresses #5534
Authored by: StefanLobbenmeier
4 days ago
llamasblade 31b417e1d1
[ie/hytale] Use `CloudflareStreamIE` explicitly (#9672)
Authored by: llamasblade
4 days ago
Hugo Azevedo fc2879ecb0
[ie/alura] Fix extractor (#9658)
Authored by: hugohaa
4 days ago
rrgomes 0a1a8e3005
[ie/nfb] Fix extractors (#9650)
Authored by: rrgomes
4 days ago
c-basalt 4cc99d7b6c
[ie/BilibiliSpaceVideo] Fix extraction (#9905)
Closes #9892
Authored by: c-basalt
5 days ago
coletdjnz 3c7a287e28
[test] Add HTTP proxy tests (#9578)
Also fixes HTTPS proxies for curl_cffi

Authored by: coletdjnz
5 days ago
sepro 98d71d8c5e
[ie/commonmistakes] Raise error on blob URLs (#9897)
Authored by: seproDev
5 days ago
kclauhk 00a9f2e1f7
[ie/canalalpha] Fix extractor (#9675)
Authored by: kclauhk
5 days ago
Mozi 73f12119b5
[ie/netease:program] Improve `--no-playlist` message (#9488)
Authored by: pzhlkj6612
5 days ago
Alexandre Huot 6b54cccdcb
[ie/Qub] Fix extractor (#7019)
Closes #4989
Authored by: alexhuot1, dirkf
7 days ago
src-tinkerer c4b87dd885
[ie/ZenYandex] Fix extractor (#9813)
Closes #9803
Authored by: src-tinkerer
7 days ago
fireattack 2338827072
[ie/bilibili] Fix `--geo-verification-proxy` support (#9817)
Closes #9797
Authored by: fireattack
7 days ago
fireattack 06d52c8731
[ie/BilibiliSpaceVideo] Better error message (#9839)
Closes #9528
Authored by: fireattack
7 days ago
sepro df5c9e733a
[ie/vk] Improve format extraction (#9885)
Closes #5675
Authored by: seproDev
7 days ago
Mozi b38018b781
[ie/mixch] Extract comments (#9860)
Authored by: pzhlkj6612
7 days ago
Rasmus Antons 145dc6f656
[ie/boosty] Add cookies support (#9522)
Closes #9401
Authored by: RasmusAntons
7 days ago
bashonly 5904853ae5
[ie/crunchyroll] Support browser impersonation (#9857)
Closes #7442
Authored by: bashonly
1 week ago
Chris Caruso c8bf48f3a8
[ie/cbc.ca:player] Improve `_VALID_URL` (#9866)
Closes #9825
Authored by: carusocr
1 week ago
The-MAGI 351368cb9a
[ie/youporn] Fix extractor (#8827)
Closes #7967
Authored by: The-MAGI
1 week ago
sepro 96da952504
[core] Warn if lack of ffmpeg alters format selection (#9805)
Authored by: seproDev, pukkandan
2 weeks ago
bashonly bec9a59e8e
[networking] Add `extensions` attribute to `Response` (#9756)
CurlCFFIRH now provides an `impersonate` field in its responses' extensions

Authored by: bashonly
2 weeks ago
bashonly 036e0d92c6
[ie/patreon] Extract multiple embeds (#9850)
Closes #9848
Authored by: bashonly
2 weeks ago
bashonly cb2fb4a643
[ie/crunchyroll] Always make metadata available (#9772)
Closes #9750
Authored by: bashonly
2 weeks ago
bashonly 231c2eacc4
[ie/soundcloud] Extract `genres` (#9821)
Authored by: bashonly
2 weeks ago
bashonly c4853655cb
[ie/wrestleuniverse] Avoid partial stream formats (#9800)
Authored by: bashonly
2 weeks ago
Simon Sawicki ac817bc83e
[build] Migrate `linux_exe` to static musl builds (#9811)
Authored by: Grub4K, bashonly

Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
2 weeks ago
bashonly 1a366403d9
[build] Run `macos_legacy` job on `macos-12` (#9804)
`macos-latest` has been bumped to `macos-14-arm64` which breaks the builds

Authored by: bashonly
2 weeks ago
Simon Sawicki 7e26bd53f9
[core/windows] Fix tests for `sys.executable` with spaces (Fix for 64766459e3)
Authored by: Grub4K
2 weeks ago
Simon Sawicki 64766459e3
[core/windows] Improve shell quoting and tests (#9802)
Authored by: Grub4K
3 weeks ago
bashonly 89f535e265
[ci] Fix `curl-cffi` installation (Bugfix for 02483bea1c)
Authored by: bashonly
3 weeks ago
bashonly ff38a011d5
[ie/crunchyroll] Fix auth and remove cookies support (#9749)
Closes #9745
Authored by: bashonly
3 weeks ago
bashonly 8056a3026e
[ie/theatercomplextown] Fix extractors (#9754)
Authored by: bashonly
3 weeks ago
Simon Sawicki 3ee1194288
[ie] Make `_search_nextjs_data` non fatal (#8937)
Authored by: Grub4K
3 weeks ago
bashonly e3b42d8b1b
[ie/facebook] Fix DASH formats extraction (#9734)
Closes #9720
Authored by: bashonly
4 weeks ago
bashonly c9ce57d9bf
[ie/patreon] Fix Vimeo embed extraction (#9712)
Fixes regression in 36b240f9a7

Closes #9709
Authored by: bashonly
4 weeks ago
bashonly 02483bea1c
[build] Normalize `curl_cffi` group to `curl-cffi` (#9698)
Closes #9682
Authored by: bashonly
4 weeks ago
bashonly 315b354429
[ie/afreecatv:live] Add `cdn` extractor-arg (#9666)
Closes #6497
Authored by: bashonly
1 month ago
bashonly 0c21c53885
[ie/jiosaavn] Extract via API and fix playlists (#9656)
Closes #9648
Authored by: bashonly
1 month ago
github-actions[bot] 168e72dcd3 Release 2024.04.09
Created by: Grub4K

:ci skip all :ci run dl
1 month ago
Simon Sawicki ff07792676
[core] Prevent RCE when using `--exec` with `%q` (CVE-2024-22423)
The shell escape function now properly escapes `%`, `\\` and `\n`. `utils.Popen` as well as `%q` output template expansion have been patched accordingly.

Prior to this fix using `--exec` together with `%q` when on Windows could cause remote code to execute. See https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-hjq6-52gw-2g7p for more details.

Authored by: Grub4K
1 month ago
bashonly 216f6a3cb5
[cleanup] Misc (#9426)
Authored by: bashonly, pukkandan
1 month ago
bashonly b19ae095fd
[build] Do not include `curl_cffi` in `macos_legacy` (#9653)
Authored by: bashonly
1 month ago
Simon Sawicki 9590cc6b47
Add new option `--progress-delta` (#9082)
Authored by: Grub4K
1 month ago
luiso1979 79a451e576
[networking] Respect `SSLKEYLOGFILE` environment variable (#9543)
Authored by: luiso1979
1 month ago
Leo Heitmann Ruiz df0e138fc0
[docs] Various manpage fixes
Authored by: leoheitmannruiz
1 month ago
bashonly 2e94602f24
[ie/jiosaavn] Support playlists (#9622)
Closes #9616
Authored by: bashonly
1 month ago
bashonly 4af9d5c2f6
[ie/nhk] Fix NHK World extractors (#9623)
Closes #9513
Authored by: bashonly
1 month ago
John Victor 36b240f9a7
[ie/patreon] Do not extract dead embed URLs (#9613)
Closes #8702
Authored by: johnvictorfs
1 month ago
bashonly fc53ec13ff
[ie/tiktok] Restore `carrier_region` API parameter (#9637)
Avoids some geo-blocks

Authored by: bashonly
1 month ago
Dmitry Meyer 2ab2651a4a
[cookies] Add `--cookies-from-browser` support for Firefox Flatpak (#9619)
Authored by: un-def
1 month ago
bashonly b15b0c1d21
[ie/vkplay] Fix `_VALID_URL` (#9636)
Closes #9635
Authored by: bashonly
1 month ago
bashonly c8a61a9100
[ie/kick] Support browser impersonation (#9611)
Closes #6748
Authored by: bashonly
1 month ago
Mozi f2fd449b46
[ie/joqrag] Fix live status detection (#9624)
Authored by: pzhlkj6612
1 month ago
Tomoka1 9415f1a5ef
[ie/afreecatv] Overhaul extractor (#9566)
Closes #4592, Closes #8862, Closes #9544
Authored by: bashonly, Tomoka1

Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
1 month ago
bashonly a48cc86d6f
[ie/dropbox] Fix formats extraction (#9627)
Closes #9533
Authored by: bashonly
1 month ago
bytedream 954e57e405
[ie/crunchyroll] Fix extractor (#9615)
Authored by: bytedream
1 month ago
Dong Heon Hee 9073ae6458
[ie/afreecatv:live] Fix extractor (#9348)
Closes #4466, Closes #9345
Authored by: hui1601
1 month ago
Offert4324 4cd9e251b9
[ie/medici] Fix extractor (#9518)
Closes #8813
Authored by: Offert4324
1 month ago
bashonly 0ae16ceb18
[ie/jiosaavn] Extract artists (#9612)
Closes #9607
Authored by: bashonly
1 month ago
bashonly 443e206ec4
[ie/jiosaavn] Fix format extensions (#9609)
Authored by: bashonly
1 month ago
bashonly 4c3b7a0769
[ie/mixch] Fix extractor (#9608)
Closes #9536
Authored by: bashonly, nipotan
1 month ago
bashonly 16be117729
Add option `--no-break-on-existing` (#9610)
Authored by: bashonly
1 month ago
trainman261 b49d5ffc53
[ie/cbc.ca:player] Support new URL format (#9561)
Closes #9534
Authored by: trainman261
1 month ago
HobbyistDev 36baaa10e0
[ie/Radio1Be] Add extractor (#9122)
Closes #8707
Authored by: HobbyistDev
1 month ago
Kacper Michajłow 02f93ff51b
[ie/twitch] Extract AV1 and HEVC formats (#9158)
Authored by: kasper93
1 month ago
Mozi c59de48e2b
[ie/mixch:archive] Fix extractor (#8761)
Closes #2373
Authored by: pzhlkj6612
1 month ago
Mozi 0284f1fee2
[ie/asobistage] Add extractor (#8735)
Authored by: pzhlkj6612
1 month ago
bashonly e8032503b9
[build] Print SHA sums to GHA logs (#9582)
Authored by: bashonly
1 month ago
bashonly 97362712a1
[ie/soundcloud] Support cookies (#9586)
Closes #997
Authored by: bashonly
1 month ago
bashonly 246571ae1d
[ie/soundcloud] Support retries for API rate-limit (#9585)
Authored by: bashonly
1 month ago
Simon Sawicki 32abfb00bd
[utils] `traverse_obj`: Convenience improvements (#9577)
Add support for:
- `http.cookies.Morsel`
- Multi type filters (`{type, type}`)

Authored by: Grub4K
1 month ago
pukkandan c305a25c1b
[cleanup] Standardize `import datetime as dt` (#8978) 1 month ago
pukkandan e3a3ed8a98
[ie, cleanup] No `from` stdlib imports in extractors (#8978) 1 month ago
pukkandan a25a424323
[ie/youtube] Calculate more accurate `filesize`
YouTube provides slightly different duration for each format.
Calculating file-size based on this duration instead of the
video duration gives more accurate results.

Ref: https://github.com/yt-dlp/yt-dlp/issues/1400#issuecomment-2007441207
1 month ago
sepro 86e3b82261
[core] Fix `filesize_approx` calculation (#9560)
Reverts 22e4dfacb6

Despite being documented as `Kbit/s`, the extractors/manifests were returning bitrates in SI units of kilobits/sec.

Authored by: seproDev, pukkandan
1 month ago
pukkandan e7b17fce14
[ie/youtube] Update `android` params
Discovered by LuanRT - https://github.com/LuanRT/YouTube.js/pull/624

Closes #9554
1 month ago
bashonly a2d0840739
[ie/soundcloud] Adjust format sorting (#9584)
- Adapt to 86a972033e

Authored by: bashonly
1 month ago
pukkandan 86a972033e
Infer `acodec` for single-codec containers 2 months ago
bashonly 50c2935231
[ie] Add extractor impersonate API (#9474)
Authored by: bashonly, Grub4K, pukkandan
2 months ago
bashonly 0df63cce69
[ie/thisoldhouse] Support Brightcove embeds (#9576)
Closes #9570
Authored by: bashonly
2 months ago
bashonly 63f685f341
[ie/tiktok] Prefer non-bytevc2 formats (#9575)
Closes #9567
Authored by: bashonly
2 months ago
Simon Sawicki 3699eeb67c
[utils] `traverse_obj`: Allow unbranching using `all` and `any` (#9571)
Authored by: Grub4K
2 months ago
Simon Sawicki 979ce2e786
[test] `traversal`: Separate traversal tests (#9574)
Authored by: Grub4K
2 months ago
bashonly 58dd0f8d1e
[build] Optional dependencies cleanup (#9550)
Authored by: bashonly
2 months ago
bashonly cb61e20c26
[ie/tiktok] Fix API extraction (#9548)
Closes #9506
Authored by: bashonly, Grub4K

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
2 months ago
bashonly 9c42b7eef5
[fd/ffmpeg] Accept output args from info dict (#9278)
Authored by: bashonly
2 months ago
coletdjnz e5d4f11104
[rh:websockets] Workaround race condition causing issues on PyPy (#9514)
Authored by: coletdjnz
2 months ago
src-tinkerer bc2b8c0596
[ie/fathom] Add extractor (#9495)
Closes #8541
Authored by: src-tinkerer
2 months ago
sta1us aa7e9ae4f4
[ie/xvideos] Support new URL format (#9493) (#9502)
Closes #9493
Authored by: sta1us
2 months ago
Shreyas Minocha 07f5b2f757
[ie/box] Support URLs without file IDs (#9504)
Authored by: shreyasminocha
2 months ago
Daniel Vogt ff349ff94a
[ie/sharepoint] Add extractor (#6531)
Authored by: C0D3D3V, bashonly

Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
2 months ago
Hasan Rüzgar f859ed3ba1
[ie/loom] Add extractors (#8686)
Closes #3715
Authored by: bashonly, hruzgar

Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
2 months ago
Aron Buzinkay 17d248a587
[ie/youtube:search] Fix params for uncensored results (#9456)
Closes #9156
Authored by: alb, pukkandan
2 months ago
sepro 388c979ac6
[docs] Update yt-dlp tagline (#9481)
Authored by: seproDev, bashonly, coletdjnz, Grub4K, pukkandan
2 months ago
sepro 22e4dfacb6
[ie/youtube] Fix tbr calculation (#9489)
Authored by: pukkandan

Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
2 months ago
Trustin 86d2f4d248
[ie/imgur] Fix extraction (#9471)
Closes #9458
Authored by: trwstin
2 months ago
coletdjnz 52f5be1f1e
[rh:curlcffi] Add support for `curl_cffi`
Authored by: coletdjnz, Grub4K, pukkandan, bashonly

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
Co-authored-by: bashonly <bashonly@protonmail.com>
2 months ago
coletdjnz 0b81d4d252
Add new options `--impersonate` and `--list-impersonate-targets`
Authored by: coletdjnz, Grub4K, pukkandan, bashonly

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
Co-authored-by: bashonly <bashonly@protonmail.com>
2 months ago
coletdjnz f849d77ab5
[test] Workaround websocket server hanging (#9467)
Authored by: coletdjnz
2 months ago
bashonly f2868b26e9
[ie/SonyLIVSeries] Fix season extraction (#9423)
Authored by: bashonly
2 months ago
bashonly be77923ffe
[ie/crunchyroll] Extract `vo_adaptive_hls` formats by default (#9447)
Closes #9439
Authored by: bashonly
2 months ago
bashonly 8c05b3ebae
[ie/tiktok] Update API hostname (#9444)
Closes #9441
Authored by: bashonly
2 months ago
jazz1611 0da66980d3
[ie/gofile] Fix extractor (#9446)
Authored by: jazz1611
2 months ago
bashonly 17b96974a3
[build] Update changelog for tarball and sdist (#9425)
Closes #9417
Authored by: bashonly
2 months ago
github-actions[bot] 8463fb510a Release 2024.03.10
Created by: Grub4K

:ci skip all :ci run dl
2 months ago
pukkandan 615a84447e
[cleanup] Misc (#8968)
Authored by: pukkandan, bashonly, seproDev
2 months ago
pukkandan ed3bb2b0a1
[cleanup] Remove unused code (#8968)
Authored by: pukkandan, seproDev
2 months ago
pukkandan 45491a2a30
[utils] Improve `repr` of `DateRange`, `match_filter_func` 2 months ago
sepro a687226b48
[cleanup, ie] Match both `http` and `https` in `_VALID_URL` (#8968)
Except for Vimeo, since that causes matching collisions.

Authored by: seproDev
2 months ago
pukkandan 93240fc184
[cleanup] Fix misc bugs (#8968)
Closes #8816

Authored by: bashonly, seproDev, pukkandan, Grub4k
2 months ago
pukkandan 47ab66db0f
[docs] Misc Cleanup (#8977)
Closes #8355, #8944

Authored by: bashonly, Grub4k, Arthurszzz, seproDev, pukkandan

Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
Co-authored-by: bashonly <bashonly@protonmail.com>
Co-authored-by: Arthurszzz <minecraftgamerarthur@gmail.com>
Co-authored-by: Simon Sawicki <accounts@grub4k.xyz>
Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
2 months ago
bashonly 0abf2f1f15
[build] Add transitional `setup.py` and `pyinst.py` (#9296)
Authored by: bashonly, Grub4K, pukkandan

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
2 months ago
Peter Hosey 2d91b98456
[fd/http] Reset resume length to handle `FileNotFoundError` (#8399)
Closes #4521
Authored by: boredzo
2 months ago
x11x 8828f4576b
[ie/youtube:tab] Fix `tags` extraction (#9413)
Closes #9412
Authored by: x11x
2 months ago
Simon Sawicki dbd8b1bff9
Improve 069b2aedae
Authored by: Grub4k
2 months ago
Bl4Cc4t 8993721ecb
[ie/roosterteeth] Support bonus features (#9406)
Authored by: Bl4Cc4t
2 months ago
bashonly 263a4b55ac
[core] Handle `--load-info-json` format selection errors (#9392)
Closes #9388
Authored by: bashonly
2 months ago
bashonly b136e2af34
Bugfix for 104a7b5a46 (#9394)
Authored by: bashonly
2 months ago
bashonly b2cc150ad8
[ie/roosterteeth] Add Brightcove fallback (#9403)
Authored by: bashonly
2 months ago
Xpl0itU 785ab1af7f
[ie/crtvg] Fix `_VALID_URL` (#9404)
Authored by: Xpl0itU
2 months ago
bashonly 7aad06541e
[ie/youtube] Further bump client versions (#9395)
Authored by: bashonly
2 months ago
DmitryScaletta d3d4187da9
[ie/duboku] Fix m3u8 formats extraction (#9161)
Closes #9159
Authored by: DmitryScaletta
2 months ago
sepro c8c9039e64
[ie/generic] Follow https redirects properly (#9121)
Authored by: seproDev
2 months ago
sepro df773c3d5d
[cleanup] Mark broken and remove dead extractors (#9238)
Authored by: seproDev
2 months ago
sepro f4f9f6d00e
[cleanup] Fix infodict returned fields (#8906)
Authored by: seproDev
2 months ago
bashonly dfd8c0b696
[ie/roosterteeth] Extract release date and timestamp (#9393)
Authored by: bashonly
2 months ago
James Martindale dd29e6e5fd
[ie/roosterteeth] Extract ad-free streams (#9355)
Closes #7647
Authored by: jkmartindale
2 months ago
bashonly 96f3924bac
[ie/craftsy] Fix extractor (#9384)
Closes #9383
Authored by: bashonly
2 months ago
Simon Sawicki 0fcefb92f3
[ie/newgrounds] Fix login and clean up extraction (#9356)
Authored by: mrmedieval, Grub4K
2 months ago
bashonly e4fbe5f886
[ie/francetv] Fix DAI livestreams (#9380)
Closes #9382
Authored by: bashonly
2 months ago
SirElderling cd7086c0d5
[ie/RideHome] Add extractor (#8875)
Authored by: SirElderling
2 months ago
bashonly cf91400a1d
[build] Add `default` optional dependency group (#9295)
Authored by: bashonly, Grub4K

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
2 months ago
sepro ac340d0745
[test:websockets] Fix timeout test on Windows (#9344)
Authored by: seproDev
2 months ago
Raphaël Droz 11ffa92a61
[ie/dailymotion] Support search (#8292)
Closes #6126
Authored by: drzraf, seproDev

Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
2 months ago
bashonly ede624d1db
[ie/francetv] Fix m3u8 formats extraction (#9347)
Authored by: bashonly
2 months ago
Mozi 40966e8da2
Bugfix for aa13a8e3dd (#9338)
Closes #9351
Authored by: pzhlkj6612
2 months ago
Roy eedb38ce40
[ie/dumpert] Improve `_VALID_URL` (#9320)
Authored by: rvsit
2 months ago
src-tinkerer 6ad11fef65
[ie/CCTV] Fix extraction (#9325)
Closes #9299
Authored by: src-tinkerer
2 months ago
Mozi f0426e9ca5
[ie/vimeo] Extract `live_status` and `release_timestamp` (#9290)
Authored by: pzhlkj6612
2 months ago
bashonly d9b4154cbc
[ie/tiktok] Fix webpage extraction (#9327)
Closes #4992, Closes #8620
Authored by: bashonly
2 months ago
bashonly 9749ac7fec
[ie/francetv] Fix extractors (#9333)
Closes #9323
Authored by: bashonly
2 months ago
bashonly 413d367580
[ie/youtube] Bump Android and iOS client versions (#9317)
Closes #9316
Authored by: bashonly
3 months ago
Mozi aa13a8e3dd
[ie/niconico] Support DMS formats (#9282)
Closes #8389, Closes #8758, Closes #9254
Authored by: pzhlkj6612, xpadev-net
3 months ago
nixxo 8f423cf805
[ie/rai] Fix m3u8 formats extraction (#9291)
Closes #887
Authored by: nixxo
3 months ago
Dong Heon Hee 804f236611
[ie/chzzk:live] Support `--wait-for-video` (#9309)
Authored by: hui1601
3 months ago
SirElderling f00c0def74
[ie/zenporn] Add extractor (#8509)
Closes #8398
Authored by: SirElderling
3 months ago
bashonly e546e5d3b3
Bugfix for 9ff9466455
Closes #9322
Authored by: bashonly
3 months ago
bashonly 4170b3d712
[ie/MujRozhlas] Fix extraction (#9306)
Closes #9304
Authored by: bashonly
3 months ago
114514ns 9ff9466455
[ie/Douyin] Fix extractor (#9239)
Closes #7854, Closes #7941
Authored by: 114514ns, bashonly

Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
3 months ago
marcdumais e28e135d6f
[ie/altcensored:channel] Fix playlist extraction (#9297)
Authored by: marcdumais
3 months ago
Tobias Gruetzmacher f1570ab84d
Bugfix for 1713c88273 (#9298)
Authored by: TobiX
3 months ago
pukkandan 069b2aedae
Create `ydl._request_director` when needed 3 months ago
Simon Sawicki 5eedc208ec
[ie/youtube] Better error when all player responses are skipped (#9083)
Authored by: Grub4K, pukkandan

Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
3 months ago
bashonly 464c919ea8
[ie/CloudflareStream] Improve embed detection (#9287)
Partially addresses #7858
Authored by: bashonly
3 months ago
bashonly 3894ab9574
[ie/archiveorg] Fix format URL encoding (#9279)
Closes #9173
Authored by: bashonly
3 months ago
bashonly b05640d532
[ie/swearnet] Raise for login required (#9281)
Closes #9110
Authored by: bashonly
3 months ago
bashonly 7a29cbbd5f
[ie/ntvru] Fix extraction (#9276)
Closes #8347
Authored by: bashonly, dirkf

Co-authored-by: dirkf <fieldhouse@gmx.net>
3 months ago
bashonly 2e8de097ad
[ie/vimeo] Fix login (#9274)
Closes #9273
Authored by: bashonly
3 months ago
bashonly f3d5face83
[ie/CloudflareStream] Improve `_VALID_URL` (#9280)
Closes #9171
Authored by: bashonly
3 months ago
bashonly eabbccc439
[build] Support failed build job re-runs (#9277)
Authored by: bashonly
3 months ago
sepro 0de09c5b9e
[ie/nebula] Support podcasts (#9140)
Closes #8838
Authored by: seproDev, c-basalt

Co-authored-by: c-basalt <117849907+c-basalt@users.noreply.github.com>
3 months ago
sepro 6a6cdcd182
[core] Warn user when not launching through shell on Windows (#9250)
Authored by: seproDev, Grub4K

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
3 months ago
J. Gonzalez 998dffb5a2
[ie/cnbc] Overhaul extractors (#8741)
Closes #5871, Closes #8378
Authored by: gonzalezjo, Noor-5, zhijinwuu, ruiminggu, seproDev

Co-authored-by: Noor Mostafa <93787875+Noor-5@users.noreply.github.com>
Co-authored-by: zhijinwuu <zhijinw@andrew.cmu.edu>
Co-authored-by: ruiminggu <ruimingg@andrew.cmu.edu>
Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
3 months ago
sepro 29a74a6126
[ie/NerdCubedFeed] Overhaul extractor (#9269)
Authored by: seproDev
3 months ago
bashonly 55f1833376
[ie/twitter] Extract numeric `channel_id` (#9263)
Authored by: bashonly
3 months ago
gmes78 3d9dc2f359
[ie/Rule34Video] Extract `creators` (#9258)
Authored by: gmes78
3 months ago
bashonly 28e53d60df
[ie/twitter] Extract bitrate for HLS audio formats (#9257)
Closes #9202
Authored by: bashonly
3 months ago
fireattack f591e605df
[ie/openrec] Pass referer for m3u8 formats (#9253)
Closes #6946
Authored by: fireattack
3 months ago
Jade Laurence Empleo 9a8afadd17
[plugins] Handle `PermissionError` (#9229)
Authored by: syntaxsurge, pukkandan
3 months ago
Lev 104a7b5a46
[ie] Migrate commonly plural fields to lists (#8917)
Authored by: llistochek, pukkandan
Related: #3944
3 months ago
alard 7e90e34fa4
[extractor/goplay] Fix extractor (#6654)
Authored by: alard
Closes #6235
3 months ago
Alard 4ce57d3b87
[ie] Support multi-period MPD streams (#6654) 3 months ago
pukkandan ffff1bc659
Fix 3725b4f0c9 3 months ago
DmitryScaletta 4f04347909
[ie/FlexTV] Add extractor (#9178)
Closes #9175
Authored by: DmitryScaletta
3 months ago
garret 4392447d94
[ie/NhkRadiru] Extract extended description (#9162)
Authored by: garret1317
3 months ago
bashonly 43cfd462c0
Bugfix for 775cde82dc (#9241)
Authored by: bashonly
3 months ago
Mozi 974d444039
[ie/niconico] Remove legacy danmaku extraction (#9209)
Closes #8684
Authored by: pzhlkj6612
3 months ago
Elan Ruusamäe 80ed8bdeba
[ie/ERRJupiter] Improve `_VALID_URL` (#9218)
Authored by: glensc
3 months ago
feederbox826 de954c1b4d
[ie/pornhub] Fix login support (#9227)
Closes #7981
Authored by: feederbox826
3 months ago
coletdjnz 0085e2bab8
[rh] Remove additional logging handlers on close (#9032)
Fixes https://github.com/yt-dlp/yt-dlp/issues/8922

Authored by: coletdjnz
3 months ago
bashonly 73fcfa39f5
Bugfix for beaa1a4455 (#9235)
[build:Makefile] Restore compatibility with GNU Make <4.0

- The != variable assignment operator is not supported by GNU Make <4.0
- $(shell) is a no-op in BSD Make, assigns an empty string to the var
- Try to assign with != and fallback to $(shell) if not assigned (?=)

- Old versions of BSD find have different -exec behavior
- Pipe to `sed` instead of using `find ... -exec dirname {}`

- BSD tar does not support --transform, --owner or --group
- Allow user to specify path to GNU tar by passing GNUTAR variable

- pandoc vars are immediately evaluated with != in gmake>=4 and bmake
- Suppress stderr output for pandoc -v in case it is not installed
- Use string comparison instead of int comparison for pandoc version

Authored by: bashonly
3 months ago
DmitryScaletta 41d6b61e98
[ie/Utreon] Support playeur.com (#9182)
Closes #9180
Authored by: DmitryScaletta
3 months ago
sepro 0bee29493c
[ie/Screencastify] Update `_VALID_URL` (#9232)
Authored by: seproDev
3 months ago
sepro 644738ddaa
[ie/OneFootball] Fix extractor (#9222)
Authored by: seproDev
3 months ago
sepro c168d8791d
[ie/Nova] Fix embed extraction (#9221)
Authored by: seproDev
3 months ago
diman8 ddd4b5e10a
[ie/SVTPage] Fix extractor (#8938)
Closes #8930
Authored by: diman8
3 months ago
nixxo f788149237
[ie/rai] Filter unavailable formats (#9189)
Closes #9154
Authored by: nixxo
3 months ago
barsnick 017adb28e7
[ie/LinkedIn] Fix metadata and extract subtitles (#9056)
Closes #9003
Authored by: barsnick
3 months ago
ringus1 2e30b5567b
[ie/facebook] Improve extraction
Partially addresses #4311

Authored by: jingtra, ringus1

Co-authored-by: Jing Kjeldsen <jingtra@gmail.com>
3 months ago
bashonly beaa1a4455
[build:Makefile] Ensure compatibility with BSD `make` (#9210)
Authored by: bashonly
3 months ago
Florian Meißner fb44020fa9
[build:Makefile] Fix man pages generated by `pandoc>=3` (#7047)
Closes #7046, Closes #8481
Authored by: t-nil
3 months ago
sepro 3dc9232e1a
[ie/MagellanTV] Support episodes (#9199)
Authored by: seproDev
3 months ago
sepro 9401736fd0
[ie/LeFigaroVideoEmbed] Fix extractor (#9198)
Authored by: seproDev
3 months ago
sepro cd0443fb14
[ie/Funk] Fix extractor (#9194)
Authored by: seproDev
3 months ago
sepro 03536126d3
[ie/CrooksAndLiars] Fix extractor (#9192)
Authored by: seproDev
3 months ago
sepro 1ed5ee2f04
[ie/Ant1NewsGrEmbed] Fix extractor (#9191)
Authored by: seproDev
3 months ago
bashonly 3876429d72
[build] Bump `actions/upload-artifact` to v4 and adjust workflows
Authored by: bashonly
3 months ago
bashonly b0059f0413
[build] Bump `conda-incubator/setup-miniconda` to v3
Authored by: bashonly
3 months ago
bashonly b14e818b37
[ci] Bump `actions/setup-python` to v5
Authored by: bashonly
3 months ago
bashonly 867f637b95
[cleanup] Build files cleanup
- Fix `AUTHORS` file by doing an unshallow checkout
- Update triggers for nightly/master release

Authored by: bashonly
3 months ago
bashonly 920397634d
[build] Fix `secretstorage` for ARM builds
Authored by: bashonly
3 months ago
bashonly b8a433aaca
[devscripts] `install_deps`: Add script and migrate to it
Authored by: bashonly
3 months ago
Simon Sawicki fd647775e2
[devscripts] `tomlparse`: Add makeshift toml parser
Authored by: Grub4K
3 months ago
bashonly 775cde82dc
[build] Migrate to `pyproject.toml` and `hatchling`
Authored by: bashonly
3 months ago
bashonly 868d2f60a7
[build:Makefile] Add automated `CODE_FOLDERS` and `CODE_FILES`
Authored by: bashonly
3 months ago
bashonly a1b7784289
[build] Move bundle scripts into `bundle` submodule
Authored by: bashonly
3 months ago
lauren n. liberda 882e3b753c
[ie/tvp] Support livestreams (#8860)
Closes #8824
Authored by: selfisekai
3 months ago
Dmitry Meyer 540b682981
[ie/Boosty] Add extractor (#9144)
Closes #5900, Closes #8704
Authored by: un-def
3 months ago
SirElderling 05420227aa
[ie/nytimes] Extract timestamp (#9142)
Authored by: SirElderling
3 months ago
Chocobozzz 35d96982f1
[ie/peertube] Update instances (#9070)
Authored by: Chocobozzz
3 months ago
DmitryScaletta acaf806c15
[ie/nuum] Add extractors (#8868)
Authored by: DmitryScaletta, seproDev

Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
3 months ago
SirElderling 07256b9fee
[ie/nytimes] Overhaul extractors (#9075)
Closes #2899, Closes #8605
Authored by: SirElderling
3 months ago
c-basalt e439693f72
[ie/bilibili] Support `--no-playlist` (#9139)
Addresses #8499
Authored by: c-basalt
3 months ago
Michal 96d0f8c1cb
[ie/eporner] Extract AV1 formats (#9028)
Authored by: michal-repo
3 months ago
YoshichikaAAA e3ce2b385e
[ie/radiko] Extract more metadata (#9115)
Authored by: YoshichikaAAA
3 months ago
sepro 4253e3b7f4
[ie/CCMA] Extract 1080p DASH formats (#9130)
Closes #5755
Authored by: seproDev
3 months ago
bashonly 8e765755f7
[ie/vimeo] Fix API headers (#9125)
Closes #9124
Authored by: bashonly
3 months ago
c-basalt ffa017cfc5
[ie/BiliBiliSearch] Set cookie to fix extraction (#9119)
Closes #5083
Authored by: c-basalt
3 months ago
HobbyistDev a0d50aabc5
[ie/orf:on] Add extractor (#9113)
Closes #8903
Authored by: HobbyistDev
3 months ago
HobbyistDev 2f4b575946
[ie/zetland] Add extractor (#9116)
Closes #9024
Authored by: HobbyistDev
3 months ago
garret fc2cc626f0
[ie/cineverse] Detect when login required (#9081)
Partially addresses #9072
Authored by: garret1317
3 months ago
columndeeply a2bac6b7ad
[ie/PrankCastPost] Add extractor (#8933)
Authored by: columndeeply
3 months ago
rrgomes 4b8b0dded8
[ie/nfb] Add support for onf.ca and series (#8997)
Closes #8198
Authored by: bashonly, rrgomes

Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
4 months ago
jazz1611 4a6ff0b47a
[ie/redtube] Support redtube.com.br URLs (#9103)
Authored by: jazz1611
4 months ago
Radu Manole 62c65bfaf8
[ie/NinaProtocol] Add extractor (#8946)
Closes #8709, Closes #8764
Authored by: RaduManole, seproDev

Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
4 months ago
bashonly d63eae7e7f
[core] Don't select storyboard formats as fallback
Closes #7715
Authored by: bashonly
4 months ago
Simon Sawicki 2792092afd
[cookies] Improve error message for Windows `--cookies-from-browser chrome` issue (#9080)
Authored by: Grub4K
4 months ago
Simon Sawicki cbed249aaa
[cookies] Fix `--cookies-from-browser` for `snap` Firefox (#9016)
Authored by: Grub4K
4 months ago
Simon Sawicki 3725b4f0c9
[core] Add `--compat-options 2023` (#9084)
Authored by: Grub4K
4 months ago
sepro 67bb70cd70
[ie/Vbox7] Fix extractor (#9100)
Closes #1098, Closes #5661
Authored by: seproDev
4 months ago
kclauhk 9b5efaf86b
[ie/facebook] Support events (#9055)
Closes #5355
Authored by: kclauhk
4 months ago
sepro 999ea80beb
[ie/art19] Add extractors (#9099)
Authored by: seproDev
4 months ago
Nur Mahmud Ul Alam Tasin 41b6cdb419
[ie/viewlift] Add support for chorki.com (#9095)
Closes #3369
Authored by: NurTasin
4 months ago
Danish Humair 02e343f6ef
[ie/MedalTV] Fix extraction (#9098)
Closes #8766
Authored by: Danish-H
4 months ago
Elan Ruusamäe a514cc2feb
[ie/ERRJupiter] Add extractor (#8549)
Authored by: glensc
4 months ago
kclauhk 87286e93af
[ie/facebook] Support permalink URLs (#9061)
Authored by: kclauhk
4 months ago
kclauhk 3c4d3ee491
[ie/facebook] Improve thumbnail extraction (#9060)
Authored by: kclauhk
4 months ago
kclauhk 5b68c478fb
[ie/facebook] Set format HTTP chunk size (#9058)
Closes #8197
Authored by: bashonly, kclauhk
4 months ago
Christopher Schreiner 9526b1f179
[ie/adn] Improve auth error handling (#9068)
Closes #9067
Authored by: infanf
4 months ago
vista-narvas 0023af81fb
[ie/RumbleChannel] Fix extractor (#9092)
Closes #8782
Authored by: vista-narvas, Pranaxcau
4 months ago
Christian Kündig cae6e46107
[ie/PlaySuisse] Add login support (#9077)
Closes #7974
Authored by: chkuendig
4 months ago
jazz1611 c91d8b1899
[ie/redtube] Fix formats extraction (#9076)
Authored by: jazz1611
4 months ago
jazz1611 77c2472ca1
[ie/Gofile] Fix extraction (#9074)
Closes #9073
Authored by: jazz1611
4 months ago
shmohawk d79c7e9937
[ie/Txxx] Extract thumbnails (#9063)
Authored by: shmohawk
4 months ago
Caesim404 5dda3b291f
[ie/lsm,cloudycdn] Add extractors (#8643)
Closes #2978
Authored by: Caesim404
4 months ago
Simon Sawicki 5f25f348f9
[ie/pr0gramm] Enable POL filter and provide tags without login (#9051)
Authored by: Grub4K
4 months ago
kclauhk a40b0070c2
[ie/facebook:ads] Add extractor (#8870)
Closes #8083
Authored by: kclauhk
4 months ago
chtk 9cd9044790
[ie/Floatplane] Improve metadata extraction (#8934)
Authored by: chtk
4 months ago
John Victor f0e8bc7c60
[ie/patreon] Fix embedded HLS extraction (#8993)
Closes #8973
Authored by: johnvictorfs
4 months ago
Stefan Lobbenmeier c099ec9392
[ie/ard:mediathek] Support cookies to verify age (#9037)
Closes #9035
Authored by: StefanLobbenmeier
4 months ago
gmes78 c0ecceeefe
[ie/Rule34Video] Fix `_VALID_URL` (#9044)
Authored by: gmes78
4 months ago
u-spec-png 3e083191cd
[ie/Newgrounds:user] Fix extractor (#9046)
Closes #7308
Authored by: u-spec-png
4 months ago
dasidiot 9f1e9dab21
[ie/motherless] Support uploader playlists (#8994)
Authored by: dasidiot
4 months ago
Martin Renold 5a63454b36
[ie/mx3] Add extractors (#8736)
Authored by: martinxyz
4 months ago
lauren n. liberda fcaa2e735b
[ie/Sejm,RedCDNLivx] Add extractors (#8676)
Authored by: selfisekai
4 months ago
coletdjnz 35f4f764a7
[rh:requests] Apply `remove_dot_segments` to absolute redirect locations
Fixes https://github.com/yt-dlp/yt-dlp/issues/9020

Authored by: coletdjnz
4 months ago
sepro f24e44e8cb
[webvtt] Don't parse single fragment files (#9034)
Partially addresses #5804
Authored by: seproDev
4 months ago
coletdjnz 811d298b23
[networking] Remove `_CompatHTTPError` (#8871)
Use `yt_dlp.networking.exceptions.HTTPError`.
`_CompatHTTPError` was to help with transition to the networking framework.

Authored by: coletdjnz
4 months ago
coletdjnz 69d3191495
[test] Skip source address tests if the address cannot be bound to (#8900)
Fixes https://github.com/yt-dlp/yt-dlp/issues/8890

Authored by: coletdjnz
4 months ago
HobbyistDev 50e06e21a6
[ie/MLBArticle] Fix extractor (#9021)
Closes #8682
Authored by: HobbyistDev
4 months ago
divStar 4310b6650e
[ie/getcourseru] Add extractors (#8873)
Authored by: divStar, seproDev

Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
4 months ago
SirElderling 1713c88273
[ie/bilibili] Add referer header and fix metadata extraction (#8832)
Closes #6640
Authored by: SirElderling
4 months ago
Alexey Neyman 4a07a455bb
[ie/GoPro] Fix extractor (#9019)
Authored by: stilor
4 months ago
Christopher Schreiner 5eb1458be4
[ie/adn] Add support for German site (#8708)
- Add extractor for seasons

Closes #6643, Closes #8945
Authored by: infanf
4 months ago
SirElderling 1a36dbad71
[ie/RinseFMArtistPlaylist] Add extractor (#8794)
Authored by: SirElderling
4 months ago
Snack 12f0427405
[ie/asobichannel] Add extractors (#8700)
Authored by: Snack-X
4 months ago
alien-developers 5154dc0a68
[ie/JioSaavnSong] Support more bitrates (#8834)
Authored by: alien-developers, bashonly

Co-authored-by: bashonly <bashonly@protonmail.com>
4 months ago
ufukk 8ab8465083
[ie/TrtWorld] Add extractor (#8701)
Closes #8455
Authored by: ufukk
4 months ago
ArnauvGilotra e641aab7a6
[ie/AmadeusTV] Add extractor (#8744)
Closes #8155
Authored by: ArnauvGilotra
4 months ago
DmitryScaletta 20cdad5a2c
[ie/KukuluLive] Add extractor (#8877)
Closes #8865
Authored by: DmitryScaletta
4 months ago
SirElderling 43694ce13c
[ie/NineNews] Add extractor (#8840)
Closes #8831
Authored by: SirElderling
4 months ago
sefidel 8226a3818f
[ie/abematv] Support login for playlists (#8901)
Authored by: sefidel
4 months ago
sefidel c51316f8a6
[ie/abematv] Fix extraction with cache (#8895)
Closes #6532
Authored by: sefidel
4 months ago
sepro a281beba8d
[ie/naver] Fix extractors (#8883)
Closes #8850, Closes #8692
Authored by: seproDev
4 months ago
DmitryScaletta ba6b0c8261
[ie/chzzk] Add extractors (#8887)
Closes #8804
Authored by: DmitryScaletta
4 months ago
Karavellas 6171b050d7
[ie/ElementorEmbed] Add extractor (#8948)
Authored by: pompos02, seproDev

Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
4 months ago
Giulio Muscarello aa5dcc4ee6
[ie/IlPost] Add extractor (#9001)
Authored by: CapacitorSet
4 months ago
Philipp Waldhauer 5e2e24b2c5
[ie/MagentaMusik] Add extractor (#7790)
Authored by: pwaldhauer, seproDev

Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
4 months ago
gmes78 fee2d8d9c3
[ie/Rule34Video] Extract more metadata (#7416)
Closes #7233
Authored by: gmes78
4 months ago
Akmal cf9af2c7f1
[ie/Facebook] Add new ID format (#3824)
Closes #3496
Authored by: Wikidepia, kclauhk

Co-authored-by: kclauhk <78251477+kclauhk@users.noreply.github.com>
4 months ago
HobbyistDev cf6413e840
[ie/BiliIntl] Fix and improve subtitles extraction (#7077)
Closes #7075, Closes #6664
Authored by: HobbyistDev, itachi-19, dirkf, seproDev

Co-authored-by: itachi-19 <16500619+itachi-19@users.noreply.github.com>
Co-authored-by: dirkf <fieldhouse@gmx.net>
Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
4 months ago
jazz1611 5498729c59
[ie/GoogleDrive] Fix source file extraction (#8990)
Closes #8976
Authored by: jazz1611
4 months ago
Nicolas Appriou 393b487a4e
[ie/ArteTV] Separate closed captions (#8231)
Authored by: Nicals, seproDev

Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
4 months ago
Bibhav48 4d9dc0abe2
[ie/cloudflarestream] Extract subtitles (#9007)
Closes #8830
Authored by: Bibhav48
4 months ago
Andrew Gibson 014cb5774d
[ie/aenetworks] Rating should be optional for AP extraction (#9005)
Authored by: agibson-fl
4 months ago
Finn R. Gärtner 8e6e365172
[ie/Piapro] Improve `_VALID_URL` (#8999)
Authored by: FinnRG
4 months ago
Max 95e82347b3
[ie/Viously] Add extractor (#8927)
Replaces Turbo extractor

Authored by: nbr23, seproDev

Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
4 months ago
DmitryScaletta 5b8c69ae04
[ie/twitch] Fix m3u8 extraction (#8960)
Closes #8958
Authored by: DmitryScaletta
4 months ago
garret 5af1f19787
[ie/NhkRadiruLive] Make metadata extraction non-fatal (#8956)
Authored by: garret1317
4 months ago
Simon Sawicki b6951271ac
[ie/ard:mediathek] Revert to using old id (#8916)
Authored by: Grub4K
4 months ago
Simon Sawicki ffbd4f2a02
[utils] `traverse_obj`: Support `xml.etree.ElementTree.Element` (#8911)
Authored by: Grub4K
4 months ago
mara004 292d60b1ed
[cleanup] Fix typo in README.md (#8894)
Authored by: antonkesy
4 months ago
Ralph Drake 85b33f5c16
[cookies] Fix `--cookies-from-browser` with macOS Firefox profiles (#8909)
Ref: https://support.mozilla.org/en-US/kb/profile-manager-create-remove-switch-firefox-profiles#firefox:mac

Closes #8898
Authored by: RalphORama
4 months ago
DmitryScaletta 85a2d07c1f
[ie/Bigo] Fix JSON extraction (#8893)
Closes #8852
Authored by: DmitryScaletta
5 months ago
github-actions[bot] 9f40cd2896 Release 2023.12.30
Created by: bashonly

:ci skip all :ci run dl
5 months ago
bashonly f10589e345
[docs] Update youtube-dl merge commit in `README.md`
Authored by: bashonly
5 months ago
Simon Sawicki f9fb3ce86e
[cleanup] Misc (#8598)
Authored by: bashonly, pukkandan, seproDev, Grub4K

Co-authored-by: bashonly <bashonly@protonmail.com>
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
5 months ago
sepro 5f009a094f
[ie/ARD] Overhaul extractors (#8878)
Closes #8731, Closes #6784, Closes #2366, Closes #2975, Closes #8760
Authored by: seproDev
5 months ago
Simon Sawicki 225cf2b830
Fix 2d1d683a54
Authored by: Grub4K
5 months ago
Simon Sawicki 2d1d683a54
[devscripts] `run_tests`: Create Python script (#8720)
Authored by: Grub4K
5 months ago
Simon Sawicki 65de7d204c
Update to ytdl-commit-be008e6 (#8836)
- [utils] Make restricted filenames ignore some Unicode categories (by dirkf)
- [ie/telewebion] Fix extraction (by Grub4K)
- [ie/imgur] Overhaul extractor (by bashonly, Grub4K)
- [ie/EpidemicSound] Add extractor (by Grub4K)

Authored by: bashonly, dirkf, Grub4K

Co-authored-by: bashonly <bashonly@protonmail.com>
5 months ago
kclauhk c39358a54b
[ie/Facebook] Fix Memories extraction (#8681)
- Support group /posts/ URLs
- Raise a proper error message if no formats are found

Closes #8669
Authored by: kclauhk
5 months ago
Lars Strojny 1f8bd8eba8
[ie/ARDBetaMediathek] Fix series extraction (#8687)
Closes #7666
Authored by: lstrojny
5 months ago
Simon Sawicki 00cdda4f6f
[core] Fix format selection parse error for CPython 3.12 (#8797)
Authored by: Grub4K
5 months ago
bashonly 116c268438
[ie/twitter] Work around API rate-limit (#8825)
Closes #8762
Authored by: bashonly
5 months ago
bashonly e7d22348e7
[ie/twitter] Prioritize m3u8 formats (#8826)
Closes #8117
Authored by: bashonly
5 months ago
bashonly 50eaea9fd7
[ie/instagram] Fix stories extraction (#8843)
Closes #8290
Authored by: bashonly
5 months ago
bashonly f45c4efcd9
[ie/litv] Fix premium content extraction (#8842)
Closes #8654
Authored by: bashonly
5 months ago
Simon Sawicki 13b3cb3c2b
[ci] Run core tests only for core changes (#8841)
Authored by: Grub4K
5 months ago
Nicolas Dato 0d531c35ec
[ie/RudoVideo] Add extractor (#8664)
Authored by: nicodato
5 months ago
barsnick bc4ab17b38
[cleanup] Fix spelling of `IE_NAME` (#8810)
Authored by: barsnick
5 months ago
bashonly 632b8ee54e
[core] Release workflow and Updater cleanup (#8640)
- Only use trusted publishing with PyPI and remove support for PyPI tokens from release workflow
- Clean up improper actions syntax in the build workflow inputs
- Refactor Updater to allow for consistent unit testing with `UPDATE_SOURCES`

Authored by: bashonly
5 months ago
barsnick c919b68f7e
[ie/bbc] Extract more formats (#8321)
Closes #4902
Authored by: barsnick, dirkf
5 months ago
bashonly 19741ab8a4
[ie/bbc] Fix JSON parsing bug
Authored by: bashonly
5 months ago
bashonly 37755a037e
[test:networking] Update tests for OpenSSL 3.2 (#8814)
Authored by: bashonly
5 months ago
coletdjnz 196eb0fe77
[networking] Strip whitespace around header values (#8802)
Fixes https://github.com/yt-dlp/yt-dlp/issues/8729
Authored by: coletdjnz
5 months ago
Mozi db8b4edc7d
[ie/JoqrAg] Add extractor (#8384)
Authored by: pzhlkj6612
5 months ago
bashonly 1c54a98e19
[ie/twitter] Extract stale tweets (#8724)
Closes #8691
Authored by: bashonly
5 months ago
Simon Sawicki 00a3e47bf5
[ie/bundestag] Add extractor (#8783)
Authored by: Grub4K
5 months ago
Amir Y. Perehodnik c5f01bf7d4
[ie/Maariv] Add extractor (#8331)
Authored by: amir16yp
5 months ago
Tristan Charpentier c91af948e4
[ie/RinseFM] Add extractor (#8778)
Authored by: hashFactory
5 months ago
Pandey Ganesha 6b5d93b0b0
[ie/youtube] Fix `like_count` extraction (#8763)
Closes #8759
Authored by: Ganesh910
5 months ago
pukkandan 298230e550
[webvtt] Fix 15f22b4880 5 months ago
Mozi d5d1517e7d
[ie/eplus] Add login support and DRM detection (#8661)
Authored by: pzhlkj6612
5 months ago
trainman261 7e09c147fd
[ie/theplatform] Extract more metadata (#8635)
Authored by: trainman261
5 months ago
Benjamin Krausse e370f9ec36
[ie] Add `media_type` field
Authored by: trainman261
5 months ago
SirElderling b1a1ec1540
[ie/bitchute] Fix and improve metadata extraction (#8507)
Closes #8492
Authored by: SirElderling
5 months ago
Simon Sawicki 0b6f829b1d
[utils] `traverse_obj`: Move `is_user_input` into output template (#8673)
Authored by: Grub4K
5 months ago
Simon Sawicki f98a3305eb
[ie/pr0gramm] Support variant formats and subtitles (#8674)
Authored by: Grub4K
5 months ago
sepro 04a5e06350
[ie/ondemandkorea] Fix upgraded format extraction (#8677)
Closes #8675
Authored by: seproDev
5 months ago
Nicolas Cisco b03c89309e
[ie/mediastream] Fix authenticated format extraction (#8657)
Authored by: NickCis
5 months ago
Pierrick Guillaume 71f28097fe
[ie/francetv] Improve metadata extraction (#8409)
Authored by: Fymyte
5 months ago
pukkandan 044886c220
[ie/youtube] Return empty playlist when channel/tab has no videos
Closes #8634
5 months ago
pukkandan 993edd3f6e
[outtmpl] Support multiplication
Related: #8683
5 months ago
OIRNOIR 6a9c7a2b52
[ie/youtube] Support cf.piped.video (#8514)
Authored by: OIRNOIR
Closes #8457
6 months ago
pukkandan a174c453ee
Let `read_stdin` obey `--quiet`
Closes #8668
6 months ago
TSRBerry 15f22b4880
[webvtt] Allow spaces before newlines for CueBlock (#7681)
Closes #7453

Ref: https://www.w3.org/TR/webvtt1/#webvtt-cue-block
6 months ago
sepro 9751a457cf
[cleanup] Remove dead extractors (#8604)
Closes #1609, Closes #3232, Closes #4763, Closes #6026, Closes #6322, Closes #7912
Authored by: seproDev
6 months ago
bashonly 5a230233d6
[ie/box] Fix formats extraction (#8649)
Closes #5098
Authored by: bashonly
6 months ago
bashonly 4903f452b6
[ie/bfmtv] Fix extractors (#8651)
Closes #8425
Authored by: bashonly
6 months ago
bashonly ff2fde1b8f
[ie/TwitCastingUser] Fix extraction (#8650)
Closes #8653
Authored by: bashonly
6 months ago
bashonly deeb13eae8
[pp/FFmpegMetadata] Embed stream metadata in single format downloads (#8647)
Closes #8568
Authored by: bashonly
6 months ago
bashonly bb5a54e6db
[ie/youtube] Improve detection of faulty HLS formats (#8646)
Closes #7747
Authored by: bashonly
6 months ago
sepro 628fa244bb
[ie/floatplane] Add extractors (#8639)
Closes #5877, Closes #5912
Authored by: seproDev
6 months ago
kclauhk 9cafb9ff17
[ie/facebook] Improve subtitles extraction (#8296)
Authored by: kclauhk
6 months ago
sepro 1732eccc0a
[core] Parse `release_year` from `release_date` (#8524)
Closes #7263
Authored by: seproDev
6 months ago
pk a0b19d319a
[core] Support `NO_COLOR` environment variable (#8385)
Authored by: prettykool, Grub4K
6 months ago
middlingphys cc07f5cc85
[ie/abematv] Fix season metadata (#8607)
Authored by: middlingphys
6 months ago
coletdjnz ccfd70f4c2
[rh:websockets] Migrate websockets to networking framework (#7720)
* Adds a basic WebSocket framework
* Introduces new minimum `websockets` version of 12.0
* Deprecates `WebSocketsWrapper`

Fixes https://github.com/yt-dlp/yt-dlp/issues/8439

Authored by: coletdjnz
6 months ago
sepro 45d82be65f
[ie/nebula] Overhaul extractors (#8566)
Closes #4300, Closes #5814, Closes #7588, Closes #6334, Closes #6538
Authored by: elyse0, pukkandan, seproDev

Co-authored-by: Elyse <26639800+elyse0@users.noreply.github.com>
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
6 months ago
Safouane Aarab 3237f8ba29
[ie/allstar] Add extractors (#8274)
Closes #6917
Authored by: S-Aarab
6 months ago
Kyraminol Endyeran 1725e943b0
[ie/vvvvid] Set user-agent to fix extraction (#8615)
Authored by: Kyraminol
6 months ago
c-basalt 9f09bdcfcb
[ie/bilibili] Support courses and interactive videos (#8343)
Closes #6135, Closes #8428
Authored by: c-basalt
6 months ago
Simon Sawicki f124fa4588
[ci] Concurrency optimizations (#8614)
Authored by: Grub4K
6 months ago
JC-Chung 585d0ed9ab
[ie/twitcasting] Detect livestreams via API and `show` page (#8601)
Authored by: JC-Chung, bashonly
6 months ago
SirElderling 1fa3f24d4b
[ie/theguardian] Add extractors (#8535)
Closes #8520
Authored by: SirElderling
6 months ago
sepro ddb2d7588b
[ie] Extract from `media` elements in SMIL manifests (#8504)
Authored by: seproDev
6 months ago
qbnu f223b1b078
[ie/vocaroo] Do not use deprecated `getheader` (#8606)
Authored by: qbnu
6 months ago
Berkay 6fe82491ed
[ie/twitter:broadcast] Extract `concurrent_view_count` (#8600)
Authored by: sonmezberkay
6 months ago
sepro 34df1c1f60
[ie/vidly] Add extractor (#8612)
Authored by: seproDev
6 months ago
Simon Sawicki 1d24da6c89
[ie/nintendo] Fix Nintendo Direct extraction (#8609)
Authored by: Grub4K
6 months ago
Elan Ruusamäe 66a0127d45
[ie/duoplay] Add extractor (#8542)
Authored by: glensc
6 months ago
Raphaël Droz 3f90813f06
[ie/altcensored] Add extractor (#8291)
Authored by: drzraf
6 months ago
Ha Tien Loi 64de1a4c25
[ie/zingmp3] Add support for radio and podcasts (#7189)
Authored by: hatienl0i261299
6 months ago
sepro f96ab86cd8
[ie/drtv] Set default ext for m3u8 formats (#8590)
Closes #8589
Authored by: seproDev
6 months ago
bashonly f4b95acafc
Remove Python 3.7 support (#8361)
Closes #7803
Authored by: bashonly
6 months ago
github-actions[bot] fe6c82ccff Release 2023.11.16
Created by: bashonly

:ci skip all :ci run dl
6 months ago
bashonly 24f827875c
[build] Make `secretstorage` an optional dependency (#8585)
Authored by: bashonly
6 months ago
bashonly 15cb3528cb
[ie/abc.net.au:iview:showseries] Fix extraction (#8586)
Closes #8554, Closes #8572
Authored by: bashonly
6 months ago
JC-Chung 2325d03aa7
[ie/twitcasting] Fix livestream detection (#8574)
Authored by: JC-Chung
6 months ago
aarubui e569c2d1f4
[ie/njpwworld] Remove (#8570)
Authored by: aarubui
6 months ago
TravisDupes a489f07150
[ie/dailymotion] Improve `_VALID_URL` (#7692)
Closes #7601
Authored by: TravisDupes
6 months ago
Boris Nagaev 5efe68b73c
[ie/ZenYandex] Fix extraction (#8454)
Closes #8275
Authored by: starius
6 months ago
Awal Garg b530118e7f
[ie/JioSaavn] Add extractors (#8307)
Authored by: awalgarg
6 months ago
Eze Livinsky dcfad52812
[ie/eltrecetv] Add extractor (#8216)
Authored by: elivinsky
6 months ago
almx 0783fd558e
[ie/DRTV] Fix extractor (#8484)
Closes #8298
Authored by: almx, seproDev

Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com>
6 months ago
FrankZ85 0f634dba3a
[ie/tv5mondeplus] Extract subtitles (#4209)
Closes #4205
Authored by: FrankZ85
6 months ago
sepro 21dc069bea
[ie/beatbump] Update `_VALID_URL` (#8576)
Authored by: seproDev
6 months ago
github-actions 5d3a3cd493 Release 2023.11.14
Created by: Grub4K

:ci skip all :ci run dl
6 months ago
bashonly a9d3f4b20a
[cleanup] Fix changelog typo
Authored by: bashonly
6 months ago
Simon Sawicki b012271d01
[cleanup] Misc (#8510)
Authored by: bashonly, coletdjnz, dirkf, gamer191, seproDev, Grub4K
6 months ago
bashonly f04b5bedad
[ie] Do not smuggle `http_headers`
See: https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-3ch3-jhc6-5r8x

Authored by: coletdjnz
6 months ago
bashonly d4f14a72dc
[ie] Do not test truth value of `xml.etree.ElementTree.Element` (#8582)
Testing the truthiness of an `xml.etree.ElementTree.Element` instance is deprecated in py3.12

Authored by: bashonly
6 months ago
bashonly 87264d4fda
[test:update] Implement simple updater unit tests
Authored by: bashonly
6 months ago
bashonly a00af29853
[cleanup] Update documentation for master and nightly channels
Authored by: bashonly, Grub4K

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
6 months ago
bashonly 0b6ad22e6a
[update] Overhaul self-updater
Authored by: bashonly, Grub4K

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
6 months ago
bashonly 5438593a35
[ci] Bump `actions/checkout` to v4
Authored by: bashonly
6 months ago
bashonly 9970d74c83
[build] Include secretstorage in Linux builds
Authored by: bashonly
6 months ago
bashonly 20314dd46f
[core] Include build origin in verbose output
Authored by: bashonly, Grub4K

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
6 months ago
bashonly 1d03633c5a
[build] Overhaul and unify release workflow
Authored by: bashonly, Grub4K

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
6 months ago
Frank Aurich 8afd9468b0
[ie/n-tv.de] Fix extractor (#8414)
Closes #3179
Authored by: 1100101
6 months ago
SirElderling ef12dbdcd3
[ie/radiocomercial] Add extractors (#8508)
Authored by: SirElderling
6 months ago
LoserFox 46acc418a5
[ie/neteasemusic] Improve metadata extraction (#8531)
Closes #8530
Authored by: LoserFox
6 months ago
Esokrates 6ba3085616
[ie/orf:podcast] Add extractor (#8486)
Closes #5265
Authored by: Esokrates
6 months ago
bashonly f6e97090d2
[ie/twitter:broadcast] Support `--wait-for-video` (#8475)
Closes #8473
Authored by: bashonly
6 months ago
bashonly 2863fcf2b6
[ie/theatercomplextown] Add extractors (#8560)
Closes #8491
Authored by: bashonly
6 months ago
bashonly c76c96677f
[ie/thisoldhouse] Add login support (#8561)
Closes #8257
Authored by: bashonly
6 months ago
c-basalt 15b252dfd2
[ie/weibo] Fix extraction (#8463)
Closes #8445
Authored by: c-basalt
6 months ago
Aniol Pagès 312a2d1e8b
[ie/LaXarxaMes] Add extractor (#8412)
Authored by: aniolpages
6 months ago
garret 54579be436
[ie/nhk] Improve metadata extraction (#8388)
Authored by: garret1317
6 months ago
sepro 05adfd883a
[ie/ondemandkorea] Overhaul extractor (#8386)
Closes #8374
Authored by: seproDev
6 months ago
Martin Pecka 3ff494f6f4
[ie/NovaEmbed] Improve `_VALID_URL` (#8368)
Authored by: peci1
6 months ago
Mozi 9b5bedf13a
[ie/brilliantpala] Fix cookies support (#8352)
Authored by: pzhlkj6612
6 months ago
bashonly cb480e390d
[ie/thisav] Remove (#8346)
Authored by: bashonly
6 months ago
sepro 25a4bd345a
[ie/sbs.co.kr] Add extractors (#8326)
Authored by: seproDev
6 months ago
Tom 3906de0755
[ie/zoom] Extract combined view formats (#7847)
Authored by: Mipsters
6 months ago
HitomaruKonpaku 7d337ca977
[ie/twitter:broadcast] Improve metadata extraction (#8383)
Authored by: HitomaruKonpaku
6 months ago
bashonly 10025b715e
[core] Add `--compat-option manifest-filesize-approx` (#8356)
Closes #7623
Authored by: bashonly
6 months ago
bashonly 595ea4a99b
[core] Fix format sorting with `--load-info-json` (#8521)
Closes #7971
Authored by: bashonly
6 months ago
bashonly 2622c804d1
[fd/dash] Force native downloader for `--live-from-start` (#8339)
Closes #8212
Authored by: bashonly
6 months ago
bashonly fd8fcf8f4f
Revert 39abae2354
The iOS client is not subject to integrity checks and is likely to be a more stable choice going forward

Authored by: bashonly
6 months ago
CrendKing 21b25281c5
[fd/aria2c] Remove duplicate `--file-allocation=none` (#8332)
Authored by: CrendKing
6 months ago
sepro 4a601c9eff
[ie/weverse] Fix login error handling (#8458)
Authored by: seproDev
7 months ago
Shubham 464327acdb
[ie/polskieradio:audition] Fix playlist extraction (#8459)
Closes #8419
Authored by: shubhexists
7 months ago
bashonly ef79d20dc9
[ie/youtube] Check newly uploaded iOS HLS formats (#8336)
Closes #7747
Authored by: bashonly
7 months ago
bashonly 39abae2354
[ie/youtube] Deprioritize iOS client formats (#8337)
Authored by: bashonly
7 months ago
bashonly 4ce2f29a50
[ie/generic] Improve direct video link ext detection (#8340)
Closes #8265
Authored by: bashonly
7 months ago
bashonly 177f0d963e
[ie/QDance] Update `_VALID_URL` (#8426)
Authored by: bashonly
7 months ago
Bart Broere 8e02a4dcc8
[ie/npo] Send `POST` request to streams API endpoint (#8413)
Closes #6398
Authored by: bartbroere
7 months ago
saintliao 7b8b1cf5eb
[ie/twitcasting] Fix livestream extraction (#8427)
Closes #8431
Authored by: JC-Chung, saintliao

Co-authored-by: JC-Chung <52159296+JC-Chung@users.noreply.github.com>
7 months ago
bashonly a40e0b37df
[core] Only ensure playlist thumbnail dir if writing thumbs (#8373)
Bugfix for 2acd1d555e

Closes #8372
Authored by: bashonly
7 months ago
Simon Sawicki 4e38e2ae9d
[rh:requests] Handle both `bytes` and `int` for `IncompleteRead.partial` (Fix 8a8b54523a) (#8348)
Authored by: bashonly, coletdjnz, Grub4K
7 months ago
coletdjnz 8a8b54523a
[rh:requests] Add handler for `requests` HTTP library (#3668)
Adds support for HTTPS proxies and persistent connections (keep-alive)

Closes https://github.com/yt-dlp/yt-dlp/issues/1890
Resolves https://github.com/yt-dlp/yt-dlp/issues/4070
Resolves https://github.com/ytdl-org/youtube-dl/issues/32549
Resolves https://github.com/ytdl-org/youtube-dl/issues/14523
Resolves https://github.com/ytdl-org/youtube-dl/issues/13734

Authored by: coletdjnz, Grub4K, bashonly
7 months ago
bashonly 700444c23d
[ci] Run core tests with dependencies
Authored by: bashonly, coletdjnz
7 months ago
github-actions b73c409318 Release 2023.10.13
Created by: bashonly

:ci skip all :ci run dl
7 months ago
bashonly b634ba742d
[cleanup] Misc (#8338)
Authored by: bashonly, gamer191
7 months ago
Riteo 2acd1d555e
[core] Ensure thumbnail output directory exists (#7985)
Closes #8203
Authored by: Riteo
7 months ago
sepro b286ec68f1
[ie/jtbc] Add extractors (#8314)
Authored by: seproDev
7 months ago
sepro e030b6b6fb
[ie/mbn] Add extractor (#8312)
Authored by: seproDev
7 months ago
bashonly b931664231
[ie/radiko] Fix bug with `downloader_options`
Closes #8333
Authored by: bashonly
7 months ago
Simon Sawicki feebf6d02f
[ie/youtube] Fix bug with `--extractor-retries inf` (#8328)
Authored by: Grub4K
7 months ago
bashonly 84e26038d4
[utils] `write_xattr`: Use `os.setxattr` if available (#8205)
Closes #8193
Authored by: bashonly, Grub4K

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
7 months ago
garret 4de94b9e16
[ie/nhk] Fix Japanese-language VOD extraction (#8309)
Closes #8303
Authored by: garret1317
7 months ago
Midnight Veil 88a99c87b6
[ie/tenplay] Add support for seasons (#7939)
Closes #7744
Authored by: midnightveil
7 months ago
Stefan Lobbenmeier 09f815ad52
[ie/ArteTV] Support age-restricted content (#8301)
Closes #7782
Authored by: StefanLobbenmeier
7 months ago
naginatana b7098d46b5
[ie/youku] Improve tudou.com support (#8160)
Authored by: naginatana
7 months ago
Simon Sawicki 1c51c520f7
[fd/fragment] Improve progress calculation (#8241)
This uses the download speed from all threads and also adds smoothing to speed and eta

Authored by: Grub4K
7 months ago
Awal Garg 9d7ded6419
[utils] `js_to_json`: Fix `Date` constructor parsing (#8295)
Authored by: awalgarg, Grub4K
7 months ago
github-actions 4392c4680c Release 2023.10.07
Created by: Grub4K

:ci skip all :ci run dl
7 months ago
Simon Sawicki 377e85a179
[cleanup] Misc (#8300)
* Simplify nuxt regex
* Fix tmz quotes and tests
* Update test python versions

Authored by: dirkf, gamer191, Grub4K
7 months ago
bashonly 03e85ea99d
[ie/youtube] Fix `heatmap` extraction (#8299)
Closes #8189
Authored by: bashonly
7 months ago
Aleri Kaisattera 792f1e64f6
[ie/theta] Remove extractors (#8251)
Authored by: alerikaisattera
7 months ago
trainman261 19c90e405b
[cleanup] Update extractor tests (#7718)
Authored by: trainman261
7 months ago
garret e831c80e8b
[ie/nhk] Fix VOD extraction (#8249)
Closes #8242
Authored by: garret1317
7 months ago
Raphaël Droz 0e722f2f3c
[ie/lbry] Extract `uploader_id` (#8244)
Closes #123
Authored by: drzraf
7 months ago
Esme 47c598783c
[ie/erocast] Add extractor (#8264)
Closes #4001
Authored by: madewokherd
7 months ago
AS6939 35d9cbaf96
[ie/iq.com] Fix extraction and subtitles (#8260)
Closes #7734, Closes #8123
Authored by: AS6939
7 months ago
garret 2ad3873f0d
[ie/radiko] Improve extraction (#8221)
Authored by: garret1317
7 months ago
Umar Getagazov 2f2dda3a7e
[ie/substack] Fix download cookies bug (#8219)
Authored by: handlerug
7 months ago
Umar Getagazov fbcc299bd8
[ie/substack] Fix embed extraction (#8218)
Authored by: handlerug
7 months ago
Raphaël Droz 48cceec1dd
[ie/lbry] Add playlist support (#8213)
Closes #5982, Closes #8204
Authored by: drzraf, bashonly, Grub4K
7 months ago
xofe a9efb4b8d7
[ie/abc.net.au:iview] Improve `episode` extraction (#8201)
Authored by: xofe
7 months ago
c-basalt f980df734c
[ie/neteasemusic] Fix extractors (#8181)
Closes #4388
Authored by: c-basalt
7 months ago
gillux 91a670a4f7
[ie/LiTV] Fix extractor (#7785)
Closes #5456
Authored by: jiru
7 months ago
bashonly b095fd3fa9
[ie/WrestleUniverseVOD] Call API with device ID (#8272)
Closes #8271
Authored by: bashonly
7 months ago
bashonly 0730d5a966
[ie/gofile] Fix token cookie bug
Authored by: bashonly
7 months ago
Simon Sawicki cc8d844152
[ie/xhamster:user] Support creator urls (#8232)
Authored by: Grub4K
8 months ago
coletdjnz eb5bdbfa70
[ie/youtube] Raise a warning for `Incomplete Data` instead of an error (#8238)
Closes https://github.com/yt-dlp/yt-dlp/issues/8206

Adds `raise_incomplete_data` extractor arg to revert this behaviour and raise an error.

Authored by: coletdjnz
Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
8 months ago
github-actions c54ddfba0f Release 2023.09.24
Created by: Grub4K

:ci skip all :ci run dl
8 months ago
Simon Sawicki 088add9567
[cleanup] Misc
Authored by: Grub4K
8 months ago
Simon Sawicki de015e9307
[core] Prevent RCE when using `--exec` with `%q` (CVE-2023-40581)
The shell escape function is now using `""` instead of `\"`. `utils.Popen` has been patched to properly quote commands.

Prior to this fix using `--exec` together with `%q` when on Windows could cause remote code to execute. See https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-42h4-v29r-42qg for reference.

Authored by: Grub4K
8 months ago
Simon Sawicki 61bdf15fc7
[core] Raise minimum recommended Python version to 3.8 (#8183)
Authored by: Grub4K
8 months ago
bashonly 1eaca74bc2
[ie/nfl.com:plus:replay] Fix extractor (#7838)
Closes #7836
Authored by: bashonly
8 months ago
Mozi 92feb5654c
[ie/brilliantpala] Add extractors (#6680)
Authored by: pzhlkj6612
8 months ago
Mozi 698beb9a49
[ie/niconicochannelplus] Add extractors (#5686)
Closes #2537
Authored by: pzhlkj6612
8 months ago
garret 15591940ff
[ie/cineverse] Add extractors (#8146)
Also removes AsianCrushIE and AsianCrushPlaylistIE (URLs do not work anymore & old IDs are unavailable).

Closes #8109
Authored by: garret1317
8 months ago
Mozi 6636021206
[ie/PIAULIZAPortal] Add extractor (#7903)
Authored by: pzhlkj6612
8 months ago
garret eaee21bf71
[ie/Monstercat] Add extractor (#8133)
Closes #8067
Authored by: garret1317
8 months ago
bashonly 5ca095cbcd
[cleanup] Misc (#8182)
Closes #7796, Closes #8028
Authored by: barsnick, sqrtNOT, gamer191, coletdjnz, Grub4K, bashonly
8 months ago
bashonly c2da0b5ea2
[ie/ArteTV] Fix HLS formats extraction
Closes #8156
Authored by: bashonly
8 months ago
Atsushi Watanabe c1d71d0d9f
[ie/twitcasting] Support `--wait-for-video` (#7975)
Authored by: at-wat
8 months ago
bashonly 661c9a1d02
[test:download] Test for `expected_exception`
Authored by: at-wat

Co-authored-by: Atsushi Watanabe <atsushi.w@ieee.org>
8 months ago
std-move 568f080518
[ie/iprima] Fix extractor (#7216)
Closes #7229
Authored by: std-move
8 months ago
bashonly 904a19ee93
[ie] Make `_search_nuxt_data` more lenient
Authored by: std-move

Co-authored-by: std-move <26625259+std-move@users.noreply.github.com>
8 months ago
bashonly 52414d64ca
[utils] `js_to_json`: Handle `Array` objects
Authored by: Grub4K, std-move

Co-authored-by: std-move <26625259+std-move@users.noreply.github.com>
Co-authored-by: Simon Sawicki <accounts@grub4k.xyz>
8 months ago
std-move 2269065ad6
[ie/NovaEmbed] Fix extractor (#7910)
Closes #8025
Authored by: std-move
8 months ago
kylegustavo a5e264d74b
[ie/Expressen] Improve `_VALID_URL` (#8153)
Closes #8141
Authored by: kylegustavo
8 months ago
ClosedPort22 b84fda7388
[ie/bilibili] Extract Dolby audio formats (#8142)
Closes #4050
Authored by: ClosedPort22
8 months ago
Simon 5fccabac27
[ie/rbgtum] Fix extraction and support new URL format (#7690)
Authored by: simon300000
8 months ago
c-basalt 21f40e75df
[ie/douyutv] Fix extractors (#7652)
Closes #2494, Closes #7295
Authored by: c-basalt
8 months ago
Elyse b3febedbeb
[ie/Canal1,CaracolTvPlay] Add extractors (#7151)
Closes #5826
Authored by: elyse0
8 months ago
Mozi 295fbb3ae3
[ie/eplus:inbound] Add extractor (#5782)
Authored by: pzhlkj6612
8 months ago
bashonly 35f9a306e6
[dependencies] Handle deprecation of `sqlite3.version` (#8167)
Closes #8152
Authored by: bashonly
8 months ago
coletdjnz 9d6254069c
Update to ytdl-commit-66ab08 (#8128)
[utils] Revert bbd3e7e, updating docstring, test instead
 66ab0814c4

Authored by: coletdjnz
8 months ago
Simon Sawicki b532556d0a
[ie/pr0gramm] Rewrite extractor (#8151)
Authored by: Grub4K
8 months ago
Rohan Dey cf11b40ac4
[ie/media.ccc.de:lists] Fix extraction (#8144)
Closes #8138
Authored by: Rohxn16
8 months ago
niemands 40999467f7
[ie/pornbox] Add extractor (#7386)
Authored by: niemands
8 months ago
u-spec-png 8ac5b6d96a
[ie/N1Info:article] Fix extractor (#7373)
Authored by: u-spec-png
8 months ago
c-basalt 69b03f84f8
[ie/weibo] Fix extractor and support user extraction (#7657)
Closes #3964, Closes #4673, Closes #6979
Authored by: c-basalt
8 months ago
c-basalt 9e68747f96
[ie/bilibili] Add support for series, favorites and watch later (#7518)
Closes #6719
Authored by: c-basalt
8 months ago
Elyse ba8e9eb2c8
[ie/radiofrance] Add support for livestreams, podcasts, playlists (#7006)
Closes #4282
Authored by: elyse0
8 months ago
coletdjnz 20fbbd9249
[networking] Fix various socks proxy bugs (#8065)
- Fixed support for IPv6 socks proxies
- Fixed support for IPv6 over socks5
- Fixed --source-address not being obeyed for socks4 and socks5
- Fixed socks4a when the destination address is an IPv4 address

Closes https://github.com/yt-dlp/yt-dlp/issues/7959
Fixes https://github.com/ytdl-org/youtube-dl/issues/15368

Authored by: coletdjnz
Co-authored-by: Simon Sawicki <accounts@grub4k.xyz>
Co-authored-by: bashonly <bashonly@bashonly.com>
8 months ago
Sebastian Koch 81f46ac573
[ie/massengeschmack.tv] Fix title extraction (#7813)
Authored by: sb0stn
8 months ago
aky-01 63e0c5748c
[ie/IndavideoEmbed] Fix extraction (#8129)
Closes #7190
Authored by: aky-01
8 months ago
Simon efa2339502
[ie/lecturio] Improve `_VALID_URL` (#7649)
Authored by: simon300000
8 months ago
soundchaser128 58493923e9
[ie/rule34video] Extract tags (#7117)
Authored by: soundchaser128
8 months ago
Simon Sawicki 30ba233d4c
[devscripts] `make_changelog`: Fix changelog grouping and add networking group (#8124)
Authored by: Grub4K
8 months ago
Simon Sawicki 836e06d246
[core] Fix support for upcoming Python 3.12 (#8130)
This also adds the following test runners:
- `3.12-dev` on `ubuntu-latest`
- `3.12-dev` on `windows-latest`
- `pypy-3.10` on `ubuntu-latest`

Authored by: Grub4K
8 months ago
bashonly 94389b225d
[ie/RTVSLO] Fix format extraction (#8131)
Closes #8020
Authored by: bashonly
8 months ago
bashonly 9652bca1bd
[ie/web.archive:vlive] Remove extractor (#8132)
Closes #8122
Authored by: bashonly
8 months ago
bashonly 538d37671a
[ie/AmazonMiniTV] Fix extractors
Closes #7817
Authored by: GautamMKGarg, bashonly

Co-authored by: GautamMKGarg <GautamMKgarg@gmail.com>
8 months ago
bashonly 2da7bcca16
Revert 9d376c4dae
Authored by: bashonly
8 months ago
garret eda0e415d2
[ie/bbc] Extract tracklist as chapters (#7788)
Authored by: garret1317
8 months ago
bashonly 20c3c9b433
[ie/reddit] Extract subtitles
Closes #7814
Authored by: bashonly
8 months ago
bashonly 635ae31f68
[ie/mediastream] Make embed extraction non-fatal
Authored by: bashonly
8 months ago
bashonly 5367585219
[ie/generic] Fix KVS thumbnail extraction
Closes #8045
Authored by: bashonly
8 months ago
fireattack 308936619c
[ie/facebook] Improve format sorting (#8074)
Authored by: fireattack
8 months ago
c-basalt 5be7e97886
[ie/sohu] Fix extractor (#7628)
Closes #1667, Closes #7463
Authored by: c-basalt, bashonly
8 months ago
barsnick b4c1c408c6
[ie/Bild.de] Extract HLS formats (#8032)
Closes #7951
Authored by: barsnick
8 months ago
Tristan Lee 23d829a342
[ie/Rumble] Fix embed extraction (#8035)
Authored by: trislee
8 months ago
04-pasha-04 0ce1f48bf1
[ie/funker530] Fix extraction (#8040)
Authored by: 04-pasha-04
8 months ago
Mozi ecef42c3ad
[ie/zaiko] Improve thumbnail extraction (#8054)
Authored by: pzhlkj6612
8 months ago
ApoorvShah111 a83da3717d
[ie/nitter] Fix title extraction fallback (#8102)
Closes #7575
Authored by: ApoorvShah111
8 months ago
Aniruddh Joshi 9d376c4dae
[ie/AmazonMiniTV] Fix extractor (#8103)
Closes #7817
Authored by: Aniruddh-J
8 months ago
c-basalt 5336bf57a7
[ie/bilibili] Extract `format_id` (#7555)
Authored by: c-basalt
8 months ago
makeworld 9bf14be775
[ie/cbc] Ignore any 426 from API (#7689)
Closes #7477
Authored by: makew0rld
8 months ago
c-basalt cebbd33b1c
[ie/twitcasting] Improve `_VALID_URL` (#8120)
Closes #7597
Authored by: c-basalt
8 months ago
bashonly 069cbece9d
[ie/tiktok] Fix webpage extraction
Closes #8089
Authored by: bashonly
8 months ago
Simon Sawicki f659e64394
[ie/bpb] Overhaul extractor (#8119)
Authored by: Grub4K
8 months ago
Jérôme Duval 7d3d658f4c
[ie/TV5MondePlus] Fix extractor (#7952)
Closes #4978
Authored by: korli, dirkf
8 months ago
hatsomatt 98eac0e6ba
[ie/videa] Fix extraction (#8003)
Closes #7427
Authored by: hatsomatt, aky-01

Co-authored-by: aky-01 <65510015+aky-01@users.noreply.github.com>
8 months ago
zhallgato 6e07e4bc7e
[ie/mediaklikk] Fix extractor (#8086)
Fixes https://github.com/yt-dlp/yt-dlp/issues/8053

Authored by: bashonly, zhallgato
8 months ago
barsnick aee6b9b88c
[ie/Axs] Add extractor (#8094)
Authored by: barsnick
8 months ago
Kshitiz Gupta 578a82e497
[ie/banbye] Support video ids containing a hyphen (#8059)
Fixes https://github.com/yt-dlp/yt-dlp/issues/7895

Authored by: kshitiz305
8 months ago
SevenLives 497bbbbd73
[ie/abematv] Fix proxy handling (#8046)
Fixes https://github.com/yt-dlp/yt-dlp/issues/8036

Authored by: SevenLives
8 months ago
garret 7b71643cc9
[ie/mixcloud] Update API URL (#8114)
Closes #8104
Authored by: garret1317
8 months ago
bashonly 66cc64ff66
[ie/zoom] Extract duration
Closes #8080
Authored by: bashonly
8 months ago
bashonly a006ce2b27
[ie/twitter] Fix retweet extraction and syndication API (#8016)
Authored by: bashonly
8 months ago
Szaby Grünwald 5d0395498d
[ie/wdr] Fix extraction (#7979)
Closes #7461
Authored by: szabyg
8 months ago
ifan-t fe371dcf0b
[ie/S4C] Add series support and extract subs/thumbs (#7776)
Authored by: ifan-t
8 months ago
ringus1 d3d81cc98f
[ie/facebook] Fix webpage extraction (#7890)
Closes #7901
Authored by: ringus1
8 months ago
bashonly 99c99c7185
[ie/gofile] Update token
Closes #7235
Authored by: bashonly
8 months ago
bashonly c6ef553792
[ie/twitter:spaces] Pass referer header to downloader
Closes #8029
Authored by: bashonly
8 months ago
bashonly 69dbfe01c4
Bugfix for bae4834245
Authored by: bashonly
8 months ago
Mattias Wadman 2301b5c1b7
[ie/SVTPlay] Fix extraction (#7789)
Closes #5595
Authored by: wader, dirkf
9 months ago
Simon Sawicki 77bff23ee9
Bugfix for 59e92b1f18
Closes #8012

Authored by: Grub4K
9 months ago
Rajeshwaran 7237c8dca0
[ie/hotstar] Extract `release_year` (#7869)
Authored by: Rajeshwaran2001
9 months ago
bashonly 30ea88591b
[ie/hotstar] Make metadata extraction non-fatal
Authored by: bashonly
9 months ago
Grabien 630a55df8d
[ie/Mediaite] Fix extraction (#7923)
Authored by: Grabien
9 months ago
RedDeffender bae4834245
[ie/NoodleMagazine] Fix extraction (#7830)
Closes #7917
Authored by: RedDeffender
9 months ago
bashonly 099fb1b35c
Bugfix for b9f2bc2dbe
Authored by: bashonly
9 months ago
Omar Atef 4b3a6ef1b3
[ie/hungama] Overhaul extractors (#7757)
Closes #7754
Authored by: Yalab7, bashonly
9 months ago
Stavros Ntentos 665876034c
[ie/antenna] Support antenna.gr (#7584)
Authored by: stdedos
9 months ago
Nathan Touzé b9f2bc2dbe
[ie/Dropbox] Fix extractor (#7926)
Closes #7005, Closes #7696
Authored by: nathantouze, bashonly, denhotte
9 months ago
sepro c2d8ee0000
[ie/weverse] Support extraction without auth (#7924)
Authored by: seproDev
9 months ago
bashonly 56b3dc0335
[ie/StagePlus] Fix m3u8 extraction (#7929)
Closes #7928
Authored by: bashonly
9 months ago
bashonly d7aee8e310
[ie/Mzaalo] Improve `_VALID_URL`
Authored by: bashonly
9 months ago
Simon Sawicki 59e92b1f18
[rh/urllib] Simplify gzip decoding (#7611)
Authored by: Grub4K
9 months ago
Simon Sawicki 1be0a96a4d
[docs] Update collaborators
Authored by: Grub4K
9 months ago
coletdjnz fcd6a76adc
[tests] Add tests for socks proxies (#7908)
Authored by: coletdjnz
9 months ago
Davin Kevin 7cccab79e7
[ie/wat.tv] Fix extraction (#7898)
Closes #7303
Authored by: davinkevin
9 months ago
trainman261 ed71189781
[ie/CBCPlayerPlaylist] Add extractor (#7870)
Authored by: trainman261
9 months ago
bashonly a0de8bb860
[ie/zee5] Update access token endpoint (#7914)
Closes #7911
Authored by: bashonly
9 months ago
garret 876b70c8ed
[ie/tbsjp] Add episode, program, playlist extractors (#7765)
Authored by: garret1317
9 months ago
trainman261 339c339fec
[ie/CBCPlayer] Extract HLS formats and subtitles (#7484)
Authored by: trainman261
9 months ago
bashonly dab87ca236
[cookies] Containers JSON should be opened as utf-8 (#7800)
Closes #7797
Authored by: bashonly
9 months ago
coletdjnz 378ae9f9fb
[ie/youtube] Fix consent cookie (#7774)
Fixes #7594

Authored by: coletdjnz
9 months ago
coletdjnz db7b054a61
[networking] Add request handler preference framework (#7603)
Preference functions that take a request and a request handler instance can be registered to prioritize different request handlers per request.

Authored by: coletdjnz
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
9 months ago
Franklin Lee db97438940
[ie/PicartoVod] Fix extractor (#7727)
Closes #2926
Authored by: Frankgoji
10 months ago
ifan-t b9de629d78
[ie/S4C] Add extractor (#7730)
Authored by: ifan-t
10 months ago
ringus1 a854fbec56
[ie/facebook] Add dash manifest URL (#7743)
Fixes #7742
Authored by: ringus1
10 months ago
ischmidt20 30b29f3715
[ie/fox] Support foxsports.com (#7724)
Authored by: ischmidt20
10 months ago
Steve 6d6081dda1
[extractor/pbs] Add extractor `PBSKidsIE` (#7602)
Authored by: snixon
Fixes #2440
10 months ago
bashonly 6014355c61
[ie/twitter] Add fallback, improve error handling (#7621)
Closes #7579, Closes #7625
Authored by: bashonly
10 months ago
pukkandan f73c118035
`FFmpegFixupM3u8PP` may need to run with ffmpeg
Bug in 62b5c94cad
Closes #7725
10 months ago
coletdjnz 546b2c28a1
[ie/youtube] Fix `player_params` arg being converted to lowercase
Fix bug in ba06d77a31

Authored by: coletdjnz
10 months ago
pukkandan 6148833f5c
[cleanup] Misc 10 months ago
pukkandan 8cb7fc44db
Fix `--check-formats`
Bug in bc344cd456
10 months ago
pukkandan 3f7965105d
[utils] HTTPHeaderDict: Handle byte values 10 months ago
pukkandan de20687ee6
[test] Fix `test_load_certifi`
Closes #7688, #7675
10 months ago
bashonly b09bd0c196
[ie/tiktok] Fix audio-only format extraction (#7712)
Closes #6608
Authored by: bashonly
10 months ago
bashonly 127a224606
[ie/LBRY] Fix original format extraction (#7711)
Authored by: bashonly
10 months ago
bashonly 86eeb044c2
[ie/hotstar] Support `/clips/` URLs (#7710)
Closes #7699
Authored by: bashonly
10 months ago
bashonly 9a04113dfb
[ie/Reddit] Fix thumbnail extraction
Authored by: bashonly
10 months ago
coletdjnz ba06d77a31
[ie/youtube] Add `player_params` extractor arg (#7719)
Authored by: coletdjnz
10 months ago
coletdjnz 4bf912282a
[networking] Remove dot segments during URL normalization (#7662)
This implements RFC3986 5.2.4 remove_dot_segments during the URL normalization process.

Closes #3355, #6526

Authored by: coletdjnz
10 months ago
nnoboa a15fcd299e
[ie/Wimbledon] Add extractor (#7551)
Closes #7462
Authored by: nnoboa
10 months ago
Amirreza Aflakparast c03a58ec99
[ie/MotorTrendOnDemand] Update `_VALID_URL` (#7683)
Closes #7680
Authored by: AmirAflak
10 months ago
coletdjnz bbeacff7fc
[networking] Ignore invalid proxies in env (#7704)
Authored by: coletdjnz
10 months ago
bashonly dae349da97
[ie/WrestleUniversePPV] Fix HLS AES key extraction
Fix bug in ef8fb7f029

Closes #7708
Authored by: bashonly
10 months ago
coletdjnz 95abea9a03
[test] Fix `httplib_validation_errors` test for old Python versions (#7677)
Fixes https://github.com/yt-dlp/yt-dlp/issues/7674

Authored by: coletdjnz
10 months ago
bashonly 550e65410a
[ie] Extract subtitles from SMIL manifests (#7667)
Authored by: bashonly, pukkandan
10 months ago
bashonly 39837ae319
[ie/triller] Fix unlisted video extraction (#7670)
Authored by: bashonly
10 months ago
coletdjnz 86aea0d3a2
[networking] Add strict Request extension checking (#7604)
Authored by: coletdjnz
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
10 months ago
bashonly 11de6fec9c
[ie/PatreonCampaign] Fix extraction (#7664)
Authored by: bashonly
10 months ago
pukkandan a250b24733
[compat] Ensure submodules are imported correctly
Closes #7663
10 months ago
pukkandan 25b6e8f946
Fix e0c4db04dc for pypy 10 months ago
pukkandan e705738338
[ie/unsupported] List more sites with DRM
Closes #7323, #3072, #5740, #5767, #6125
10 months ago
pukkandan 62b5c94cad
[cleanup] Misc fixes
Closes #7528
10 months ago
pukkandan e0c4db04dc
[compat] Add `types.NoneType` 10 months ago
pukkandan 81b4712bca
[extractor] Fix `--load-pages` 10 months ago
pukkandan 994f7ef8e6
[ie/generic] Fix generic title for embeds
Closes #7067
10 months ago
pukkandan a264433c9f
[outtmpl] Fix replacement for `playlist_index` 10 months ago
pukkandan 9f66247289
[ie/abematv] Temporary fix for protocol handler
Closes #7622
10 months ago
bashonly e57eb98222
[fd/external] Fix ffmpeg input from stdin (#7655)
Bugfix for 1ceb657bdd

Authored by: bashonly
10 months ago
Simon Sawicki 9b16762f48
[ie/crunchyroll] Remove initial state extraction (#7632)
Authored by: Grub4K
10 months ago
bashonly 65cfa2b057
[ie/MuseAI] Add extractor (#7614)
Closes #7543
Authored by: bashonly
10 months ago
bashonly f4ea501551
[ie/MagellanTV] Add extractor (#7616)
Closes #7529
Authored by: bashonly
10 months ago
bashonly af86873218
[utils] Improve `parse_duration`
Authored by: bashonly
10 months ago
bashonly 75dc8e673b
[networking] Fix `--legacy-server-connect` (#7645)
Bugfix for 227bf1a33b

Authored by: bashonly
10 months ago
bashonly 71baa490eb
[networking] Fix POST requests with zero-length payloads (#7648)
Bugfix for 227bf1a33b

Authored by: bashonly
10 months ago
bashonly 613dbce177
[ie/twitter:spaces] Fix format protocol (#7550)
Closes #7536
Authored by: bashonly
10 months ago
Văn Anh bb5d84c9d2
[ie/facebook:reel] Fix extraction (#7564)
Closes #7469
Authored by: demon071, bashonly
10 months ago
zhong-yiyu 1d3d579c21
[ie/pornhub] Update access cookies for UK (#7591)
Closes #7590
Authored by: zhong-yiyu
10 months ago
bashonly 42ded0a429
[fd/external] Fixes to cookie handling
- Fix bug in `axel` Cookie header arg
- Pass cookies to `curl` as strings
- Write session cookies for `aria2c` and `wget`

Closes #7539
Authored by: bashonly
10 months ago
bashonly 6c5211cebe
[core] Fix HTTP headers and cookie handling
- Remove `Cookie` header from `http_headers` immediately after loading into cookiejar
- Restore compat for `--load-info-json` cookies
- Add more tests
- Fix improper passing of Cookie header by `MailRu` extractor

Closes #7558
Authored by: bashonly, pukkandan
10 months ago
Aaruni Kaushik 2b029ca0a9
[cleanup] Add color to `download-archive` message (#5138)
Authored by: aaruni96, Grub4K, pukkandan
Closes #4913
10 months ago
pukkandan 131d132da5
[build] Make sure deprecated modules are added 10 months ago
coletdjnz 3d2623a898
[compat, networking] Deprecate old functions (#2861)
Authored by: coletdjnz, pukkandan
10 months ago
coletdjnz 227bf1a33b
[networking] Rewrite architecture (#2861)
New networking interface consists of a `RequestDirector` that directs
each `Request` to appropriate `RequestHandler` and returns the
`Response` or raises `RequestError`. The handlers define adapters to
transform its internal Request/Response/Errors to our interfaces.

User-facing changes:
- Fix issues with per request proxies on redirects for urllib
- Support for `ALL_PROXY` environment variable for proxy setting
- Support for `socks5h` proxy
   - Closes https://github.com/yt-dlp/yt-dlp/issues/6325, https://github.com/ytdl-org/youtube-dl/issues/22618, https://github.com/ytdl-org/youtube-dl/pull/28093
- Raise error when using `https` proxy instead of silently converting it to `http`

Authored by: coletdjnz
10 months ago
pukkandan c365dba843
[networking] Add module (#2861)
No actual changes - code is only moved around
10 months ago
pukkandan 1b392f905d
[utils] Add temporary shim for logging
Related: #5680, #7517
10 months ago
coletdjnz 1ba6fe9db5
[ie/youtube:tab] Detect looping feeds (#6621)
Closes https://github.com/yt-dlp/yt-dlp/issues/5555

Note: the first page may still be repeated, however this is better than nothing.

Authored by: coletdjnz
10 months ago
Finn R. Gärtner 1bcb9fe871
[ie/piapro] Support `/content` URL (#7592)
Authored by: FinnRG
10 months ago
Neurognostic 8a4cd12c8f
[pp/EmbedThumbnail] Support `m4v` (#7583)
Authored by: Neurognostic
10 months ago
Aleri Kaisattera 2cfe221fbb
[ie/streamanity] Remove (#7571)
Service is dead
Authored by: alerikaisattera
10 months ago
Mahmoud Abdel-Fattah 2af4eeb772
[utils] `clean_podcast_url`: Handle more trackers (#7556)
Authored by: mabdelfattah, bashonly
Closes #7544
10 months ago
Zprokkel 325191d0c9
[ie/vrt] Update token signing key (#7519)
Authored by: Zprokkel
10 months ago
GD-Slime bdd0b75e3f
[ie/BiliBiliBangumi] Fix extractors (#7337)
- Overhaul BiliBiliBangumi extractor for the site's new API
- Add BiliBiliBangumiSeason extractor
- Refactor BiliBiliBangumiMedia extractor

Closes #6701, Closes #7400
Authored by: GD-Slime
10 months ago
bashonly 92315c0377
[extractor/twitter] Fix GraphQL and legacy API (#7516)
Authored by: bashonly
10 months ago
pukkandan b03fa78345
Revert 49296437a8 10 months ago
github-actions cc0619f62d Release 2023.07.06
Created by: pukkandan

:ci skip all :ci run dl
10 months ago
pukkandan b532a34810
[docs] Minor fixes
Closes #7515
10 months ago
Simon Sawicki 3121512228
[core] Change how `Cookie` headers are handled
Cookies are now saved and loaded under `cookies` key in the info dict
instead of `http_headers.Cookie`. Cookies passed in headers are
auto-scoped to the input URLs with a warning.

Ref: https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-v8mc-9377-rwjj

Authored by: Grub4K
10 months ago
coletdjnz f8b4bcc0a7
[core] Prevent `Cookie` leaks on HTTP redirect
Ref: https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-v8mc-9377-rwjj

Authored by: coletdjnz
10 months ago
bashonly 1ceb657bdd
[fd/external] Scope cookies
- ffmpeg: Calculate cookies from cookiejar and pass with `-cookies` arg instead of `-headers`
- aria2c, curl, wget: Write cookiejar to file and use external FD built-in cookiejar support
- httpie: Calculate cookies from cookiejar instead of `http_headers`
- axel: Calculate cookies from cookiejar and disable http redirection if cookies are passed
    - May break redirects, but axel simply don't have proper cookie support

Ref: https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-v8mc-9377-rwjj

Authored by: bashonly, coletdjnz
10 months ago
pukkandan ad8902f616
[ie/vidlii] Handle relative URLs
Closes #7480
10 months ago
pukkandan 94ed638a43
[ie/youtube] Avoid false DRM detection (#7396)
Some master manifests contain a mix of DRM and non-DRM formats
10 months ago
pukkandan bc344cd456
[core] Allow extractors to mark formats as potentially DRM (#7396)
This is useful for HLS where detecting whether the format is
actually DRM requires the child manifest to be downloaded.

Makes the error message when using `--test` inconsistent,
but doesn't really matter.
10 months ago
pukkandan 906c0bdcd8
[formats] Fix best fallback for storyboards
Partial fix for #7478
10 months ago
pukkandan 337734d4a8
[cleanup] Misc 10 months ago
pukkandan fa44802809
[devscripts/make_changelog] Skip reverted commits 10 months ago
pukkandan 47bcd43724
[outtmpl] Pad `playlist_index` etc even when with internal formatting
Closes #7501
10 months ago
pukkandan 662ef1e910
[downloader/http] Avoid infinite loop when no data is received
Closes #7504
10 months ago
Jorge 6355b5f1e1
[misc] Add CodeQL workflow (#7497) 10 months ago
coletdjnz 90db9a3c00
[extractor/youtube:stories] Remove (#7459)
YouTube killed them

https://web.archive.org/web/20230630153050/https://support.google.com/youtube/thread/217640760
10 months ago
bashonly 49296437a8
[extractor/twitter] Fix unauthenticated extraction (#7476)
Closes #7473
Authored by: bashonly
11 months ago
bashonly 1cffd621cb
[extractor/twitter:spaces] Fix extraction (#7512)
Closes #7455
Authored by: bashonly
11 months ago
RfadnjdExt 3b7f5300c5
[extractor/googledrive] Fix source format extraction (#7395)
Closes #7344
Authored by: RfadnjdExt
11 months ago
coletdjnz 4dc4d8473c
[extractor/youtube] Ignore incomplete data for comment threads by default (#7475)
For both `--ignore-errors` and `--ignore-errors only_download`. Pass `--no-ignore-errors` to not ignore.

Closes https://github.com/yt-dlp/yt-dlp/issues/7474

Authored by: coletdjnz
11 months ago
c-basalt 8776349ef6
[extractor/vk] VKPlay, VKPlayLive: Add extractors (#7358)
Closes #7107
Authored by: c-basalt
11 months ago
urectanc af1fd12f67
[extractor/stacommu] Add extractors (#7432)
Authored by: urectanc
11 months ago
coletdjnz fcbc9ed760
[extractor/youtube:tab] Support shorts-only playlists (#7425)
Fixes https://github.com/yt-dlp/yt-dlp/issues/7424

Authored by: coletdjnz
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
11 months ago
bashonly a2be9781fb
[extractor/Douyin] Fix extraction from webpage
Closes #7431
Authored by: bashonly
11 months ago
Xiao Han 8f05fbae2a
[extractor/abc] Fix extraction (#7434)
Closes #6433
Authored by: meliber
11 months ago
Aman Salwan 5b4b92769a
[extractor/crunchyroll:music] Fix `_VALID_URL` (#7439)
Closes #7419
Authored by: AmanSal1, rdamas

Co-authored-by: Robert Damas <robert.damas@byom.de>
11 months ago
pukkandan 91302ed349
[utils] clean_podcast_url: Handle protocol in redirect URL
Closes #7430
11 months ago
pukkandan f393bbe724
[extractor/sbs] Python 3.7 compat
Closes #7410
11 months ago
pukkandan 8a8af356e3
[downloader/aria2c] Add `--no-conf`
Closes #7404
11 months ago
pukkandan d949c10c45
[extractor/youtube] Process `post_live` over 2 hours 11 months ago
bashonly ef8509c300
[extractor/kick] Fix `_VALID_URL`
Closes #7384
Authored by: bashonly
11 months ago
nnoboa 5e16cf92eb
[extractor/AdultSwim] Extract subtitles from m3u8 (#7421)
Authored by: nnoboa
Closes #6191
11 months ago
bashonly f0a1ff1181
[extractor/qdance] Add extractor (#7420)
Closes #7385
Authored by: bashonly
11 months ago
pukkandan 58786a10f2
[extractor/youtube] Add extractor-arg `formats`
Closes #7417
11 months ago
pukkandan e59e20744e
Bugfix for b4e0d75848 11 months ago
Simon 89bed01374
[extractor/youtube] Fix comments' `is_favorited` (#7390)
Authored by: bbilly1
Closes #7389
11 months ago
github-actions de4cf77ec1 Release 2023.06.22
Created by: pukkandan

:ci skip all :ci run dl
11 months ago
pukkandan 812cdfa06c
[cleanup] Misc 11 months ago
pukkandan cd810afe2a
[extractor/youtube] Improve nsig function name extraction 11 months ago
pukkandan b4e0d75848
Improve `--download-sections`
* Support negative time-ranges
* Add `*from-url` to obey time-ranges in URL

Closes #7248
11 months ago
Berkan Teber 71dc18fa29
[extractor/youtube] Improve description parsing performance (#7315)
* The parsing is skipped when not needed
* The regex is improved by simulating atomic groups with lookaheads

Authored by: pukkandan, berkanteber
11 months ago
bashonly 98cb1eda7a
[extractor/rheinmaintv] Add extractor (#7311)
Authored by: barthelmannk

Co-authored-by: barthelmannk <81305638+barthelmannk@users.noreply.github.com>
11 months ago
bashonly 774aa09dd6
[extractor/dplay] GlobalCyclingNetworkPlus: Add extractor (#7360)
* Allows `country` API param to be configured with `--xff`/`geo_bypass_country`

Closes #7324
Authored by: bashonly
11 months ago
rexlambert22 f2ff0f6f19
[extractor/motherless] Add gallery support, fix groups (#7211)
Authored by: rexlambert22
11 months ago
pukkandan 5fd8367496
[extractor] Support multiple `_VALID_URL`s (#5812)
Authored by: nixxo
11 months ago
pukkandan 0dff8e4d1e
Indicate `filesize` approximated from `tbr` better 11 months ago
pukkandan 1e75d97db2
[extractor/youtube] Add `ios` to default clients used
* IOS is affected neither by 403 or by nsig so helps mitigate them preemptively
* IOS also has higher bit-rate "premium" formats though they are not labeled as such
11 months ago
pukkandan 81ca451480
[extractor/youtube] Workaround 403 for android formats
Ref: https://github.com/TeamNewPipe/NewPipe/issues/9038#issuecomment-1289756816
11 months ago
pukkandan a4486bfc1d
Revert "[misc] Add automatic duplicate issue detection"
This reverts commit 15b2d3db1d.
11 months ago
Roland Hieber 3f756c8c40
[extractor/nebula] Fix extractor (#7156)
Closes #7017
Authored by: Lamieur, rohieb

Co-authored-by: Lam <github@Lam.pl>
11 months ago
bashonly 7f9c6a63b1
[cleanup] Misc
Authored by: bashonly
11 months ago
OverlordQ db22142f6f
[extractor/dropout] Fix season extraction (#7304)
Authored by: OverlordQ
11 months ago
pukkandan d7cd97e8d8
Fix bug in db3ad8a676
Closes #7367
11 months ago
github-actions d1b2156149 Release 2023.06.21
Created by: pukkandan

:ci skip all :ci run dl
11 months ago
pukkandan 42f2d40b47
Update to ytdl-commit-07af47
[YouTube] Improve fix for ae8ba2c
07af47960f
11 months ago
pukkandan 1619ab3e67
Bugfix for ebe1b4e34f 11 months ago
pukkandan 84078a8b38
[core] Fix `filepath` being copied to underlying format dict
Closes #6536
11 months ago
pukkandan ad54c9130e
[cleanup] Misc
Closes #6288, Closes #7197, Closes #7265, Closes #7353, Closes #5773
Authored by: mikf, freezboltz, pukkandan
11 months ago
Nicolai Dagestad db3ad8a676
Add option `--netrc-cmd` (#6682)
Authored by: NDagestad, pukkandan
Closes #1706
11 months ago
MMM af7585c824
[extractor/tagesschau] Fix single audio urls (#6626)
Authored by: flashdagger
11 months ago
pukkandan 02948a17d9
[update] Do not restart into versions without `--update-to` 11 months ago
pukkandan 424f3bf033
[downloader/fragment] Do not sleep between fragments
Closes #6599
11 months ago
pukkandan ebe1b4e34f
[outtmpl] Fix some minor bugs
Closes #7164
11 months ago
pukkandan a35af4306d
[utils] `strftime_or_none`: Handle negative timestamps
Closes #6706
Authored by pukkandan, dirkf
11 months ago
pukkandan 93b39cdbd9
Add `--compat-option playlist-match-filter`
Closes #6073
11 months ago
pukkandan 97afb093d4
[extractor/youtube] Ignore wrong fps of some formats 11 months ago
pukkandan 2e023649ea
[cookies] Revert compatibility breakage in b38d4c941d 11 months ago
pukkandan 51a07b0dca
[extractor/youtube] Prioritize premium formats
Closes #7283
11 months ago
pukkandan eedda5252c
[utils] `FormatSorter`: Improve `size` and `br`
Closes #1596

Previously, when some formats have accurate size and some approximate,
the ones with accurate size was always prioritized

For formats with known tbr and unknown vbr/abr, we were setting
(vbr=tbr, abr=0) for sorting to work. This is no longer needed.

Authored by pukkandan, u-spec-png
11 months ago
Mozi 5cc09c004b
[extractor/zaiko] ZaikoETicket: Add extractor (#7347)
Authored by: pzhlkj6612
11 months ago
Vladislav 6f69101dc9
[extractor/yappy] YappyProfile: Add extractor (#7346)
Authored by: 7vlad7
11 months ago
garret 81c8b9bdd9
[extractor/nhk] `NhkRadiruLive`: Add extractor (#7332)
Authored by: garret1317
11 months ago
pukkandan 01aba2519a
[jsinterp] Fix global object extraction
Closes #7327
11 months ago
pukkandan 13ff780953
[postprocessor] Print newline for `--progress-template`
Closes #7193
11 months ago
pukkandan ff9b0e071f
[extractor/youtube] Determine audio language using automatic captions 11 months ago
toomyzoom 0a5d7c39e1
[extractor/iwara] Fix authentication (#7137)
Closes #7035, Closes #7207
Authored by: toomyzoom
11 months ago
TxI5 125ffaa173
[extractor/tv4] Fix extractor (#5649)
Closes #5535
Authored by: TxI5, dirkf
11 months ago
foreignBlade f9213f8a2d
[extractor/stripchat] Fix extractor (#7306)
Closes #7305
Authored by: foreignBlade
11 months ago
Jeong, Heon fdd69db389
[extractor/afreecatv] Fix extractor (#6283)
Closes #6133
Authored by: blmarket
11 months ago
Elyse 83465fc410
[extractor/ettutv] Add extractor (#6579)
Closes #6359
Authored by: elyse0
11 months ago
RjY 6daaf21092
[extractor/discogs] Add extractor (#6624)
Authored by: rjy
11 months ago
hoaluvn 7bcd481321
[extractor/urplay] Extract all subtitles (#7309)
Authored by: hoaluvn
11 months ago
bashonly c8561c6d03
[extractor/wrestleuniverse] Fix cookies support
Closes #7298
Authored by: bashonly
11 months ago
Cyberes cab94a0cd8
[extractor/funker530] Add extractor (#7291)
Authored by: Cyberes
11 months ago
c-basalt 345b4c0aed
[extractor/zaiko] Add extractor (#7254)
Closes #7196
Authored by: c-basalt
11 months ago
linsui 8790ea7b25
[extractor/ximalaya] Sort playlist entries (#7292)
Authored by: linsui
11 months ago
puc9 ab6057ec80
[extractor/tiktok] Fix resolution extraction (#7237)
Authored by: puc9
11 months ago
bashonly 9d7fde89a4
[extractor/zee5] Fix extraction of new content (#7280)
Authored by: bashonly
11 months ago
bashonly 1a2eb5bda5
[extractor/odnoklassniki] Fix formats extraction (#7217)
Closes #2959, Closes #4462, Closes #7201
Authored by: bashonly
11 months ago
DataGhost f8ae441501
[extractor/Dumpert] Fix m3u8 and support new URL pattern (#6091)
Authored by: DataGhost, pukkandan
Closes #5032
11 months ago
bashonly b4a252fba8
[jsinterp] Fix division (#7279)
* Fixes nsig decryption for Youtube JS player `8c7583ff`

Authored by: bashonly
11 months ago
bashonly 4f7b11cc1c
[extractor/voot] Fix extractor (#7227)
Closes #6715
Authored by: bashonly
11 months ago
bashonly d1795f4a6a
[extractor/twitter] Add login support (#7258)
Closes #6951
Authored by: bashonly
11 months ago
bashonly 44c0d66442
[extractor/lbry] Extract original quality formats (#7257)
Closes #7251
Authored by: bashonly
11 months ago
coletdjnz 8213ce28a4
[extractor/youtube] Extract `channel_is_verified` (#7213)
Authored by: coletdjnz
11 months ago
pukkandan 14a14335b2
[extractor/youtube] Misc cleanup
Authored by: coletdjnz
11 months ago
stanoarn c2b801fea5
[extractor/rozhlas] `MujRozhlas`: Add extractor (#7129)
Authored by: stanoarn
11 months ago
bashonly 59d9fe0831
[extractor/mgtv] Fix formats extraction (#7234)
Closes #7008
Authored by: bashonly
12 months ago
bashonly ee0ed0338d
[extractor/zdf] Fix formats extraction
Closes #7238, Closes #7240
Authored by: bashonly
12 months ago
bashonly c2a1bdb009
[extractor/tiktok] Extract 1080p adaptive formats (#7228)
Closes #7109
Authored by: bashonly
12 months ago
bashonly 7f8ddebbb5
[extractor/hotstar] Support `/shows/` URLs (#7225)
Closes #6463
Authored by: bashonly
12 months ago
bashonly 7bc9251746
[extractor/shemaroome] Pass `stream_key` header to downloader (#7224)
Closes #7133
Authored by: bashonly
12 months ago
bashonly 4815d35c19
[extractor/sonyliv] Fix login with token (#7223)
Authored by: bashonly
12 months ago
bashonly 97d60ad8cd
[extractor/foxnews] Fix extractors (#7222)
Closes #6050
Authored by: bashonly
12 months ago
bashonly 5ee9a7d6e1
[extractor/sverigesradio] Support slug URLs (#7220)
Closes #7145
Authored by: bashonly
12 months ago
bashonly 971d901d12
[extractor/tencent] Fix fatal metadata extraction (#7219)
Closes #7177
Authored by: bashonly
12 months ago
bashonly 12037d8b0a
[extractor/substack] Fix extraction (#7218)
Closes #7155
Authored by: bashonly
12 months ago
Paul Wise c91ac833ea
[extractor/acast] Support embeds (#7212)
Authored by: pabs3
12 months ago
coletdjnz 2fb35f6004
[extractor/youtube] Support shorter relative time format (#7191)
See: https://github.com/TeamNewPipe/NewPipeExtractor/issues/1067

Authored by: coletdjnz
12 months ago
Jeroen Jacobs 1a7dcca378
[extractor/vrt] Overhaul extractors (#6244)
* Fixes `VrtNU` extractor to work with the VRT MAX site change
* Adapts `VRT`, `Ketnet` and `DagelijkseKost` extractors to the new VRT API
* Removes `Canvas` and `CanvasEen` extractors; the sites and API no longer exist
* Moves all remaining VRT-related extractors into the `vrt` module

Closes #4908
Authored by: jeroenj, bergoid, bashonly

Co-authored-by: bergoid <bergoid@users.noreply.github.com>
Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
12 months ago
Mohamed Al Mehairbi 55ed4ff734
[extractor/DigitalConcertHall] Support films (#7202)
Authored by: ItzMaxTV
Closes #7184
12 months ago
bashonly 01231feb14
[extractor/twitch] Update `_CLIENT_ID` and add extractor-arg (#7200)
Closes #7058, Closes #7183
Authored by: bashonly
12 months ago
Daniel Rich f41b949a2e
[extractor/nhk] Fix API extraction (#7180)
Closes #6992
Authored by: sjthespian, menschel

Co-authored-by: Patrick Menschel <menschel.p@posteo.de>
12 months ago
coletdjnz c35448b7b1
[extractor/youtube] Extract more metadata for comments (#7179)
Adds new comment fields:
* `author_url` - The url to the comment author's page
* `author_is_verified` - Whether the author is verified on the platform
* `is_pinned` - Whether the comment is pinned to the top of the comments

Closes https://github.com/yt-dlp/yt-dlp/issues/5411

Authored by: coletdjnz
12 months ago
CeruleanSky 1c16d9df53
[extractor/twitter:spaces] Add `release_timestamp` (#7186)
Authored by: CeruleanSky
12 months ago
Mohamed Al Mehairbi ecfe47973f
[extractor/elevensports] Add extractor (#7172)
Closes #6737
Authored by: ItzMaxTV
12 months ago
coletdjnz 18f8fba7c8
[extractor/youtube] Fix continuation loop with no comments (#7148)
Deep check the response for incomplete data.

Authored by: coletdjnz
12 months ago
mrscrapy c2502cfed9
[extractor/recurbate] Add extractor (#6297)
Authored by: mrscrapy
12 months ago
bashonly 1fe5bf240e
[extractor/bravotv] Detect DRM (#7171)
Authored by: bashonly
12 months ago
Mohamed Al Mehairbi 26c517b29c
[extractor/crtvg] Add extractor (#7168)
Closes #6609
Authored by: ItzMaxTV
12 months ago
Elyse 6f10cdcf7e
[extractor/bilibili:SpaceVideo] Extract signature (#7149)
Authored by: elyse0
Closes #6956, closes #7081
12 months ago
HobbyistDev 03789976d3
[extractor/europarl] Rewrite extractor (#7114)
Authored by: HobbyistDev
Closes #6396
12 months ago
Mohamed Al Mehairbi dc3c44f349
[extractor/Mzaalo] Add extractor (#7163)
Authored by: ItzMaxTV
12 months ago
Ivan Skodje 937264419f
[extractor/tvplay] Remove outdated domains (#7106)
Closes #3920
Authored by: ivanskodje
12 months ago
Ivan Skodje 372a0f3b9d
Auto-select default format in `-f-` (#7101)
Authored by: ivanskodje, pukkandan
Closes #6720
12 months ago
garret 4cbfa570a1
[extractor/camfm] Add extractors (#7083)
Authored by: garret1317
12 months ago
HobbyistDev 45e87ea106
[extractor/eurosport] Improve `_VALID_URL` (#7076)
Closes #7042
Authored by: HobbyistDev
12 months ago
Florian Albrechtskirchinger dbce5afa6b
[extractor/twitch:vod] Support links from schedule tab (#7071)
Authored by: falbrechtskirchinger
12 months ago
Stefan Lobbenmeier f78eb41e1c
[extractor/ARDBetaMediathek] Add thumbnail (#6890)
Closes #6889
Authored by: StefanLobbenmeier
12 months ago
Matt Broadway b38d4c941d
[cookies] Update for chromium changes (#6897)
Authored by: mbway
12 months ago
hasezoey 489f51279d
[extractor/nekohacker] Add extractor (#7003)
Authored by: hasezoey
12 months ago
JChris246 2d306c03d6
[extractor/rottentomatoes] Fix extractor (#6844)
Closes #6729
Authored by: JChris246
12 months ago
bashonly f6e43d6fa9
[extractor/cbsnews] Overhaul extractors (#6681)
Closes #6565
Authored by: bashonly
12 months ago
bashonly fd5d93f704
Bugfix for b844a3f8b1
[extractor/weverse] Avoid unnecessary duplicate login

Authored by: bashonly
12 months ago
Lesmiscore f8f9250fe2
[extractor/niconico:live] Add extractor (#5764)
Authored by: Lesmiscore
12 months ago
Lesmiscore 3459d3c5af
[extractor/JStream] Add extractor (#6252)
Authored by: Lesmiscore
12 months ago
bashonly c25cac2f8e
[extractor/dacast] Add extractors (#6896)
Closes #6163
Authored by: bashonly
12 months ago
Nam Vu a58182b75a
[cookies] Support custom Safari cookies path (#6783)
Authored by: NextFire
12 months ago
jo-nike 4afb208cf0
[extractor/cbc] Ignore 426 from API (#6781)
Closes #6716
Authored by: jo-nike
12 months ago
ping 5c14b21367
[extractor/idolplus] Add extractor (#6732)
Authored by:  ping
Closes #6246
12 months ago
bepvte 02312c03cf
[extractor/twitch] Support mobile clips (#6699)
Authored by: bepvte
12 months ago
Stefan Borer 94627c5dde
[extractor/playsuisse] Support new url format (#6528)
Authored by: sbor23
12 months ago
Daniel Vogt c6d4b82a8b
[extractor/owncloud] Add extractor (#6533)
Authored by: C0D3D3V
12 months ago
Ha Tien Loi 17d7ca84ea
[extractor/zingmp3] Fix and improve extractors (#6367)
Authored by: hatienl0i261299
12 months ago
Mohit Tokas bfdf144c7e
[extractor/livestream] Support videos with account id (#6324)
Authored by: theperfectpunk
Closes #2225
12 months ago
nixxo c6d3f81a40
[extractor/rai] Rewrite extractors (#5940)
Authored by: nixxo, danog
Closes #5672, closes #6341

Co-authored-by: Daniil Gentili <daniil@daniil.it>
12 months ago
lauren n. liberda aed945e1b9
[extractor/wykop] Add extractors (#6140)
Authored by: selfisekai
12 months ago
JChris246 fc5a7f9b27
[extractor/daftsex] Update domain and embed player url (#5966)
Closes #5881
Authored by: JChris246
12 months ago
lauren n. liberda 738c90a463
[extractor/polskieradio] Improve extractors (#5948)
Authored by: selfisekai
12 months ago
coletdjnz 93e12ed76e
[extractor/youtube] Extract uploader metadata for feed/playlist items
Fixes https://github.com/yt-dlp/yt-dlp/issues/7104

Authored by: coletdjnz
12 months ago
Mohamed Al Mehairbi 6dc00acf0f
[extractor/weyyak] Add extractor (#7124)
Closes #7118
Authored by: ItzMaxTV
12 months ago
coletdjnz daafbf49b3
[core] Support decoding multiple content encodings (#7142)
Authored by: coletdjnz
12 months ago
coletdjnz 3f66b6fe50
[core] Workaround erroneous urllib Windows proxy parsing (#7092)
Convert proxies extracted from windows registry to http for older Python versions.
See: https://github.com/python/cpython/issues/86793

Authored by: coletdjnz
12 months ago
coletdjnz b87e01c123
[cookies] Move `YoutubeDLCookieJar` to cookies module (#7091)
Authored by: coletdjnz
12 months ago
coletdjnz 08916a49c7
[core] Improve HTTP redirect handling (#7094)
Aligns HTTP redirect handling with what browsers commonly do and RFC standards. 

Fixes issues afac4caa7d missed.

Authored by: coletdjnz
12 months ago
sqrtNOT 66468bbf49
[extractor/comedycentral] Add support for movies (#7108)
Closes #1926
Authored by: sqrtNOT
12 months ago
bashonly b844a3f8b1
[extractor/weverse] Add extractors (#6711)
Closes #4786
Authored by: bashonly
12 months ago
Audrey 5caf30dbc3
[extractor/youtube] Extract `heatmap` data (#7100)
Closes #3888
Authored by: tntmod54321
12 months ago
MMM 4ad58667c1
[extractor/bibeltv] Fix extraction, support live streams and series (#6505)
Authored by: flashdagger
12 months ago
Simon Sawicki edbe5b589d
Bugfixes for 4823ec9f46
Hotfix for fragmented downloads

Authored by: bashonly
12 months ago
Simon Sawicki 032de83ea9
[extractor/crunchyroll] Rework with support for movies, music and artists (#6237)
This adds `CrunchyrollMusicIE` and `CrunchyrollArtistIE` extractors using the new, reworked base class and expands the `CrunchyrollBetaIE` with support for movies and movie listings and more complete metadata extraction

Authored by: Grub4K
12 months ago
Simon Sawicki 8417f26b8a
[core] Implement `--color` flag (#6904)
Authored by: Grub4K
12 months ago
pukkandan 7aeda6cc9e
[jsinterp] Do not compile regex 12 months ago
pukkandan 15b2d3db1d
[misc] Add automatic duplicate issue detection 12 months ago
pukkandan 4823ec9f46
Update to ytdl-commit-d1c6c5
[YouTube] [core] Improve platform debug log, based on yt-dlp
d1c6c5c4d6

Except:
    * 6ed34338285f722d0da312ce0af3a15a077a3e2a [jsinterp] Add short-cut evaluation for common expression
        * There was no performance improvement when tested with https://github.com/ytdl-org/youtube-dl/issues/30641
    * e8de54bce50f6f77a4d7e8e80675f7003d5bf630 [core] Handle `/../` sequences in HTTP URLs
        * We plan to implement this differently
12 months ago
pukkandan 46f1370e9a
[devscripts/cli_to_api] Add script 12 months ago
kangalio 69a40e4a7f
[extractor/youtube:music:search_url] Extract title (#7102)
Authored by: kangalio
Closes #7095
12 months ago
coletdjnz 955c89584b
[core] Deprecate internal `Youtubedl-no-compression` header (#6876)
Authored by: coletdjnz
1 year ago
coletdjnz 69bec6730e
[cleanup, utils] Split into submodules (#7090)
Closes https://github.com/yt-dlp/yt-dlp/pull/2173

Authored by: pukkandan, coletdjnz
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
1 year ago
Simon Sawicki 23c39a4bea
[devscripts] `make_changelog`: Various improvements
- Make single items collapse into one line
- Don't hide "Important changes" in `<details>`
- Move upstream merge into priority
- Properly support comma separated prefixes

Authored by: Grub4K
1 year ago
bashonly b73193c99a
[build] Implement build verification using `--update-to`
Authored by: bashonly, Grub4K
1 year ago
bashonly c4efa0aefe
[build] Various build workflow improvements
- Wait for build before publishing to PyPI
- Do not run `meta_files` job if release is cancelled
- Customizable channel in release workflow
- Display badges above changelog

Authored by: bashonly, Grub4K
1 year ago
Simon Sawicki 44a79958f0
[build] Fix macOS target
Authored by: Grub4K
1 year ago
Simon Sawicki 665472a7de
[update] Implement `--update-to` repo
Authored by: Grub4K, pukkandan
1 year ago
Simon Sawicki d2e84d5eb0
[update] Better error handling
Authored by: pukkandan
1 year ago
coletdjnz 447afb9eaa
[extractor/youtube] Support podcasts and releases tabs
Closes https://github.com/yt-dlp/yt-dlp/issues/6893

Authored by: coletdjnz
1 year ago
pukkandan 6f2287cb18
[cleanup] Misc
Closes #7030, closes #6967
1 year ago
pukkandan 1d7656184c
[jsinterp] Handle `NaN` in bitwise operators
Closes #6131
1 year ago
pukkandan f7f7a877bf
[extractor/booyah] Remove extractor
Site shut down. Closes #6425
1 year ago
pukkandan c8bc203fbf
[docs] Misc improvements
Closes #6814, closes #6940, closes #6733, closes #6923, closes #6566, closes #6726, closes #6728
1 year ago
toomyzoom 21b9413cf7
[extractor/iwara] Implement login (#6721)
Authored by: toomyzoom
1 year ago
bashonly ef8fb7f029
[extractor/wrestleuniverse] Fix extraction, add login (#6982)
Closes #6975
Authored by: bashonly, Grub4K

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
1 year ago
ringus1 3b52a60688
[extractor/facebook] Fix metadata extraction (#6856)
Closes #3432
Authored by: ringus1
1 year ago
Lesmiscore c449c0655d
[extractor/abematv] Add fallback for title and description extraction and extract more metadata (#6994)
Authored by: Lesmiscore
1 year ago
lauren n. liberda 0c7ce146e4
[extractor/tvp] Use new API (#6989)
Authored by: selfisekai
Closes #6987
1 year ago
pukkandan ddae33754a
[extractor/youporn] Extract m3u8 formats
Closes #6977
1 year ago
Eveldee 45998b3e37
[utils] `locked_file`: Fix for virtiofs (#6840)
Authored by: brandon-dacrib
Closes #6823
1 year ago
bashonly 2f07c4c1da
[extractor/clipchamp] Add extractor (#6978)
Closes #6973
Authored by: bashonly
1 year ago
Nicholas Defranco b423b6a48e
[extractor/dlf] Add extractors (#6697)
Closes #6430
Authored by: nick-cd
1 year ago
bashonly 147e62fc58
[extractor/twitter] Default to GraphQL, handle auth errors (#6957)
Closes #6763
Authored by: bashonly
1 year ago
Simon Sawicki b079c26f0a
[utils] `traverse_obj`: More fixes (#6959)
- Fix result when branching with `traverse_string`
- Fix `slice` path on `dict`s
- Fix tests and docstrings from 21b5ec86c2
- Add `is_iterable_like` helper function

Authored by: Grub4K
1 year ago
bashonly 4d9280c9c8
[extractor/reddit] Add login support (#6950)
Closes #6949
Authored by: bashonly
1 year ago
pukkandan 17ba4343cf
Fix f005a35aa7
Printing inside `finally` causes the order of logging to change
when there is an error, which is undesirable. So this is reverted.

The issue of `--print` being blocked by pre-processors was an
unintentional side-effect of changing the operation orders in
170605840e, and this is also partially
reverted.
1 year ago
pukkandan f005a35aa7
Ensure pre-processor errors do not block `--print`
Closes #6937
1 year ago
makeworld 7a7b1376fb
[extractor/cbc] Fix live extractor, playlist `_VALID_URL` (#6625)
Authored by: makew0rld
1 year ago
pukkandan b5f61b69d4
Fix bug in 170605840e
and related refactor
1 year ago
pukkandan 7cf51f2191
[jsinterp] Handle negative numbers better
Closes #6131
1 year ago
pukkandan 170605840e
Populate `filename` and `urls` fields at all stages of `--print`
Closes https://github.com/yt-dlp/yt-dlp/issues/6920
1 year ago
garret 30647668a9
[extractor/globalplayer] Add extractors (#6903)
Authored by: garret1317
1 year ago
Alex Klapheke ed81b74802
[extractor/aeonco] Support Youtube embeds (#6591)
Authored by: alexklapheke
1 year ago
Noah 62beefa818
[extractor/pornhub] Set access cookies to fix extraction (#6685)
Closes #4299
Authored by: Schmoaaaaah, arobase-che

Co-authored-by: Noah <nkempers@outlook.de>
Co-authored-by: ache <ache@ache.one>
1 year ago
Neurognostic 0c4e0fbcad
[extractor/bitchute] Add more fallback subdomains (#6907)
Authored by: Neurognostic
1 year ago
sqrtNOT c86e433c35
[extractor/NiconicoSeries] Fix extraction (#6898)
Authored by: sqrtNOT
1 year ago
Elyse 9b30cd3dfc
[extractors/rtvc] Add extractors (#6578)
* Add `RTVCPlay` extractor
* Add `RTVCPlayEmbed` extractor
* Add `RTVCKaltura` extractor
* Add `SenalColombiaLive` extractor

Closes #6457
Authored by: elyse0
1 year ago
Simon Sawicki 21b5ec86c2
[utils] `traverse_obj`: Allow iterables in traversal (#6902)
Authored by: Grub4K
1 year ago
pukkandan c16644642b
Add option `--xff`
Deprecates `--geo-bypass`, `--no-geo-bypass, `--geo-bypass-country`, `--geo-bypass-ip-block`
1 year ago
pukkandan 04f8018a05
[extractor/hentaistigma] Remove extractor
Piracy site

Closes #6870
1 year ago
pukkandan d669772c65
Add `--no-quiet`
Closes #6796
1 year ago
pukkandan ec9311c41b
[outtmpl] Support `str.format` syntax inside replacements
Closes #6843
1 year ago
pukkandan 78fde6e339
[outtmpl] Allow `\n` in replacements and default.
Fixes: https://github.com/yt-dlp/yt-dlp/issues/6808#issuecomment-1510055357
Fixes: https://github.com/yt-dlp/yt-dlp/issues/6808#issuecomment-1510363645
1 year ago
JC-Chung 80b732b7a9
[extractor/twitch] Extract original size thumbnail (#6629)
Authored by: JC-Chung
1 year ago
truedread 1ea15603d8
[extractor/wevidi] Add extractor (#6868)
Closes #6129
Authored by: truedread
1 year ago
garret 8f0be90ecb
[extractor/nhk] Add `NhkRadiru` extractor (#6819)
* Add `NhkRadioNewsPage` extractor

Authored by: garret1317
1 year ago
vidiot720 6a765f135c
[extractor/sbs] Overhaul extractor for new API (#6839)
Closes #6543
Authored by: vidiot720, dirkf, bashonly
1 year ago
qbnu ab29e47029
[extractor/bilibili] Support festival videos (#6547)
Closes #6138
Authored by: qbnu
1 year ago
bashonly e5265dc651
[extractor/stageplus] Add extractor (#6838)
Closes #6806
Authored by: bashonly
1 year ago
zhgwn cbdf9408e6
[extractor/pornez] Support new URL formats (#6792)
Closes #6791, Closes #6298
Authored by: zhgwn
1 year ago
CoryTibbettsDev 2c566ed141
[extractor/whyp] Add extractor (#6803)
Authored by: CoryTibbettsDev
1 year ago
satan1st 9c92b803fa
[extractor/gronkh] Extract duration and chapters (#6817)
Authored by: satan1st
1 year ago
bashonly 7a6f6f2459
[extractor/reddit] Support cookies and short URLs (#6825)
Closes #6665, Closes #6753
Authored by: bashonly
1 year ago
bashonly ea05708203
[extractor/adobepass] Handle `Charter_Direct` MSO as `Spectrum` (#6824)
Authored by: bashonly
1 year ago
pukkandan 9874e82b5a
Do not translate newlines in `--print-to-file`
Fixes https://github.com/yt-dlp/yt-dlp/issues/6808#issuecomment-1509361107
1 year ago
pukkandan 84ffeb7d5e
[extractor] Do not warn for invalid chapter data in description
Fixes https://github.com/yt-dlp/yt-dlp/issues/6811#issuecomment-1509876209
1 year ago
coletdjnz 7666b93604
[extractor/youtube] Define strict uploader metadata mapping (#6384)
New mapping:
```
channel -> channel name
channel_id -> UCID
channel_url -> UCID channel url

uploader -> channel name (same as channel field)
uploader_id -> @handle
uploader_url -> @handle channel url 
```

Authored by: coletdjnz
1 year ago
bashonly 93e7c6995e
[extractor/generic] Attempt to detect live HLS (#6775)
* Extract duration for non-live generic HLS videos
* Add extractor-arg `is_live` to bypass live HLS check

Closes #6705
Authored by: bashonly
1 year ago
bashonly 3f7e2bd80e
[FFmpegFixupM3u8PP] Check audio codec before fixup (#6778)
Closes #6673
Authored by: bashonly
1 year ago
bashonly 925936908a
[extractor/tiktok] Fix and improve metadata extraction (#6777)
Authored by: bashonly
1 year ago
bashonly 90c1f51206
[extractor/zoom] Fix share URL extraction (#6789)
Authored by: bashonly
1 year ago
hasezoey 56793f74c3
[extractor/iwara] Fix format sorting (#6651)
Authored by: hasezoey
1 year ago
Lesmiscore d1483ec693 [extractor/iwara] Fix typo
Authored by: Lesmiscore

Closes #6795
1 year ago
MyNey 979568f26e
[extractor/BrainPOP] Add extractors (#6106)
Authored by: MinePlayersPE
Based on https://github.com/ytdl-org/youtube-dl/pull/10025
1 year ago
HobbyistDev b093c38cc9
[extractor/biliIntl] Add comment extraction (#6079)
Authored by: HobbyistDev
1 year ago
HobbyistDev 2d97d154fe
[extractor/gmanetwork] Add extractor (#5945)
Authored by: HobbyistDev
Partially fixes #5770
1 year ago
pukkandan c3f624ef0a
Relaxed validation for numeric format filters
Continued from f96bff99cb

Closes #6782
1 year ago
Lesmiscore 52ecc33e22
[extractor/niconico] Download comments from the new endpoint (#6773)
Authored by: Lesmiscore
1 year ago
pukkandan 26010b5cec
[postprocessor/FixupDuplicateMoov] Fix bug in triggering 1 year ago
pukkandan c6786ff3ba
[extractor/youtube] Revert default formats to `https` 1 year ago
Shreyas Minocha 79c77e85b7
[extractor/zoom] Fix extractor (#6741)
Authored by: shreyasminocha
Closes #6677
1 year ago
sian1468 faa0332ed6
[extractor/line] Remove extractors (#6734)
Service has shut down - https://archive.ph/txVKy
Authored by: sian1468
1 year ago
lauren n. liberda 7e35526d5b
[extractor/hrefli] Add extractor (#6762)
Authored by: selfisekai
1 year ago
Chris Caruso ef0848abd4
[extractor/youku] Improve error message (#6690)
Authored by: carusocr
Closes #6551
1 year ago
bashonly 0a6918a4a1
[extractor/kick] Make initial request non-fatal
Authored by: bashonly
1 year ago
coletdjnz 141a8dff98
[extractor/youtube] Fix comment loop detection for pinned comments (#6714)
Pinned comments may repeat a second time - this is expected.

Fixes https://github.com/yt-dlp/yt-dlp/issues/6712

Authored by: coletdjnz
1 year ago
Lesmiscore 68be95bd0c
[extractor/YahooGyaOIE,extactor/YahooGyaOPlayerIE] Delete extractors due to website close (#6218)
Authored by: Lesmiscore
1 year ago
Lesmiscore ab92d8651c
[extractor/iwara] Accept old URLs
Authored by: Lesmiscore

Closes #6669
1 year ago
Lesmiscore 0f0875ed55
[postprocessor/EmbedThumbnail,postprocessor/FFmpegMetadata] Fix error on attaching thumbnails and info json for mkv/mka (#6647)
Authored by: Lesmiscore

Current yt-dlp code never hit this bug, but would hit once filename sanitization gets better
1 year ago
Lesmiscore 95a383be1b
[extractor/iwara] Report private videos (#6641)
Authored by: Lesmiscore
1 year ago
bashonly 9be0fe1fd9
[extractor/nbc] Fix `NBCStations` direct mp4 formats (#6637)
Authored by: bashonly
1 year ago
bashonly 33b737bedf
[extractor/triller] Support short URLs, detect removed videos (#6636)
Authored by: bashonly
1 year ago
Simon Sawicki 0898c5c8cc
[utils] `js_to_json`: Implement template strings (#6623)
Authored by: Grub4K
1 year ago
pukkandan f68434cc74
[extractor] Extract more metadata from ISM
Fixes 81b6102d20 (r105892531)
1 year ago
pukkandan baa922b5c7
[extractor] Do not exit early for unsuitable `url_result` 1 year ago
bashonly 9bfe0d15bd
Fix 5cc0a8fd2e
Authored by: bashonly
1 year ago
bashonly 8ceb07e870
[extractor/tiktok] Fix mp3 formats (#6615)
Closes #6608
Authored by: bashonly
1 year ago
bashonly 6bdb64e2a2
[extractor/hollywoodreporter] Add extractors (#6614)
Closes #6525
Authored by: bashonly
1 year ago
bashonly 3ae182ad89
[extractor/pgatour] Add extractor (#6613)
Closes #6537
Authored by: bashonly
1 year ago
bashonly 5cc0a8fd2e
[extractor/generic] Accept values for `fragment_query`, `variant_query` (#6600)
Closes #6593
Authored by: bashonly
1 year ago
pukkandan 6994afc030
[extractor/rumble] Fix videos without quality selection
Closes #6612
1 year ago
pukkandan 78bc1868ff
[extractor/rumble] Detect timeline format
Closes #6607
1 year ago
bashonly 69b2f838d3
[extractor/telecaribe] Expand livestream support (#6601)
Closes #6598
Authored by: bashonly
1 year ago
bashonly 44369c9afa
[extractor/cbs] Add `ParamountPressExpress` extractor (#6604)
Closes #6597
Authored by: bashonly
1 year ago
bashonly c2e0fc40a7
[extractor/generic] Add extractor-args `hls_key`, `variant_query` (#6567)
Authored by: bashonly
1 year ago
bashonly 06966cb896
[extractor/bravotv] Fix extractor (#6568)
Closes #6562
Authored by: bashonly
1 year ago
bashonly e4cf7741f9
[extractor/rozhlas] Extract manifest formats (#6590)
Closes #6584
Authored by: bashonly
1 year ago
Lesmiscore c14af7a741
[extractor/iwara] Overhaul extractors (#6557)
Authored by: Lesmiscore
1 year ago
viktor-enzell 9a06b7b189
[extractor/drtv] Fix radio page extraction (#6552)
Authored by: viktor-enzell
1 year ago
bashonly 216bcb66d7
[extractor/tiktok] Improve `TikTokLive` extractor (#6520)
Closes #6459
Authored by: bashonly
1 year ago
bashonly 460da07439
[extractor/genius] Add support for articles (#6474)
Closes #6465
Authored by: bashonly
1 year ago
bashonly 03025b6e10
[extractor/mediastream] Improve `WinSports` and embed extraction (#6426)
Closes #6419, Closes #6527
Authored by: bashonly
1 year ago
Nicholas Defranco 071670cbea
[extractor/youtube] Fix parsing `comment_count` (#6523)
Closes #5849
Authored by: nick-cd
1 year ago
pukkandan 427a8fafbb
[build] Pin `pyinstaller` version for MacOS
Workaround for #6541
1 year ago
coletdjnz 607510b9f2
[extractor/youtube] Handle incomplete initial data from watch page (#6510)
Authored by: coletdjnz
1 year ago
pukkandan 98ac902c49
[dependencies/Cryptodome] Fix `__bool__`
Bug in 65f6e80780
1 year ago
unbeatable-101 cbfe2e5cbe
[extractor/nebula] Add `beta.nebula.tv` (#6516)
Authored by: unbeatable-101
1 year ago
Chris Caruso cf9fd52fab
[extractor/jwplatform] Update `_extract_embed_urls` (#6383)
Authored by: carusocr
1 year ago
JChris246 80ea6d3dea
[extractor/Parler] Rewrite extractor (#6446)
Authored by: JChris246
Closes #6068
1 year ago
Joshua Lochner 1e3c2b6ec2
[extractor/medaltv] Fix clips (#6502)
Closes #6489
Authored by: xenova
1 year ago
Ha Tien Loi 026435714c
[extractor/LastFM] Rewrite playlist extraction (#6379)
Authored by: hatienl0i261299, pukkandan
Closes #5975
1 year ago
Ha Tien Loi 0181b9a1b3
[extractor/thesun] Update `_VALID_URL` (#6522)
Authored by: hatienl0i261299
Closes #6479
1 year ago
pukkandan e389d172b6
Fix 2a23d92d9e
Closes #6517
1 year ago
pukkandan 2a23d92d9e
[extractor/youtube] Construct fragment list lazily
Building fragment list for all formats take significant time for large videos
1 year ago
pukkandan 86cb922118
[extractor/youtube] Add extractor-arg `include_duplicate_formats` 1 year ago
Lesmiscore c795c39f27
[extractor/youtube] Add client name to `format_note` when `-v` (#6254)
Authored by: Lesmiscore, pukkandan
1 year ago
vampirefrog 7a6c8a0807
[extractor/rokfin] Re-construct manifest url (#6507)
Authored by: vampirefrog
1 year ago
Daniel Vogt 89dbf08483
[extractor/opencast] Fix format bug (#6512)
Authored by: C0D3D3V
1 year ago
pukkandan e6ab678e36
[extractor/hidive] Fix login
Fixes https://github.com/yt-dlp/yt-dlp/issues/6493#issuecomment-1462906556
1 year ago
pukkandan ab1de9cb1e
Support loading info.json with a list at it's root 1 year ago
makeworld 871c907454
[extractor/cbc:gem] Update `_VALID_URL` (#6499)
Authored by: makeworld-the-better-one
Closes #6395
1 year ago
Elyse 0551511b45
[extractor/twitch] Fix `is_live` (#6500)
Closes #6494
Authored by: elyse0
1 year ago
pukkandan c9abebb851
[extractor/youtube] Bypass throttling for `-f17`
and related cleanup

Thanks @AudricV for the finding
1 year ago
pukkandan 66aeaac9aa
[downloader/curl] Fix progress reporting
Bug in 8c53322cda
Closes #6490
1 year ago
Daniel Vogt 3588be59ce
[extractor/opencast] Add ltitools to `_VALID_URL` (#6371)
Authored by: C0D3D3V
1 year ago
D0LLYNH0 2d5cae9636
[extractor/iq] Set more language codes (#6476)
Authored by: D0LLYNH0
1 year ago
Simon Sawicki 9b7a48abd1
[cookies] Defer extraction of v11 key from keyring
Closes #6082

Authored by: Grub4K
1 year ago
bashonly 01ddec7e66
[postprocessor] Fix chapters if duration is not extracted (#6037)
Authored by: bashonly
1 year ago
bashonly 6f4fc5660f
[extractor/chilloutzone] Fix extractor (#6445)
Closes #6029
Authored by: bashonly
1 year ago
Simon Sawicki 3b479100df
[utils] `write_string`: Fix noconsole behavior
Ref: https://github.com/pyinstaller/pyinstaller/pull/7217

Authored by: Grub4K
1 year ago
permunkle d4e6ef4077
[extractor/nubilesporn] Add extractor (#6231)
Authored by: permunkle
1 year ago
bashonly c459d45dd4
[extractor/teamcoco] Fix extractor (#6437)
Closes #6339
Authored by: bashonly
1 year ago
github-actions 8729e7b57c Release 2023.03.04
Created by: pukkandan

:ci skip all :ci run dl
1 year ago
pukkandan 392389b7df
[cleanup] Misc 1 year ago
Elyse eb8fd6d044
[extractor/lefigaro] Add extractors (#6309)
Authored by: elyse0
Closes #6197
1 year ago
Ferdinand Bachmann f44cb4e77b
[extractor/tubetugraz] Support `--twofactor` (#6424) (#6427)
Authored by: Ferdi265
Closes #6424
1 year ago
Elyse 46580ced56
[extractor/tunein] Fix extractors (#6310)
Authored by: elyse0
Closes #2973
1 year ago
Elyse b404712822
[extractor/telecaribe] Add extractor (#6311)
Authored by: elyse0
Closes #6001
1 year ago
Chris Caruso 1f8489cccb
[extractor/lumni] Add extractor (#6302)
Authored by: carusocr
Closes #6202
1 year ago
columndeeply ed4cc4ea79
[extractor/Prankcast] Fix tags (#6316)
Authored by: columndeeply
1 year ago
lauren n. liberda cf60522652
[extractor/twitter] Fix retweet extraction (#6422)
Authored by: selfisekai
1 year ago
pukkandan 45db357289
[extractor/SportDeutschland] Rewrite extractor
Note: `multi_video` live streams are untested

Closes #6417, closes #6418, closes #6420
1 year ago
LXYan2333 8a83baaf21
[extractor/bilibili] Fix for downloading wrong subtitles (#6358)
Closes #6357
Authored by: LXYan2333
1 year ago
pukkandan 7accdd9845
[devscripts] `make_changelog`: Stop at `Release ...` commit
Closes #6415
1 year ago
Yakabuff 283a0b5bc5
[xvideos:quickies] Add extractor (#6414)
Authored by: Yakabuff
Closes #6356
1 year ago
mushbite 22ccd5420b
[extractor/rutube] Extract chapters from description (#6345)
Authored by: mushbite
1 year ago
Simon Sawicki 08ff6d59f9
[build] Only archive if `vars.ARCHIVE_REPO` is set
Authored by: Grub4K
1 year ago
Elyse 4a6272c6d1
[extractor/twitch] Update for GraphQL API changes (#6318)
Authored by: elyse0
Closes #6308
1 year ago
Venkata Krishna S 640c934823
[extractor/ESPNcricinfo] Handle new URL pattern (#6321)
Authored by: venkata-krishnas
Closes #6164
1 year ago
bashonly 55676fe498
[build] Fix publishing to PyPI and homebrew
Closes #6411
Authored by: bashonly
1 year ago
github-actions 354d5fca7a Release 2023.03.03
Created by: Grub4K

:ci skip all :ci run dl
1 year ago
Simon Sawicki 9344964281
Fix d400e261cf
Authored by: Grub4K
1 year ago
pukkandan bfc861a91e
Fix bug in 29cb20bd56 1 year ago
pukkandan fe2ce85aff
Add option `--break-match-filters`
* Deprecates `--break-on-reject`

Closes #5962
1 year ago
pukkandan d21056f4cf
Fix `--break-on-existing` with `--lazy-playlist`
Closes #6399
1 year ago
pukkandan b2e0343ba0
[cleanup, jsinterp] Give functions names to help debugging 1 year ago
pukkandan 4815bbfc41
[cleanup] Misc 1 year ago
bashonly 776d1c3f0c
[build] Add `cffi` as a dependency for `yt_dlp_linux`
Closes #6394
Authored by: bashonly
1 year ago
Simon Sawicki 12647e03d4
[build] Sign SHA files and release public key
Closes #6344
Authored by: Grub4K
1 year ago
Simon Sawicki 77df20f14c
[update] Add option `--update-to`, including to nightly (#6220)
* By default, stable will only update to stable, and nightly to nightly

Authored by: Grub4K, bashonly, pukkandan

Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
1 year ago
Simon Sawicki 29cb20bd56
[build] Automated builds and nightly releases (#6220)
Closes #1839
Authored by: Grub4K, bashonly

Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
1 year ago
Simon Sawicki d400e261cf
[devscripts] Script to generate changelog (#6220)
Authored by: Grub4K
1 year ago
pukkandan 9acf1ee25f
[jsinterp] Handle `Date` at epoch 0
Closes #6400
1 year ago
bashonly 40d77d8902
[extractor/yle_areena] Extract non-Kaltura videos (#6402)
Closes #6066
Authored by: bashonly
1 year ago
bashonly 2d5a8c5db2
[extractor/mediastream] Improve WinSports support (#6401)
Closes #6360
Authored by: bashonly
1 year ago
bashonly 77d6d13646
[extractor/ntvru] Extract HLS and DASH formats (#6403)
Closes #5915
Authored by: bashonly
1 year ago
std-move 9fddc12ab0
[extractor/iprima] Fix extractor (#6291)
Authored by: std-move
Closes #6187
1 year ago
bashonly b38cae49e6
[extractor/generic] Detect manifest links via extension
Authored by: bashonly
1 year ago
coletdjnz 7f51861b18
[extractor/youtube] Detect and break on looping comments (#6301)
Fixes https://github.com/yt-dlp/yt-dlp/issues/6290

Authored by: coletdjnz
1 year ago
pukkandan 5b28cef72d
[cleanup] Misc 1 year ago
pukkandan 31e183557f
[extractor/youtube] Extract channel `view_count` when `/about` tab is passed 1 year ago
pukkandan f34804b2f9
[extractor/youtube] Fix 5038f6d713
* [fragment] Fix `request_data`
* [youtube] Don't use POST for now. It may be easier to break in future

Authored by: bashonly, coletdjnz
1 year ago
pukkandan 65f6e80780
[dependencies] Simplify `Cryptodome`
Closes #6292, closes #6272, closes #6338
1 year ago
pukkandan b059188383
[plugins] Don't look in `.egg` directories
Closes #6306
1 year ago
pukkandan 5038f6d713
[extractor/youtube] Construct dash formats with `range` query
Closes #6369
1 year ago
pukkandan 4d248e29d2
[extractor/GoogleDrive] Fix some audio
Only those with source url, but no confirmation page
1 year ago
pukkandan 8e9fe43cd3
[extractor/generic] Handle basic-auth when checking redirects
Closes #6352
1 year ago
pukkandan 43a3eaf963
[extractor] Fix DRM detection in m3u8
Fixes https://github.com/ytdl-org/youtube-dl/issues/31693#issuecomment-1445202857
1 year ago
pukkandan cc09083636
[utils] `LenientJSONDecoder`: Parse unclosed objects 1 year ago
Simon Sawicki da8e2912b1
[utils] `Popen`: Shim undocumented `text_mode` property
Fixes #6317

Authored by: Grub4K
1 year ago
Zhong Lufan 18d295c9e0
[extractor/tencent] Add more formats and info (#5950)
Authored by: Hill-98
1 year ago
pukkandan 17ca19ab60
[cleanup] Fix `Changelog` 1 year ago
github-actions 41bd0dc4d7 [version] update
Created by: pukkandan

:ci skip all :ci run dl
1 year ago
pukkandan a0a7c01542
Release 2023.02.17 1 year ago
pukkandan 45b2ee6f4f
Update to ytdl-commit-2dd6c6e
[YouTube] Avoid crash if uploader_id extraction fails
2dd6c6edd8

Except:
    * 295736c9cba714fb5de7d1c3dd31d86e50091cf8 [jsinterp] Improve parsing
    * 384f632e8a9b61e864a26678d85b2b39933b9bae [ITV] Overhaul ITV extractor
    * 33db85c571304bbd6863e3407ad8d08764c9e53b [feat]: Add support to external downloader aria2p
1 year ago
pukkandan a538772969
[cleanup] Misc
Closes #5897
1 year ago
HobbyistDev 30031be974
[extractor/tempo] Add IVXPlayer extractor (#5837)
Authored by: HobbyistDev
1 year ago
HobbyistDev 9acca71237
[extractor/boxcast] Add extractor (#5983)
Authored by: HobbyistDev
Closes #5769
1 year ago
Henrik Heimbuerger d50ea3ce5a
[extractor/nebula] Remove broken cookie support (#5979)
Authored by: hheimbuerger
Closes #4002
1 year ago
bashonly c61cf091a5
[extractor/youtube] `uploader_id` includes `@` with handle
Authored by: bashonly
1 year ago
Chris Caruso f737fb16d8
[ExtractAudio] Handle outtmpl without ext (#6005)
Authored by: carusocr
Closes #5968
1 year ago
Friedrich Rehren 5e1a54f63e
[extractor/SportDeutschland] Fix extractor (#6041)
Authored by: FriedrichRehren
Closes #3005
1 year ago
HobbyistDev 31c279a2a2
[extractor/hypergryph] Add extractor (#6094)
Authored by: HobbyistDev, bashonly
Closes #6052
1 year ago
HobbyistDev a4ad59ff2d
[extractor/anchorfm] Add episode extractor (#6092)
Authored by: HobbyistDev, bashonly
Closes #6081
1 year ago
Alex Ionescu b25d6cb963
[utils] Fix race condition in `make_dir` (#6089)
Authored by: aionescu
1 year ago
HobbyistDev 3616300155
[extractor/yappy] Add extractor (#6111)
Authored by: HobbyistDev
Closes #3522
1 year ago
qbnu e4a8b1769e
[extractor/vocaroo] Add extractor (#6117)
Authored by: qbnu, SuperSonicHub1
Closes #6152
1 year ago
JChris246 da880559a6
[extractor/ebay] Add extractor (#6170)
Closes #6134
Authored by: JChris246
1 year ago
Felix Yan 65e5c021e7
[utils] Don't use Content-length with encoding (#6176)
Authored by: felixonmars
Closes #3772, #6178
1 year ago
OIRNOIR a9189510ba
[extractor/nitter] Update instance list (#6236)
Authored by: OIRNOIR
1 year ago
HobbyistDev 10fd9e6ee8
[extractor/odkmedia] Add `OnDemandChinaEpisodeIE` (#6116)
Authored by: HobbyistDev, pukkandan
1 year ago
HobbyistDev 72671a212d
[extractor/viu] Add `ViuOTTIndonesiaIE` extractor (#6099)
Authored by: HobbyistDev
Closes #1757
1 year ago
Siddhartha Sahu 376aa24b15
Improve default subtitle language selection (#6240)
Authored by: sdht0
1 year ago
Simon Sawicki c9d14bd22a
[extractor/crunchyroll] Fix incorrect premium-only error
Closes #6234

Authored by: Grub4K
1 year ago
bashonly 149eb0bbf3
[extractor/youtube] Fix `uploader_id` extraction
Closes #6247
Authored by: bashonly
1 year ago
pukkandan 9ebac35577
Bugfix for 39f32f1715
when `--ignore-no-formats-error`
1 year ago
bashonly 8b37c58f8b
[extractor/nfl] Add `NFLPlus` extractors (#6222)
Closes #6165
Authored by: bashonly
1 year ago
Greg Sadetsky d3bb187f01
[extractor/NZOnScreen] Add extractor (#6208)
Authored by: gregsadetsky, pukkandan
Closes #6193
1 year ago
pukkandan 44699d10dc
[extractor/crunchyroll] Better message for premium videos
Closes #6227
1 year ago
Marenga a9c685453f
[extractor/vk] Fix playlists for new API (#6122)
Authored by: the-marenga
Closes #6219
1 year ago
pukkandan c154302c58
Bugfix for 39f32f1715 1 year ago
pukkandan 5712943b76
Imply `--no-progress` when `--print` 1 year ago
pukkandan 39f32f1715
Sanitize formats before sorting
Closes #4501
1 year ago
shirt 365b900605
[Build] Update pyinstaller 1 year ago
nixxo c6b657867a
[extractor/rcs] Fix extractors (#5700)
Authored by: nixxo, pukkandan
Closes #5683
1 year ago
Lesmiscore a4f1683221
[extractor/AbemaTV] Cache user token whenever appropriate (#6216)
Authored by: Lesmiscore
1 year ago
Simon Sawicki b6795fd310
[extractor/twitter] Fix `--no-playlist` and add media `view_count` when using GraphQL (#6211)
Authored by: Grub4K
1 year ago
pukkandan 2e269bd998
[pyinst] Fix for pyinstaller 5.8
Fixes comment https://github.com/yt-dlp/yt-dlp/issues/1839#issuecomment-1427002271
1 year ago
Bruno Guerreiro 78a78fa74d
[extractor/youtube] Add hyperpipe instances (#6020)
Authored by: Generator
1 year ago
HobbyistDev 0ba87dd279
[extractor/biliintl] Add intro and ending chapters (#6018)
Authored by: HobbyistDev
1 year ago
Roland Hieber 05799a48c7
[extractor/youtube] Update invidious and piped instances (#6030)
Authored by: rohieb
1 year ago
ByteDream 93abb7406b
[extractor/crunchyroll] Add intro chapter (#6023)
Authored by: ByteDream
1 year ago
LowSuggestion912 b23167e754
[extractor/common] Fix `_search_nuxt_data` (#6062)
Authored by: LowSuggestion912
1 year ago
Chris Caruso 417cdaae08
[extractor/ximalaya] Update album `_VALID_URL` (#6110)
Authored by: carusocr
Closes #6059
1 year ago
sepro b3eaab7ca2
[extractor/vlive] Replace with `VLiveWebArchiveIE` (#6196)
vlive has shut down: https://web.archive.org/web/20221031171019/https://www.vlive.tv/notice/4749

Authored by: seproDev
1 year ago
lauren n. liberda a31d0fa6c3
[extractor/tvp] Support `stream.tvp.pl` (#6139)
Authored by: selfisekai
1 year ago
sepro cc2389c8ac
[extractor/npo] Fix extractor and add HD support (#6155)
Authored by: seproDev
1 year ago
Chris Caruso 20266508dd
[extractor/bfmtv] Support `rmc` prefix (#6025)
Authored by: carusocr
Closes #6021
1 year ago
qulaz cc13293c28
[extractor/clyp] Support `wav` (#6102)
Authored by: qulaz
1 year ago
oxamun 989f47b631
[extractor/tnaflix] Fix extractor (#6086)
Closes #6085
Authored by: oxamun, bashonly
1 year ago
JChris246 7d5f919bad
[extractor/Stripchat] Fix extractor (#5985)
Authored by bashonly, JChris246
Closes #5963, closes #5866
1 year ago
panatexxa c62e64cf01
[extractor/moviepilot] Fix extractor (#5954)
Authored by: panatexxa
1 year ago
pmitchell86 c085cc2def
[extractor/91porn] Fix title and comment extraction (#5932)
Authored by: pmitchell86
Fixes #3256
1 year ago
Alex Berg 7708df8da0
[extractor/Hidive] Fix subtitles and age-restriction (#5828)
Authored by: chexxor
Closes #408
1 year ago
pukkandan b85faf6ffb
[devscripts/pyinstaller] Analyze sub-modules of `Cryptodome`
Ref: https://github.com/yt-dlp/yt-dlp/issues/6185#issuecomment-1423523986
1 year ago
Master 203a06f855
[extractor/radiko] Fix format sorting for Time Free (#6159)
Authored by: road-master
1 year ago
Simon Sawicki 6839ae1f6d
[utils] `traverse_obj`: Fix more bugs
and cleanup uses of `default=[]`

Continued from b1bde57bef
1 year ago
LeoniePhiline c0cd13fb1c
[extractor/vimeo] Fix `playerConfig` extraction (#6203)
Authored by: bashonly, LeoniePhiline
Closes #6149
1 year ago
Ha Tien Loi f14c233348
[extractor/DouyuTV]: Use new API (#6074)
Authored by: hatienl0i261299
1 year ago
pukkandan 768a001781
[compat_utils] Simplify `EnhancedModule` 1 year ago
pukkandan acb1042a9f
[devscripts] Provide pyinstaller hooks
Closes #6185
1 year ago
Stefan Lobbenmeier f40e32fb1a
[extractor/servus] Rewrite extractor (#6036)
Closes #1076, closes #4240, closes #2748, closes #1045, closes #1498
Authored by: FrankZ85, Ashish0804, StefanLobbenmeier

Co-authored-by: FrankZ85 <43293037+FrankZ85@users.noreply.github.com>
1 year ago
bashonly e61acb40b2
[extractor/wrestleuniverse] Add extractors (#6158)
Authored by bashonly, Grub4K
Closes #6120

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
1 year ago
bashonly 7e68567e50
[downloader/hls] Allow extractors to provide AES key (#6158)
and related cleanup

Authored by: bashonly, Grub4K

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
1 year ago
JChris246 f7efe6dc95
[extractor/pornez] Handle relative URLs in iframe (#6171)
Authored by: JChris246
Closes #6162
1 year ago
Simon Sawicki b1bde57bef
[utils] `traverse_obj`: Fix several behavioral problems
See #6180 for further info

Authored by: Grub4K
1 year ago
pukkandan 88426d9446
[compat_utils] Improve `passthrough_module` 1 year ago
pukkandan f6a765ceb5
[dependencies] Standardize `Cryptodome` imports 1 year ago
pukkandan 754c84e2e4
Support module level `__bool__` and `property` 1 year ago
pukkandan 7aefd19afe
Make `title` completely non-fatal
Ref: https://github.com/yt-dlp/yt-dlp/pull/6158#discussion_r1096984349
1 year ago
Felix Yan fbbb5508ea
[extractor/huya] Support HD streams (#6172)
Authored by: felixonmars
1 year ago
OMEGA_RAZER c77df98b1a
[extractor/reddit] Support user posts (#6173)
Authored by: OMEGARAZER
1 year ago
Jeroen Jacobs d27bde9883
[extractor/GoPlay] Use new API (#6151)
Authored by: jeroenj
Closes #6032
1 year ago
sepro 0fe87a8730
[extractor/zdf] Use android API endpoint for UHD downloads (#6150)
Authored by: seproDev
1 year ago
Matumo 3b161265ad
[extractor/niconico] Add support for like history (#5705)
Authored by: Matumo, pukkandan
1 year ago
chio0hai 389896df85
[extractor/txxx] Add extractors (#5240)
Authored by: chio0hai
Closes #5021
1 year ago
pukkandan b032ff0f03
[extractor/youtube] Handle `consent.youtube` 1 year ago
pukkandan dad2210c0c
[extractor/youtube] Support `/live/` URL 1 year ago
Jasper Rebane 9cfdbcbf3f
[extractor/freesound] Workaround invalid URL in webpage (#6147)
Authored by: rebane2001
Closes #6146
1 year ago
lauren n. liberda 7543c9c99b
[extractor/twitter] Fix graphql extraction on some tweets (#6075)
Authored by: selfisekai
1 year ago
Simon Sawicki acacb57c7e [extractor/rumble] Fix format sorting
Closes #6119
Authored by: pukkandan
1 year ago
Simon Sawicki 776995bc10
[utils] `traverse_obj`: Various improvements
- Add `set` key for transformations/filters
- Add `re.Match` group names
- Fix behavior for `expected_type` with `dict` key
- Raise for filter function signature mismatch in debug

Authored by: Grub4K
1 year ago
pukkandan 8b008d6254
[jsinterp] Support `if` statements
Closes #6131
1 year ago
Lesmiscore 83c4970e52
[utils] Fix `time_seconds` to use the provided TZ (#6118)
Authored by: Lesmiscore, Grub4K

Fixes https://github.com/yt-dlp/yt-dlp/pull/6056
1 year ago
bashonly 8aa0bd5d10
[extractor/generic] Avoid catastrophic backtracking in KVS regex
Authored by: bashonly
1 year ago
Simon Sawicki 37e325b92f [utils] Use local kernel32 for file locking on Windows
Ref: https://github.com/ytdl-org/youtube-dl/issues/21545

Authored by: Grub4K
1 year ago
pukkandan 59d7de0da5
Fix `--concat-playlist`
Closes #6080
1 year ago
pukkandan 88d8928bf7
[plugins] Fix zip search paths
Closes #6011
1 year ago
bashonly 176a068cde
[extractor/nbc] Fix XML parsing
Python 3.7 compat bug in cb73b8460c
Authored by: bashonly
1 year ago
bashonly 5ab3534d44
[extractor/slideslive] Fix slides and chapters/duration (#6024)
* Fix slides/thumbnails extraction
* Extract duration to fix issues w/ `--embed-chapters`, `--split-chapters`
* Add `InfoExtractor._extract_mpd_vod_duration` method
* Expand applicability of `InfoExtractor._parse_m3u8_vod_duration` method
Authored by: bashonly
1 year ago
bashonly cb73b8460c
[extractor/nbc] Fix `NBC` and `NBCStations` extractors (#6033)
Improve `InfoExtractor._parse_smil_formats` extension detection
Closes #6019
Authored by: bashonly
1 year ago
bashonly 7481998b16
[extractor/drtv] Fix bug in ab4cbef (#6034)
Fixes bug in ab4cbef ab4cbeff00
Closes #5993
Authored by: bashonly
1 year ago
pukkandan 87ebab0615
[extractor/embedly] Embedded links may be for other extractors
Bug in bfd973ece3
Closes #5987
1 year ago
Marek Hudik 355d781bed
[extractor/rozhlas] Add extractor RozhlasVltavaIE (#5951)
Authored by: amra
1 year ago
github-actions 7287ab92f6 [version] update
Created by: pukkandan

:ci skip all :ci run dl
1 year ago
pukkandan 6becd2508c
Release 2023.01.06 1 year ago
pukkandan edfc7725b1
[cleanup] Misc 1 year ago
JChris246 b382c1fc6a
[xanimu] Add extractor (#5969)
Authored by: JChris246
Closes #5810
1 year ago
Christoph Flathmann 8a6b167723
[extractor/crunchyroll:show] Add `language` to entries (#5687)
Authored by: Chrissi2812
1 year ago
mzhou 253ac4ba6a
[extractor/youtube] Retry manifest refresh for live-from-start (#5670)
Avoids ending download early when live stream is temporarily offline.
Best used with somewhat large `--retry-sleep extractor:` and `--extractor-retries`

Authored by: mzhou
1 year ago
George Schizas 84e0e33a19
[extractor/reddit] Add subreddit as `channel_id` (#5685)
Authored by: gschizas
Closes #5684
1 year ago
Frederik Nordahl Jul Sabroe ab4cbeff00
[extractor/drtv] Add series extractors (#5644)
Authored by: FrederikNS
Closes #3567
1 year ago
Simon Sawicki 773c272d66
Fix config locations (#5933)
Bug in 8e40b9d1ec
Closes #5953

Authored by: Grub4k, coletdjnz, pukkandan
1 year ago
Jacob Truman c3366fdfd0
[extractor/nbc] Update graphql query (#5952)
Closes #5918
Authored by: jacobtruman
1 year ago
Simon Sawicki 5be214abed
[update] Fix updater file removal on windows (#5970)
Reverts 2fb0f85868
Closes #5632
Authored by: Grub4K
1 year ago
HobbyistDev d37422f1db
[extractor/biliIntl] Add fallback to `video_data` (#5971)
Authored by: HobbyistDev
1 year ago
JC-Chung 933ed882e9
[extractor/tiktok] Add `TikTokLive` extractor (#5637)
Closes #3698
Authored by: JC-Chung
1 year ago
HobbyistDev a1d9aca338
[extractor/aitube] Add extractor (#5946)
Closes #5627
Authored by: HobbyistDev
1 year ago
HobbyistDev 91d54e9b99
[extractor/volejtv] Add extractor (#5943)
Authored by: HobbyistDev
Closes #5883
1 year ago
HobbyistDev 76c3ceccfb
[extractor/biliintl] Add `/media` to `VALID_URL` (#5939)
Authored by: HobbyistDev
1 year ago
pukkandan ad68b16a1e
[downloader/aria2c] Disable native progress
Closes #5931, closes #5928, Re-opens #2038
1 year ago
pukkandan f079514957
[utils] `windows_enable_vt_mode`: Better error handling
Closes #5927
1 year ago
pukkandan e9df3d42c4
[build] Add minimal `pyproject.toml` 1 year ago
pukkandan d80ca5deaa
[utils] `mimetype2ext`: weba is not standard
Fix bug in fbb7383306, 2647c933b8
Closes #5935
1 year ago
OndrejBakan 1a3cd8ec35
[extractor/joj] Fix extractor (#5934)
Authored by: OndrejBakan, pukkandan
1 year ago
github-actions 990dd7b00f [version] update
Created by: pukkandan

:ci skip all :ci run dl
1 year ago
pukkandan d83b0ad809
Release 2023.01.02 1 year ago
pukkandan 08e29b9f1f
[cleanup] Misc
Closes #5576, closes #5887
1 year ago
pukkandan 8e174ba7de
[docs] Improvements
Closes #5846, closes #5774
1 year ago
bashonly 05997b6e98
[extractor/generic] Decode unicode-escaped embed URLs (#5919)
Authored by: bashonly
Closes #5854
1 year ago
Simon Sawicki 32a84bcf4e
Update to ytdl-commit-195f22f6
[generic] Improve KVS (etc) extraction
195f22f679

Closes #3716
Authored by: Grub4k, pukkandan
1 year ago
Matthew 8300774c4a
Add `--enable-file-urls` (#5917)
Closes https://github.com/yt-dlp/yt-dlp/issues/3675

Authored by: coletdjnz
1 year ago
bashonly d7f9871469
[extractor/iqiyi] Fix `Iq` JS regex (#5922)
Closes #5702
Authored by: bashonly
1 year ago
bashonly 13f930abc0
[extractor/fifa] Fix Preplay extraction (#5921)
Closes #5839
Authored by: dirkf
1 year ago
bashonly b23b503e22
[extractor/odnoklassniki] Extract subtitles (#5920)
Closes #5744
Authored by: bashonly
1 year ago
Matthew e756f45ba0
Improve handling for overriding extractors with plugins (#5916)
* Extractors replaced with plugin extractors now show in debug output
* Better testcase handling
* Added documentation
Authored by: coletdjnz, pukkandan
1 year ago
Lesmiscore 8c53322cda
[downloader/aria2c] Native progress for aria2c via RPC (#3724)
Authored by: Lesmiscore, pukkandan

Closes #2038
1 year ago
pukkandan 193fb150b7
Fix bug in 119e40ef64 1 year ago
pukkandan 26fdfc3704
[extractor/biliintl:series] Make partial download of series faster 1 year ago
pukkandan 78d25e0b7c
[extractor/embedly] Handle vimeo embeds
Closes #3360
1 year ago
pukkandan 2a06bb4eb6
Add `--compat-options 2021,2022`
Use these to guard against future compat changes. This allows devs to
change defaults and make other potentially breaking changes more easily.
If you need everything to work exactly as-is, put this in your config
1 year ago
pukkandan 88fb942577
Add message when there are no subtitles/thumbnails
Closes #5551
1 year ago
pukkandan 1cdda32998
[utils] `get_exe_version`: Detect broken executables
Authored by: dirkf, pukkandan
Closes #5561
1 year ago
coletdjnz 3e01ce744a
[extractor/generic] Use `Accept-Encoding: identity` for initial request
The existing comment seems to imply this was the desired behavior from the beginning.

Partial fix for https://github.com/yt-dlp/yt-dlp/issues/5855, https://github.com/yt-dlp/yt-dlp/issues/5851, https://github.com/yt-dlp/yt-dlp/issues/4748
1 year ago
Matthew 8e40b9d1ec
Improve plugin architecture (#5553)
to make plugins easier to develop and use:
* Plugins are now loaded as namespace packages.
* Plugins can be loaded in any distribution of yt-dlp (binary, pip, source, etc.).
* Plugin packages can be installed and managed via pip, or dropped into any of the documented locations.
* Users do not need to edit any code files to install plugins.
* Backwards-compatible with previous plugin architecture.

As a side-effect, yt-dlp will now search in a few more locations for config files.

Closes https://github.com/yt-dlp/yt-dlp/issues/1389

Authored by: flashdagger, coletdjnz, pukkandan, Grub4K
Co-authored-by: Marcel <flashdagger@googlemail.com>
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
Co-authored-by: Simon Sawicki <accounts@grub4k.xyz>
1 year ago
pukkandan 2fb0f85868
[update] Workaround #5632 1 year ago
Stel Abrego a0e526ed4d
[extractor/bandcamp] Add `album_artist` (#5537)
Closes #5536 
Authored by: stelcodes
1 year ago
pukkandan 8d1ddb0805
[extractor/udemy] Fix lectures that have no URL and detect DRM
Closes #5662
1 year ago
pukkandan 9bb856998b
[extractor/youtube] Extract DRC formats 1 year ago
pukkandan fbb7383306
Add `weba` to known extensions 1 year ago
pukkandan ec54bd43f3
Fix bug in writing playlist info-json
Closes #4889
1 year ago
pukkandan f74371a97d
[extractor/bilibili] Fix `--no-playlist` for anthology
Closes #5797
1 year ago
ChillingPepper d5f043d127
[utils] js_to_json: Fix bug in f55523c (#5771)
Authored by: ChillingPepper, pukkandan
1 year ago
pukkandan fe74d5b592
Let `--parse/replace-in-metadata` run at any post-processing stage
Closes #5808, #456
1 year ago
pukkandan 119e40ef64
Add pre-processor stage `video`
Related: #456, #5808
1 year ago
pukkandan 4455918e7f
[extractor/stv] Detect DRM
Closes #5320
1 year ago
Anant Murmu efa944f4bc
[cleanup] Use `random.choices` (#5800)
Authored by: freezboltz
1 year ago
nosoop e107c2b8cf
[extractor/soundcloud] Support user permalink (#5842)
Closes #5841
Authored by: nosoop
1 year ago
Lesmiscore ca2f6e14e6
[extractor/BiliLive] Fix extractor
- Remove unnecessary group in `_VALID_URL`
- This extractor always returns livestreams
1 year ago
bashonly c1edb853b0
[extractor/kick] Add extractor (#5736)
Closes #5722
Authored by: bashonly
1 year ago
bashonly 2647c933b8
[extractor/wistia] Improve extension detection (#5415)
Closes #5053
Authored by: bashonly, Grub4k, pukkandan
1 year ago
bashonly 53006b35ea
[extractor/amazon] Add `AmazonReviews` extractor (#5857)
Closes #5766
Authored by: bashonly
1 year ago
bashonly 4b183d4962
[extractor/videoken] Add extractors (#5824)
Closes #5818
Authored by: bashonly
1 year ago
bashonly 3d667e0047
[extractor/slideslive] Support embeds and slides (#5784)
Authored by: bashonly, Grub4K, pukkandan
1 year ago
Sam 9a9006ba20
[extractor/twitcasting] Fix videos with password (#5894)
Closes #5888
Authored by: bashonly, Spicadox
1 year ago
HobbyistDev 153e88a751
[extractor/netverse] Add `NetverseSearch` extractor (#5838)
Authored by: HobbyistDev
1 year ago
JChris246 9fcd8ad1f2
[extractor/spankbang] Fix extractor (#5791)
Authored by: JChris246
Closes #5731
1 year ago
monnef 6b71d186dd
[extractor/curiositystream] Fix auth (#5730)
Authored by: mnn
1 year ago
lkw123 074b2fae90
[extractor/kankanews] Add extractor (#5729)
Authored by: synthpop123
1 year ago
Kurt Bestor 06a9d68eb8
[extractor/youku] Fix extractor (#5622)
Closes #4456
Authored by: KurtBestor
1 year ago
Damiano Amatruda a4d6ead30f
[extractor/ciscowebex] Support password-protected videos (#5601)
Authored by: damianoamatruda
1 year ago
lauren n. liberda d1b5f3d79c
[extractor/polskieradio] Adapt to next.js redesigns (#5416)
Authored by: selfisekai
1 year ago
lauren n. liberda da8d2de208
[extractor/cda] Support premium and misc improvements (#5529)
* Fix cache for non-ASCII key
* Improve error messages
* Better UA for fingerprint bypass

Authored by: selfisekai
1 year ago
chris 15e9e578c0
[extractor/ArteTV] Extract chapters (#5879)
Authored by: iw0nderhow, bashonly
1 year ago
Bobscorn 0ef3d47027
[extractor/beatbump] Add extractors (#5304)
Authored by: Bobscorn, pukkandan
Closes #4653
1 year ago
barsnick 247c8dd4f5
[extractor/urplay] Support for audio-only formats (#4606)
Closes #4605
Authored by: barsnick
1 year ago
HobbyistDev 032f22020c
[extractor/trtcocuk] Add extractor (#5009)
Closes #2635
Authored by: HobbyistDev
1 year ago
pukkandan 4af47a0003
Fix 9012d20b23 1 year ago
pukkandan 9012d20b23
[extractor/mixch] Support `--wait-for-video` 1 year ago
Giulio Muscarello d61ef7f343
[extractor/ARD] Add vtt subtitles (#5835)
Authored by: CapacitorSet
1 year ago
skbeh 1c226ccdd4
[extractor/bilibili] Improve `_VALID_URL` (#5820)
Authored by: skbeh
1 year ago
pukkandan 8791e78ccc
Fix `original_url` in playlists 1 year ago
pukkandan 69f5fe45b9
[FFmpegVideoConvertor] Add `gif` to `--recode-video` 1 year ago
pukkandan 0b5546c723
[extractor] Let `_extract_format` functions obey `--ignore-no-formats` 1 year ago
bashonly 1fc089143c
[extractor/reddit] Extract crossposted media (#5801)
Closes #5798
Authored by: bashonly
1 year ago
Lesmiscore 5424dbaf91
Deprioritize HEVC-over-FLV formats (#5823)
Authored by: Lesmiscore
1 year ago
Matthew c733555106
[extractor/youtube:tab] Extract metadata from channel items (#5569)
Authored by: coletdjnz
1 year ago
HobbyistDev 81388c0954
[extractor/oneplace] Add OnePlacePodcast extractor (#5549)
Closes #5543
Authored by: HobbyistDev
1 year ago
Denis df10bad267
[extractor/rutube] Support private videos (#5761)
Authored by: mexus
1 year ago
HobbyistDev f0f3fa028b
[extractor/netverse] Extract comments (#5568)
Authored by: HobbyistDev
1 year ago
HobbyistDev 22697a84f6
[extractor/europarl] Add EuroParlWebstream Extractor (#5547)
Authored by: HobbyistDev
Closes #4933
1 year ago
HobbyistDev 3ac5476430
[extractor/nosnl] Add support for /video (#5590)
Authored by: HobbyistDev
1 year ago
HobbyistDev e318b5b87a
[extractor/airtv] Add extractor (#5533)
Authored by: HobbyistDev
Closes #5132
1 year ago
bashonly f549b18512
[extractor/pinterest] Fix extractor (#5739)
Closes #1772
Authored by: bashonly
1 year ago
bashonly 7c5e1701f6
[extractor/foxsports] Fix extractor (#5719)
Closes #5714
Authored by: bashonly
1 year ago
bashonly 16bed382fd
[extractor/twitter] Heed `--no-playlist` for multi-video tweets (#5757)
Closes #5752
Authored by: bashonly, Grub4K
1 year ago
bashonly 3cf50fa8e9
[downloader/ffmpeg] Fix headers for video+audio formats (#5659)
Authored by: bashonly, Grub4K
1 year ago
bashonly f69b0554eb
[extractor/slideslive] Fix extractor (#5737)
Closes #1532
Authored by: bashonly, Grub4K
1 year ago
pukkandan e74a3c6dcc
[extractor/hotstar] Improve format metadata 1 year ago
pukkandan 7108221662
Add `ac4` to known codecs
Note: ffmpeg does not currently support this format

Related #5738
1 year ago
nixxo 10dc85924a
[extractor/mediaset] Better embed detection and error messages (#5664)
Authored by: nixxo
1 year ago
Vita b05f0a50e0
[extractor/yle_areena] Support restricted videos (#5735)
* and improve metadata

Closes #5734
Authored by: docbender
1 year ago
Elyse 3d79ebc8b7
[extractor/mediastream] Add extractor (#5640)
Closes #5532, closes #4431, closes #4425
Authored by: elyse0, HobbyistDev

Co-authored-by: HobbyistDev <tesutonihon4@gmail.com>
1 year ago
pukkandan b44cd29851
[jsinterp] Escape regex that looks like nested set
Closes #5749
1 year ago
milkknife 85a802969e
[extractor/webcamerapl] Add extractor (#5715)
Authored by: milkknife
1 year ago
nixxo 72f96c5566
[extractor/la7] Improve extractor (#5538)
Authored by: nixxo
Closes #5360
1 year ago
MMM 839e2a62ae
[extractor/rumble] Add RumbleIE extractor (#5515)
Closes #2846
Authored by: flashdagger
1 year ago
HobbyistDev 28b8f57b4b
[extractor/noice] Add NoicePodcast extractor (#5621)
Authored by: HobbyistDev
1 year ago
lkw123 dfc186d422
[extractor/xiami] Remove extractors (#5711)
Authored by: synthpop123
1 year ago
David Turner 42ec478fc4
[extractor/plutotv] Fix videos with non-zero start (#5745)
Authored by: digitall
1 year ago
pukkandan 7991ae57a8
[extractor/sibnet] Separate from VKIE
Fixes bfd973ece3 (commitcomment-91834251)
1 year ago
pukkandan 935bac1e4d
Fix `--cookies-from-browser` CLI parsing
Closes #5716
1 year ago
bashonly c4cbd3bebd
[extractor/tiktok] Update `_VALID_URL`, add `api_hostname` arg (#5708)
Closes #5706
Authored by: bashonly
1 year ago
pukkandan c53a18f016
[utils] windows_enable_vt_mode: Proper implementation
Authored by: Grub4K
1 year ago
pukkandan 71df9b7fd5
[cleanup] Misc 1 year ago
Benjamin Ryan c9f5ce5118
[extractor/tiktok] Update API hostname (#5690)
Closes #5688
Authored by: redraskal
1 year ago
bashonly ddf1e22d48
[extractor/swearnet] Fix description bug (#5681)
Bug in 049565df2e
Closes #5643
Authoried by: bashonly
1 year ago
bashonly 0e96b408b9
[extractor/reddit] Extract video embeds in text posts (#5677)
Closes #5612
Authored by: bashonly
1 year ago
bashonly ba72399723
[extractor/tiktok] Fix subs, `DouyinIE`, improve `_VALID_URL` (#5676)
Closes #5665, Closes #2267
Authored by: bashonly
1 year ago
pukkandan 9bcfe33be7
[utils] Make `ExtractorError` mutable 1 year ago
pukkandan 71eb82d1b2
[extractor/youtube] Subtitles cannot be translated to `und`
Closes #5674
1 year ago
pukkandan a9d069f5b8
[extractor/amazonminitv] Cleanup 48652590ec 1 year ago
alexia 48652590ec
[extractor/amazonminitv] Add extractors (#3628)
Authored by: nyuszika7h, GautamMKGarg
1 year ago
marieell 86f557b636
[extractor/youporn] Fix metadata (#2768)
Authored by: marieell
1 year ago
pukkandan c0caa80515
[extractor/naver] Treat fan subtitles as separate language
Closes #5467
1 year ago
Mudassir Chapra 0d95d8b00a
[extractor/gronkh] Fix `_VALID_URL` (#5628)
Closes #5531
Authored by: muddi900
1 year ago
Elan Ruusamäe 9d52bf65ff
[extractor/kanal2] Add extractor (#5575)
Authored by: glensc, pukkandan, bashonly
2 years ago
bashonly d761dfd059
[extractor/naver] Improve `_VALID_URL` for `NaverNowIE` (#5620)
Authored by: bashonly
2 years ago
bashonly 27c0f899c8
[extractor/screencastify] Add extractor (#5604)
Closes #5603
Authored by: bashonly
2 years ago
bashonly 7ff2fafe47
[extractor/vimeo] Add `VimeoProIE` (#5596)
* Add support for VimeoPro URLs not containing a Vimeo video ID
* Add support for password-protected VimeoPro pages
Closes #5594
Authored by: bashonly, pukkandan
2 years ago
bashonly 3b021eacef
[extractor/generic] Add `fragment_query` extractor arg for DASH and HLS (#5528)
* `fragment_query`: passthrough any query in generic mpd/m3u8 manifest URLs to their fragments
* Add support for `extra_param_to_segment_url` to DASH downloader
Authored by: bashonly, pukkandan
2 years ago
Marcel f352a09778
[webvtt] Handle premature EOF
Closes #2867, closes #5600
Authored by: flashdagger
2 years ago
chengzhicn 02b2f9fa7d
[extractor/reddit] Add vcodec to fallback format (#5591)
Authored by: chengzhicn
2 years ago
pukkandan 29ca408219
[FormatSort] Add `mov` to `vext`
Closes #5581
2 years ago
pukkandan 8486540257
[extractor/unsupported] Add more URLs
Closes #5557, Closes #2744, Closes #5578
2 years ago
bashonly ed027fd9d8
[extractor/generic] Fix JSON LD manifest extraction (#5577)
Closes #5572
Authored by: bashonly, pukkandan
2 years ago
bashonly 352e7d9873
[extractor/twitter] Refresh guest token when expired (#5560)
Closes #5548
Authored by: bashonly, Grub4K
2 years ago
nixxo 9a0416c6a5
[extractor/twitter:spaces] Add 'Referer' to m3u8 (#5580)
Closes #5565
Authored by: nixxo
2 years ago
bashonly f5a9e9df0d
[extractor/brightcove] Add `BrightcoveNewBaseIE` and fix embed extraction (#5558)
* Move Brightcove embed extraction and tests into the IEs
* Split `BrightcoveNewBaseIE` from `BrightcoveNewIE`
* Fix bug in ade1fa70cb with the "wrong" spelling of `referrer` being smuggled

Closes #5539
2 years ago
bashonly f96a3fb7d3
[extractor/redgifs] Fix bug in 8c188d5d09 (#5559) 2 years ago
Bnyro bc87dac75f
[extractor/youtube] Add `piped.video` (#5571)
Closes #5518
Authored by: Bnyro
2 years ago
pukkandan 9f14daf22b
[extractor] Deprecate `_sort_formats` 2 years ago
pukkandan 784320c98c
Implement universal format sorting
Closes #5566
2 years ago
pukkandan d0d74b7197
[utils] Move format sorting code into `utils` 2 years ago
pukkandan 64c464a144
[utils] Move `FileDownloader.parse_bytes` into utils 2 years ago
pukkandan 4de88a6a36
[extractor/generic] Don't report redirect to https 2 years ago
pukkandan 105bfd90f5
Add new field `aspect_ratio`
Closes #5402
2 years ago
pukkandan 6368e2e639
[cleanup] Misc
Closes #5541
2 years ago
pukkandan a4894d3e25
[extractor/youtube] Consider language in format de-duplication 2 years ago
pukkandan d7b460d0e5
Make early reject of `--match-filter` stricter
Closes #5509
2 years ago
pukkandan 171a31dbe8
[extractor] Add a way to distinguish IEs that returns only videos 2 years ago
pukkandan 83cc7b8aae
[utils] `classproperty`: Add cache support 2 years ago
Elyse 0a4b2f4180
[extractor/tencent] Fix geo-restricted video (#5505)
Closes #5230
Authored by: elyse0
2 years ago
pukkandan a8c754cc00
[extractor/youtube] Fix bug in handling of music URLs
Bug in bd7e919a75
Closes #5502
2 years ago
pukkandan bc5c2f8a2c
Fix bugs in `PlaylistEntries` 2 years ago
Audrey d965856235
[extractor/Veoh] Add user extractor (#5242)
Authored by: tntmod54321
2 years ago
pukkandan 08270da5c3
[extractor/youtube] Fix `ytuser:` 2 years ago
github-actions 5e39fb982e [version] update
Created by: pukkandan

:ci skip all :ci run dl
2 years ago
pukkandan 8b644025b1
Release 2022.11.11 2 years ago
Robert Geislinger 7aaf4cd2a8
[cleanup] Misc
Closes #5471, Closes #5312

Authored by: pukkandan, Alienmaster
2 years ago
pukkandan 8522226d2f
[ThumbnailsConvertor] Fix filename escaping
Closes #4604
Authored by: pukkandan, dirkf
2 years ago
Vitaly Khabarov f4b2c59cfe
[extractor/YleAreena] Add extractor (#5270)
Closes #2508
Authored by: vitkhab, pukkandan
2 years ago
Timendum 7c8c63529e
[extractor/cinetecamilano] Add extractor (#5279)
Closes #5031
Authored by: timendum
2 years ago
bashonly e4221b700f
Fix `--list` options not implying `-s` in some cases (#5296)
Authored by: bashonly, Grub4K
2 years ago
pukkandan bd7e919a75
[extractor/youtube:tab] Improvements to tab handling (#5487)
* Better handling of direct channel URLs - See https://github.com/yt-dlp/yt-dlp/pull/5439#issuecomment-1309322019
* Prioritize tab id from URL slug - Closes #5486
* Add metadata for the wrapping playlist
* Simplify redirect for music playlists
2 years ago
pukkandan f7fc8d39e9
[extractor] Fix `fatal=False` for `_search_nuxt_data`
Closes #5423
2 years ago
mlampe a6858cda29
[build] Make linux binary truly standalone using `conda` (#5423)
Authored by: mlampe
2 years ago
MrOctopus 17fc3dc48a
[build] Create armv7l and aarch64 releases (#5449)
Closes #5436
Authored by: MrOctopus, pukkandan
2 years ago
Matthew 3f5c216969
[extractor/nzherald] Support new video embed (#5493)
Authored by: coletdjnz
2 years ago
Matthew e72e48c53f
[extractor/youtube] Ignore incomplete data error for comment replies (#5490)
When --ignore-errors is used.
Closes https://github.com/yt-dlp/yt-dlp/issues/4669
Authored by: coletdjnz
2 years ago
Matthew 0cf643b234
[extractor/youtube] Differentiate between no and disabled comments (#5491)
`comments` and `comment_count` will be set to None, as opposed to 
an empty list and 0, respectively.

Fixes https://github.com/yt-dlp/yt-dlp/issues/5068

Authored by: coletdjnz, pukkandan
2 years ago
Sergey dc3028d233
[build] `py2exe`: Migrate to freeze API (#5149)
Closes #5135
Authored by: SG5, pukkandan
2 years ago
Matthew 4dc23a8051
[extractor/youtube:tab] Fix video metadata from tabs (#5489)
Closes #5488
Authored by: coletdjnz
2 years ago
pukkandan 495322b95b
[test] Allow `extract_flat` in download tests
Authored by: coletdjnz, pukkandan
2 years ago
Alex c789fb7787
[build, test] Harden workflows' security (#5410)
Authored by: sashashura
2 years ago
pukkandan ed6bec168d
[extractor/doodstream] Remove extractor
It was added in youtube-dlc, likely without sufficient scrutiny

Closes #3808, Closes #5251, Closes #5403
2 years ago
MMM 0d8affc17f
[extractor/rumble] Add HLS formats and extract more metadata (#5280)
Closes #5177, #5277 
Authored by: flashdagger
2 years ago
Matthew d9df9b4919
[extractor/unsupported] Raise error on known DRM-only sites (#5483)
Authored by: coletdjnz
2 years ago
MMM efdc45a6ea
[extractor/bitchute] Better error for geo-restricted videos (#5474)
Authored by: flashdagger
2 years ago
Matthew 86973308cd
[extractor/youtube:tab] Update tab handling for redesign (#5439)
Closes #5432, #5430, #5419
Authored by: coletdjnz, pukkandan
2 years ago
MMM c61473c1d6
[extractor/bitchute] Improve `BitChuteChannelIE` (#5066)
Authored by: flashdagger, pukkandan
2 years ago
zulaport 8fddc232bf
[extractor/camsoda] Add extractor (#5465)
Authored by: zulaport
2 years ago
pukkandan fad689c7b6
[extractor/hotstar] Refactor v1 API calls 2 years ago
m4tu4g db6fa6960c
[extractor/hotstar] Add season support (#5479)
Closes #5473
Authored by: m4tu4g
2 years ago
Anant Murmu 3b87f4d943
[extractor/stripchat] Improve error message (#5475)
Authored by: freezboltz
2 years ago
pukkandan 581e86b512
[extractor/uktvplay] Fix `_VALID_URL`
Closes #5472
2 years ago
megapro17 8196182a12
[extractor/odnoklassniki] Support boosty.to embeds (#5105)
Closes #4212
Authored by: megapro17, Lesmiscore, pukkandan
2 years ago
m4tu4g 9b383177c9
[extractor/mxplayer] Improve extractor (#5303)
Closes #5276
Authored by: m4tu4g
2 years ago
ClosedPort22 fbb0ee7747
[compat] Fix `shutils.move` in restricted ACL mode on BSD (#5309)
Authored by: ClosedPort22, pukkandan
2 years ago
Lesmiscore c7e4ab278a
[extractor/niconico] Always use HTTPS for requests
This prevents MITM attacks from malicious parties like insane ISPs

Closes #5469
2 years ago
pukkandan e9ce4e9250
[extractor/foxnews] Add `FoxNewsVideo` extractor
Closes #5133
2 years ago
pukkandan 5da08bde9e
[extractor/vlive] Extract `release_timestamp`
Closes #5424
2 years ago
pukkandan ff48fc04d0
[update] Use error code 100 for update errors
This error code was previously used for
"Exiting to finish update", but is no longer used

Closes #5198
2 years ago
pukkandan 46d09f8707
[cleanup] Lint and misc cleanup 2 years ago
pukkandan db4678e448
Update to ytdl-commit-de39d128
[extractor/ceskatelevize] Back-port extractor from yt-dlp
de39d1281c

Closes #5361, Closes #4634, Closes #5210
2 years ago
zulaport a349d4d641
[extractor/stripchat] Fix hostname for HLS stream (#5445)
Closes #5227 
Authored by: zulaport
2 years ago
Matthew ac8e69dd32
Do not backport Python 3.10 SSL configuration for LibreSSL (#5464)
Until further investigation.

Fixes regression in 5b9f253fa0

Authored by: coletdjnz
2 years ago
bashonly 96b9e9cf62
[extractor/telegram] Add playlist support and more metadata (#5358)
Authored by: bashonly, bsun0000
2 years ago
Jeff Huffman cb1553e966
[extractor/crunchyroll] Beta is now the only layout (#5294)
Closes #5292
Authored by: tejing1
2 years ago
Alex Karabanov 0d2a0ecac3
[extractor/listennotes] Add extractor (#5310)
Closes #5262
Authored by: lksj, pukkandan
2 years ago
changren-wcr c94df4d19d
[extractor/qingting] Add extractor (#5329)
Closes #5323
Authored by: changren-wcr, bashonly
2 years ago
lauren 728f4b5c2e
[extractor/tvp] Update extractors (#5346)
Closes #5328
Authored by: selfisekai
2 years ago
Kevin Wood 8c188d5d09
[extractor/redgifs] Refresh auth token for 401 (#5352)
Closes #5351
Authored by: endotronic, pukkandan
2 years ago
Bruno Guerreiro e14ea7fbd9
[extractor/youtube] Update piped instances (#5441)
Closes #5286
Authored by: Generator
2 years ago
Richard Gibson 7053aa3a48
[extractor/epoch] Support videos without data-trailer (#5387)
Closes #5359
Authored by: gibson042, pukkandan
2 years ago
HobbyistDev 049565df2e
[extractor/swearnet] Add extractor (#5371)
Authored by: HobbyistDev
2 years ago
CrankDatSouljaBoy cc1d3bf96b
[extractor/deuxm] Add extractors (#5388)
Authored by: CrankDatSouljaBoy
2 years ago
Matthew 5b9f253fa0
Backport SSL configuration from Python 3.10 (#5437)
Partial fix for https://github.com/yt-dlp/yt-dlp/pull/5294#issuecomment-1289363572, https://github.com/yt-dlp/yt-dlp/issues/4627

Authored by: coletdjnz
2 years ago
nixxo d715b0e413
[extractor/skyit] Fix extractors (#5442)
Closes #5392
Authored by: nixxo
2 years ago
Matthew 6141346d18
[extractor/youtube] Update playlist metadata extraction for new layout (#5376)
Fixes https://github.com/yt-dlp/yt-dlp/issues/5373

Authored by: coletdjnz
2 years ago
MMM 59a0c35865
[extractor/lbry] Authenticate with cookies (#5435)
Closes #5431
Authored by: flashdagger
2 years ago
Lesmiscore da9a60ca0d
[extractor/twitcasting] Fix `data-movie-playlist` extraction (#5453)
Authored by: Lesmiscore
2 years ago
sam 0d113603ac
[extractor/oftv] Add extractors (#5134)
Closes #5017
Authored by: DoubleCouponDay
2 years ago
pukkandan 2e30b46fe4
[extractor/youtube] Improve chapter parsing from description
Closes #5448
2 years ago
bashonly 68a9a450d4
[extractor/genius] Add extractors (#5221)
Closes #5209
Authored by: bashonly
2 years ago
sam ed13a772d7
[extractor/bbc] Support onion domains (#5211)
Authored by: DoubleCouponDay
2 years ago
lauren 78545664bf
[extractor/agora] Add extractors (#5101)
Authored by: selfisekai
2 years ago
pukkandan f72218c199
[extractor/bitchute] Simplify extractor (#5066)
* Check alternate domains when a URL does not work
* Obey `--no-check-formats`
* Remove webseeds (doesnt seem to exist anymore)

Authored by: flashdagger, pukkandan

Co-authored-by: Marcel <flashdagger@googlemail.com>
2 years ago
James Woglom 58fb927ebd
[kaltura] Support playlists (#4986)
Authored by: jwoglom, pukkandan
2 years ago
pukkandan 62b8dac490
[extractor] Improve `_generic_title` 2 years ago
Lesmiscore 682b4524bf
[extractor/japandiet] Add extractors (#5368)
Authored by: Lesmiscore
2 years ago
nosoop 9da6612b0f
[extractor/youtube] Fix `duration` for premieres (#5382)
Closes #5378
Authored by: nosoop
2 years ago
coletdjnz e63faa101c
[extractor/youtube] Fix `live_status` extraction for playlist videos
Regression in 867c66ff97

Authored by: coletdjnz
2 years ago
pukkandan 497074f044
Write API params in debug head 2 years ago
pukkandan c90c5b9bdd
[extractor/bilibili] Add chapters and misc cleanup (#4221)
Authored by: lockmatrix, pukkandan
2 years ago
Locke ad97487606
[extractor/bilibili] Fix BilibiliIE and Bangumi extractors (#4945)
Closes #1878, #4071, #4397
Authored by: lockmatrix, pukkandan
2 years ago
HobbyistDev e091fb92da
[extractor/mlb] Add `MLBArticle` extractor (#4832)
Closes #3475
Authored by: HobbyistDev
2 years ago
Alex Karabanov c9bd65185c
[extractor/zenyandex] Fix extractors (#3750, #5268)
Closes #3736
Authored by:  lksj, puc9, pukkandan

Co-authored-by: puc9 <51006296+puc9@users.noreply.github.com>
2 years ago
bashonly c66ed4e2e5
[extractor/americastestkitchen] Fix extractor (#5343)
Fix `_VALID_URL` and season extraction

Closes #5343
Authored by: bashonly
2 years ago
pukkandan 2530b68d44
[extractor/iprima] Make json+ld non-fatal
Closes #5318

Authored by: bashonly
2 years ago
Lesmiscore 7d61d2306e
[build] Replace `set-output` with `GITHUB_OUTPUT` (#5315)
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/

Authored by: Lesmiscore
2 years ago
m4tu4g 385adffcf5
[extractor/zee5] Improve `_VALID_URL` (#5316)
Authored by: m4tu4g
2 years ago
pukkandan 0c908911f9
[extractor/redgifs] Fix extractors
Superseeds f47cf86eff

Closes #5311

Authored by: bashonly
2 years ago
m4tu4g c13a301a94
[extractor/zeenews] Add extractor (#5289)
Closes #4967 
Authored by: m4tu4g, pukkandan
2 years ago
pukkandan f47cf86eff
[extractor/redgifs] Fix extractors
Closes #5202, closes #5216
2 years ago
Simon Sawicki 7a26ce2641
[extractor/twitter] Add Spaces extractor and GraphQL API (#5247, #4864)
Closes #1605, Closes #5233, Closes #1249

Authored by: Grub4K, nixxo, bashonly, pukkandan

Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
Co-authored-by: nixxo <nixxo@protonmail.com>
2 years ago
bashonly 3639df54c3
[extractor/paramountplus] Update API token (#5285)
Closes #5273
Authored by: bashonly
2 years ago
Anant Murmu a4713ba96d
[extractor/voot] Improve `_VALID_URL` (#5283)
Authored by: freezboltz
2 years ago
bsun0000 5318156f1c
[extractor/youtube] Mark videos as fully watched
Closes #2555
Authored by: bsun0000
2 years ago
pukkandan d5d1df8afd
[cleanup Misc
Closes #5162
2 years ago
pukkandan cd5df121f3
[SponsorBlock] Relax duration check for large segments 2 years ago
jahway603 73ac0e6b85
[docs, devscripts] Document `pyinst`'s argument passthrough (#5235)
Closes #4631
Authored by: jahway603
2 years ago
pukkandan a7ddbc0475
[ModifyChapters] Handle the entire video being marked for removal
Closes #5238
2 years ago
pukkandan 8fab23301c
[SponsorBlock] Obey `--retry-sleep extractor` 2 years ago
pukkandan 1338ae3ba3
[SponsorBlock] Add `type` field 2 years ago
Ajay Ramachandran 63c547d71c
[SponsorBlock] Support `chapter` category (#5260)
Authored by: ajayyy, pukkandan
2 years ago
pukkandan 814bba3933
[downloader/fragment] HLS download can continue without first fragment
Closes #5274
2 years ago
cruel-efficiency 2576d53a31
Fix end time of clips (#5255)
Closes #5256
Authored by: cruel-efficiency
2 years ago
Matthew 217753f4aa
[extractor/YoutubeWebArchive] Improve metadata extraction (#4968)
Closes https://github.com/yt-dlp/yt-dlp/issues/4574

Authored by: coletdjnz
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
2 years ago
Vitaly Khabarov 42a44f01c3
[extractor/Fox] Extract thumbnail (#5243)
Closes #1679
Authored by: vitkhab
2 years ago
pukkandan 9b9dad119a
[outtmpl] Ensure ASCII in json and add option for Unicode
Closes #5236
2 years ago
Matthew 6dca2aa66d
[extractor/generic:quoted-html] Add extractor (#5213)
Extracts embeds from escaped HTML within `data-html` attribute.
Related: https://github.com/ytdl-org/youtube-dl/issues/21294, https://github.com/yt-dlp/yt-dlp/pull/5121

Authored by: coletdjnz
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
2 years ago
pukkandan 6678a4f0b3
[extractor/youtube] Fix live_status
Bug in 4d37720a0c
2 years ago
pukkandan d51b2816e3
[extractor/iq] Increase phantomjs timeout
Closes #5161
2 years ago
lauren 34f00179db
[extractor/cda]: Support login through API (#5100)
Authored by: selfisekai
2 years ago
pukkandan 5225df50cf
[extractor/youtube:tab] Let `approximate_date` return timestamp 2 years ago
pukkandan 94dc8604dd
Do more processing in `--flat-playlist` 2 years ago
Simon Sawicki a71b812f53
[utils] `js_to_json`: Improve escape handling (#5217)
Authored by: Grub4K
2 years ago
sam c6989aa3ae
[extractor/aeon] Add extractor (#5205)
Closes #1653
Authored by: DoubleCouponDay
2 years ago
pukkandan a79bf78397
[extractor/tnaflix] Fix 09c127ff83
Closes #5188
2 years ago
sam 82fb2357d9
[extractor/twitter] Add onion site to `_VALID_URL` (#5208)
See #3053
Authored by: DoubleCouponDay
2 years ago
Simon Sawicki 13b2ae29c2
[extractor/twitter] Support multi-video posts (#5183)
Closes #5157, Closes #5147
Authored by: Grub4K
2 years ago
Simon Sawicki 36069409ec
[cookies] Improve `LenientSimpleCookie` (#5195)
Closes #5186 
Authored by: Grub4K
2 years ago
pukkandan 0468a3b325
[jsinterp] Improve separating regex
Fixes https://github.com/yt-dlp/yt-dlp/issues/4635#issuecomment-1273974909
2 years ago
pukkandan d509c1f5a3
[utils] `strftime_or_none`: Workaround Python bug on Windows
CLoses #5185
2 years ago
schnusch 2c98d99818
[extractors/podbayfm] Add extractor (#4971)
Authored by: schnusch
2 years ago
bashonly 226c0f3a54
[extractor/sbs] Improve `_VALID_URL` (#5193)
Closes #5045
Authored by: bashonly
2 years ago
pukkandan ade1fa70cb
[extractor/generic] Separate embed extraction into own function (#5176) 2 years ago
Matthew 4c9a1a3ba5
[extractor/wordpress:mb.miniAudioPlayer] Add embed extractor (#5087)
Closes https://github.com/yt-dlp/yt-dlp/issues/4994

Authored by: coletdjnz
2 years ago
Simon Sawicki 1d55ebabc9
[extractor/common] Fix `json_ld` type checks (#5145)
Closes #5144, #5143
Authored by: Grub4K
2 years ago
tkgmomosheep f324fe8c59
[extractor/viu] Support subtitles of on-screen text (#5173)
Authored by: tkgmomosheep
2 years ago
HobbyistDev 866f037344
[extractor/nos.nl] Add extractor (#4822)
Closes #4649
Authored by: HobbyistDev
2 years ago
Marenga 5d14b73491
[VK] Fix playlist URLs (#4930)
Closes #2825
Authored by: the-marenga
2 years ago
Teemu Ikonen 540236ce11
[extractor/screen9] Add extractor (#5137)
Authored by: tpikonen
2 years ago
Simon Sawicki 7b0127e1e1
[utils] `traverse_obj`: Allow `re.Match` objects (#5174)
Authored by: Grub4K
2 years ago
Simon Sawicki f99bbfc983
[utils] `traverse_obj`: Always return list when branching (#5170)
Fixes #5162
Authored by: Grub4K
2 years ago
bashonly 3b55aaac59
[extractor/tubitv] Better DRM detection (#5171)
Closes #5128
Authored by: bashonly
2 years ago
bashonly 2e565f5bca
[extractor/reddit] Add fallback format (#5165)
Closes #5160
Authored by: bashonly
2 years ago
Noah e02e6d86db
[embedthumbnail] Fix thumbnail name in mp3 (#5163)
Authored by: How-Bout-No
2 years ago
Matthew 867c66ff97
[extractor/youtube] Extract concurrent view count for livestreams (#5152)
Adds new field `concurrent_view_count`
Closes https://github.com/yt-dlp/yt-dlp/issues/4843

Authored by: coletdjnz
2 years ago
bashonly f03940963e
[extractor/dplay] Add MotorTrendOnDemand extractor (#5151)
Closes #5141
Authored by: bashonly
2 years ago
Sergey 09c127ff83
[extractor/Tnaflix] Fix for HTTP 500 (#5150)
Closes #5107
Authored by: SG5
2 years ago
pukkandan aebb4f4ba7
Fix for formats=None
Fixes: https://github.com/yt-dlp/yt-dlp/pull/4965#issuecomment-1267682512
2 years ago
invertico bf2e1ec67a
[extractor/livestreamfails] Support posts (#5139)
Authored by: invertico
2 years ago
pukkandan 98d4ec1ef2
[build] Pin `py2exe` version
Workaround for #5135
2 years ago
pukkandan 1305b659ef
[extractor/detik] Avoid unnecessary extraction 2 years ago
github-actions 57fb88093e [version] update
Created by: pukkandan

:ci skip all :ci run dl
2 years ago
pukkandan 4e0511f27d
Release 2022.10.04 2 years ago
gamer191 304ad45a9b
[cleanup] Misc (#5044)
Authored by: gamer191, pukkandan
2 years ago
pukkandan 878eac3e2e
[docs] Separate notes about environment variables 2 years ago
coletdjnz 34859e4b32
[extractor/onenewsnz] Add extractor (#5088)
Authored by: coletdjnz
2 years ago
columndeeply 143a2ccab3
[extractor/prankcast] Add extractor (#4774)
Authored by: columndeeply, HobbyistDev
2 years ago
coletdjnz 1e0daeb314
[extractor/24tv.ua] Add extractors (#5121)
Closes #4287
Authored by: coletdjnz
2 years ago
HobbyistDev 7f5b3cb8b3
[extractor/booyah] Add extractor (#4834)
Closes #4583
Authored by: HobbyistDev, elyse0
2 years ago
jhwgh1968 c53e5cf59f
[extractor/redgifs] Fix extractor (#4892)
Closes #4805
Authored by: jhwgh1968
2 years ago
HobbyistDev c7f540ea1e
[extractor/detik] Generalize extractors (#4899)
Authored by: HobbyistDev, coletdjnz
2 years ago
Locke 12f153a827
[extractor/BilibiliSpace] Fix extractor, better error message (#5043)
Closes #5038
Authored by: lockmatrix
2 years ago
Bobscorn 0d887f273a
[extractor/IsraelNationalNews] Add extractor (#5089)
Closes #4019
Authored by: Bobscorn
2 years ago
Lesmiscore 4d37720a0c
[extractor/youtube] Download `post_live` videos from start (#5091)
* The fragments are generated as a `LazyList`. So only the required formats are expanded during download, but all fragment lists are printed/written in infojson.
* The m3u8 formats which cannot be downloaded from start are not extracted by default, but can be enabled with an extractor-arg. The extractor-arg `include_live_dash` is renamed to `include_incomplete_formats` to account for this new use-case.

Closes #1564
Authored by: Lesmiscore, pukkandan
2 years ago
bashonly dd4411aac2
[extractor/nfl] Fix extractor (#5130)
Closes #1708
Authored by: bashonly
2 years ago
Livia Medeiros 1d77d8ce07
[extractor/holodex] Fix `_VALID_URL` (#4948)
Authored by: LiviaMedeiros
2 years ago
pukkandan a057779d5e
[cleanup] Minor fixes
Closes #5129, Closes #4982
2 years ago
coletdjnz 7474e4531e
[extractor/AmazonStore] Fix JSON extraction (#5111)
Fixes https://github.com/yt-dlp/yt-dlp/issues/5110

Authored by: coletdjnz
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
2 years ago
coletdjnz d3a3d7f0cc
[extractor/JWPlatform] Fix extractor (#5112)
Fix bitrate and filesize extraction and support embeds with unquoted urls.

Related: #5106 

Authored by: coletdjnz
2 years ago
bashonly 8671f995cc
[extractor/paramountplus] Better DRM detection (#5126)
Closes #5119
Authored by: bashonly
2 years ago
bashonly 4a61501db9
[extractor/anvato] Fix extractor and refactor (#5074)
Authored by: bashonly
2 years ago
m4tu4g 7244895bde
[extractor/zee5] Fix `_VALID_URL` (#5124)
Closes #4612
Authored by: m4tu4g
2 years ago
sam 177662e0f2
[extractor/MicrosoftEmbed] Add extractor (#5082)
Closes #2638
Authored by: DoubleCouponDay
2 years ago
Fabi019 f48ab881f6
[extractor/bundesliga] Add extractor (#5094)
Closes #2339
Authored by: Fabi019
2 years ago
zenerdi0de eb2d9504b9
[extractor/tennistv] Fix timestamp (#5085)
Authored by: zenerdi0de
2 years ago
Nitish Kumar 8a04054647
[extractor/hrfensehen] Fix extractor (#5096)
Authored by: snapdgn
2 years ago
pukkandan 8b7fb8b60d
[extractor] Make search_json able to parse lists
Now `contains_pattern` can be set to `\[.+\]`
2 years ago
Teemu Ikonen a83333c432
[extractor/iltalehti] Add extractor (#5117)
Authored by: tpikonen
2 years ago
Dhruv 573a98d6f0
[extractor/bongacams] Update `_VALID_URL` (#5104)
Closes #5075
Authored by: 0xGodspeed
2 years ago
std-move af7a5eef2f
[downloader/aria2c] Fix filename containing leading whitespace (#5099)
Similar to eb55bad5a0, but for fragmented downloads
Authored by: std-move
2 years ago
Itachi 576faf00b2
[extractor/Mxplayer] Fix extractor (#4966)
Closes #4946
Authored by: itachi-19
2 years ago
nixxo 81b6102d20
[downloader/ism] Support ec-3 codec (#5004)
Closes #296
Authored by: nixxo
2 years ago
tobi1805 acf306d1f9
[extractor/tv2] Support new url format (#5063)
Closes #4973
Authored by: tobi1805
2 years ago
HobbyistDev 20a7304e4c
[extractor/unscripted] Add extractor (#5008)
Closes #4903
Authored by: HobbyistDev
2 years ago
Simon Sawicki 2e0f8d4f6e
[extractor/yandexvideopreview] Update _VALID_URL (#5084)
Closes #5065
Authored by: Grub4K
2 years ago
HobbyistDev 7e378287c4
[extractor/malltv] Fix video_id extraction (#4883)
Closes #4870
Authored by: HobbyistDev
2 years ago
Mehavoid 9cc5aed990
[extractor/trovo] Fix extractors (#4880)
Authored by: Mehavoid
Closes #4878
2 years ago
Elyse 48f535f5f8
[extractor/tencent] Add Iflix extractor (#4829)
Closes #4823
Authored by: elyse0
2 years ago
Teemu Ikonen 8dbad2a439
[extractor/audioboom] Support direct URLs and refactor (#4803)
Authored by: tpikonen, pukkandan
2 years ago
bashonly 11398b922c
[extractor/nbc] Add NBCStations extractor (#5077)
Closes #4571
Authored by: bashonly
2 years ago
Simon Sawicki dfea94f8f6
[extractor/crunchyroll:beta] Improve handling of hardsubs (#5041)
Closes #3397
Authored by: Grub4K
2 years ago
coletdjnz f1aae71568
[extractor/rcs] Fix embed extraction
Fixes https://github.com/yt-dlp/yt-dlp/issues/5076

Authored by: coletdjnz
2 years ago
Anant Murmu a5642f2c4a
[extractor/zee5] Generate device ids (#5062)
Closes #4937
Authored by: freezboltz
2 years ago
Julien Hadley Jack 10e2eb4f81
[extractor/ondemandkorea] Update `jw_config` regex (#5040)
Authored by: julien-hadleyjack
2 years ago
coletdjnz c9eba8075f
[extractor/wordpress:playlist] Add generic embed extractor (#5012)
Fixes https://github.com/yt-dlp/yt-dlp/issues/4955

Authored by: coletdjnz
2 years ago
Fabi019 9d69c4e4b4
[extractor/BerufeTV] Add extractor (#4921)
Closes #4632
Authored by: Fabi019
2 years ago
Timendum 292fdad297
[extractor/dplay:italy] Add default authentication (#5056)
Closes #2950

Authored by: Timendum
2 years ago
Kyle Anthony Williams c04cc2e28e
[extractor/soundcloud:search] More metadata in `--flat-playlist` (#4965)
Authored by: SuperSonicHub1
2 years ago
pukkandan 7a32c70d13
[cleanup] Fix flake8 and minor refactor
Issues from ab029d7e92, 1fb53b946c
2 years ago
pukkandan 709ee21417
[extractor/youtube] Do not warn on duplicate chapters
Eg: vYbaM8w8yzw
2 years ago
pukkandan 1fb53b946c
[extractor/youtube:tab] Improve continuation items extraction 2 years ago
pukkandan 1dd18a8808
[extractor/YoutubeShortsAudioPivot] Support `source` URLs
`ytshortsap:` is no longer needed
2 years ago
pukkandan 0a5095fe8d
[extractor/youtube:tab] Support `reporthistory` page
Closes #4929
2 years ago
pukkandan 0f60ba6e65
[extractor] Improve json+ld extraction
Related #5035
2 years ago
Simon Sawicki 1534aba865
[extractor/artetv] Remove duplicate stream urls (#5047)
Closes #4510
Authored by: Grub4K
2 years ago
coletdjnz 0ca0f88121
[extractor/heise] Fix extractor (#5029)
Fixes https://github.com/yt-dlp/yt-dlp/issues/1520
Authored by: coletdjnz
2 years ago
pukkandan 0500ee3d81
Don't download entire video when no matching `--download-sections` 2 years ago
pukkandan 46a5b335e7
[cookies] Let `_get_mac_keyring_password` fail gracefully
Closes #4915
2 years ago
pukkandan 914491b8e0
[utils] `Popen.run`: Fix default return in binary mode 2 years ago
Simon Sawicki ab029d7e92
[utils] `traverse_obj`: Rewrite, document and add tests (#5024)
Authored by: Grub4K
2 years ago
pukkandan 0bd5a039ea
Playlists maynot always have webpage_url 2 years ago
Lesmiscore 5c8b2ee9ec
[extractor/RUTV] Fix warnings for livestreams (#5016)
Authored by: Lesmiscore
2 years ago
Lesmiscore faf7863bb0
[extractor/Smotrim] Add extractor (#5015)
Authored by: nikita-moor, Lesmiscore
2 years ago
coletdjnz d42763a443
[extractor/rutube] Fix `_EMBED_REGEX`
Closes https://github.com/yt-dlp/yt-dlp/issues/4797

Authored by: coletdjnz
2 years ago
coletdjnz 3c757d5ed2
[extractor/wistia] Add support for channels (#4819)
Fixes https://github.com/yt-dlp/yt-dlp/issues/4748
Related: https://github.com/yt-dlp/yt-dlp/issues/4985

Authored by: coletdjnz
2 years ago
pukkandan f55523cfdd
[utils] `js_to_json`: Improve
Closes #4900
2 years ago
coletdjnz 32972518da
[extractor/telegraaf] Use mobile GraphQL API endpoint
Workaround for Cloudflare 403
Fixes https://github.com/yt-dlp/yt-dlp/issues/5000
Authored by: coletdjnz
2 years ago
Pritam Das 2e7675489f
[extractor/instagram] Extract more metadata (#4708)
Authored by: pritam20ps05
2 years ago
coletdjnz 80eb0bd9b9
[extractor/youtube] Add support for Shorts audio pivot feed (#4932)
This feed shows Shorts using the audio of a given video. 

ytshortsap: prefix can be used as a shortcut until YouTube
implements an official view. 

Closes #4911
Authored by: coletdjnz
2 years ago
Tanner Anderson 4cca2eb1bf
[extractor/nebula] Add nebula.tv (#4918)
Closes #4917
Authored by: tannertechnology
2 years ago
GautamMKGarg 1c09783f7a
[extractor/hungama] Add subtitle (#4856)
Authored by: GautamMKGarg, pukkandan
2 years ago
bashonly 163281178a
[extractor/wistia] Match IDs in embed URLs (#4990)
Closes #4985
Authored by: bashonly
2 years ago
pukkandan 2fa669f759
[docs] Misc improvements
Closes #4987, Closes #4906, Closes #4919, Closes #4977, Closes #4979
2 years ago
pukkandan 8ca48a1a54
[extractor] Fix `fatal=False` in `RetryManager` 2 years ago
pukkandan b27bc13af6
[extractor/patreon] Sort formats 2 years ago
bashonly f7c5a5e967
[extractor/tiktok] Fix TikTokIE (#4984)
Authored by: bashonly
2 years ago
Jeroen Jacobs fada8272b6
[extractor/GoPlay] Add extractor (#3412)
Replaces old Vier extractors

Closes https://github.com/yt-dlp/yt-dlp/issues/1546
Based on: https://github.com/ytdl-org/youtube-dl/pull/27815
Authored by: jeroenj, CNugteren, basrieter
2 years ago
josanabr 46d72cd2c7
[devscripts] make_lazy_extractors: Fix for Docker (#4958)
Authored by: josanabr
2 years ago
pukkandan 19b4e59a1e
[extractor/web.archive:youtube] Fix _YT_INITIAL_PLAYER_RESPONSE_RE 2 years ago
pukkandan dab284f80f
Workaround `libc_ver` not be available on Windows Store version of Python 2 years ago
pukkandan 9665f15a96
[outtmpl] Make `%s` work in strfformat for all systems 2 years ago
pukkandan 2b24afa6d7
Improve 5736d79172 2 years ago
pukkandan 3166e6840c
[extractor/generic] Pass through referer from json-ld
Closes #4941
2 years ago
Simon Sawicki 8817a80d3a
[cookies] Parse cookies leniently (#4780)
Closes #4776, #3778
Authored by: Grub4K
2 years ago
pukkandan 5736d79172
Support environment variables in `--ffmpeg-location`
Closes #4938
2 years ago
Lesmiscore fc2ba496fd
Allow open ranges for time ranges (#4940)
Authored by: Lesmiscore
2 years ago
Locke 2b9d02167f
[extractor/bilibili] Add space.bilibili extractors (#4468)
Authored by: lockmatrix
2 years ago
pukkandan 2314b4d89f
Allow plugin extractors to replace the built-in ones
This allows easier plugin chaining; e.g.
- https://gist.github.com/pukkandan/24f13ff1ed385c5a390c1d7bd130d8f7
- https://gist.github.com/pukkandan/fcf5ca1785c80f64e471f0ee14f990fb
2 years ago
pukkandan 1060f82f89
Fix `--config-location -` 2 years ago
bashonly 22df97f9c5
Fix bug in 941e881e1f (#4893)
Authored by: bashonly
2 years ago
pukkandan 9c935fbc72
Fix bug in ae1035646a
Closes #4890
2 years ago
pukkandan deae7c1711
[cleanup] Misc 2 years ago
pukkandan 941e881e1f
Fix bug in ae1035646a
Closes #4881
2 years ago
pukkandan 0cb0fdbbfe
[extractor/common] Escape `%` in `representation_id` of m3u8
Closes #4877
2 years ago
coletdjnz 0831d95c46
[extractor/BiliIntl] Support uppercase lang in `_VALID_URL`
Seen in some rare cases
Authored by: coletdjnz
2 years ago
coletdjnz c26f9b991a
[extractor/youtube] Support changing extraction language (#4470)
Adds `--extractor-args youtube:lang=<supported lang code>` extractor arg to prefer translated fields (e.g. title and description) of that language, if available, for all YouTube extractors. See README or error message for list of supported language codes.

Closes https://github.com/yt-dlp/yt-dlp/issues/387

Authored by: coletdjnz
2 years ago
CplPwnies 0c0b78b273
[extractor/adobepass] Add MSO AlticeOne (Optimum TV) (#4875)
* Suddenlink rebrand to Optimum. Fixes #4874

Authored by: CplPwnies
2 years ago
coletdjnz 3ffb2f5bea
[extractor/youtube] Fix video like count extraction
Support new combined button layout
Authored by: coletdjnz
2 years ago
pukkandan ae1035646a
Allow a `set` to be passed as `download_archive` 2 years ago
pukkandan 1015ceeeaf
[extractor/MLBTV] Detect live streams 2 years ago
pukkandan 17ffed1842
[docs] Improvements
* Move detailed installation instructions to https://github.com/yt-dlp/yt-dlp/wiki/Installation
* Link to wiki where applicable
* Fix some mistakes. Closes #4853, Closes #4855, Closes #4852
* Improve some error messages
2 years ago
pukkandan be9c0884d7
[extractor/BiliIntlSeries] Fix `_VALID_URL`
Closes #4825
2 years ago
pukkandan 48c8424bd9
Fix bug in 07a1250e0e 2 years ago
Elyse 7657ec7ed6
[utils] `base_url`: URL paths can contain `&` (#4841)
Authored by: elyse0
Closes #4187
2 years ago
pukkandan 07a1250e0e
[outtmpl] Curly braces to filter keys 2 years ago
Elyse 69082b38dc
[phantomjs] Fix bug in 587021cd9f (#4833)
Authored by: elyse0
2 years ago
coletdjnz aa824dd10b
[extractor/mediaworksnzvod] Add extractor (#4817)
Authored by: coletdjnz
2 years ago
TokyoBlackHole a12d03e15d
[extractor/animeondemand] Remove extractor (#4830)
Authored by: TokyoBlackHole
2 years ago
pukkandan 1a7c9fad9f
[jsinterp] Workaround operator associativity issue
https://github.com/yt-dlp/yt-dlp/issues/4635#issuecomment-1235384480
2 years ago
Lesmiscore 3c7a276234
[extractor/amazonstore] Retry to avoid captcha page (#4811)
Authored by: Lesmiscore
2 years ago
bashonly d6f8871964
[extractor/triller] Fix auth token (#4813)
Authored by: bashonly
2 years ago
pukkandan 5469a4ab11
[extractor/motorsport] Support native embeds
Closes #4749
2 years ago
pukkandan 2c475e48b5
[extractor/bandcamp] Extract `uploader_url`
Closes #4755
2 years ago
pukkandan 7c6eb424d3
[extractor/youtube] Detect `lazy-load-for-videos` embeds
Closes #4812
2 years ago
github-actions adba24d207 [version] update
Created by: pukkandan

:ci skip all :ci run dl
2 years ago
pukkandan 5d7c7d6569
Release 2022.09.01 2 years ago
pukkandan d2c8aadf79
[cleanup] Misc
Closes #4710, Closes #4754, Closes #4723
Authored by: pukkandan, MrRawes, DavidH-2022
2 years ago
pukkandan 1ac7f46184
Update to ytdl-commit-ed5c44e7
[compat] Replace deficient ChainMap class in Py3.3 and earlier
ed5c44e7b7
2 years ago
pukkandan 05deb747bb
[jsinterp] Fix escape in regex 2 years ago
pukkandan b505e8517a
[extractor/youtube] Fallback regex for nsig code extraction 2 years ago
pukkandan f2e9fa3ef7
[FormatSort] Fix `aext` for `--prefer-free-formats`
Closes #4735
2 years ago
satan1st 50a399326f
[build] `make tar' should not follow `DESTDIR` (#4790)
Ref: https://www.gnu.org/prep/standards/html_node/DESTDIR.html
Authored by: satan1st
2 years ago
coletdjnz 1ff88b7aec
[extractor/youtube] Add `no-youtube-prefer-utc-upload-date` compat option (#4771)
This option reverts 992f9a730b and 17322130a9 to prefer the non-UTC upload date in microformats.

Authored by: coletdjnz, pukkandan
2 years ago
bashonly 825d3ce386
[cookies] Improve container support (#4806)
Closes #4800
Authored by: bashonly, pukkandan, coletdjnz
2 years ago
bashonly 92aa6d6883
[extractor/triller] Add extractor (#4712)
Closes #4703
Authored by: bashonly
2 years ago
Elyse b2a4db425b
[VQQ] Add extractors (#4706)
Closes #1666
Authored by: elyse0
2 years ago
Yifu Yu de49cdbe9d
[extractor/bilibili] Extract `flac` with premium account (#4759)
Authored by: jackyyf
2 years ago
shirt 9f9c85dda4
[Build] Update pyinstaller 2 years ago
HobbyistDev 11734714c2
[extractor/eurosport] Add extractor (#4613)
Closes #2487
Authored by: HobbyistDev
2 years ago
pukkandan b86ca447ce
[extractor/mediaset] Fix embed extraction
Closes #4804
2 years ago
Tejas Arlimatti f8c7ba9984
[extractor/epoch] Add extractor (#4772)
Closes #4714
Authored by: tejasa97
2 years ago
DepFA 76f2bb175d
[extractor/stripchat] Don't modify input URL (#4781)
Authored by: dfaker
2 years ago
Elyse f26af78a8a
[jsinterp] Add `charcodeAt` and bitwise overflow (#4706)
Authored by: elyse0
2 years ago
Lesmiscore bfbecd1174
[extractor/newspicks] Add extractor (#4725)
Authored by: Lesmiscore
2 years ago
bashonly 9bd13fe5bb
[cookies] Support firefox container in `--cookies-from-browser` (#4753)
Authored by: bashonly
2 years ago
Jeff Huffman 459262ac97
[extractor/crunchyroll:beta] Use anonymous access (#4704)
Closes #4692
Authored by: tejing1
2 years ago
Lesmiscore 82ea226c61
Restore LD_LIBRARY_PATH when using PyInstaller (#4666)
Authored by: Lesmiscore
2 years ago
pukkandan da4db748fa
[utils] Add `deprecation_warning`
See https://github.com/yt-dlp/yt-dlp/pull/2173#issuecomment-1097021515
2 years ago
pukkandan e1eabd7beb
[downloader/external] Smarter detection of executable
Closes #4778
2 years ago
pukkandan d81ba7d491
[jsinterp, extractor/youtube] Minor fixes 2 years ago
OHaiiBuzzle 5135ed3d4a
[extractor/huya] Fix stream extraction (#4798)
Closes #4658
Authored by: ohaiibuzzle
2 years ago
pukkandan c4b2df872d
[jsinterp] Fix `_separate`
Ref: https://github.com/yt-dlp/yt-dlp/issues/4635#issuecomment-1231126941
2 years ago
Samantaz Fox 224b5a35f7
[extractor/youtube] Update iOS Innertube clients (#4792)
Authored by: SamantazFox
2 years ago
coletdjnz 50ac0e5416
[extractor/youtube] Use device-specific user agent (#4770)
Thwart latest fingerprinting attempt (see https://github.com/iv-org/invidious/issues/3230#issuecomment-1226887639)

Authored by: coletdjnz
2 years ago
Lesmiscore e0992d5558
[extractor/IslamChannel] Add extractors (#4779)
Authored by: Lesmiscore
2 years ago
pukkandan 5e01315aa1
[cache, extractor/youtube] Invalidate old cache 2 years ago
pukkandan 4e4982ab5b
[extractor/generic] Don't return JW player without formats
CLoses #4765
2 years ago
cgrigis 89e4d86171
[extractor/arte] Bug fix (#4769)
Closes #4768
Authored by: cgrigis
2 years ago
Shreyas Minocha a1af516259
[extractor/screencastomatic] Support `--video-password` (#4761)
Authored by: shreyasminocha
2 years ago
pukkandan 1d64a59547
[extractor/vimeo:user] Fix _VALID_URL
Closes #4758
2 years ago
pukkandan ca7f8b8f31
Bugfix for 822d66e591
Closes #4760
2 years ago
pukkandan 164b03c486
[jsinterp] Fix bug in operator precedence
Fixes https://github.com/yt-dlp/yt-dlp/issues/4635#issuecomment-1226659543
2 years ago
pukkandan e5458d1d88
Fix lazy extractor bug in fe7866d0ed
and add test

Fixes https://github.com/yt-dlp/yt-dlp/pull/3234#issuecomment-1225347071
2 years ago
pukkandan b5e7a2e69d
Add version to infojson 2 years ago
pukkandan 2516cafb28
Fix bug in fe7866d0ed 2 years ago
pukkandan fd404bec7e
Fix `--break-per-url --max-downloads` 2 years ago
pukkandan fe7866d0ed
Add option `--use-extractors`
Deprecates `--force-generic-extractor`

Closes #3234, Closes #2044

Related: #4307, #1791
2 years ago
pukkandan 5314b52192
[utils] Add orderedSet_from_options 2 years ago
pukkandan 13db4e7b9e
[extractor/mixcloud] All formats are audio-only
Closes #4740
2 years ago
Joshua Lochner 07275b708b
[extractor/medaltv] Fix extraction (#4739)
Authored by: xenova
2 years ago
Elyse b85703d11a
[extractor/rtbf] Fix jwt extraction (#4738)
Closes #4683
Authored by: elyse0
2 years ago
pukkandan 992dc6b486
[jsinterp] Implement timeout
Workaround for #4716
2 years ago
pukkandan 822d66e591
Fix bug in `--alias` 2 years ago
pukkandan 8d1ad6378f
[extractor/BiliBiliSearch] Don't sort by date
Related #4682
2 years ago
pukkandan 2d1019542a
[extractor/BiliBiliSearch] Fix infinite loop
Closes #4682
2 years ago
pukkandan b25cac650f
[extractor/youtube] Fix bug in format sorting 2 years ago
pukkandan 90a1df305b
[test] Fix test_youtube_signature 2 years ago
pukkandan 0a6b4b82e9
[extractor/uktv] Improve _VALID_URL
Closes #4707
Authored by: dirkf
2 years ago
pukkandan 1704c47ba8
[extractor/bitchute] Mark errors as expected
Closes #4685
2 years ago
github-actions b76e9cedb3 [version] update
Created by: pukkandan

:ci skip all :ci run dl
2 years ago
pukkandan 48c88e088c
Release 2022.08.19 2 years ago
pukkandan a831c2ea90
[cleanup] Misc 2 years ago
pukkandan be13a6e525
[jsinterp] Bring on-par with youtube-dl
Code from: https://github.com/ytdl-org/youtube-dl/pull/31175, https://github.com/ytdl-org/youtube-dl/pull/31182

Authored by pukkandan, dirkf
2 years ago
bashonly 8a3da4c68c
[extractor/instagram] Fix bugs in 7d3b98be4c (#4701)
Authored by: bashonly
2 years ago
nixxo 4d37d4a77c
[extractor/rai] Minor fix (#4700)
Closes #4691, #4690
2 years ago
bashonly 7d3b98be4c
[extractor/instagram] Fix extraction (#4696)
Closes #4657, #4532, #4475
Authored by: bashonly, pritam20ps05
2 years ago
Elyse 2b3e43e247
[extractor/rtbf] Fix stream extractor (#4671)
Closes #4656
Authored by: elyse0
2 years ago
Alexander Seiler f60ef66371
[extractor/zattoo] Fix Zattoo resellers (#4675)
Closes #4630
Authored by: goggle
2 years ago
pukkandan 25836db6be
[extractor/youtube] Add fallback to phantomjs
Related #4635
2 years ago
pukkandan 587021cd9f
[phantomjs] Add function to execute JS without a DOM
Authored by: MinePlayersPE, pukkandan
2 years ago
pukkandan 580ce00782
[youtube] Improve signature caching
and refactor related functions
2 years ago
ChillingPepper 2f1a299c50
[extractor/SovietsCloset] Fix extractor (#4688)
Closes #4200 
Authored by: ChillingPepper
2 years ago
pukkandan f6ca640b12
[jsinterp] Fix for youtube player 1f7d5369
Closes #4635 again
2 years ago
pukkandan 3ce2933693
[youtube] Fix error reporting of "Incomplete data"
Related: #4669
2 years ago
pukkandan c200096c03
Fix bug in --download-archive
Closes #4668
2 years ago
pukkandan 6d3e7424bf
[jsinterp] Fix for youtube player c81bbb4a 2 years ago
pukkandan 5c6d2ef9d1
[youtube] Improve format sorting for IOS formats
When no itag/resolution is available for reference, use the closest resolution
2 years ago
Lesmiscore 460eb9c50e
[build] Exclude devscripts from installs
Closes #4667
2 years ago
github-actions 9fd03a1696 [version] update
Created by: pukkandan

:ci skip all :ci run dl
2 years ago
pukkandan 55937202b7
Release 2022.08.14 2 years ago
pukkandan 1e4fca9a87
[cleanup] Misc 2 years ago
pukkandan 49b4ceaedf
[jsinterp] Bring or-par with youtube-dl
Partially cherry-picked from: d231b56717

Authored by pukkandan, dirkf
2 years ago
pukkandan d711839760
Update to ytdl-commit-e6a836d
[core] Make `--max-downloads ...` stop immediately on reaching the limit
e6a836d54c
2 years ago
pukkandan 48732becfe
Fix bug in 1155ecef29 2 years ago
pukkandan 6440c45ff3
[update] Copy bitmask from old binary
Improves a6125983ab

Authored by: Lesmiscore
2 years ago
masta79 ef6342bd07
[extractor/toggo] Improve `_VALID_URL` (#4663)
Authored by: masta79
2 years ago
ischmidt20 e183bb8c9b
[extractor/MLB] New extractor (#4586)
Authored by: ischmidt20
2 years ago
HobbyistDev 7695f5a0a7
[extractor/moview] Add extractor (#4607)
Authored by: HobbyistDev
2 years ago
Ben Welsh cb7cc448c0
[extractor/truth] Add extractor (#4609)
Closes #3865
Authored by: palewire
2 years ago
bashonly 63be30e3e0
[extractor/facebook] Add reel support (#4660)
Closes #4039 
Authored by: bashonly
2 years ago
Ben Welsh 43cf982ac3
[extractor/parler] Add extractor (#4616)
Authored by: palewire
2 years ago
nixxo 7e82397441
[extractor/rai] Misc fixes (#4600)
Authored by: nixxo
2 years ago
Aldo Ridhoni 66c4afd828
[extractor/doodstream] Add `wf` domain (#4648)
Authored by: aldoridhoni
2 years ago
pukkandan 0e0ce898f6
[ThumbnailsConvertor] Fix conversion after fixup_webp
Closes #4565
2 years ago
pukkandan a6125983ab
[update] Set executable bit-mask
Closes #4621
2 years ago
pukkandan 8f84770acd
[utils] Fix `get_compatible_ext`
Closes #4647
2 years ago
Lesmiscore 62b58c0936
[docs] Consistent use of `e.g.` (#4643)
Authored by: Lesmiscore
2 years ago
pukkandan 8f53dc44a0
[jsinterp] Handle new youtube signature functions
Closes #4635
2 years ago
Jacob Truman 1cddfdc52b
[extractor/aenetworks] Add formats parameter (#4645)
Closes #4047
Authored by: jacobtruman
2 years ago
coletdjnz cea4b857f0
[patreon] Ignore erroneous media attachments (#4638)
Fixes https://github.com/yt-dlp/yt-dlp/issues/4608
Authored by: coletdjnz
2 years ago
shirt ffcd62c289
[extractor/tubitv] Extract additional formats (#4646)
Authored by: shirt-dev
2 years ago
pukkandan a1c5bd82ec
[jsinterp] Truncate error messages
Related: #4635
2 years ago
pukkandan 5da42f2b9b
[extractor/crunchyroll] Improve `_VALID_URL`s
Closes #4633
2 years ago
pukkandan 1155ecef29
[extractor/zattoo] Fix resellers
Fixes #4630
2 years ago
pukkandan 96623ab5c6
[devscripts] Fix import
Closes #4603
2 years ago
pukkandan 7e798d725e
[extractor] Fix format sorting of `channels` 2 years ago
pukkandan 8420a4d063
[ffmpeg] Smarter detection of ffprobe filename 2 years ago
pukkandan b5e9a641f5
[postprocessor/embedthumbnail] Detect libatomicparsley.so 2 years ago
pukkandan c220d9efc8
[ffmpeg] Disable avconv unless `--prefer-avconv` 2 years ago
pukkandan 81e0195998
[build] Fix changelog
Bug in c4b6c5c7c9
2 years ago
github-actions f1e2d4a9a2 [version] update
Created by: pukkandan

:ci skip all :ci run dl
2 years ago
pukkandan 3157158f76
Release 2022.08.08 2 years ago
pukkandan 16d4535abc
Update to ytdl-commit-adb5294
[aenetworks] Update _THEPLATFORM_KEY and _THEPLATFORM_SECRET
adb5294177
2 years ago
Elyse 2a5e5477bc
[extractor/redbee] Unify and update extractors (#4479)
Closes #4443
Authored by: elyse0
2 years ago
Eren Kemer e251986cbe
[extractor/harpodeon] Add extractor (#4540)
Closes #4450
Authored by: eren-kemer
2 years ago
pukkandan f0ad6f8c51
Remove filtered entries from `-J`
Closes #4369
2 years ago
pukkandan 70b2340909
[build, devscripts] Add devscript to set a build variant
Closes #4471
2 years ago
pukkandan 115add4387
[devscripts] Create `utils` and refactor 2 years ago
shirt c4b6c5c7c9
[build] Improve build process (#4513)
Authored by: shirt-dev
2 years ago
coletdjnz c7dcf0b31e
[extractor/youtube] Add `androidSdkVersion` parameter to Android Innertube clients
Required to prevent YouTube returning a bad player response in some cases.

See: https://github.com/yt-dlp/yt-dlp/pull/4593, https://github.com/TeamNewPipe/NewPipe/issues/8713, https://github.com/iv-org/invidious/issues/3230, https://github.com/Tyrrrz/YoutubeExplode/issues/647

Authored by: coletdjnz
2 years ago
Djeson 298d9c0e89
[extractor/ninegag] Extract uploader (#4597)
Closes #4587
Authored by: DjesonPV
2 years ago
pukkandan a416623436
[extractor/youtube] Extract more format info 2 years ago
pukkandan b8ed0f15d4
[extractor] Add field `audio_channels` 2 years ago
pukkandan 22b22b7d5c
[extractor/WASDTV:record] Fix `_VALID_URL` 2 years ago
HobbyistDev 1f6b90ed8d
[extractor/tviplayer] Improve `_VALID_URL` (#4585)
Closes #4578
Authored by: HobbyistDev
2 years ago
coletdjnz a3e9642116
[extractor/youtube] Prevent redirect to unwanted videos (#4593)
Example: https://www.youtube.com/watch?v=aQvGIIdgFDM

Authored by: coletdjnz
2 years ago
pukkandan 43aebb7db4
Bugfix for bfd973ece3
`_extract_embed_urls` is not a list

Closes #4581
2 years ago
Yash Kumar 061a17abd3
[extractor/FIFA] Change API endpoint (#4577)
Closes #4566
Authored by: yashkc2025, Bricio
2 years ago
HobbyistDev d380fc1614
[extractor/kompas] Add extractor (#4562)
Authored by: HobbyistDev
2 years ago
HobbyistDev ad26f15a06
[extractor/vidio] Support embed link (#4564)
Authored by: HobbyistDev
2 years ago
Bojidar Qnkov aeaf905e22
[extractor/NovaPlay] Fix extractor (#4415)
Closes #4439
Authored by: Bojidarist
2 years ago
pukkandan 97d9c79e92
Fix tests for 989a01c261 2 years ago
Jeff Huffman f62f553d46
[extractor/crunchyroll:beta] Use streams API (#4555)
Closes #4452
Authored by: tejing1
2 years ago
pukkandan 989a01c261
[outtmpl] Smarter replacing of unsupported characters
Closes #1330
2 years ago
pukkandan 05e2243e80
Fix bug in be5c1ae862 2 years ago
pukkandan 4080efeb01
[extractor/vimeo] Bugfix in bfd973ece3 2 years ago
Lauren N. Liberda fc61aff41b
Determine merge container better (See desc) (#1482)
* Determine the container early. Closes #4069
* Use codecs instead of just file extensions
* Obey `--prefer-free-formats`
* Allow fallbacks in `--merge-output`

Authored by: pukkandan, selfisekai
2 years ago
pukkandan fe0918bb65
Import ctypes only when necessary
Closes #4541
2 years ago
Jeff Huffman b99ba3df09
[extractor/crunchyroll:beta] Extract timestamp and fix tests (#4535)
Closes #4533
Authored by: tejing1
2 years ago
pukkandan 7356a44443
Fix misleading DRM message
Closes #4534
2 years ago
coletdjnz a0c830f488
[extractor/youtube] Bump Innertube client versions
YouTube may be requiring new versions soon. See https://github.com/iv-org/invidious/issues/3230, https://github.com/TeamNewPipe/NewPipe/issues/8713

Authored by: coletdjnz
2 years ago
pukkandan a6ca61d427
Fix bug in 0647d9251f 2 years ago
Galiley d8657ff76f
[extractor/xfileshare] Add Referer (#4494)
Authored by: Galiley
2 years ago
pukkandan 5770293d25
[extractor/orf:radio] Rewrite extractors
Closes #4522
2 years ago
pukkandan 0647d9251f
Minor bugfixes 2 years ago
pukkandan be5c1ae862
Standardize retry mechanism (#1649)
* [utils] Create `RetryManager`
* Migrate all retries to use the manager
* [extractor] Add wrapper methods for convenience
* Standardize console messages for retries
* Add `--retry-sleep` for extractors
2 years ago
pukkandan bfd973ece3 [extractors] Use new framework for existing embeds (#4307)
`Brightcove` is difficult to migrate because it's subclasses may depend
on the signature of the current functions. So it is left as-is for now

Note: Tests have not been migrated
2 years ago
pukkandan 1e8fe57e5c [extractor] Support multiple archive ids for one video (#4307)
Closes #4352
2 years ago
pukkandan f14a2d8382 [extractor/html5] Separate into own extractor (#4307)
Closes #4291

Authored by: coletdjnz, pukkandan
2 years ago
pukkandan 5fff2e576f [extractor/camtasia] Separate into own extractor (#4307)
Authored by: coletdjnz
2 years ago
pukkandan f2e8dbcc00 [extractor, test] Basic framework for embed tests (#4307)
and split download tests so they can be more easily run in CI

Authored by: coletdjnz
2 years ago
pukkandan 8f97a15d1c [extractor] Framework for embed detection (#4307) 2 years ago
nixxo 47304e07dc
[extractor/rai] Add raisudtirol extractor (#4524)
Closes #4206
Authored by: nixxo
2 years ago
Lesmiscore 565a4c5944
[extractor/YahooJapanNews] Fix extractor (#4480)
Authored by: Lesmiscore
2 years ago
pukkandan 2ebe6fefbe
[extractor/yandexmusic] Extract higher quality format
Closes #4512
2 years ago
pukkandan 5f2a7f7c4a
[FFmpegThumbnailsConvertor] Fix conversion from GIF
Closes #2988
2 years ago
pukkandan 30389593c2
[docs] Clarify `best*`
Closes #4373
2 years ago
christoph-heinrich d4ada3574e
[docs] Fix capitalization in references (#4515)
Authored by: christoph-heinrich
2 years ago
Juhmer Tena e1bd953f45
[extractor/angel] Add extractor (#4410)
Closes #1243
Authored by: AxiosDeminence
2 years ago
sqrtNOT 98a60600b2
[extractors/holodex] Add extractor (#4434)
Closes #726 
Authored by: sqrtNOT, pukkandan
2 years ago
lazypete365 e325a21a1f
[extractor/youtube] Add `live_status=post_live` (#4495)
Related: https://github.com/yt-dlp/yt-dlp/issues/1564
Authored by: lazypete365
2 years ago
pukkandan 3df4f81dfe
[downloader] Add average speed to final progress line
Fixes: https://github.com/ytdl-org/youtube-dl/issues/31122
2 years ago
pukkandan 31b532a1f2
[cleanup] Misc 2 years ago
pukkandan daef791100
[utils] sanitize_open: Allow any IO stream as stdout
Fixes: https://github.com/yt-dlp/yt-dlp/issues/3298#issuecomment-1181754989
2 years ago
pukkandan a6bcaf71fc
[outtmpl] Treat empty values as None in filenames
Workaround for #4485
2 years ago
pukkandan 4f04be6add
Validate `--merge-output-format`
Closes #4489
2 years ago
pukkandan 8dc5930511
[utils, cleanup] Consolidate known media extensions 2 years ago
pukkandan b4daacb4ec
[mhtml, cleanup] Use imghdr 2 years ago
pukkandan 6a7d3a0a09
[ffmpeg] Set `ffmpeg_location` in a contextvar
Fixes #2191 for the CLI, but not when used through the API
2 years ago
pukkandan c646d76f67
[webvtt, extractor/youtube] Extract auto-subs from livestream VODs
Closes #4130

Authored by: pukkandan, fstirlitz
2 years ago
pukkandan 07b47084ba
[extractor/youtube] Parse translated subtitles only when requested
Closes #4274
2 years ago
pukkandan 4f547d6d2c
[metadataparser] Don't set `None` when the field didn't match
Fixes: https://github.com/ytdl-org/youtube-dl/issues/31118#issuecomment-1198254512
2 years ago
ischmidt20 2eae7d507c
[extractor/ESPN] Extract duration (#4499)
Authored by: ischmidt20
2 years ago
mpeter50 1cdf69c57e
[extractor/twitch] Extract chapters for single chapter VODs (#4453)
Closes #4421 
Authored by: mpeter50
2 years ago
Galiley b6cd135ac2
[extractor/doodstream] Support more domains (#4493)
Authored by: Galiley
2 years ago
Anant Murmu befcac11a0
[extractor/stripchat] Fix _VALID_URL (#4491)
Closes https://github.com/yt-dlp/yt-dlp/issues/4486

Authored by: freezboltz
2 years ago
haobinliang 7f71cee020
[extractor/cloudflarestream] Fix video_id padding (#4384)
Fixes https://github.com/ytdl-org/youtube-dl/issues/26640

Authored by: haobinliang
2 years ago
Elyse db5f248204
[extractor/ina] Improve extractor (#4487)
Closes #4419
Authored by: elyse0
2 years ago
coletdjnz 871a8929bc
[extractor/archiveorg] Improve handling of formats (#4461)
* Ignore private formats if not logged in (fixes https://github.com/yt-dlp/yt-dlp/issues/3832)
* Prefer original formats
* Support mpg formats

Authored by: coletdjnz, pukkandan
2 years ago
ajj8 edebb65170
[extractor/bbc] Fix news articles (#4472)
Authored by: ajj8
2 years ago
pukkandan f640e42ffa
[extractor/arte] Fix title extraction
Fixes: https://github.com/yt-dlp/yt-dlp/pull/3302#issuecomment-1197568420
2 years ago
Mehavoid 59f63c8f0f
[extractor/vk] Fix extractor (#4128)
Closes #4437
Authored by: Mehavoid
2 years ago
ping bfbb5a1bb1
[extractor/NaverNow] Change endpoint (#4457)
Authored by: ping
2 years ago
Felix S 051d6b450c
[extractor/arte] Move to v2 API (#3302)
Closes #3622, #3502, #3086

Authored by: fstirlitz, pukkandan
2 years ago
HobbyistDev 67685a541d
[extractor/tempo] Add extractor (#4463)
Authored by: HobbyistDev
2 years ago
pukkandan 964b5493a4
Bugfix for f1042989c1 2 years ago
pukkandan 3955b20703
Fix bugs in 3bec830a59
Closes #4454
2 years ago
pukkandan f1042989c1
[crunchyroll] Fix language code in _VALID_URLs
Closes #4451
2 years ago
ischmidt20 e2884db36a
[extractor/Go] Extract timestamp (#4186)
Authored by: ischmidt20
2 years ago
winterbird-code 2c646fe42c
[extractor/hidive] Fix cookie login when netrc is also given (#4447)
Closes #3336

Authored by: winterbird-code
2 years ago
pukkandan 693f060040
[youtube,twitch] Allow waiting for channels to become live
Closes #2597
2 years ago
pukkandan 3bec830a59
Reject entire playlists faster with `--match-filter`
Rejected based on `playlist_id` etc can be checked before any entries are extracted

Related: #4383
2 years ago
Burve 7d0f6f0c45
[extractor/Crunchyroll] Handle missing metadata correctly (#4405)
Closes #4399

Authored by pukkandan, Burve
2 years ago
Sipherdrakon 26bafe7028
[extractor/dplay] Add MotorTrend extractor (#4446)
Authored by: Sipherdrakon
2 years ago
nixxo 0cd2810379
[extractor/rai] Fix RaiNews extraction (#4380)
Authored by: nixxo

Closes #3911
2 years ago
m4tu4g 0f7247f88e
[extractor/zee5] Update Device ID (#4423)
Closes #4378

Authored by: m4tu4g
2 years ago
sqrtNOT 2dc4970e08
[extractor/tubi] Exclude playlists from playlist entries (#4416)
Closes #4409 

Authored by: sqrtNOT
2 years ago
coletdev 4f08e58655
[extractor/patreon] Fix and improve extractors (#4398)
* Add workaround for 403s - Fixes https://github.com/yt-dlp/yt-dlp/issues/3631
* Support m3u8 post file videos - Fixes https://github.com/yt-dlp/yt-dlp/issues/2277
* Raise useful error messages - Fixes https://github.com/yt-dlp/yt-dlp/issues/2914
* `--write-comments` support

Authored by: coletdjnz, pukkandan
2 years ago
sqrtNOT dcbf7394ab
[vgtv] Support tv.vg.no (#4404)
Closes #4400 
Authored by: sqrtNOT
2 years ago
Bricio c40f327a16
[extractor/globo:article] Remove false positives (#4396)
Authored by: Bricio
2 years ago
pukkandan 81bf0943ea
[docs] Fix bug report issue template
Closes #4393
2 years ago
pukkandan b79f9e302d
`--compat-option no-live-chat` should disable danmaku
Closes #4387
2 years ago
Lesmiscore bc83b4b06c
[extractor/AbemaTVTitle] Implement paging (#4376)
Authored by: Lesmiscore
2 years ago
shirt 8ef5af1942
[build] Update pyinstaller 2 years ago
pukkandan 6929b41a21
Remove Python 3.6 support
Closes #3764
2 years ago
github-actions 0b5583b112 [version] update
Created by: pukkandan

:ci skip all :ci run dl
2 years ago
pukkandan 135f05ef66
Release 2022.07.18 2 years ago
pukkandan c6e07cf1e1
[cleanup] Misc 2 years ago
pukkandan ce7f6aa660
Fix bug in 2aab569f1c
Closes #4371
2 years ago
pukkandan 1765c6039e
[extractor/MangoTV] Fix subtitle languages
Closes #4315
2 years ago
pukkandan fbb888a3d5
[extractor/BiliIntl] Fix subtitle extraction
Closes #4359
Authored by: MinePlayersPE
2 years ago
Elyse 2aab569f1c
[extractor/wetv] Add extractors (#4330)
Closes #1115
Authored by: elyse0
2 years ago
Ehtisham Sabir 2e2c60c4ba
[extractor/wikimedia] Add extractor (#4314)
Based on https://github.com/ytdl-org/youtube-dl/pull/30796
Authored by: EhtishamSabir, pukkandan
2 years ago
HobbyistDev 306770819e
[extractor/Netverse] Improve playlist extractor (#3854)
Authored by: HobbyistDev
2 years ago
chris dfa6661e0f
[extractor/rtvsl] Add extractor (#2586)
Authored by: iw0nderhow, pukkandan
2 years ago
pukkandan 24093d52a7
[update] Prepare to remove Python 3.6 support 2 years ago
pukkandan f5e438a976
[compat] Let PyInstaller detect _legacy module 2 years ago
pukkandan d08e1e6875
Fix bug in 5200976949 2 years ago
sqrtNOT 956f1cf805
[extractor/philharmoniedeparis] Fix extractor (#4367)
Closes #4297
Authored by: sqrtNOT
2 years ago
sqrtNOT 129dfa5f45
[extractor/WSJArticle] Fix video id extraction (#4268)
Closes #4249
Authored by: sqrtNOT
2 years ago
pukkandan 3df6a603e4
[extractor/WatchESPN] Improve _VALID_URL
Closes #4362
Authored by: dirkf, IONECarter
2 years ago
pukkandan a7dc6a89f6
Support `--no-progress` for `--wait-for-video`
Closes #4365
2 years ago
odo2063 5200976949
[build] Fix architecture suffix of executables (#4355)
Authored by: odo2063
2 years ago
Pritam Das e3e606de12
[extractor/instagram] Fix post/story extractors (#4074)
Closes #4343, #3077, #2736, #3002
Authored by: pritam20ps05, pukkandan
2 years ago
pukkandan 88f60feb32
Fix a904a7f8c6 2 years ago
Lesmiscore a904a7f8c6
Allow users to specify encoding in each config files (#4357)
Authored by: Lesmiscore
2 years ago
Ferdinand Bachmann 49afc1d84a
[extractor/TubeTuGraz] Add extractor (#2397)
Based on https://github.com/ytdl-org/youtube-dl/pull/26778
Authored by: Ferdi265, pukkandan
2 years ago
pukkandan 6edf28081f
[extractor] Passthrough `errnote=False` to parsing 2 years ago
HobbyistDev 5f2da312fa
[extractor/rtl.lu] Add extractor (#4222)
Closes #1721
Authored by: HobbyistDev
2 years ago
Tim Weber eb2333bce1
[extractor/StarTrek] Add extractor (#4191)
Authored by: scy
2 years ago
u-spec-png 660c0c4efd
[extractor/Trovo] Fix extractor (#4208)
Authored by: u-spec-png
2 years ago
Locke fe588ce8ef
[extractor/acfun] Add extractors (#4228)
Closes #3545
Authored by: lockmatrix
2 years ago
HobbyistDev 26b92a919d
[extractor/tviplayer] Add extractor (#4281)
Closes #2134
Authored by: HobbyistDev
2 years ago
HobbyistDev 8f47b39b27
[extractor/detik] Add extractor (#4284)
Closes #4283
Authored by: HobbyistDev
2 years ago
llamasblade 2f1b7afe32
[extractor/hytale] Add extractor (#4326)
Authored by: llamasblade, pukkandan
2 years ago
Locke dd634acd71
[extractor/Ximalaya] Fix extractors (#4339)
Authored by: lockmatrix
2 years ago
pukkandan ebf99aaf70
[utils] Fix `get_domain`
Bug in ae61d108dd

Closes #4344
2 years ago
HobbyistDev cbd4f237b4
[extractor/cellebrite] Add extractor (#4333)
Closes #4014
Authored by: HobbyistDev
2 years ago
ftk 418bbfd722
[extractor/twitch] Support storyboards for VODs (#4342)
Authored by: ftk
2 years ago
ftk 45e8a04e48
[extractor/youtube] More metadata for storyboards (#4334)
Authored by: ftk
2 years ago
Sebastian Wallkötter 0f44636597
[docs] Improve docstring of `download_ranges` (#4340)
Authored by: FirefoxMetzger
2 years ago
Elyse 7a7eeb1005
[aes] Add multiple padding modes in CBC
Authored by: elyse0
2 years ago
Dosychev Peter 4e7f375c94
[extractor/theholetv] Add extractor (#4325)
Authored by: dosy4ev
2 years ago
pukkandan f5ea47488a
[cleanup] Minor fixes 2 years ago
pukkandan 134c913cca
Discard info_dict from memory if no longer needed
Closes #1399
2 years ago
pukkandan 56b5b832bf
[extractor/crunchyroll] Improve _VALID_URL
<http://www.crunchyroll.com/series/GR24PVM76/nichijou-my-ordinary-life>
should be handled by Generic

Closes #4322
2 years ago
pukkandan cb794ee010
Do not allow extractors to return `None` 2 years ago
pukkandan 6d645b5577
[http] Ensure the file handle is always closed
Closes #4323
2 years ago
pukkandan 563e0bf82a
Fix rounding of integers in format table 2 years ago
pukkandan d816f61fbf
[utils, cleanup] Refactor parse_codecs 2 years ago
pukkandan 4019bf0525
[ModifyChapters] Modify duration in infodict 2 years ago
HobbyistDev 65ea4cba29
[extractor/mocha] Add extractor (#4213)
Closes https://github.com/yt-dlp/yt-dlp/issues/3752
Authored by: HobbyistDev
2 years ago
Misael Aguayo 17a23f0930
[extractor/syvdk] Add extractor (#4250)
Closes https://github.com/yt-dlp/yt-dlp/issues/4077
Authored by: misaelaguayo
2 years ago
pukkandan 258d88f301
[test] Split download tests so they can be more easily run in CI 2 years ago
pukkandan a3fb1ca5ab
[extractor/youtube] Fix duration check for post-live manifestless mode 2 years ago
Lesmiscore (Naoya Ozaki) 1275aeb955
[extractor/bigo] Fix extractor (#4312)
Closes #4139

Authored by: Lesmiscore
2 years ago
ischmidt20 170a031386
[extractor/fifa] Fix extractor (#4272)
Authored by: ischmidt20
2 years ago
Felix S 65493f64e1
[extractor/Audiodraft] Add extractors (#4288)
Based on https://github.com/yt-dlp/yt-dlp/pull/4259
Closes https://github.com/yt-dlp/yt-dlp/issues/4028

Authored by: fstirlitz, Ashish0804
2 years ago
HobbyistDev 63e66cd0ad
[extractor/liputan6] Add extractor (#4304)
Closes #4303

Authored by: HobbyistDev
2 years ago
pukkandan f2df407165
[cleanup] Misc cleanup 2 years ago
Lesmiscore (Naoya Ozaki) ca9def714a
Skip some fixup if remux/recode is needed (#4266)
Authored by: Lesmiscore
2 years ago
pukkandan 47cdc68e03
[outtmpl] Add alternate form `h` for HTML escaping
Related: https://github.com/yt-dlp/yt-dlp/issues/3292
2 years ago
pukkandan 7b84d6f9b3
[build] Improve `setup.py`
Closes #4296
2 years ago
Andrew 12a1b2254d
[extractor/youtube, cleanup] Fix tests (#4293)
Authored by: sheerluck
2 years ago
pukkandan 6154438178
[extractor/generic] Remove HEAD request 2 years ago
pukkandan 168bbc4f38
Do not load system certificates when `certifi` is used
This causes `CERTIFICATE_VERIFY_FAILED` if there is an
expired/bad certificate in the system store

Partially reverts 8a82af3511

Related: #4145
2 years ago
pukkandan a3976e0760
Improve chapter sanitization 2 years ago
pukkandan 385f7f3895
[extractor/iq] Set language correctly for Korean subtitles
Closes #3500
2 years ago
Lesmiscore 5c0dc6e603
[devscripts/update-formulae] Do not change dependency section
Closes #4223
2 years ago
pukkandan 284a60c516
[options] Fix aliases to `--config-location` 2 years ago
Lesmiscore 44f14eb43e
Fix bug in 612f2be5d3 2 years ago
pukkandan ca9f1df253
[docs] Improve issue templates 2 years ago
pukkandan a63b35a60c
[update] Do not check `_update_spec` when up to date 2 years ago
pukkandan 28cdb605aa
[build] Fix bug in 6d916fe709 2 years ago
Chris Lamb 5b836d4739
[build] Consistent order for lazy extractors (#4220)
Authored by: lamby
2 years ago
github-actions 84a251e1f5 [version] update
Created by: pukkandan

:ci skip all :ci run dl
2 years ago
pukkandan 9d339c41e2
Release 2022.06.29 2 years ago
pukkandan ae61d108dd
[cleanup] Misc cleanup 2 years ago
pukkandan 47046464fa
[extractor] Fix empty `BaseURL` in MPD
Closes #4113
2 years ago
pukkandan b1f94422cc
[update] Ability to set a maximum version for specific variants 2 years ago
pukkandan c2c8921b41
[build] Draft release until complete
Related: #4133

:ci skip
2 years ago
nomevi 844086505f
[extractor/livestreamfails] Add extractor (#4204)
Authored by: nomevi
2 years ago
Stefan Lobbenmeier 63da2d0911
Fix bug in 6d916fe709 (#4219)
Update only to legacy version on old MacOS

Authored by: StefanLobbenmeier
2 years ago
FestplattenSchnitzel 1db1461272
[extractor/ViMP] Add playlist extractor (#4147)
Authored by: FestplattenSchnitzel
2 years ago
HobbyistDev 5fb450a64c
[extractor/steam] Add broadcast extractor (#4137)
Closes #4083

Authored by: HobbyistDev
2 years ago
Stefan Lobbenmeier 6d916fe709
[build] Standalone x64 builds for MacOS 10.9 (#4106)
Authored by: StefanLobbenmeier
2 years ago
Abubukker Chaudhary 2c60eae899
[extractor/Scrolller] Add extractor (#4010)
Closes #3635
Authored by: LunarFang416
2 years ago
crazymoose77756 962ffcf89c
[cleanup] Fix some typos (#4194)
Authored by: crazymoose77756
2 years ago
MMM 8a40bffaf9
[exractor/lbry] Use HEAD request for redirect URL (#4181)
and misc cleanup 

Authored by: flashdagger
2 years ago
pukkandan e08f72e675
[extractor/mediaset] Improve `_VALID_URL`
Fixes https://github.com/yt-dlp/yt-dlp/issues/4141#issuecomment-1166521057
2 years ago
pukkandan 1685d46007
[extractor/ertflix] Improve `_VALID_URL`
Closes #4180
2 years ago
ischmidt20 8d214c484c
[extractor/CWTV] Extract thumbnail (#4185)
Authored by: ischmidt20
2 years ago
pukkandan 9eef7c4e55
Sanitize `chapters`
Closes #4182
2 years ago
pukkandan bbae437723
[hls] Warn user when trying to download live HLS
We do not automatically switch to ffmpeg because the detection is not 100% accurate
2 years ago
HobbyistDev 30d22d775b
[extractor/premiershiprugby] Add extractor (#4129)
Closes #2980
Authored by: HobbyistDev
2 years ago
pukkandan c043c24625
[extractor] Fix `_create_request` when headers is None
Closes #4164
2 years ago
FestplattenSchnitzel 74900105be
[extractor/ViMP] Add thumbnail and support more sites (#4147)
Authored by: FestplattenSchnitzel
2 years ago
HobbyistDev d1bf2e199c
[extractor/fuyin] Add extractor (#4151)
Closes #2871

Authored by: HobbyistDev
2 years ago
pukkandan c800598cd1
[options] Fix `parse_known_args` for `--`
Closes #4167
2 years ago
pukkandan 14f25df2b6
[compat] Remove deprecated functions from core code 2 years ago
pukkandan 54007a45f1
[cleanup] Consistent style for file heads 2 years ago
pukkandan ac66811112
[compat] Remove more functions
Removing any more will require changes to a large number of extractors
2 years ago
pukkandan 3c5386cd71
[compat] Fix `compat.WINDOWS_VT_MODE` 2 years ago
pukkandan bc40160883
Fix `section_end` of clips
Closes #4165
2 years ago
coletdev 379a4f161d
[utils] Fix inconsistent default handling between HTTP and HTTPS requests (#4158)
Default headers such as `Content-Type` were only being added for HTTPS requests among other handling.

Fixes bug in be4a824d74

Authored-by: coletdjnz
2 years ago
Brett824 06cc8f103b
[extractor/youtube] Mark videos as fully watched (#4146)
* Also fixes videos appearing as shorts in watch history

Closes #2555
Authored by: Brett824
2 years ago
Jelle Besseling 34baaced11
[extractor/dropout] Support cookies and login only as needed (#4075)
Closes #4035
Authored by: pingiun, pukkandan
2 years ago
pukkandan 9809740ba5
[extractor, cleanup] Reduce direct use of `_downloader` 2 years ago
pukkandan f67baae17e
[ffmpeg] Write full output to debug on error
Bug in f0c9fb9682
2 years ago
zenerdi0de 37e40d693b
[extractor/tennistv] Rewrite extractor (#2324)
Closes #2177
Authored by: zenerdi0de, pukkandan
2 years ago
pukkandan 0c36dc00d7
[extractor/npr] Implement e50c3500b4 differently
Closes #4141
2 years ago
pukkandan 28163422a6
Fix `--downloader native`
Bug in 7b2c3f47c6
2 years ago
pukkandan 1ac4fd80c8
Fix playlist error handling
Bug in 7e88d7d78f
2 years ago
pukkandan 885fe351fb
[build] Fix release tag commit
bug in b5899f4f19
2 years ago
github-actions f92347c312 [version] update
Created by: pukkandan

:ci skip all :ci run dl
2 years ago
pukkandan a86e01e743
Release 2022.06.22.1 2 years ago
pukkandan 1ed70fd0b7
[build] Fix updating homebrew formula
bug in b5899f4f19
2 years ago
github-actions def4973ae7 [version] update
Created by: pukkandan

:ci skip all :ci run dl
2 years ago

@ -1,7 +1,14 @@
name: Broken site
description: Report broken or misfunctioning site
name: Broken site support
description: Report issue with yt-dlp on a supported site
labels: [triage, site-bug]
body:
- type: checkboxes
attributes:
label: DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE
description: Fill all fields even if you think it is irrelevant for the issue
options:
- label: I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field
required: true
- type: checkboxes
id: checklist
attributes:
@ -9,15 +16,15 @@ body:
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
- label: I'm reporting that yt-dlp is broken on a **supported** site
required: true
- label: I've verified that I'm running yt-dlp version **2022.05.18** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- label: I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
required: true
- label: I've checked that all provided URLs are playable in a browser with the same IP and same login details
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)
- label: I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#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
- label: I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and 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
@ -26,37 +33,46 @@ body:
id: region
attributes:
label: Region
description: "Enter the region the site is accessible from"
placeholder: "India"
description: Enter the country/region that 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
label: Provide a description that is worded well enough to be understood
description: See [is-the-description-of-the-issue-itself-sufficient](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-description-of-the-issue-itself-sufficient)
placeholder: Provide any additional information, any suggested solutions, and as much context and examples as possible
validations:
required: true
- type: checkboxes
id: verbose
attributes:
label: Provide verbose output that clearly demonstrates the problem
options:
- label: Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
required: true
- label: "If using API, add `'verbose': True` to `YoutubeDL` params instead"
required: false
- label: Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below
required: true
- type: textarea
id: log
attributes:
label: Verbose log
label: Complete Verbose Output
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:
It should start like 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.05.18 (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] Command-line config: ['-vU', 'https://www.youtube.com/watch?v=BaW_jenozKc']
[debug] Encodings: locale cp65001, fs utf-8, pref cp65001, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@... from yt-dlp/yt-dlp [b634ba742] (win_exe)
[debug] Python 3.8.10 (CPython 64bit) - Windows-10-10.0.22000-SP0
[debug] exe versions: ffmpeg N-106550-g072101bd52-20220410 (fdk,setts), ffprobe N-106624-g391ce570c8-20220415, phantomjs 2.1.1
[debug] Optional libraries: Cryptodome-3.15.0, brotli-1.0.9, certifi-2022.06.15, mutagen-1.45.1, sqlite3-2.6.0, websockets-10.3
[debug] Proxy map: {}
yt-dlp is up to date (2022.05.18)
[debug] Request Handlers: urllib, requests
[debug] Loaded 1893 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
yt-dlp is up to date (nightly@... from yt-dlp/yt-dlp-nightly-builds)
[youtube] Extracting URL: https://www.youtube.com/watch?v=BaW_jenozKc
<more lines>
render: shell
validations:

@ -2,6 +2,13 @@ name: Site support request
description: Request support for a new site
labels: [triage, site-request]
body:
- type: checkboxes
attributes:
label: DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE
description: Fill all fields even if you think it is irrelevant for the issue
options:
- label: I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field
required: true
- type: checkboxes
id: checklist
attributes:
@ -11,13 +18,13 @@ body:
options:
- label: I'm reporting a new site support request
required: true
- label: I've verified that I'm running yt-dlp version **2022.05.18** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- label: I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
required: true
- label: I've checked that all provided URLs are playable in a browser with the same IP and same login details
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
- label: I've checked that none of provided URLs [violate any copyrights](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-website-primarily-used-for-piracy) 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
- label: I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and 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
@ -26,8 +33,8 @@ body:
id: region
attributes:
label: Region
description: "Enter the region the site is accessible from"
placeholder: "India"
description: Enter the country/region that the site is accessible from
placeholder: India
- type: textarea
id: example-urls
attributes:
@ -43,31 +50,41 @@ body:
- type: textarea
id: description
attributes:
label: Description
description: |
Provide any additional information
placeholder: WRITE DESCRIPTION HERE
label: Provide a description that is worded well enough to be understood
description: See [is-the-description-of-the-issue-itself-sufficient](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-description-of-the-issue-itself-sufficient)
placeholder: Provide any additional information, any suggested solutions, and as much context and examples as possible
validations:
required: true
- type: checkboxes
id: verbose
attributes:
label: Provide verbose output that clearly demonstrates the problem
options:
- label: Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
required: true
- label: "If using API, add `'verbose': True` to `YoutubeDL` params instead"
required: false
- label: Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below
required: true
- type: textarea
id: log
attributes:
label: Verbose log
label: Complete Verbose Output
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:
It should start like 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.05.18 (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] Command-line config: ['-vU', 'https://www.youtube.com/watch?v=BaW_jenozKc']
[debug] Encodings: locale cp65001, fs utf-8, pref cp65001, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@... from yt-dlp/yt-dlp [b634ba742] (win_exe)
[debug] Python 3.8.10 (CPython 64bit) - Windows-10-10.0.22000-SP0
[debug] exe versions: ffmpeg N-106550-g072101bd52-20220410 (fdk,setts), ffprobe N-106624-g391ce570c8-20220415, phantomjs 2.1.1
[debug] Optional libraries: Cryptodome-3.15.0, brotli-1.0.9, certifi-2022.06.15, mutagen-1.45.1, sqlite3-2.6.0, websockets-10.3
[debug] Proxy map: {}
yt-dlp is up to date (2022.05.18)
[debug] Request Handlers: urllib, requests
[debug] Loaded 1893 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
yt-dlp is up to date (nightly@... from yt-dlp/yt-dlp-nightly-builds)
[youtube] Extracting URL: https://www.youtube.com/watch?v=BaW_jenozKc
<more lines>
render: shell
validations:

@ -2,6 +2,13 @@ name: Site feature request
description: Request a new functionality for a supported site
labels: [triage, site-enhancement]
body:
- type: checkboxes
attributes:
label: DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE
description: Fill all fields even if you think it is irrelevant for the issue
options:
- label: I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field
required: true
- type: checkboxes
id: checklist
attributes:
@ -11,11 +18,11 @@ body:
options:
- label: I'm requesting a site-specific feature
required: true
- label: I've verified that I'm running yt-dlp version **2022.05.18** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- label: I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
required: true
- label: I've checked that all provided URLs are playable in a browser with the same IP and same login details
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
- label: I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and 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
@ -24,8 +31,8 @@ body:
id: region
attributes:
label: Region
description: "Enter the region the site is accessible from"
placeholder: "India"
description: Enter the country/region that the site is accessible from
placeholder: India
- type: textarea
id: example-urls
attributes:
@ -39,33 +46,41 @@ body:
- 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
label: Provide a description that is worded well enough to be understood
description: See [is-the-description-of-the-issue-itself-sufficient](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-description-of-the-issue-itself-sufficient)
placeholder: Provide any additional information, any suggested solutions, and as much context and examples as possible
validations:
required: true
- type: checkboxes
id: verbose
attributes:
label: Provide verbose output that clearly demonstrates the problem
options:
- label: Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
required: true
- label: "If using API, add `'verbose': True` to `YoutubeDL` params instead"
required: false
- label: Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below
required: true
- type: textarea
id: log
attributes:
label: Verbose log
label: Complete Verbose Output
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:
It should start like 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.05.18 (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] Command-line config: ['-vU', 'https://www.youtube.com/watch?v=BaW_jenozKc']
[debug] Encodings: locale cp65001, fs utf-8, pref cp65001, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@... from yt-dlp/yt-dlp [b634ba742] (win_exe)
[debug] Python 3.8.10 (CPython 64bit) - Windows-10-10.0.22000-SP0
[debug] exe versions: ffmpeg N-106550-g072101bd52-20220410 (fdk,setts), ffprobe N-106624-g391ce570c8-20220415, phantomjs 2.1.1
[debug] Optional libraries: Cryptodome-3.15.0, brotli-1.0.9, certifi-2022.06.15, mutagen-1.45.1, sqlite3-2.6.0, websockets-10.3
[debug] Proxy map: {}
yt-dlp is up to date (2022.05.18)
[debug] Request Handlers: urllib, requests
[debug] Loaded 1893 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
yt-dlp is up to date (nightly@... from yt-dlp/yt-dlp-nightly-builds)
[youtube] Extracting URL: https://www.youtube.com/watch?v=BaW_jenozKc
<more lines>
render: shell
validations:

@ -1,7 +1,14 @@
name: Bug report
name: Core bug report
description: Report a bug unrelated to any particular site or extractor
labels: [triage, bug]
body:
- type: checkboxes
attributes:
label: DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE
description: Fill all fields even if you think it is irrelevant for the issue
options:
- label: I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field
required: true
- type: checkboxes
id: checklist
attributes:
@ -11,46 +18,54 @@ body:
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.05.18** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- label: I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
required: true
- label: I've checked that all provided URLs are playable in a browser with the same IP and same login details
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)
- label: I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#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
- label: I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and 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
label: Provide a description that is worded well enough to be understood
description: See [is-the-description-of-the-issue-itself-sufficient](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-description-of-the-issue-itself-sufficient)
placeholder: Provide any additional information, any suggested solutions, and as much context and examples as possible
validations:
required: true
- type: checkboxes
id: verbose
attributes:
label: Provide verbose output that clearly demonstrates the problem
options:
- label: Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
required: true
- label: "If using API, add `'verbose': True` to `YoutubeDL` params instead"
required: false
- label: Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below
required: true
- type: textarea
id: log
attributes:
label: Verbose log
label: Complete Verbose Output
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:
It should start like 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.05.18 (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] Command-line config: ['-vU', 'https://www.youtube.com/watch?v=BaW_jenozKc']
[debug] Encodings: locale cp65001, fs utf-8, pref cp65001, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@... from yt-dlp/yt-dlp [b634ba742] (win_exe)
[debug] Python 3.8.10 (CPython 64bit) - Windows-10-10.0.22000-SP0
[debug] exe versions: ffmpeg N-106550-g072101bd52-20220410 (fdk,setts), ffprobe N-106624-g391ce570c8-20220415, phantomjs 2.1.1
[debug] Optional libraries: Cryptodome-3.15.0, brotli-1.0.9, certifi-2022.06.15, mutagen-1.45.1, sqlite3-2.6.0, websockets-10.3
[debug] Proxy map: {}
yt-dlp is up to date (2022.05.18)
[debug] Request Handlers: urllib, requests
[debug] Loaded 1893 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
yt-dlp is up to date (nightly@... from yt-dlp/yt-dlp-nightly-builds)
[youtube] Extracting URL: https://www.youtube.com/watch?v=BaW_jenozKc
<more lines>
render: shell
validations:

@ -2,6 +2,13 @@ name: Feature request
description: Request a new functionality unrelated to any particular site or extractor
labels: [triage, enhancement]
body:
- type: checkboxes
attributes:
label: DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE
description: Fill all fields even if you think it is irrelevant for the issue
options:
- label: I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field
required: true
- type: checkboxes
id: checklist
attributes:
@ -13,41 +20,47 @@ body:
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.05.18** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- label: I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
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
- label: I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and 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
label: Provide a description that is worded well enough to be understood
description: See [is-the-description-of-the-issue-itself-sufficient](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-description-of-the-issue-itself-sufficient)
placeholder: Provide any additional information, any suggested solutions, and as much context and examples as possible
validations:
required: true
- type: checkboxes
id: verbose
attributes:
label: Provide verbose output that clearly demonstrates the problem
options:
- label: Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- label: "If using API, add `'verbose': True` to `YoutubeDL` params instead"
required: false
- label: Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below
- type: textarea
id: log
attributes:
label: Verbose log
label: Complete Verbose Output
description: |
If your feature request involves an existing 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:
It should start like 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] Command-line config: ['-vU', 'https://www.youtube.com/watch?v=BaW_jenozKc']
[debug] Encodings: locale cp65001, fs utf-8, pref cp65001, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@... from yt-dlp/yt-dlp [b634ba742] (win_exe)
[debug] Python 3.8.10 (CPython 64bit) - Windows-10-10.0.22000-SP0
[debug] exe versions: ffmpeg N-106550-g072101bd52-20220410 (fdk,setts), ffprobe N-106624-g391ce570c8-20220415, phantomjs 2.1.1
[debug] Optional libraries: Cryptodome-3.15.0, brotli-1.0.9, certifi-2022.06.15, mutagen-1.45.1, sqlite3-2.6.0, websockets-10.3
[debug] Proxy map: {}
yt-dlp is up to date (2021.12.01)
[debug] Request Handlers: urllib, requests
[debug] Loaded 1893 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
yt-dlp is up to date (nightly@... from yt-dlp/yt-dlp-nightly-builds)
[youtube] Extracting URL: https://www.youtube.com/watch?v=BaW_jenozKc
<more lines>
render: shell

@ -2,6 +2,19 @@ name: Ask question
description: Ask yt-dlp related question
labels: [question]
body:
- type: checkboxes
attributes:
label: DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE
description: Fill all fields even if you think it is irrelevant for the issue
options:
- label: I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field
required: true
- type: markdown
attributes:
value: |
### Make sure you are **only** asking a question and not reporting a bug or requesting a feature.
If your question contains "isn't working" or "can you add", this is most likely the wrong template.
If you are in doubt whether this is the right template, **USE ANOTHER TEMPLATE**!
- type: checkboxes
id: checklist
attributes:
@ -13,43 +26,47 @@ body:
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.05.18** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- label: I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
required: true
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar questions including closed ones. DO NOT post duplicates
- label: I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar questions **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: 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
label: Please make sure the question is worded well enough to be understood
description: See [is-the-description-of-the-issue-itself-sufficient](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-description-of-the-issue-itself-sufficient)
placeholder: Provide any additional information and as much context and examples as possible
validations:
required: true
- type: checkboxes
id: verbose
attributes:
label: Provide verbose output that clearly demonstrates the problem
options:
- label: Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- label: "If using API, add `'verbose': True` to `YoutubeDL` params instead"
required: false
- label: Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below
- type: textarea
id: log
attributes:
label: Verbose log
label: Complete Verbose Output
description: |
If your question involves 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:
It should start like 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] Command-line config: ['-vU', 'https://www.youtube.com/watch?v=BaW_jenozKc']
[debug] Encodings: locale cp65001, fs utf-8, pref cp65001, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@... from yt-dlp/yt-dlp [b634ba742] (win_exe)
[debug] Python 3.8.10 (CPython 64bit) - Windows-10-10.0.22000-SP0
[debug] exe versions: ffmpeg N-106550-g072101bd52-20220410 (fdk,setts), ffprobe N-106624-g391ce570c8-20220415, phantomjs 2.1.1
[debug] Optional libraries: Cryptodome-3.15.0, brotli-1.0.9, certifi-2022.06.15, mutagen-1.45.1, sqlite3-2.6.0, websockets-10.3
[debug] Proxy map: {}
yt-dlp is up to date (2021.12.01)
[debug] Request Handlers: urllib, requests
[debug] Loaded 1893 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
yt-dlp is up to date (nightly@... from yt-dlp/yt-dlp-nightly-builds)
[youtube] Extracting URL: https://www.youtube.com/watch?v=BaW_jenozKc
<more lines>
render: shell

@ -1,7 +1,8 @@
name: Broken site
description: Report broken or misfunctioning site
name: Broken site support
description: Report issue with yt-dlp on a supported site
labels: [triage, site-bug]
body:
%(no_skip)s
- type: checkboxes
id: checklist
attributes:
@ -9,15 +10,15 @@ body:
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
- label: I'm reporting that yt-dlp is broken on a **supported** 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)) or later (specify commit)
- label: I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
required: true
- label: I've checked that all provided URLs are playable in a browser with the same IP and same login details
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)
- label: I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#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
- label: I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and 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
@ -26,38 +27,14 @@ body:
id: region
attributes:
label: Region
description: "Enter the region the site is accessible from"
placeholder: "India"
description: Enter the country/region that 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
label: Provide a description that is worded well enough to be understood
description: See [is-the-description-of-the-issue-itself-sufficient](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-description-of-the-issue-itself-sufficient)
placeholder: Provide any additional information, any suggested solutions, and as much context and examples as possible
validations:
required: true
%(verbose)s

@ -2,6 +2,7 @@ name: Site support request
description: Request support for a new site
labels: [triage, site-request]
body:
%(no_skip)s
- type: checkboxes
id: checklist
attributes:
@ -11,13 +12,13 @@ body:
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)) or later (specify commit)
- label: I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
required: true
- label: I've checked that all provided URLs are playable in a browser with the same IP and same login details
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
- label: I've checked that none of provided URLs [violate any copyrights](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-website-primarily-used-for-piracy) 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
- label: I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and 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
@ -26,8 +27,8 @@ body:
id: region
attributes:
label: Region
description: "Enter the region the site is accessible from"
placeholder: "India"
description: Enter the country/region that the site is accessible from
placeholder: India
- type: textarea
id: example-urls
attributes:
@ -43,32 +44,9 @@ body:
- 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
label: Provide a description that is worded well enough to be understood
description: See [is-the-description-of-the-issue-itself-sufficient](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-description-of-the-issue-itself-sufficient)
placeholder: Provide any additional information, any suggested solutions, and as much context and examples as possible
validations:
required: true
%(verbose)s

@ -2,6 +2,7 @@ name: Site feature request
description: Request a new functionality for a supported site
labels: [triage, site-enhancement]
body:
%(no_skip)s
- type: checkboxes
id: checklist
attributes:
@ -11,11 +12,11 @@ body:
options:
- label: I'm requesting a site-specific feature
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)) or later (specify commit)
- label: I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
required: true
- label: I've checked that all provided URLs are playable in a browser with the same IP and same login details
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
- label: I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and 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
@ -24,8 +25,8 @@ body:
id: region
attributes:
label: Region
description: "Enter the region the site is accessible from"
placeholder: "India"
description: Enter the country/region that the site is accessible from
placeholder: India
- type: textarea
id: example-urls
attributes:
@ -39,34 +40,9 @@ body:
- 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
label: Provide a description that is worded well enough to be understood
description: See [is-the-description-of-the-issue-itself-sufficient](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-description-of-the-issue-itself-sufficient)
placeholder: Provide any additional information, any suggested solutions, and as much context and examples as possible
validations:
required: true
%(verbose)s

@ -1,7 +1,8 @@
name: Bug report
name: Core bug report
description: Report a bug unrelated to any particular site or extractor
labels: [triage, bug]
body:
%(no_skip)s
- type: checkboxes
id: checklist
attributes:
@ -11,47 +12,22 @@ body:
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)) or later (specify commit)
- label: I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
required: true
- label: I've checked that all provided URLs are playable in a browser with the same IP and same login details
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)
- label: I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#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
- label: I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and 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
label: Provide a description that is worded well enough to be understood
description: See [is-the-description-of-the-issue-itself-sufficient](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-description-of-the-issue-itself-sufficient)
placeholder: Provide any additional information, any suggested solutions, and as much context and examples as possible
validations:
required: true
%(verbose)s

@ -2,6 +2,7 @@ name: Feature request
description: Request a new functionality unrelated to any particular site or extractor
labels: [triage, enhancement]
body:
%(no_skip)s
- type: checkboxes
id: checklist
attributes:
@ -13,41 +14,18 @@ body:
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)) or later (specify commit)
- label: I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
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
- label: I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and 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
label: Provide a description that is worded well enough to be understood
description: See [is-the-description-of-the-issue-itself-sufficient](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-description-of-the-issue-itself-sufficient)
placeholder: Provide any additional information, any suggested solutions, and as much context and examples as possible
validations:
required: true
- type: textarea
id: log
attributes:
label: Verbose log
description: |
If your feature request involves an existing 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
%(verbose_optional)s

@ -2,6 +2,13 @@ name: Ask question
description: Ask yt-dlp related question
labels: [question]
body:
%(no_skip)s
- type: markdown
attributes:
value: |
### Make sure you are **only** asking a question and not reporting a bug or requesting a feature.
If your question contains "isn't working" or "can you add", this is most likely the wrong template.
If you are in doubt whether this is the right template, **USE ANOTHER TEMPLATE**!
- type: checkboxes
id: checklist
attributes:
@ -13,43 +20,18 @@ body:
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)) or later (specify commit)
- label: I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
required: true
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar questions including closed ones. DO NOT post duplicates
- label: I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar questions **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: 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
label: Please make sure the question is worded well enough to be understood
description: See [is-the-description-of-the-issue-itself-sufficient](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-description-of-the-issue-itself-sufficient)
placeholder: Provide any additional information and as much context and examples as possible
validations:
required: true
- type: textarea
id: log
attributes:
label: Verbose log
description: |
If your question involves 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
%(verbose_optional)s

@ -1,5 +1,23 @@
**IMPORTANT**: PRs without the template will be CLOSED
### Description of your *pull request* and other information
<!--
Explanation of your *pull request* in arbitrary form goes here. Please **make sure the description explains the purpose and effect** of your *pull request* and is worded well enough to be understood. Provide as much **context and examples** as possible
-->
ADD DESCRIPTION HERE
Fixes #
<details open><summary>Template</summary> <!-- OPEN is intentional -->
<!--
# Please follow the guide below
# PLEASE FOLLOW THE GUIDE BELOW
- You will be asked some questions, please read them **carefully** and answer honestly
- Put an `x` into all the boxes `[ ]` relevant to your *pull request* (like [x])
@ -12,7 +30,7 @@
- [ ] [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) and [ran relevant tests](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#developer-instructions)
### 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:
### 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 all of the following options that apply:
- [ ] 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)
@ -22,8 +40,4 @@
- [ ] Core bug fix/improvement
- [ ] New feature (It is strongly [recommended to open an issue first](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#adding-new-feature-or-making-overarching-changes))
---
### Description of your *pull request* and other information
Explanation of your *pull request* in arbitrary form goes here. Please **make sure the description explains the purpose and effect** of your *pull request* and is worded well enough to be understood. Provide as much **context and examples** as possible.
</details>

10
.github/banner.svg vendored

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 15 KiB

@ -1,396 +1,507 @@
name: Build
on: workflow_dispatch
name: Build Artifacts
on:
workflow_call:
inputs:
version:
required: true
type: string
channel:
required: false
default: stable
type: string
unix:
default: true
type: boolean
linux_static:
default: true
type: boolean
linux_arm:
default: true
type: boolean
macos:
default: true
type: boolean
macos_legacy:
default: true
type: boolean
windows:
default: true
type: boolean
windows32:
default: true
type: boolean
origin:
required: false
default: ''
type: string
secrets:
GPG_SIGNING_KEY:
required: false
workflow_dispatch:
inputs:
version:
description: |
VERSION: yyyy.mm.dd[.rev] or rev
required: true
type: string
channel:
description: |
SOURCE of this build's updates: stable/nightly/master/<repo>
required: true
default: stable
type: string
unix:
description: yt-dlp, yt-dlp.tar.gz
default: true
type: boolean
linux_static:
description: yt-dlp_linux
default: true
type: boolean
linux_arm:
description: yt-dlp_linux_aarch64, yt-dlp_linux_armv7l
default: true
type: boolean
macos:
description: yt-dlp_macos, yt-dlp_macos.zip
default: true
type: boolean
macos_legacy:
description: yt-dlp_macos_legacy
default: true
type: boolean
windows:
description: yt-dlp.exe, yt-dlp_min.exe, yt-dlp_win.zip
default: true
type: boolean
windows32:
description: yt-dlp_x86.exe
default: true
type: boolean
origin:
description: Origin
required: false
default: 'current repo'
type: choice
options:
- 'current repo'
permissions:
contents: read
jobs:
create_release:
process:
runs-on: ubuntu-latest
outputs:
version_suffix: ${{ steps.version_suffix.outputs.version_suffix }}
ytdlp_version: ${{ steps.bump_version.outputs.ytdlp_version }}
upload_url: ${{ steps.create_release.outputs.upload_url }}
origin: ${{ steps.process_origin.outputs.origin }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-python@v2
with:
python-version: '3.10'
- 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
id: bump_version
run: |
python devscripts/update-version.py ${{ steps.version_suffix.outputs.version_suffix }}
make issuetemplates
- name: Push to 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 :ci run dl"
git push origin --force ${{ github.event.ref }}:release
echo ::set-output name=head_sha::$(git rev-parse HEAD)
- name: Update master
env:
PUSH_VERSION_COMMIT: ${{ secrets.PUSH_VERSION_COMMIT }}
if: "env.PUSH_VERSION_COMMIT != ''"
run: git push origin ${{ github.event.ref }}
- name: Get Changelog
run: |
changelog=$(grep -oPz '(?s)(?<=### ${{ steps.bump_version.outputs.ytdlp_version }}\n{2}).+?(?=\n{2,3}###)' Changelog.md) || true
echo "changelog<<EOF" >> $GITHUB_ENV
echo "$changelog" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- 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
---
### Changelog:
${{ env.changelog }}
draft: false
prerelease: false
build_unix:
needs: create_release
runs-on: ubuntu-18.04 # Standalone executable should be built on minimum supported OS
outputs:
sha256_bin: ${{ steps.get_sha.outputs.sha256_bin }}
sha512_bin: ${{ steps.get_sha.outputs.sha512_bin }}
sha256_tar: ${{ steps.get_sha.outputs.sha256_tar }}
sha512_tar: ${{ steps.get_sha.outputs.sha512_tar }}
sha256_linux: ${{ steps.get_sha.outputs.sha256_linux }}
sha512_linux: ${{ steps.get_sha.outputs.sha512_linux }}
sha256_linux_zip: ${{ steps.get_sha.outputs.sha256_linux_zip }}
sha512_linux_zip: ${{ steps.get_sha.outputs.sha512_linux_zip }}
- name: Process origin
id: process_origin
run: |
echo "origin=${{ inputs.origin == 'current repo' && github.repository || inputs.origin }}" | tee "$GITHUB_OUTPUT"
unix:
needs: process
if: inputs.unix
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.10'
- name: Install Requirements
run: |
sudo apt-get -y install zip pandoc man
python -m pip install --upgrade pip setuptools wheel twine
python -m pip install Pyinstaller -r requirements.txt
- name: Prepare
run: |
python devscripts/update-version.py ${{ needs.create_release.outputs.version_suffix }}
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Needed for changelog
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install Requirements
run: |
sudo apt -y install zip pandoc man sed
- name: Prepare
run: |
python devscripts/update-version.py -c "${{ inputs.channel }}" -r "${{ needs.process.outputs.origin }}" "${{ inputs.version }}"
python devscripts/update_changelog.py -vv
python devscripts/make_lazy_extractors.py
- name: Build Unix executables
run: |
- name: Build Unix platform-independent binary
run: |
make all tar
python pyinst.py --onedir
(cd ./dist/yt-dlp_linux && zip -r ../yt-dlp_linux.zip .)
python pyinst.py
- name: Get SHA2-SUMS
id: get_sha
run: |
echo "::set-output name=sha256_bin::$(sha256sum yt-dlp | awk '{print $1}')"
echo "::set-output name=sha512_bin::$(sha512sum yt-dlp | awk '{print $1}')"
echo "::set-output name=sha256_tar::$(sha256sum yt-dlp.tar.gz | awk '{print $1}')"
echo "::set-output name=sha512_tar::$(sha512sum yt-dlp.tar.gz | awk '{print $1}')"
echo "::set-output name=sha256_linux::$(sha256sum dist/yt-dlp_linux | awk '{print $1}')"
echo "::set-output name=sha512_linux::$(sha512sum dist/yt-dlp_linux | awk '{print $1}')"
echo "::set-output name=sha256_linux_zip::$(sha256sum dist/yt-dlp_linux.zip | awk '{print $1}')"
echo "::set-output name=sha512_linux_zip::$(sha512sum dist/yt-dlp_linux.zip | awk '{print $1}')"
- name: Upload zip binary
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.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: ${{ needs.create_release.outputs.upload_url }}
asset_path: ./yt-dlp.tar.gz
asset_name: yt-dlp.tar.gz
asset_content_type: application/gzip
- name: Upload standalone binary
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_path: ./dist/yt-dlp_linux
asset_name: yt-dlp_linux
asset_content_type: application/octet-stream
- name: Upload onedir binary
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_path: ./dist/yt-dlp_linux.zip
asset_name: yt-dlp_linux.zip
asset_content_type: application/zip
- name: Build and publish on PyPi
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
if: "env.TWINE_PASSWORD != ''"
run: |
rm -rf dist/*
python setup.py sdist bdist_wheel
twine upload dist/*
- name: Install SSH private key for Homebrew
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/
python 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
build_macos:
- name: Verify --update-to
if: vars.UPDATE_TO_VERIFICATION
run: |
chmod +x ./yt-dlp
cp ./yt-dlp ./yt-dlp_downgraded
version="$(./yt-dlp --version)"
./yt-dlp_downgraded -v --update-to yt-dlp/yt-dlp@2023.03.04
downgraded_version="$(./yt-dlp_downgraded --version)"
[[ "$version" != "$downgraded_version" ]]
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: build-bin-${{ github.job }}
path: |
yt-dlp
yt-dlp.tar.gz
compression-level: 0
linux_static:
needs: process
if: inputs.linux_static
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build static executable
env:
channel: ${{ inputs.channel }}
origin: ${{ needs.process.outputs.origin }}
version: ${{ inputs.version }}
run: |
mkdir ~/build
cd bundle/docker
docker compose up --build static
sudo chown "${USER}:docker" ~/build/yt-dlp_linux
- name: Verify --update-to
if: vars.UPDATE_TO_VERIFICATION
run: |
chmod +x ~/build/yt-dlp_linux
cp ~/build/yt-dlp_linux ~/build/yt-dlp_linux_downgraded
version="$(~/build/yt-dlp_linux --version)"
~/build/yt-dlp_linux_downgraded -v --update-to yt-dlp/yt-dlp@2023.03.04
downgraded_version="$(~/build/yt-dlp_linux_downgraded --version)"
[[ "$version" != "$downgraded_version" ]]
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: build-bin-${{ github.job }}
path: |
~/build/yt-dlp_linux
compression-level: 0
linux_arm:
needs: process
if: inputs.linux_arm
permissions:
contents: read
packages: write # for creating cache
runs-on: ubuntu-latest
strategy:
matrix:
architecture:
- armv7
- aarch64
steps:
- uses: actions/checkout@v4
with:
path: ./repo
- name: Virtualized Install, Prepare & Build
uses: yt-dlp/run-on-arch-action@v2
with:
# Ref: https://github.com/uraimo/run-on-arch-action/issues/55
env: |
GITHUB_WORKFLOW: build
githubToken: ${{ github.token }} # To cache image
arch: ${{ matrix.architecture }}
distro: ubuntu18.04 # Standalone executable should be built on minimum supported OS
dockerRunArgs: --volume "${PWD}/repo:/repo"
install: | # Installing Python 3.10 from the Deadsnakes repo raises errors
apt update
apt -y install zlib1g-dev libffi-dev python3.8 python3.8-dev python3.8-distutils python3-pip
python3.8 -m pip install -U pip setuptools wheel
# Cannot access any files from the repo directory at this stage
python3.8 -m pip install -U Pyinstaller mutagen pycryptodomex websockets brotli certifi secretstorage cffi
run: |
cd repo
python3.8 devscripts/install_deps.py -o --include build
python3.8 devscripts/install_deps.py --include pyinstaller --include secretstorage # Cached version may be out of date
python3.8 devscripts/update-version.py -c "${{ inputs.channel }}" -r "${{ needs.process.outputs.origin }}" "${{ inputs.version }}"
python3.8 devscripts/make_lazy_extractors.py
python3.8 -m bundle.pyinstaller
if ${{ vars.UPDATE_TO_VERIFICATION && 'true' || 'false' }}; then
arch="${{ (matrix.architecture == 'armv7' && 'armv7l') || matrix.architecture }}"
chmod +x ./dist/yt-dlp_linux_${arch}
cp ./dist/yt-dlp_linux_${arch} ./dist/yt-dlp_linux_${arch}_downgraded
version="$(./dist/yt-dlp_linux_${arch} --version)"
./dist/yt-dlp_linux_${arch}_downgraded -v --update-to yt-dlp/yt-dlp@2023.03.04
downgraded_version="$(./dist/yt-dlp_linux_${arch}_downgraded --version)"
[[ "$version" != "$downgraded_version" ]]
fi
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: build-bin-linux_${{ matrix.architecture }}
path: | # run-on-arch-action designates armv7l as armv7
repo/dist/yt-dlp_linux_${{ (matrix.architecture == 'armv7' && 'armv7l') || matrix.architecture }}
compression-level: 0
macos:
needs: process
if: inputs.macos
runs-on: macos-11
needs: create_release
outputs:
sha256_macos: ${{ steps.get_sha.outputs.sha256_macos }}
sha512_macos: ${{ steps.get_sha.outputs.sha512_macos }}
sha256_macos_zip: ${{ steps.get_sha.outputs.sha256_macos_zip }}
sha512_macos_zip: ${{ steps.get_sha.outputs.sha512_macos_zip }}
steps:
- uses: actions/checkout@v2
# NB: In order to create a universal2 application, the version of python3 in /usr/bin has to be used
- name: Install Requirements
run: |
- uses: actions/checkout@v4
# NB: Building universal2 does not work with python from actions/setup-python
- name: Install Requirements
run: |
brew install coreutils
/usr/bin/python3 -m pip install -U --user pip Pyinstaller -r requirements.txt
- name: Prepare
run: |
/usr/bin/python3 devscripts/update-version.py ${{ needs.create_release.outputs.version_suffix }}
/usr/bin/python3 devscripts/make_lazy_extractors.py
- name: Build
run: |
/usr/bin/python3 pyinst.py --target-architecture universal2 --onedir
python3 devscripts/install_deps.py --user -o --include build
python3 devscripts/install_deps.py --print --include pyinstaller > requirements.txt
# We need to ignore wheels otherwise we break universal2 builds
python3 -m pip install -U --user --no-binary :all: -r requirements.txt
# We need to fuse our own universal2 wheels for curl_cffi
python3 -m pip install -U --user delocate
mkdir curl_cffi_whls curl_cffi_universal2
python3 devscripts/install_deps.py --print -o --include curl-cffi > requirements.txt
for platform in "macosx_11_0_arm64" "macosx_11_0_x86_64"; do
python3 -m pip download \
--only-binary=:all: \
--platform "${platform}" \
--pre -d curl_cffi_whls \
-r requirements.txt
done
python3 -m delocate.cmd.delocate_fuse curl_cffi_whls/curl_cffi*.whl -w curl_cffi_universal2
python3 -m delocate.cmd.delocate_fuse curl_cffi_whls/cffi*.whl -w curl_cffi_universal2
cd curl_cffi_universal2
for wheel in *cffi*.whl; do mv -n -- "${wheel}" "${wheel/x86_64/universal2}"; done
python3 -m pip install -U --user *cffi*.whl
- name: Prepare
run: |
python3 devscripts/update-version.py -c "${{ inputs.channel }}" -r "${{ needs.process.outputs.origin }}" "${{ inputs.version }}"
python3 devscripts/make_lazy_extractors.py
- name: Build
run: |
python3 -m bundle.pyinstaller --target-architecture universal2 --onedir
(cd ./dist/yt-dlp_macos && zip -r ../yt-dlp_macos.zip .)
/usr/bin/python3 pyinst.py --target-architecture universal2
- name: Get SHA2-SUMS
id: get_sha
run: |
echo "::set-output name=sha256_macos::$(sha256sum dist/yt-dlp_macos | awk '{print $1}')"
echo "::set-output name=sha512_macos::$(sha512sum dist/yt-dlp_macos | awk '{print $1}')"
echo "::set-output name=sha256_macos_zip::$(sha256sum dist/yt-dlp_macos.zip | awk '{print $1}')"
echo "::set-output name=sha512_macos_zip::$(sha512sum dist/yt-dlp_macos.zip | awk '{print $1}')"
- name: Upload standalone binary
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_path: ./dist/yt-dlp_macos
asset_name: yt-dlp_macos
asset_content_type: application/octet-stream
- name: Upload onedir binary
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_path: ./dist/yt-dlp_macos.zip
asset_name: yt-dlp_macos.zip
asset_content_type: application/zip
build_windows:
python3 -m bundle.pyinstaller --target-architecture universal2
- name: Verify --update-to
if: vars.UPDATE_TO_VERIFICATION
run: |
chmod +x ./dist/yt-dlp_macos
cp ./dist/yt-dlp_macos ./dist/yt-dlp_macos_downgraded
version="$(./dist/yt-dlp_macos --version)"
./dist/yt-dlp_macos_downgraded -v --update-to yt-dlp/yt-dlp@2023.03.04
downgraded_version="$(./dist/yt-dlp_macos_downgraded --version)"
[[ "$version" != "$downgraded_version" ]]
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: build-bin-${{ github.job }}
path: |
dist/yt-dlp_macos
dist/yt-dlp_macos.zip
compression-level: 0
macos_legacy:
needs: process
if: inputs.macos_legacy
runs-on: macos-12
steps:
- uses: actions/checkout@v4
- name: Install Python
# We need the official Python, because the GA ones only support newer macOS versions
env:
PYTHON_VERSION: 3.10.5
MACOSX_DEPLOYMENT_TARGET: 10.9 # Used up by the Python build tools
run: |
# Hack to get the latest patch version. Uncomment if needed
#brew install python@3.10
#export PYTHON_VERSION=$( $(brew --prefix)/opt/python@3.10/bin/python3 --version | cut -d ' ' -f 2 )
curl https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-macos11.pkg -o "python.pkg"
sudo installer -pkg python.pkg -target /
python3 --version
- name: Install Requirements
run: |
brew install coreutils
python3 devscripts/install_deps.py --user -o --include build
python3 devscripts/install_deps.py --user --include pyinstaller
- name: Prepare
run: |
python3 devscripts/update-version.py -c "${{ inputs.channel }}" -r "${{ needs.process.outputs.origin }}" "${{ inputs.version }}"
python3 devscripts/make_lazy_extractors.py
- name: Build
run: |
python3 -m bundle.pyinstaller
mv dist/yt-dlp_macos dist/yt-dlp_macos_legacy
- name: Verify --update-to
if: vars.UPDATE_TO_VERIFICATION
run: |
chmod +x ./dist/yt-dlp_macos_legacy
cp ./dist/yt-dlp_macos_legacy ./dist/yt-dlp_macos_legacy_downgraded
version="$(./dist/yt-dlp_macos_legacy --version)"
./dist/yt-dlp_macos_legacy_downgraded -v --update-to yt-dlp/yt-dlp@2023.03.04
downgraded_version="$(./dist/yt-dlp_macos_legacy_downgraded --version)"
[[ "$version" != "$downgraded_version" ]]
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: build-bin-${{ github.job }}
path: |
dist/yt-dlp_macos_legacy
compression-level: 0
windows:
needs: process
if: inputs.windows
runs-on: windows-latest
needs: create_release
outputs:
sha256_win: ${{ steps.get_sha.outputs.sha256_win }}
sha512_win: ${{ steps.get_sha.outputs.sha512_win }}
sha256_py2exe: ${{ steps.get_sha.outputs.sha256_py2exe }}
sha512_py2exe: ${{ steps.get_sha.outputs.sha512_py2exe }}
sha256_win_zip: ${{ steps.get_sha.outputs.sha256_win_zip }}
sha512_win_zip: ${{ steps.get_sha.outputs.sha512_win_zip }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with: # 3.8 is used for Win7 support
python-version: '3.8'
- name: Install Requirements
run: | # Custom pyinstaller built with https://github.com/yt-dlp/pyinstaller-builds
python -m pip install --upgrade pip setuptools wheel py2exe
pip install "https://yt-dlp.github.io/Pyinstaller-Builds/x86_64/pyinstaller-4.10-py3-none-any.whl" -r requirements.txt
- name: Prepare
run: |
python devscripts/update-version.py ${{ needs.create_release.outputs.version_suffix }}
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: # 3.8 is used for Win7 support
python-version: "3.8"
- name: Install Requirements
run: | # Custom pyinstaller built with https://github.com/yt-dlp/pyinstaller-builds
python devscripts/install_deps.py -o --include build
python devscripts/install_deps.py --include py2exe --include curl-cffi
python -m pip install -U "https://yt-dlp.github.io/Pyinstaller-Builds/x86_64/pyinstaller-5.8.0-py3-none-any.whl"
- name: Prepare
run: |
python devscripts/update-version.py -c "${{ inputs.channel }}" -r "${{ needs.process.outputs.origin }}" "${{ inputs.version }}"
python devscripts/make_lazy_extractors.py
- name: Build
run: |
python setup.py py2exe
- name: Build
run: |
python -m bundle.py2exe
Move-Item ./dist/yt-dlp.exe ./dist/yt-dlp_min.exe
python pyinst.py
python pyinst.py --onedir
python -m bundle.pyinstaller
python -m bundle.pyinstaller --onedir
Compress-Archive -Path ./dist/yt-dlp/* -DestinationPath ./dist/yt-dlp_win.zip
- name: Get SHA2-SUMS
id: get_sha
run: |
echo "::set-output name=sha256_py2exe::$((Get-FileHash dist\yt-dlp_min.exe -Algorithm SHA256).Hash.ToLower())"
echo "::set-output name=sha512_py2exe::$((Get-FileHash dist\yt-dlp_min.exe -Algorithm SHA512).Hash.ToLower())"
echo "::set-output name=sha256_win::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA256).Hash.ToLower())"
echo "::set-output name=sha512_win::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA512).Hash.ToLower())"
echo "::set-output name=sha256_win_zip::$((Get-FileHash dist\yt-dlp_win.zip -Algorithm SHA256).Hash.ToLower())"
echo "::set-output name=sha512_win_zip::$((Get-FileHash dist\yt-dlp_win.zip -Algorithm SHA512).Hash.ToLower())"
- name: Upload py2exe binary
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_path: ./dist/yt-dlp_min.exe
asset_name: yt-dlp_min.exe
asset_content_type: application/vnd.microsoft.portable-executable
- name: Upload standalone binary
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_path: ./dist/yt-dlp.exe
asset_name: yt-dlp.exe
asset_content_type: application/vnd.microsoft.portable-executable
- name: Upload onedir binary
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_path: ./dist/yt-dlp_win.zip
asset_name: yt-dlp_win.zip
asset_content_type: application/zip
build_windows32:
- name: Verify --update-to
if: vars.UPDATE_TO_VERIFICATION
run: |
foreach ($name in @("yt-dlp","yt-dlp_min")) {
Copy-Item "./dist/${name}.exe" "./dist/${name}_downgraded.exe"
$version = & "./dist/${name}.exe" --version
& "./dist/${name}_downgraded.exe" -v --update-to yt-dlp/yt-dlp@2023.03.04
$downgraded_version = & "./dist/${name}_downgraded.exe" --version
if ($version -eq $downgraded_version) {
exit 1
}
}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: build-bin-${{ github.job }}
path: |
dist/yt-dlp.exe
dist/yt-dlp_min.exe
dist/yt-dlp_win.zip
compression-level: 0
windows32:
needs: process
if: inputs.windows32
runs-on: windows-latest
needs: create_release
outputs:
sha256_win32: ${{ steps.get_sha.outputs.sha256_win32 }}
sha512_win32: ${{ steps.get_sha.outputs.sha512_win32 }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with: # 3.7 is used for Vista support. See https://github.com/yt-dlp/yt-dlp/issues/390
python-version: '3.7'
architecture: 'x86'
- name: Install Requirements
run: |
python -m pip install --upgrade pip setuptools wheel
pip install "https://yt-dlp.github.io/Pyinstaller-Builds/i686/pyinstaller-4.10-py3-none-any.whl" -r requirements.txt
- name: Prepare
run: |
python devscripts/update-version.py ${{ needs.create_release.outputs.version_suffix }}
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.8"
architecture: "x86"
- name: Install Requirements
run: |
python devscripts/install_deps.py -o --include build
python devscripts/install_deps.py
python -m pip install -U "https://yt-dlp.github.io/Pyinstaller-Builds/i686/pyinstaller-5.8.0-py3-none-any.whl"
- name: Prepare
run: |
python devscripts/update-version.py -c "${{ inputs.channel }}" -r "${{ needs.process.outputs.origin }}" "${{ inputs.version }}"
python devscripts/make_lazy_extractors.py
- name: Build
run: |
python pyinst.py
- name: Get SHA2-SUMS
id: get_sha
run: |
echo "::set-output name=sha256_win32::$((Get-FileHash dist\yt-dlp_x86.exe -Algorithm SHA256).Hash.ToLower())"
echo "::set-output name=sha512_win32::$((Get-FileHash dist\yt-dlp_x86.exe -Algorithm SHA512).Hash.ToLower())"
- name: Upload standalone binary
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_path: ./dist/yt-dlp_x86.exe
asset_name: yt-dlp_x86.exe
asset_content_type: application/vnd.microsoft.portable-executable
finish:
- name: Build
run: |
python -m bundle.pyinstaller
- name: Verify --update-to
if: vars.UPDATE_TO_VERIFICATION
run: |
foreach ($name in @("yt-dlp_x86")) {
Copy-Item "./dist/${name}.exe" "./dist/${name}_downgraded.exe"
$version = & "./dist/${name}.exe" --version
& "./dist/${name}_downgraded.exe" -v --update-to yt-dlp/yt-dlp@2023.03.04
$downgraded_version = & "./dist/${name}_downgraded.exe" --version
if ($version -eq $downgraded_version) {
exit 1
}
}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: build-bin-${{ github.job }}
path: |
dist/yt-dlp_x86.exe
compression-level: 0
meta_files:
if: always() && !cancelled()
needs:
- process
- unix
- linux_static
- linux_arm
- macos
- macos_legacy
- windows
- windows32
runs-on: ubuntu-latest
needs: [create_release, build_unix, build_windows, build_windows32, build_macos]
steps:
- name: Make SHA2-SUMS files
run: |
echo "${{ needs.build_unix.outputs.sha256_bin }} yt-dlp" >> SHA2-256SUMS
echo "${{ needs.build_unix.outputs.sha256_tar }} yt-dlp.tar.gz" >> SHA2-256SUMS
echo "${{ needs.build_unix.outputs.sha256_linux }} yt-dlp_linux" >> SHA2-256SUMS
echo "${{ needs.build_unix.outputs.sha256_linux_zip }} yt-dlp_linux.zip" >> SHA2-256SUMS
echo "${{ needs.build_windows.outputs.sha256_win }} yt-dlp.exe" >> SHA2-256SUMS
echo "${{ needs.build_windows.outputs.sha256_py2exe }} yt-dlp_min.exe" >> SHA2-256SUMS
echo "${{ needs.build_windows32.outputs.sha256_win32 }} yt-dlp_x86.exe" >> SHA2-256SUMS
echo "${{ needs.build_windows.outputs.sha256_win_zip }} yt-dlp_win.zip" >> SHA2-256SUMS
echo "${{ needs.build_macos.outputs.sha256_macos }} yt-dlp_macos" >> SHA2-256SUMS
echo "${{ needs.build_macos.outputs.sha256_macos_zip }} yt-dlp_macos.zip" >> SHA2-256SUMS
echo "${{ needs.build_unix.outputs.sha512_bin }} yt-dlp" >> SHA2-512SUMS
echo "${{ needs.build_unix.outputs.sha512_tar }} yt-dlp.tar.gz" >> SHA2-512SUMS
echo "${{ needs.build_unix.outputs.sha512_linux }} yt-dlp_linux" >> SHA2-512SUMS
echo "${{ needs.build_unix.outputs.sha512_linux_zip }} yt-dlp_linux.zip" >> SHA2-512SUMS
echo "${{ needs.build_windows.outputs.sha512_win }} yt-dlp.exe" >> SHA2-512SUMS
echo "${{ needs.build_windows.outputs.sha512_py2exe }} yt-dlp_min.exe" >> SHA2-512SUMS
echo "${{ needs.build_windows32.outputs.sha512_win32 }} yt-dlp_x86.exe" >> SHA2-512SUMS
echo "${{ needs.build_windows.outputs.sha512_win_zip }} yt-dlp_win.zip" >> SHA2-512SUMS
echo "${{ needs.build_macos.outputs.sha512_macos }} yt-dlp_macos" >> SHA2-512SUMS
echo "${{ needs.build_macos.outputs.sha512_macos_zip }} yt-dlp_macos.zip" >> SHA2-512SUMS
- name: Upload SHA2-256SUMS file
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_path: ./SHA2-256SUMS
asset_name: SHA2-256SUMS
asset_content_type: text/plain
- name: Upload SHA2-512SUMS file
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_path: ./SHA2-512SUMS
asset_name: SHA2-512SUMS
asset_content_type: text/plain
- uses: actions/download-artifact@v4
with:
path: artifact
pattern: build-bin-*
merge-multiple: true
- name: Make SHA2-SUMS files
run: |
cd ./artifact/
# make sure SHA sums are also printed to stdout
sha256sum * | tee ../SHA2-256SUMS
sha512sum * | tee ../SHA2-512SUMS
- name: Make Update spec
run: |
cat >> _update_spec << EOF
# This file is used for regulating self-update
lock 2022.08.18.36 .+ Python 3\.6
lock 2023.11.16 (?!win_x86_exe).+ Python 3\.7
lock 2023.11.16 win_x86_exe .+ Windows-(?:Vista|2008Server)
lockV2 yt-dlp/yt-dlp 2022.08.18.36 .+ Python 3\.6
lockV2 yt-dlp/yt-dlp 2023.11.16 (?!win_x86_exe).+ Python 3\.7
lockV2 yt-dlp/yt-dlp 2023.11.16 win_x86_exe .+ Windows-(?:Vista|2008Server)
lockV2 yt-dlp/yt-dlp-nightly-builds 2023.11.15.232826 (?!win_x86_exe).+ Python 3\.7
lockV2 yt-dlp/yt-dlp-nightly-builds 2023.11.15.232826 win_x86_exe .+ Windows-(?:Vista|2008Server)
lockV2 yt-dlp/yt-dlp-master-builds 2023.11.15.232812 (?!win_x86_exe).+ Python 3\.7
lockV2 yt-dlp/yt-dlp-master-builds 2023.11.15.232812 win_x86_exe .+ Windows-(?:Vista|2008Server)
EOF
- name: Sign checksum files
env:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}
if: env.GPG_SIGNING_KEY != ''
run: |
gpg --batch --import <<< "${{ secrets.GPG_SIGNING_KEY }}"
for signfile in ./SHA*SUMS; do
gpg --batch --detach-sign "$signfile"
done
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: build-${{ github.job }}
path: |
_update_spec
SHA*SUMS*
compression-level: 0
overwrite: true

@ -0,0 +1,65 @@
name: "CodeQL"
on:
push:
branches: [ 'master', 'gh-pages', 'release' ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ 'master' ]
schedule:
- cron: '59 11 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"

@ -1,5 +1,32 @@
name: Core Tests
on: [push, pull_request]
on:
push:
paths:
- .github/**
- devscripts/**
- test/**
- yt_dlp/**.py
- '!yt_dlp/extractor/*.py'
- yt_dlp/extractor/__init__.py
- yt_dlp/extractor/common.py
- yt_dlp/extractor/extractors.py
pull_request:
paths:
- .github/**
- devscripts/**
- test/**
- yt_dlp/**.py
- '!yt_dlp/extractor/*.py'
- yt_dlp/extractor/__init__.py
- yt_dlp/extractor/common.py
- yt_dlp/extractor/extractors.py
permissions:
contents: read
concurrency:
group: core-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
tests:
name: Core Tests
@ -9,26 +36,26 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
# CPython 3.9 is in quick-test
python-version: ['3.6', '3.7', '3.10', 3.11-dev, pypy-3.6, pypy-3.7, pypy-3.8]
run-tests-ext: [sh]
# CPython 3.8 is in quick-test
python-version: ['3.9', '3.10', '3.11', '3.12', pypy-3.8, pypy-3.10]
include:
# atleast one of each CPython/PyPy tests must be in windows
- os: windows-latest
python-version: '3.8'
run-tests-ext: bat
- os: windows-latest
python-version: '3.12'
- os: windows-latest
python-version: pypy-3.9
run-tests-ext: bat
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install pytest
run: pip install pytest
- name: Install test requirements
run: python3 ./devscripts/install_deps.py --include dev --include curl-cffi
- name: Run tests
continue-on-error: False
run: ./devscripts/run_tests.${{ matrix.run-tests-ext }} core
# Linter is in quick-test
run: |
python3 -m yt_dlp -v || true # Print debug head
python3 ./devscripts/run_tests.py core

@ -1,32 +1,48 @@
name: Download Tests
on: [push, pull_request]
permissions:
contents: read
jobs:
tests:
name: Download Tests
quick:
name: Quick Download Tests
if: "contains(github.event.head_commit.message, 'ci run dl')"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.9
- name: Install test requirements
run: python3 ./devscripts/install_deps.py --include dev
- name: Run tests
continue-on-error: true
run: python3 ./devscripts/run_tests.py download
full:
name: Full Download Tests
if: "contains(github.event.head_commit.message, 'ci run dl all')"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
os: [ubuntu-latest]
python-version: ['3.6', '3.7', '3.9', '3.10', 3.11-dev, pypy-3.6, pypy-3.7, pypy-3.8]
run-tests-ext: [sh]
python-version: ['3.10', '3.11', '3.12', pypy-3.8, pypy-3.10]
include:
# atleast one of each CPython/PyPy tests must be in windows
- os: windows-latest
python-version: '3.8'
run-tests-ext: bat
- os: windows-latest
python-version: pypy-3.9
run-tests-ext: bat
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install pytest
run: pip install pytest
- name: Install test requirements
run: python3 ./devscripts/install_deps.py --include dev
- name: Run tests
continue-on-error: true
run: ./devscripts/run_tests.${{ matrix.run-tests-ext }} download
run: python3 ./devscripts/run_tests.py download

@ -1,33 +1,37 @@
name: Quick Test
on: [push, pull_request]
permissions:
contents: read
jobs:
tests:
name: Core Test
if: "!contains(github.event.head_commit.message, 'ci skip all')"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
- uses: actions/checkout@v4
- name: Set up Python 3.8
uses: actions/setup-python@v5
with:
python-version: 3.9
python-version: '3.8'
- name: Install test requirements
run: pip install pytest pycryptodomex
run: python3 ./devscripts/install_deps.py --include dev
- name: Run tests
run: ./devscripts/run_tests.sh core
run: |
python3 -m yt_dlp -v || true
python3 ./devscripts/run_tests.py core
flake8:
name: Linter
if: "!contains(github.event.head_commit.message, 'ci skip all')"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.9
python-version: '3.8'
- name: Install flake8
run: pip install flake8
run: python3 ./devscripts/install_deps.py -o --include dev
- name: Make lazy extractors
run: python devscripts/make_lazy_extractors.py
run: python3 ./devscripts/make_lazy_extractors.py
- name: Run flake8
run: flake8 .

@ -0,0 +1,29 @@
name: Release (master)
on:
push:
branches:
- master
paths:
- "yt_dlp/**.py"
- "!yt_dlp/version.py"
- "bundle/*.py"
- "pyproject.toml"
- "Makefile"
- ".github/workflows/build.yml"
concurrency:
group: release-master
permissions:
contents: read
jobs:
release:
if: vars.BUILD_MASTER != ''
uses: ./.github/workflows/release.yml
with:
prerelease: true
source: master
permissions:
contents: write
packages: write
id-token: write # mandatory for trusted publishing
secrets: inherit

@ -0,0 +1,42 @@
name: Release (nightly)
on:
schedule:
- cron: '23 23 * * *'
permissions:
contents: read
jobs:
check_nightly:
if: vars.BUILD_NIGHTLY != ''
runs-on: ubuntu-latest
outputs:
commit: ${{ steps.check_for_new_commits.outputs.commit }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for new commits
id: check_for_new_commits
run: |
relevant_files=(
"yt_dlp/*.py"
':!yt_dlp/version.py'
"bundle/*.py"
"pyproject.toml"
"Makefile"
".github/workflows/build.yml"
)
echo "commit=$(git log --format=%H -1 --since="24 hours ago" -- "${relevant_files[@]}")" | tee "$GITHUB_OUTPUT"
release:
needs: [check_nightly]
if: ${{ needs.check_nightly.outputs.commit }}
uses: ./.github/workflows/release.yml
with:
prerelease: true
source: nightly
permissions:
contents: write
packages: write
id-token: write # mandatory for trusted publishing
secrets: inherit

@ -0,0 +1,383 @@
name: Release
on:
workflow_call:
inputs:
prerelease:
required: false
default: true
type: boolean
source:
required: false
default: ''
type: string
target:
required: false
default: ''
type: string
version:
required: false
default: ''
type: string
workflow_dispatch:
inputs:
source:
description: |
SOURCE of this release's updates:
channel, repo, tag, or channel/repo@tag
(default: <current_repo>)
required: false
default: ''
type: string
target:
description: |
TARGET to publish this release to:
channel, tag, or channel@tag
(default: <source> if writable else <current_repo>[@source_tag])
required: false
default: ''
type: string
version:
description: |
VERSION: yyyy.mm.dd[.rev] or rev
(default: auto-generated)
required: false
default: ''
type: string
prerelease:
description: Pre-release
default: false
type: boolean
permissions:
contents: read
jobs:
prepare:
permissions:
contents: write
runs-on: ubuntu-latest
outputs:
channel: ${{ steps.setup_variables.outputs.channel }}
version: ${{ steps.setup_variables.outputs.version }}
target_repo: ${{ steps.setup_variables.outputs.target_repo }}
target_repo_token: ${{ steps.setup_variables.outputs.target_repo_token }}
target_tag: ${{ steps.setup_variables.outputs.target_tag }}
pypi_project: ${{ steps.setup_variables.outputs.pypi_project }}
pypi_suffix: ${{ steps.setup_variables.outputs.pypi_suffix }}
head_sha: ${{ steps.get_target.outputs.head_sha }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Process inputs
id: process_inputs
run: |
cat << EOF
::group::Inputs
prerelease=${{ inputs.prerelease }}
source=${{ inputs.source }}
target=${{ inputs.target }}
version=${{ inputs.version }}
::endgroup::
EOF
IFS='@' read -r source_repo source_tag <<<"${{ inputs.source }}"
IFS='@' read -r target_repo target_tag <<<"${{ inputs.target }}"
cat << EOF >> "$GITHUB_OUTPUT"
source_repo=${source_repo}
source_tag=${source_tag}
target_repo=${target_repo}
target_tag=${target_tag}
EOF
- name: Setup variables
id: setup_variables
env:
source_repo: ${{ steps.process_inputs.outputs.source_repo }}
source_tag: ${{ steps.process_inputs.outputs.source_tag }}
target_repo: ${{ steps.process_inputs.outputs.target_repo }}
target_tag: ${{ steps.process_inputs.outputs.target_tag }}
run: |
# unholy bash monstrosity (sincere apologies)
fallback_token () {
if ${{ !secrets.ARCHIVE_REPO_TOKEN }}; then
echo "::error::Repository access secret ${target_repo_token^^} not found"
exit 1
fi
target_repo_token=ARCHIVE_REPO_TOKEN
return 0
}
source_is_channel=0
[[ "${source_repo}" == 'stable' ]] && source_repo='yt-dlp/yt-dlp'
if [[ -z "${source_repo}" ]]; then
source_repo='${{ github.repository }}'
elif [[ '${{ vars[format('{0}_archive_repo', env.source_repo)] }}' ]]; then
source_is_channel=1
source_channel='${{ vars[format('{0}_archive_repo', env.source_repo)] }}'
elif [[ -z "${source_tag}" && "${source_repo}" != */* ]]; then
source_tag="${source_repo}"
source_repo='${{ github.repository }}'
fi
resolved_source="${source_repo}"
if [[ "${source_tag}" ]]; then
resolved_source="${resolved_source}@${source_tag}"
elif [[ "${source_repo}" == 'yt-dlp/yt-dlp' ]]; then
resolved_source='stable'
fi
revision="${{ (inputs.prerelease || !vars.PUSH_VERSION_COMMIT) && '$(date -u +"%H%M%S")' || '' }}"
version="$(
python devscripts/update-version.py \
-c "${resolved_source}" -r "${{ github.repository }}" ${{ inputs.version || '$revision' }} | \
grep -Po "version=\K\d+\.\d+\.\d+(\.\d+)?")"
if [[ "${target_repo}" ]]; then
if [[ -z "${target_tag}" ]]; then
if [[ '${{ vars[format('{0}_archive_repo', env.target_repo)] }}' ]]; then
target_tag="${source_tag:-${version}}"
else
target_tag="${target_repo}"
target_repo='${{ github.repository }}'
fi
fi
if [[ "${target_repo}" != '${{ github.repository}}' ]]; then
target_repo='${{ vars[format('{0}_archive_repo', env.target_repo)] }}'
target_repo_token='${{ env.target_repo }}_archive_repo_token'
${{ !!secrets[format('{0}_archive_repo_token', env.target_repo)] }} || fallback_token
pypi_project='${{ vars[format('{0}_pypi_project', env.target_repo)] }}'
pypi_suffix='${{ vars[format('{0}_pypi_suffix', env.target_repo)] }}'
fi
else
target_tag="${source_tag:-${version}}"
if ((source_is_channel)); then
target_repo="${source_channel}"
target_repo_token='${{ env.source_repo }}_archive_repo_token'
${{ !!secrets[format('{0}_archive_repo_token', env.source_repo)] }} || fallback_token
pypi_project='${{ vars[format('{0}_pypi_project', env.source_repo)] }}'
pypi_suffix='${{ vars[format('{0}_pypi_suffix', env.source_repo)] }}'
else
target_repo='${{ github.repository }}'
fi
fi
if [[ "${target_repo}" == '${{ github.repository }}' ]] && ${{ !inputs.prerelease }}; then
pypi_project='${{ vars.PYPI_PROJECT }}'
fi
echo "::group::Output variables"
cat << EOF | tee -a "$GITHUB_OUTPUT"
channel=${resolved_source}
version=${version}
target_repo=${target_repo}
target_repo_token=${target_repo_token}
target_tag=${target_tag}
pypi_project=${pypi_project}
pypi_suffix=${pypi_suffix}
EOF
echo "::endgroup::"
- name: Update documentation
env:
version: ${{ steps.setup_variables.outputs.version }}
target_repo: ${{ steps.setup_variables.outputs.target_repo }}
if: |
!inputs.prerelease && env.target_repo == github.repository
run: |
python devscripts/update_changelog.py -vv
make doc
- name: Push to release
id: push_release
env:
version: ${{ steps.setup_variables.outputs.version }}
target_repo: ${{ steps.setup_variables.outputs.target_repo }}
if: |
!inputs.prerelease && env.target_repo == github.repository
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -u
git commit -m "Release ${{ env.version }}" \
-m "Created by: ${{ github.event.sender.login }}" -m ":ci skip all :ci run dl"
git push origin --force ${{ github.event.ref }}:release
- name: Get target commitish
id: get_target
run: |
echo "head_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Update master
env:
target_repo: ${{ steps.setup_variables.outputs.target_repo }}
if: |
vars.PUSH_VERSION_COMMIT != '' && !inputs.prerelease && env.target_repo == github.repository
run: git push origin ${{ github.event.ref }}
build:
needs: prepare
uses: ./.github/workflows/build.yml
with:
version: ${{ needs.prepare.outputs.version }}
channel: ${{ needs.prepare.outputs.channel }}
origin: ${{ needs.prepare.outputs.target_repo }}
permissions:
contents: read
packages: write # For package cache
secrets:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}
publish_pypi:
needs: [prepare, build]
if: ${{ needs.prepare.outputs.pypi_project }}
runs-on: ubuntu-latest
permissions:
id-token: write # mandatory for trusted publishing
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install Requirements
run: |
sudo apt -y install pandoc man
python devscripts/install_deps.py -o --include build
- name: Prepare
env:
version: ${{ needs.prepare.outputs.version }}
suffix: ${{ needs.prepare.outputs.pypi_suffix }}
channel: ${{ needs.prepare.outputs.channel }}
target_repo: ${{ needs.prepare.outputs.target_repo }}
pypi_project: ${{ needs.prepare.outputs.pypi_project }}
run: |
python devscripts/update-version.py -c "${{ env.channel }}" -r "${{ env.target_repo }}" -s "${{ env.suffix }}" "${{ env.version }}"
python devscripts/update_changelog.py -vv
python devscripts/make_lazy_extractors.py
sed -i -E '0,/(name = ")[^"]+(")/s//\1${{ env.pypi_project }}\2/' pyproject.toml
- name: Build
run: |
rm -rf dist/*
make pypi-files
printf '%s\n\n' \
'Official repository: <https://github.com/yt-dlp/yt-dlp>' \
'**PS**: Some links in this document will not work since this is a copy of the README.md from Github' > ./README.md.new
cat ./README.md >> ./README.md.new && mv -f ./README.md.new ./README.md
python devscripts/set-variant.py pip -M "You installed yt-dlp with pip or using the wheel from PyPi; Use that to update"
make clean-cache
python -m build --no-isolation .
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
verbose: true
publish:
needs: [prepare, build]
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/download-artifact@v4
with:
path: artifact
pattern: build-*
merge-multiple: true
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Generate release notes
env:
head_sha: ${{ needs.prepare.outputs.head_sha }}
target_repo: ${{ needs.prepare.outputs.target_repo }}
target_tag: ${{ needs.prepare.outputs.target_tag }}
run: |
printf '%s' \
'[![Installation](https://img.shields.io/badge/-Which%20file%20to%20download%3F-white.svg?style=for-the-badge)]' \
'(https://github.com/${{ github.repository }}#installation "Installation instructions") ' \
'[![Discord](https://img.shields.io/discord/807245652072857610?color=blue&labelColor=555555&label=&logo=discord&style=for-the-badge)]' \
'(https://discord.gg/H5MNcFW63r "Discord") ' \
'[![Donate](https://img.shields.io/badge/_-Donate-red.svg?logo=githubsponsors&labelColor=555555&style=for-the-badge)]' \
'(https://github.com/yt-dlp/yt-dlp/blob/master/Collaborators.md#collaborators "Donate") ' \
'[![Documentation](https://img.shields.io/badge/-Docs-brightgreen.svg?style=for-the-badge&logo=GitBook&labelColor=555555)]' \
'(https://github.com/${{ github.repository }}' \
'${{ env.target_repo == github.repository && format('/tree/{0}', env.target_tag) || '' }}#readme "Documentation") ' \
${{ env.target_repo == 'yt-dlp/yt-dlp' && '\
"[![Nightly](https://img.shields.io/badge/Nightly%20builds-purple.svg?style=for-the-badge)]" \
"(https://github.com/yt-dlp/yt-dlp-nightly-builds/releases/latest \"Nightly builds\") " \
"[![Master](https://img.shields.io/badge/Master%20builds-lightblue.svg?style=for-the-badge)]" \
"(https://github.com/yt-dlp/yt-dlp-master-builds/releases/latest \"Master builds\")"' || '' }} > ./RELEASE_NOTES
printf '\n\n' >> ./RELEASE_NOTES
cat >> ./RELEASE_NOTES << EOF
#### A description of the various files are in the [README](https://github.com/${{ github.repository }}#release-files)
---
$(python ./devscripts/make_changelog.py -vv --collapsible)
EOF
printf '%s\n\n' '**This is a pre-release build**' >> ./PRERELEASE_NOTES
cat ./RELEASE_NOTES >> ./PRERELEASE_NOTES
printf '%s\n\n' 'Generated from: https://github.com/${{ github.repository }}/commit/${{ env.head_sha }}' >> ./ARCHIVE_NOTES
cat ./RELEASE_NOTES >> ./ARCHIVE_NOTES
- name: Publish to archive repo
env:
GH_TOKEN: ${{ secrets[needs.prepare.outputs.target_repo_token] }}
GH_REPO: ${{ needs.prepare.outputs.target_repo }}
version: ${{ needs.prepare.outputs.version }}
channel: ${{ needs.prepare.outputs.channel }}
if: |
inputs.prerelease && env.GH_TOKEN != '' && env.GH_REPO != '' && env.GH_REPO != github.repository
run: |
title="${{ startswith(env.GH_REPO, 'yt-dlp/') && 'yt-dlp ' || '' }}${{ env.channel }}"
gh release create \
--notes-file ARCHIVE_NOTES \
--title "${title} ${{ env.version }}" \
${{ env.version }} \
artifact/*
- name: Prune old release
env:
GH_TOKEN: ${{ github.token }}
version: ${{ needs.prepare.outputs.version }}
target_repo: ${{ needs.prepare.outputs.target_repo }}
target_tag: ${{ needs.prepare.outputs.target_tag }}
if: |
env.target_repo == github.repository && env.target_tag != env.version
run: |
gh release delete --yes --cleanup-tag "${{ env.target_tag }}" || true
git tag --delete "${{ env.target_tag }}" || true
sleep 5 # Enough time to cover deletion race condition
- name: Publish release
env:
GH_TOKEN: ${{ github.token }}
version: ${{ needs.prepare.outputs.version }}
target_repo: ${{ needs.prepare.outputs.target_repo }}
target_tag: ${{ needs.prepare.outputs.target_tag }}
head_sha: ${{ needs.prepare.outputs.head_sha }}
if: |
env.target_repo == github.repository
run: |
title="${{ github.repository == 'yt-dlp/yt-dlp' && 'yt-dlp ' || '' }}"
title+="${{ env.target_tag != env.version && format('{0} ', env.target_tag) || '' }}"
gh release create \
--notes-file ${{ inputs.prerelease && 'PRERELEASE_NOTES' || 'RELEASE_NOTES' }} \
--target ${{ env.head_sha }} \
--title "${title}${{ env.version }}" \
${{ inputs.prerelease && '--prerelease' || '' }} \
${{ env.target_tag }} \
artifact/*

18
.gitignore vendored

@ -27,10 +27,13 @@ cookies
*.ass
*.avi
*.desktop
*.f4v
*.flac
*.flv
*.gif
*.jpeg
*.jpg
*.lrc
*.m4a
*.m4v
*.mhtml
@ -38,13 +41,18 @@ cookies
*.mov
*.mp3
*.mp4
*.mpg
*.mpga
*.oga
*.ogg
*.opus
*.png
*.sbv
*.srt
*.ssa
*.swf
*.swp
*.tt
*.ttml
*.url
*.vtt
@ -67,6 +75,7 @@ dist/
zip/
tmp/
venv/
.venv/
completions/
# Misc
@ -83,6 +92,7 @@ updates_key.pem
.tox
*.class
*.isorted
*.stackdump
# Generated
AUTHORS
@ -114,9 +124,5 @@ yt-dlp.zip
*/extractor/lazy_extractors.py
# Plugins
ytdlp_plugins/extractor/*
!ytdlp_plugins/extractor/__init__.py
!ytdlp_plugins/extractor/sample.py
ytdlp_plugins/postprocessor/*
!ytdlp_plugins/postprocessor/__init__.py
!ytdlp_plugins/postprocessor/sample.py
ytdlp_plugins/
yt-dlp-plugins

@ -79,7 +79,7 @@ Before reporting any issue, type `yt-dlp -U`. This should report that you're up-
### 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/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.
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, subscribe to it to be notified when there is any progress. Unless you have something useful to add to the conversation, please refrain from commenting.
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.
@ -127,7 +127,7 @@ While these steps won't necessarily ensure that no misuse of the account takes p
### Is the website primarily used for piracy?
We follow [youtube-dl's policy](https://github.com/ytdl-org/youtube-dl#can-you-add-support-for-this-anime-video-site-or-site-which-shows-current-movies-for-free) to not support services that is primarily used for infringing copyright. Additionally, it has been decided to not to support porn sites that specialize in deep fake. We also cannot support any service that serves only [DRM protected content](https://en.wikipedia.org/wiki/Digital_rights_management).
We follow [youtube-dl's policy](https://github.com/ytdl-org/youtube-dl#can-you-add-support-for-this-anime-video-site-or-site-which-shows-current-movies-for-free) to not support services that is primarily used for infringing copyright. Additionally, it has been decided to not to support porn sites that specialize in fakes. We also cannot support any service that serves only [DRM protected content](https://en.wikipedia.org/wiki/Digital_rights_management).
@ -138,14 +138,11 @@ Most users do not need to build yt-dlp and can [download the builds](https://git
To run yt-dlp as a developer, you don't need to build anything either. Simply execute
python -m yt_dlp
python3 -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 all the available core tests, use:
python -m unittest discover
python test/test_download.py
nosetests
pytest
python3 devscripts/run_tests.py
See item 6 of [new extractor tutorial](#adding-support-for-a-new-site) for how to run extractor specific test cases.
@ -154,14 +151,14 @@ If you want to create a build of yt-dlp yourself, you can follow the instruction
## Adding new feature or making overarching changes
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.
Before you start writing code for implementing a new feature, open an issue explaining your feature request and at least 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**.
If you want to add support for a new site, first of all **make sure** this site is **not dedicated to [copyright infringement](#is-the-website-primarily-used-for-piracy)**. 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`):
@ -187,15 +184,21 @@ After you have ensured this site is distributing its content legally, you can fo
'url': 'https://yourextractor.com/watch/42',
'md5': 'TODO: md5 sum of the first 10241 bytes of the video file (use --test)',
'info_dict': {
# For videos, only the 'id' and 'ext' fields are required to RUN the test:
'id': '42',
'ext': 'mp4',
'title': 'Video title goes here',
'thumbnail': r're:^https?://.*\.jpg$',
# TODO more properties, either as:
# * A value
# * MD5 checksum; start the string with md5:
# * A regular expression; start the string with re:
# * Any Python type (for example int or float)
# Then if the test run fails, it will output the missing/incorrect fields.
# Properties can be added as:
# * A value, e.g.
# 'title': 'Video title goes here',
# * MD5 checksum; start the string with 'md5:', e.g.
# 'description': 'md5:098f6bcd4621d373cade4e832627b4f6',
# * A regular expression; start the string with 're:', e.g.
# 'thumbnail': r're:^https?://.*\.jpg$',
# * A count of elements in a list; start the string with 'count:', e.g.
# 'tags': 'count:10',
# * Any Python type, e.g.
# 'view_count': int,
}
}]
@ -215,14 +218,14 @@ After you have ensured this site is distributing its content legally, you can fo
}
```
1. Add an import in [`yt_dlp/extractor/_extractors.py`](yt_dlp/extractor/_extractors.py). Note that the class name must end with `IE`.
1. Run `python test/test_download.py TestDownload.test_YourExtractor` (note that `YourExtractor` doesn't end with `IE`). 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`
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.
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. Run `python3 devscripts/run_tests.py YourExtractor`. This *may fail* at first, but you can continually re-run it until you're done. Upon failure, it will output the missing fields and/or correct values which you can copy. If you decide to add more than one test, the tests will then be named `YourExtractor`, `YourExtractor_1`, `YourExtractor_2`, etc. Note that tests with an `only_matching` key in the test's dict are not included in the count. You can also run all the tests in one go with `YourExtractor_all`
1. Make sure you have at least 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.
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#L119-L440). 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 yt_dlp/extractor/yourextractor.py
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.
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.8 and above. Backward compatibility is not required for even older versions of Python.
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 yt_dlp/extractor/_extractors.py
@ -234,7 +237,7 @@ After you have ensured this site is distributing its content legally, you can fo
In any case, thank you very much for your contributions!
**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:
**Tip:** To test extractors that require login information, create a file `test/local_parameters.json` and add `"usenetrc": true` or your `username`&`password` or `cookiefile`/`cookiesfrombrowser` in it:
```json
{
"username": "your user name",
@ -246,12 +249,12 @@ In any case, thank you very much for your contributions!
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 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.
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 extractor will remain broken.
### Mandatory and optional metafields
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:
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#L119-L440) 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)
- `title` (media title)
@ -261,7 +264,7 @@ The aforementioned metafields are the critical data that the extraction does not
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.
The extractor is allowed to return the info dict without url or formats in some special cases if it allows the user to extract useful information with `--ignore-no-formats-error` - e.g. 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.
@ -351,8 +354,9 @@ Say you extracted a list of thumbnails into `thumbnail_data` and want to iterate
```python
thumbnail_data = data.get('thumbnails') or []
thumbnails = [{
'url': item['url']
} for item in thumbnail_data] # correct
'url': item['url'],
'height': item.get('h'),
} for item in thumbnail_data if item.get('url')] # correct
```
and not like:
@ -360,12 +364,27 @@ and not like:
```python
thumbnail_data = data.get('thumbnails')
thumbnails = [{
'url': item['url']
'url': item['url'],
'height': item.get('h'),
} for item in thumbnail_data] # incorrect
```
In this 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 `or []` avoids this error and results in setting an empty list in `thumbnails` instead.
Alternately, this can be further simplified by using `traverse_obj`
```python
thumbnails = [{
'url': item['url'],
'height': item.get('h'),
} for item in traverse_obj(data, ('thumbnails', lambda _, v: v['url']))]
```
or, even better,
```python
thumbnails = traverse_obj(data, ('thumbnails', ..., {'url': 'url', 'height': 'h'}))
```
### Provide fallbacks
@ -457,7 +476,7 @@ title = self._search_regex( # incorrect
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
Here the presence or absence of other attributes including `style` is irrelevant for the data we need, and so the regex must not depend on it
#### Keep the regular expressions as simple as possible, but no simpler
@ -501,7 +520,7 @@ There is a soft limit to keep lines of code under 100 characters long. This mean
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.
Conversely, don't unnecessarily 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
@ -680,7 +699,7 @@ formats = [
### Use convenience conversion and parsing functions
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.
Wrap all extracted numeric data into safe functions from [`yt_dlp/utils/`](yt_dlp/utils/): `int_or_none`, `float_or_none`. Use them for string to number conversions as well.
Use `url_or_none` for safe URL processing.
@ -688,7 +707,7 @@ Use `traverse_obj` and `try_call` (superseeds `dict_get` and `try_get`) for safe
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 [`yt_dlp/utils.py`](yt_dlp/utils.py) for more useful convenience functions.
Explore [`yt_dlp/utils/`](yt_dlp/utils/) for more useful convenience functions.
#### Examples

@ -2,7 +2,8 @@ pukkandan (owner)
shirt-dev (collaborator)
coletdjnz/colethedj (collaborator)
Ashish0804 (collaborator)
nao20010128nao/Lesmiscore (collaborator)
bashonly (collaborator)
Grub4K (collaborator)
h-h-h-h
pauldubois98
nixxo
@ -267,3 +268,345 @@ sqrtNOT
bubbleguuum
darkxex
miseran
StefanLobbenmeier
crazymoose77756
nomevi
Brett824
pingiun
dosy4ev
EhtishamSabir
Ferdi265
FirefoxMetzger
ftk
lamby
llamasblade
lockmatrix
misaelaguayo
odo2063
pritam20ps05
scy
sheerluck
AxiosDeminence
DjesonPV
eren-kemer
freezboltz
Galiley
haobinliang
Mehavoid
winterbird-code
yashkc2025
aldoridhoni
jacobtruman
masta79
palewire
cgrigis
DavidH-2022
dfaker
jackyyf
ohaiibuzzle
SamantazFox
shreyasminocha
tejasa97
xenov
satan1st
0xGodspeed
5736d79
587021c
basrieter
Bobscorn
CNugteren
columndeeply
DoubleCouponDay
Fabi019
GautamMKGarg
itachi-19
jeroenj
josanabr
LiviaMedeiros
nikita-moor
snapdgn
SuperSonicHub1
tannertechnology
Timendum
tobi1805
TokyoBlackHole
ajayyy
Alienmaster
bsun0000
changren-wcr
ClosedPort22
CrankDatSouljaBoy
cruel-efficiency
endotronic
Generator
gibson042
How-Bout-No
invertico
jahway603
jwoglom
lksj
megapro17
mlampe
MrOctopus
nosoop
puc9
sashashura
schnusch
SG5
the-marenga
tkgmomosheep
vitkhab
glensc
synthpop123
tntmod54321
milkknife
Bnyro
CapacitorSet
stelcodes
skbeh
muddi900
digitall
chengzhicn
mexus
JChris246
redraskal
Spicadox
barsnick
docbender
KurtBestor
Chrissi2812
FrederikNS
gschizas
JC-Chung
mzhou
OndrejBakan
ab4cbef
aionescu
amra
ByteDream
carusocr
chexxor
felixonmars
FrankZ85
FriedrichRehren
gregsadetsky
LeoniePhiline
LowSuggestion912
Matumo
OIRNOIR
OMEGARAZER
oxamun
pmitchell86
qbnu
qulaz
rebane2001
road-master
rohieb
sdht0
seproDev
Hill-98
LXYan2333
mushbite
venkata-krishnas
7vlad7
alexklapheke
arobase-che
bepvte
bergoid
blmarket
brandon-dacrib
c-basalt
CoryTibbettsDev
Cyberes
D0LLYNH0
danog
DataGhost
falbrechtskirchinger
foreignBlade
garret1317
hasezoey
hoaluvn
ItzMaxTV
ivanskodje
jo-nike
kangalio
linsui
makew0rld
menschel
mikf
mrscrapy
NDagestad
Neurognostic
NextFire
nick-cd
permunkle
pzhlkj6612
ringus1
rjy
Schmoaaaaah
sjthespian
theperfectpunk
toomyzoom
truedread
TxI5
unbeatable-101
vampirefrog
vidiot720
viktor-enzell
zhgwn
barthelmannk
berkanteber
OverlordQ
rexlambert22
Ti4eeT4e
AmanSal1
bbilly1
meliber
nnoboa
rdamas
RfadnjdExt
urectanc
nao20010128nao/Lesmiscore
04-pasha-04
aaruni96
aky-01
AmirAflak
ApoorvShah111
at-wat
davinkevin
demon071
denhotte
FinnRG
fireattack
Frankgoji
GD-Slime
hatsomatt
ifan-t
kshitiz305
kylegustavo
mabdelfattah
nathantouze
niemands
Rajeshwaran2001
RedDeffender
Rohxn16
sb0stn
SevenLives
simon300000
snixon
soundchaser128
szabyg
trainman261
trislee
wader
Yalab7
zhallgato
zhong-yiyu
Zprokkel
AS6939
drzraf
handlerug
jiru
madewokherd
xofe
awalgarg
midnightveil
naginatana
Riteo
1100101
aniolpages
bartbroere
CrendKing
Esokrates
HitomaruKonpaku
LoserFox
peci1
saintliao
shubhexists
SirElderling
almx
elivinsky
starius
TravisDupes
amir16yp
Fymyte
Ganesh910
hashFactory
kclauhk
Kyraminol
lstrojny
middlingphys
NickCis
nicodato
prettykool
S-Aarab
sonmezberkay
TSRBerry
114514ns
agibson-fl
alard
alien-developers
antonkesy
ArnauvGilotra
Arthurszzz
Bibhav48
Bl4Cc4t
boredzo
Caesim404
chkuendig
chtk
Danish-H
dasidiot
diman8
divStar
DmitryScaletta
feederbox826
gmes78
gonzalezjo
hui1601
infanf
jazz1611
jingtra
jkmartindale
johnvictorfs
llistochek
marcdumais
martinxyz
michal-repo
mrmedieval
nbr23
Nicals
Noor-5
NurTasin
pompos02
Pranaxcau
pwaldhauer
RaduManole
RalphORama
rrgomes
ruiminggu
rvsit
sefidel
shmohawk
Snack-X
src-tinkerer
stilor
syntaxsurge
t-nil
ufukk
vista-narvas
x11x
xpadev-net
Xpl0itU
YoshichikaAAA
zhijinwuu
alb
hruzgar
kasper93
leoheitmannruiz
luiso1979
nipotan
Offert4324
sta1us
Tomoka1
trwstin

File diff suppressed because it is too large Load Diff

@ -8,6 +8,7 @@ You can also find lists of all [contributors of yt-dlp](CONTRIBUTORS) and [autho
## [pukkandan](https://github.com/pukkandan)
[![ko-fi](https://img.shields.io/badge/_-Ko--fi-red.svg?logo=kofi&labelColor=555555&style=for-the-badge)](https://ko-fi.com/pukkandan)
[![gh-sponsor](https://img.shields.io/badge/_-Github-white.svg?logo=github&labelColor=555555&style=for-the-badge)](https://github.com/sponsors/pukkandan)
* Owner of the fork
@ -25,15 +26,17 @@ You can also find lists of all [contributors of yt-dlp](CONTRIBUTORS) and [autho
## [coletdjnz](https://github.com/coletdjnz)
[![gh-sponsor](https://img.shields.io/badge/_-Sponsor-red.svg?logo=githubsponsors&labelColor=555555&style=for-the-badge)](https://github.com/sponsors/coletdjnz)
[![gh-sponsor](https://img.shields.io/badge/_-Github-white.svg?logo=github&labelColor=555555&style=for-the-badge)](https://github.com/sponsors/coletdjnz)
* Improved plugin architecture
* Rewrote the networking infrastructure, implemented support for `requests`
* 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
* Added support for new websites MainStreaming, PRX, nzherald, etc
* Added support for new websites YoutubeWebArchive, MainStreaming, PRX, nzherald, Mediaklikk, StarTV etc
* Improved/fixed support for Patreon, panopto, gfycat, itv, pbs, SouthParkDE etc
## [Ashish0804](https://github.com/Ashish0804)
## [Ashish0804](https://github.com/Ashish0804) <sub><sup>[Inactive]</sup></sub>
[![ko-fi](https://img.shields.io/badge/_-Ko--fi-red.svg?logo=kofi&labelColor=555555&style=for-the-badge)](https://ko-fi.com/ashish0804)
@ -42,10 +45,19 @@ You can also find lists of all [contributors of yt-dlp](CONTRIBUTORS) and [autho
* Improved/fixed support for HiDive, HotStar, Hungama, LBRY, LinkedInLearning, Mxplayer, SonyLiv, TV2, Vimeo, VLive etc
## [Lesmiscore](https://github.com/Lesmiscore) (nao20010128nao)
## [bashonly](https://github.com/bashonly)
**Bitcoin**: bc1qfd02r007cutfdjwjmyy9w23rjvtls6ncve7r3s
**Monacoin**: mona1q3tf7dzvshrhfe3md379xtvt2n22duhglv5dskr
* `--update-to`, self-updater rewrite, automated/nightly/master releases
* `--cookies-from-browser` support for Firefox containers, external downloader cookie handling overhaul
* Added support for new websites like Dacast, Kick, NBCStations, Triller, VideoKen, Weverse, WrestleUniverse etc
* Improved/fixed support for Anvato, Brightcove, Reddit, SlidesLive, TikTok, Twitter, Vimeo etc
* 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
## [Grub4K](https://github.com/Grub4K)
[![gh-sponsor](https://img.shields.io/badge/_-Github-white.svg?logo=github&labelColor=555555&style=for-the-badge)](https://github.com/sponsors/Grub4K) [![ko-fi](https://img.shields.io/badge/_-Ko--fi-red.svg?logo=kofi&labelColor=555555&style=for-the-badge)](https://ko-fi.com/Grub4K)
* `--update-to`, self-updater rewrite, automated/nightly/master releases
* Reworked internals like `traverse_obj`, various core refactors and bugs fixes
* Implemented proper progress reporting for parallel downloads
* Improved/fixed/added Bundestag, crunchyroll, pr0gramm, Twitter, WrestleUniverse etc

@ -1,10 +0,0 @@
include AUTHORS
include Changelog.md
include LICENSE
include README.md
include completions/*/*
include supportedsites.md
include yt-dlp.1
include requirements.txt
recursive-include devscripts *
recursive-include test *

@ -2,26 +2,29 @@ all: lazy-extractors yt-dlp doc pypi-files
clean: clean-test clean-dist
clean-all: clean clean-cache
completions: completion-bash completion-fish completion-zsh
doc: README.md CONTRIBUTING.md issuetemplates supportedsites
doc: README.md CONTRIBUTING.md CONTRIBUTORS issuetemplates supportedsites
ot: offlinetest
tar: yt-dlp.tar.gz
# Keep this list in sync with MANIFEST.in
# Keep this list in sync with pyproject.toml includes/artifacts
# intended use: when building a source distribution,
# make pypi-files && python setup.py sdist
# make pypi-files && python3 -m build -sn .
pypi-files: AUTHORS Changelog.md LICENSE README.md README.txt supportedsites \
completions yt-dlp.1 requirements.txt setup.cfg devscripts/* test/*
completions yt-dlp.1 pyproject.toml setup.cfg devscripts/* test/*
.PHONY: all clean install test tar pypi-files completions ot offlinetest codetest supportedsites
.PHONY: all clean clean-all clean-test clean-dist clean-cache \
completions completion-bash completion-fish completion-zsh \
doc issuetemplates supportedsites ot offlinetest codetest test \
tar pypi-files lazy-extractors install uninstall
clean-test:
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 *.ass *.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
*.3gp *.ape *.ass *.avi *.desktop *.f4v *.flac *.flv *.gif *.jpeg *.jpg *.lrc *.m4a *.m4v *.mhtml *.mkv *.mov *.mp3 *.mp4 \
*.mpg *.mpga *.oga *.ogg *.opus *.png *.sbv *.srt *.ssa *.swf *.swp *.tt *.ttml *.url *.vtt *.wav *.webloc *.webm *.webp
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
yt_dlp/extractor/lazy_extractors.py *.spec CONTRIBUTING.md.tmp yt-dlp yt-dlp.exe yt_dlp.egg-info/ AUTHORS
clean-cache:
find . \( \
-type d -name .pytest_cache -o -type d -name __pycache__ -o -name "*.pyc" -o -name "*.class" \
@ -33,17 +36,19 @@ completion-zsh: completions/zsh/_yt-dlp
lazy-extractors: yt_dlp/extractor/lazy_extractors.py
PREFIX ?= /usr/local
DESTDIR ?= .
BINDIR ?= $(PREFIX)/bin
MANDIR ?= $(PREFIX)/man
SHAREDIR ?= $(PREFIX)/share
PYTHON ?= /usr/bin/env python3
GNUTAR ?= tar
# set SYSCONFDIR to /etc if PREFIX=/usr or PREFIX=/usr/local
SYSCONFDIR = $(shell if [ $(PREFIX) = /usr -o $(PREFIX) = /usr/local ]; then echo /etc; else echo $(PREFIX)/etc; fi)
# 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)
# set markdown input format to "markdown-smart" for pandoc version 2+ and to "markdown" for pandoc prior to version 2
PANDOC_VERSION_CMD = pandoc -v 2>/dev/null | head -n1 | cut -d' ' -f2 | head -c1
PANDOC_VERSION != $(PANDOC_VERSION_CMD)
PANDOC_VERSION ?= $(shell $(PANDOC_VERSION_CMD))
MARKDOWN_CMD = if [ "$(PANDOC_VERSION)" = "1" -o "$(PANDOC_VERSION)" = "0" ]; then echo markdown; else echo markdown-smart; fi
MARKDOWN != $(MARKDOWN_CMD)
MARKDOWN ?= $(shell $(MARKDOWN_CMD))
install: lazy-extractors yt-dlp yt-dlp.1 completions
mkdir -p $(DESTDIR)$(BINDIR)
@ -74,25 +79,28 @@ test:
offlinetest: codetest
$(PYTHON) -m pytest -k "not download"
# XXX: This is hard to maintain
CODE_FOLDERS = yt_dlp yt_dlp/downloader yt_dlp/extractor yt_dlp/postprocessor yt_dlp/compat \
yt_dlp/extractor/anvato_token_generator
yt-dlp: yt_dlp/*.py yt_dlp/*/*.py
CODE_FOLDERS_CMD = find yt_dlp -type f -name '__init__.py' | sed 's,/__init__.py,,' | grep -v '/__' | sort
CODE_FOLDERS != $(CODE_FOLDERS_CMD)
CODE_FOLDERS ?= $(shell $(CODE_FOLDERS_CMD))
CODE_FILES_CMD = for f in $(CODE_FOLDERS) ; do echo "$$f" | sed 's,$$,/*.py,' ; done
CODE_FILES != $(CODE_FILES_CMD)
CODE_FILES ?= $(shell $(CODE_FILES_CMD))
yt-dlp: $(CODE_FILES)
mkdir -p zip
for d in $(CODE_FOLDERS) ; do \
mkdir -p zip/$$d ;\
cp -pPR $$d/*.py zip/$$d/ ;\
done
touch -t 200001010101 zip/yt_dlp/*.py zip/yt_dlp/*/*.py zip/yt_dlp/*/*/*.py
(cd zip && touch -t 200001010101 $(CODE_FILES))
mv zip/yt_dlp/__main__.py zip/
cd zip ; zip -q ../yt-dlp yt_dlp/*.py yt_dlp/*/*.py yt_dlp/*/*/*.py __main__.py
(cd zip && zip -q ../yt-dlp $(CODE_FILES) __main__.py)
rm -rf zip
echo '#!$(PYTHON)' > yt-dlp
cat yt-dlp.zip >> yt-dlp
rm yt-dlp.zip
chmod a+x yt-dlp
README.md: yt_dlp/*.py yt_dlp/*/*.py devscripts/make_readme.py
README.md: $(CODE_FILES) devscripts/make_readme.py
COLUMNS=80 $(PYTHON) yt_dlp/__main__.py --ignore-config --help | $(PYTHON) devscripts/make_readme.py
CONTRIBUTING.md: README.md devscripts/make_contributing.py
@ -117,24 +125,26 @@ yt-dlp.1: README.md devscripts/prepare_manpage.py
pandoc -s -f $(MARKDOWN) -t man yt-dlp.1.temp.md -o yt-dlp.1
rm -f yt-dlp.1.temp.md
completions/bash/yt-dlp: yt_dlp/*.py yt_dlp/*/*.py devscripts/bash-completion.in
completions/bash/yt-dlp: $(CODE_FILES) devscripts/bash-completion.in
mkdir -p completions/bash
$(PYTHON) devscripts/bash-completion.py
completions/zsh/_yt-dlp: yt_dlp/*.py yt_dlp/*/*.py devscripts/zsh-completion.in
completions/zsh/_yt-dlp: $(CODE_FILES) devscripts/zsh-completion.in
mkdir -p completions/zsh
$(PYTHON) devscripts/zsh-completion.py
completions/fish/yt-dlp.fish: yt_dlp/*.py yt_dlp/*/*.py devscripts/fish-completion.in
completions/fish/yt-dlp.fish: $(CODE_FILES) devscripts/fish-completion.in
mkdir -p completions/fish
$(PYTHON) devscripts/fish-completion.py
_EXTRACTOR_FILES = $(shell find yt_dlp/extractor -name '*.py' -and -not -name 'lazy_extractors.py')
_EXTRACTOR_FILES_CMD = find yt_dlp/extractor -name '*.py' -and -not -name 'lazy_extractors.py'
_EXTRACTOR_FILES != $(_EXTRACTOR_FILES_CMD)
_EXTRACTOR_FILES ?= $(shell $(_EXTRACTOR_FILES_CMD))
yt_dlp/extractor/lazy_extractors.py: devscripts/make_lazy_extractors.py devscripts/lazy_load_template.py $(_EXTRACTOR_FILES)
$(PYTHON) devscripts/make_lazy_extractors.py $@
yt-dlp.tar.gz: all
@tar -czf $(DESTDIR)/yt-dlp.tar.gz --transform "s|^|yt-dlp/|" --owner 0 --group 0 \
@$(GNUTAR) -czf yt-dlp.tar.gz --transform "s|^|yt-dlp/|" --owner 0 --group 0 \
--exclude '*.DS_Store' \
--exclude '*.kate-swp' \
--exclude '*.pyc' \
@ -146,12 +156,17 @@ yt-dlp.tar.gz: all
-- \
README.md supportedsites.md Changelog.md LICENSE \
CONTRIBUTING.md Collaborators.md CONTRIBUTORS AUTHORS \
Makefile MANIFEST.in yt-dlp.1 README.txt completions \
setup.py setup.cfg yt-dlp yt_dlp requirements.txt \
devscripts test
AUTHORS: .mailmap
git shortlog -s -n | cut -f2 | sort > AUTHORS
.mailmap:
git shortlog -s -e -n | awk '!(out[$$NF]++) { $$1="";sub(/^[ \t]+/,""); print}' > .mailmap
Makefile yt-dlp.1 README.txt completions .gitignore \
setup.cfg yt-dlp yt_dlp pyproject.toml devscripts test
AUTHORS: Changelog.md
@if [ -d '.git' ] && command -v git > /dev/null ; then \
echo 'Generating $@ from git commit history' ; \
git shortlog -s -n HEAD | cut -f2 | sort > $@ ; \
fi
CONTRIBUTORS: Changelog.md
@if [ -d '.git' ] && command -v git > /dev/null ; then \
echo 'Updating $@ from git commit history' ; \
$(PYTHON) devscripts/make_changelog.py -v -c > /dev/null ; \
fi

File diff suppressed because it is too large Load Diff

@ -0,0 +1,10 @@
services:
static:
build: static
environment:
channel: ${channel}
origin: ${origin}
version: ${version}
volumes:
- ~/build:/build
- ../..:/yt-dlp

@ -0,0 +1,21 @@
FROM alpine:3.19 as base
RUN apk --update add --no-cache \
build-base \
python3 \
pipx \
;
RUN pipx install pyinstaller
# Requires above step to prepare the shared venv
RUN ~/.local/share/pipx/shared/bin/python -m pip install -U wheel
RUN apk --update add --no-cache \
scons \
patchelf \
binutils \
;
RUN pipx install staticx
WORKDIR /yt-dlp
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT /entrypoint.sh

@ -0,0 +1,13 @@
#!/bin/ash
set -e
source ~/.local/share/pipx/venvs/pyinstaller/bin/activate
python -m devscripts.install_deps --include secretstorage
python -m devscripts.make_lazy_extractors
python devscripts/update-version.py -c "${channel}" -r "${origin}" "${version}"
python -m bundle.pyinstaller
deactivate
source ~/.local/share/pipx/venvs/staticx/bin/activate
staticx /yt-dlp/dist/yt-dlp_linux /build/yt-dlp_linux
deactivate

@ -0,0 +1,59 @@
#!/usr/bin/env python3
# Allow execution from anywhere
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import warnings
from py2exe import freeze
from devscripts.utils import read_version
VERSION = read_version()
def main():
warnings.warn(
'py2exe builds do not support pycryptodomex and needs VC++14 to run. '
'It is recommended to run "pyinst.py" to build using pyinstaller instead')
freeze(
console=[{
'script': './yt_dlp/__main__.py',
'dest_base': 'yt-dlp',
'icon_resources': [(1, 'devscripts/logo.ico')],
}],
version_info={
'version': VERSION,
'description': 'A feature-rich command-line audio/video downloader',
'comments': 'Official repository: <https://github.com/yt-dlp/yt-dlp>',
'product_name': 'yt-dlp',
'product_version': VERSION,
},
options={
'bundle_files': 0,
'compressed': 1,
'optimize': 2,
'dist_dir': './dist',
'excludes': [
# py2exe cannot import Crypto
'Crypto',
'Cryptodome',
# py2exe appears to confuse this with our socks library.
# We don't use pysocks and urllib3.contrib.socks would fail to import if tried.
'urllib3.contrib.socks'
],
'dll_excludes': ['w9xpopen.exe', 'crypt32.dll'],
# Modules that are only imported dynamically must be added here
'includes': ['yt_dlp.compat._legacy', 'yt_dlp.compat._deprecated',
'yt_dlp.utils._legacy', 'yt_dlp.utils._deprecated'],
},
zipfile=None,
)
if __name__ == '__main__':
main()

@ -0,0 +1,132 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import platform
from PyInstaller.__main__ import run as run_pyinstaller
from devscripts.utils import read_version
OS_NAME, MACHINE, ARCH = sys.platform, platform.machine().lower(), platform.architecture()[0][:2]
if MACHINE in ('x86', 'x86_64', 'amd64', 'i386', 'i686'):
MACHINE = 'x86' if ARCH == '32' else ''
def main():
opts, version = parse_options(), read_version()
onedir = '--onedir' in opts or '-D' in opts
if not onedir and '-F' not in opts and '--onefile' not in opts:
opts.append('--onefile')
name, final_file = exe(onedir)
print(f'Building yt-dlp v{version} for {OS_NAME} {platform.machine()} with options {opts}')
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')
opts = [
f'--name={name}',
'--icon=devscripts/logo.ico',
'--upx-exclude=vcruntime140.dll',
'--noconfirm',
'--additional-hooks-dir=yt_dlp/__pyinstaller',
*opts,
'yt_dlp/__main__.py',
]
print(f'Running PyInstaller with {opts}')
run_pyinstaller(opts)
set_version_info(final_file, version)
def parse_options():
# Compatibility 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
def exe(onedir):
"""@returns (name, path)"""
name = '_'.join(filter(None, (
'yt-dlp',
{'win32': '', 'darwin': 'macos'}.get(OS_NAME, OS_NAME),
MACHINE,
)))
return name, ''.join(filter(None, (
'dist/',
onedir and f'{name}/',
name,
OS_NAME == 'win32' and '.exe'
)))
def version_to_list(version):
version_list = version.split('.')
return list(map(int, version_list)) + [0] * (4 - len(version_list))
def set_version_info(exe, version):
if OS_NAME == 'win32':
windows_set_version(exe, version)
def windows_set_version(exe, version):
from PyInstaller.utils.win32.versioninfo import (
FixedFileInfo,
StringFileInfo,
StringStruct,
StringTable,
VarFileInfo,
VarStruct,
VSVersionInfo,
)
try:
from PyInstaller.utils.win32.versioninfo import SetVersion
except ImportError: # Pyinstaller >= 5.8
from PyInstaller.utils.win32.versioninfo import write_version_info_to_executable as SetVersion
version_list = version_to_list(version)
suffix = MACHINE and f'_{MACHINE}'
SetVersion(exe, VSVersionInfo(
ffi=FixedFileInfo(
filevers=version_list,
prodvers=version_list,
mask=0x3F,
flags=0x0,
OS=0x4,
fileType=0x1,
subtype=0x0,
date=(0, 0),
),
kids=[
StringFileInfo([StringTable('040904B0', [
StringStruct('Comments', 'yt-dlp%s Command Line Interface' % suffix),
StringStruct('CompanyName', 'https://github.com/yt-dlp'),
StringStruct('FileDescription', 'yt-dlp%s' % (MACHINE and f' ({MACHINE})')),
StringStruct('FileVersion', version),
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(
'ProductVersion', f'{version}{suffix} on Python {platform.python_version()}'),
])]), VarFileInfo([VarStruct('Translation', [0, 1200])])
]
))
if __name__ == '__main__':
main()

Binary file not shown.

Binary file not shown.

@ -1,9 +1,12 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import yt_dlp
BASH_COMPLETION_FILE = "completions/bash/yt-dlp"

@ -0,0 +1,151 @@
[
{
"action": "add",
"when": "29cb20bd563c02671b31dd840139e93dd37150a1",
"short": "[priority] **A new release type has been added!**\n * [`nightly`](https://github.com/yt-dlp/yt-dlp/releases/tag/nightly) builds will be made after each push, containing the latest fixes (but also possibly bugs).\n * When using `--update`/`-U`, a release binary will only update to its current channel (either `stable` or `nightly`).\n * The `--update-to` option has been added allowing the user more control over program upgrades (or downgrades).\n * `--update-to` can change the release channel (`stable`, `nightly`) and also upgrade or downgrade to specific tags.\n * **Usage**: `--update-to CHANNEL`, `--update-to TAG`, `--update-to CHANNEL@TAG`"
},
{
"action": "add",
"when": "5038f6d713303e0967d002216e7a88652401c22a",
"short": "[priority] **YouTube throttling fixes!**"
},
{
"action": "remove",
"when": "2e023649ea4e11151545a34dc1360c114981a236"
},
{
"action": "add",
"when": "01aba2519a0884ef17d5f85608dbd2a455577147",
"short": "[priority] YouTube: Improved throttling and signature fixes"
},
{
"action": "change",
"when": "c86e433c35fe5da6cb29f3539eef97497f84ed38",
"short": "[extractor/niconico:series] Fix extraction (#6898)",
"authors": ["sqrtNOT"]
},
{
"action": "change",
"when": "69a40e4a7f6caa5662527ebd2f3c4e8aa02857a2",
"short": "[extractor/youtube:music_search_url] Extract title (#7102)",
"authors": ["kangalio"]
},
{
"action": "change",
"when": "8417f26b8a819cd7ffcd4e000ca3e45033e670fb",
"short": "Add option `--color` (#6904)",
"authors": ["Grub4K"]
},
{
"action": "change",
"when": "b4e0d75848e9447cee2cd3646ce54d4744a7ff56",
"short": "Improve `--download-sections`\n - Support negative time-ranges\n - Add `*from-url` to obey time-ranges in URL",
"authors": ["pukkandan"]
},
{
"action": "change",
"when": "1e75d97db21152acc764b30a688e516f04b8a142",
"short": "[extractor/youtube] Add `ios` to default clients used\n - IOS is affected neither by 403 nor by nsig so helps mitigate them preemptively\n - IOS also has higher bit-rate 'premium' formats though they are not labeled as such",
"authors": ["pukkandan"]
},
{
"action": "change",
"when": "f2ff0f6f1914b82d4a51681a72cc0828115dcb4a",
"short": "[extractor/motherless] Add gallery support, fix groups (#7211)",
"authors": ["rexlambert22", "Ti4eeT4e"]
},
{
"action": "change",
"when": "a4486bfc1dc7057efca9dd3fe70d7fa25c56f700",
"short": "[misc] Revert \"Add automatic duplicate issue detection\"",
"authors": ["pukkandan"]
},
{
"action": "add",
"when": "1ceb657bdd254ad961489e5060f2ccc7d556b729",
"short": "[priority] Security: [[CVE-2023-35934](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-35934)] Fix [Cookie leak](https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-v8mc-9377-rwjj)\n - `--add-header Cookie:` is deprecated and auto-scoped to input URL domains\n - Cookies are scoped when passed to external downloaders\n - Add `cookies` field to info.json and deprecate `http_headers.Cookie`"
},
{
"action": "change",
"when": "b03fa7834579a01cc5fba48c0e73488a16683d48",
"short": "[ie/twitter] Revert 92315c03774cfabb3a921884326beb4b981f786b",
"authors": ["pukkandan"]
},
{
"action": "change",
"when": "fcd6a76adc49d5cd8783985c7ce35384b72e545f",
"short": "[test] Add tests for socks proxies (#7908)",
"authors": ["coletdjnz"]
},
{
"action": "change",
"when": "4bf912282a34b58b6b35d8f7e6be535770c89c76",
"short": "[rh:urllib] Remove dot segments during URL normalization (#7662)",
"authors": ["coletdjnz"]
},
{
"action": "change",
"when": "59e92b1f1833440bb2190f847eb735cf0f90bc85",
"short": "[rh:urllib] Simplify gzip decoding (#7611)",
"authors": ["Grub4K"]
},
{
"action": "add",
"when": "c1d71d0d9f41db5e4306c86af232f5f6220a130b",
"short": "[priority] **The minimum *recommended* Python version has been raised to 3.8**\nSince Python 3.7 has reached end-of-life, support for it will be dropped soon. [Read more](https://github.com/yt-dlp/yt-dlp/issues/7803)"
},
{
"action": "add",
"when": "61bdf15fc7400601c3da1aa7a43917310a5bf391",
"short": "[priority] Security: [[CVE-2023-40581](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-40581)] [Prevent RCE when using `--exec` with `%q` on Windows](https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-42h4-v29r-42qg)\n - The shell escape function is now using `\"\"` instead of `\\\"`.\n - `utils.Popen` has been patched to properly quote commands."
},
{
"action": "change",
"when": "8a8b54523addf46dfd50ef599761a81bc22362e6",
"short": "[rh:requests] Add handler for `requests` HTTP library (#3668)\n\n\tAdds support for HTTPS proxies and persistent connections (keep-alive)",
"authors": ["bashonly", "coletdjnz", "Grub4K"]
},
{
"action": "add",
"when": "1d03633c5a1621b9f3a756f0a4f9dc61fab3aeaa",
"short": "[priority] **The release channels have been adjusted!**\n\t* [`master`](https://github.com/yt-dlp/yt-dlp-master-builds) builds are made after each push, containing the latest fixes (but also possibly bugs). This was previously the `nightly` channel.\n\t* [`nightly`](https://github.com/yt-dlp/yt-dlp-nightly-builds) builds are now made once a day, if there were any changes."
},
{
"action": "add",
"when": "f04b5bedad7b281bee9814686bba1762bae092eb",
"short": "[priority] Security: [[CVE-2023-46121](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-46121)] Patch [Generic Extractor MITM Vulnerability via Arbitrary Proxy Injection](https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-3ch3-jhc6-5r8x)\n\t- Disallow smuggling of arbitrary `http_headers`; extractors now only use specific headers"
},
{
"action": "change",
"when": "15f22b4880b6b3f71f350c64d70976ae65b9f1ca",
"short": "[webvtt] Allow spaces before newlines for CueBlock (#7681)",
"authors": ["TSRBerry"]
},
{
"action": "change",
"when": "4ce57d3b873c2887814cbec03d029533e82f7db5",
"short": "[ie] Support multi-period MPD streams (#6654)",
"authors": ["alard", "pukkandan"]
},
{
"action": "change",
"when": "aa7e9ae4f48276bd5d0173966c77db9484f65a0a",
"short": "[ie/xvideos] Support new URL format (#9502)",
"authors": ["sta1us"]
},
{
"action": "remove",
"when": "22e4dfacb61f62dfbb3eb41b31c7b69ba1059b80"
},
{
"action": "change",
"when": "e3a3ed8a981d9395c4859b6ef56cd02bc3148db2",
"short": "[cleanup:ie] No `from` stdlib imports in extractors",
"authors": ["pukkandan"]
},
{
"action": "add",
"when": "9590cc6b4768e190183d7d071a6c78170889116a",
"short": "[priority] Security: [[CVE-2024-22423](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-22423)] [Prevent RCE when using `--exec` with `%q` on Windows](https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-hjq6-52gw-2g7p)\n - The shell escape function now properly escapes `%`, `\\` and `\\n`.\n - `utils.Popen` has been patched accordingly."
}
]

@ -0,0 +1,96 @@
{
"$schema": "http://json-schema.org/draft/2020-12/schema",
"type": "array",
"uniqueItems": true,
"items": {
"type": "object",
"oneOf": [
{
"type": "object",
"properties": {
"action": {
"enum": [
"add"
]
},
"when": {
"type": "string",
"pattern": "^([0-9a-f]{40}|\\d{4}\\.\\d{2}\\.\\d{2})$"
},
"hash": {
"type": "string",
"pattern": "^[0-9a-f]{40}$"
},
"short": {
"type": "string"
},
"authors": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"action",
"short"
]
},
{
"type": "object",
"properties": {
"action": {
"enum": [
"remove"
]
},
"when": {
"type": "string",
"pattern": "^([0-9a-f]{40}|\\d{4}\\.\\d{2}\\.\\d{2})$"
},
"hash": {
"type": "string",
"pattern": "^[0-9a-f]{40}$"
}
},
"required": [
"action",
"hash"
]
},
{
"type": "object",
"properties": {
"action": {
"enum": [
"change"
]
},
"when": {
"type": "string",
"pattern": "^([0-9a-f]{40}|\\d{4}\\.\\d{2}\\.\\d{2})$"
},
"hash": {
"type": "string",
"pattern": "^[0-9a-f]{40}$"
},
"short": {
"type": "string"
},
"authors": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"action",
"hash",
"short",
"authors"
]
}
]
}
}

@ -13,9 +13,11 @@ import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from test.helper import gettestcases
from yt_dlp.utils import compat_urllib_parse_urlparse, compat_urllib_request
import urllib.parse
import urllib.request
from test.helper import gettestcases
if len(sys.argv) > 1:
METHOD = 'LIST'
@ -26,7 +28,7 @@ else:
for test in gettestcases():
if METHOD == 'EURISTIC':
try:
webpage = compat_urllib_request.urlopen(test['url'], timeout=10).read()
webpage = urllib.request.urlopen(test['url'], timeout=10).read()
except Exception:
print('\nFail: {}'.format(test['name']))
continue
@ -36,7 +38,7 @@ for test in gettestcases():
RESULT = 'porn' in webpage.lower()
elif METHOD == 'LIST':
domain = compat_urllib_parse_urlparse(test['url']).netloc
domain = urllib.parse.urlparse(test['url']).netloc
if not domain:
print('\nFail: {}'.format(test['name']))
continue

@ -0,0 +1,48 @@
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import yt_dlp
import yt_dlp.options
create_parser = yt_dlp.options.create_parser
def parse_patched_options(opts):
patched_parser = create_parser()
patched_parser.defaults.update({
'ignoreerrors': False,
'retries': 0,
'fragment_retries': 0,
'extract_flat': False,
'concat_playlist': 'never',
})
yt_dlp.options.create_parser = lambda: patched_parser
try:
return yt_dlp.parse_options(opts)
finally:
yt_dlp.options.create_parser = create_parser
default_opts = parse_patched_options([]).ydl_opts
def cli_to_api(opts, cli_defaults=False):
opts = (yt_dlp.parse_options if cli_defaults else parse_patched_options)(opts).ydl_opts
diff = {k: v for k, v in opts.items() if default_opts[k] != v}
if 'postprocessors' in diff:
diff['postprocessors'] = [pp for pp in diff['postprocessors']
if pp not in default_opts['postprocessors']]
return diff
if __name__ == '__main__':
from pprint import pprint
print('\nThe arguments passed translate to:\n')
pprint(cli_to_api(sys.argv[1:]))
print('\nCombining these with the CLI defaults gives:\n')
pprint(cli_to_api(sys.argv[1:], True))

@ -1,10 +1,14 @@
#!/usr/bin/env python3
import optparse
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import optparse
import yt_dlp
from yt_dlp.utils import shell_quote

@ -1,11 +1,15 @@
#!/usr/bin/env python3
import codecs
# Allow direct execution
import os
import subprocess
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import codecs
import subprocess
from yt_dlp.aes import aes_encrypt, key_expansion
from yt_dlp.utils import intlist_to_bytes

@ -0,0 +1,73 @@
#!/usr/bin/env python3
# Allow execution from anywhere
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import re
import subprocess
from pathlib import Path
from devscripts.tomlparse import parse_toml
from devscripts.utils import read_file
def parse_args():
parser = argparse.ArgumentParser(description='Install dependencies for yt-dlp')
parser.add_argument(
'input', nargs='?', metavar='TOMLFILE', default=Path(__file__).parent.parent / 'pyproject.toml',
help='input file (default: %(default)s)')
parser.add_argument(
'-e', '--exclude', metavar='DEPENDENCY', action='append',
help='exclude a dependency')
parser.add_argument(
'-i', '--include', metavar='GROUP', action='append',
help='include an optional dependency group')
parser.add_argument(
'-o', '--only-optional', action='store_true',
help='only install optional dependencies')
parser.add_argument(
'-p', '--print', action='store_true',
help='only print requirements to stdout')
parser.add_argument(
'-u', '--user', action='store_true',
help='install with pip as --user')
return parser.parse_args()
def main():
args = parse_args()
project_table = parse_toml(read_file(args.input))['project']
optional_groups = project_table['optional-dependencies']
excludes = args.exclude or []
targets = []
if not args.only_optional: # `-o` should exclude 'dependencies' and the 'default' group
targets.extend(project_table['dependencies'])
if 'default' not in excludes: # `--exclude default` should exclude entire 'default' group
targets.extend(optional_groups['default'])
for include in filter(None, map(optional_groups.get, args.include or [])):
targets.extend(include)
targets = [t for t in targets if re.match(r'[\w-]+', t).group(0).lower() not in excludes]
if args.print:
for target in targets:
print(target)
return
pip_args = [sys.executable, '-m', 'pip', 'install', '-U']
if args.user:
pip_args.append('--user')
pip_args.extend(targets)
return subprocess.call(pip_args)
if __name__ == '__main__':
sys.exit(main())

@ -6,17 +6,23 @@ from ..utils import (
age_restricted,
bug_reports_message,
classproperty,
variadic,
write_string,
)
# These bloat the lazy_extractors, so allow them to passthrough silently
ALLOWED_CLASSMETHODS = {'extract_from_webpage', 'get_testcases', 'get_webpage_testcases'}
_WARNED = False
class LazyLoadMetaClass(type):
def __getattr__(cls, name):
# "_TESTS" bloat the lazy_extractors
if '_real_class' not in cls.__dict__ and name != 'get_testcases':
write_string(
'WARNING: Falling back to normal extractor since lazy extractor '
f'{cls.__name__} does not have attribute {name}{bug_reports_message()}\n')
global _WARNED
if ('_real_class' not in cls.__dict__
and name not in ALLOWED_CLASSMETHODS and not _WARNED):
_WARNED = True
write_string('WARNING: Falling back to normal extractor since lazy extractor '
f'{cls.__name__} does not have attribute {name}{bug_reports_message()}\n')
return getattr(cls.real_class, name)

@ -0,0 +1,510 @@
from __future__ import annotations
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import enum
import itertools
import json
import logging
import re
from collections import defaultdict
from dataclasses import dataclass
from functools import lru_cache
from pathlib import Path
from devscripts.utils import read_file, run_process, write_file
BASE_URL = 'https://github.com'
LOCATION_PATH = Path(__file__).parent
HASH_LENGTH = 7
logger = logging.getLogger(__name__)
class CommitGroup(enum.Enum):
PRIORITY = 'Important'
CORE = 'Core'
EXTRACTOR = 'Extractor'
DOWNLOADER = 'Downloader'
POSTPROCESSOR = 'Postprocessor'
NETWORKING = 'Networking'
MISC = 'Misc.'
@classmethod
@lru_cache
def subgroup_lookup(cls):
return {
name: group
for group, names in {
cls.MISC: {
'build',
'ci',
'cleanup',
'devscripts',
'docs',
'test',
},
cls.NETWORKING: {
'rh',
},
}.items()
for name in names
}
@classmethod
@lru_cache
def group_lookup(cls):
result = {
'fd': cls.DOWNLOADER,
'ie': cls.EXTRACTOR,
'pp': cls.POSTPROCESSOR,
'upstream': cls.CORE,
}
result.update({item.name.lower(): item for item in iter(cls)})
return result
@classmethod
def get(cls, value: str) -> tuple[CommitGroup | None, str | None]:
group, _, subgroup = (group.strip().lower() for group in value.partition('/'))
result = cls.group_lookup().get(group)
if not result:
if subgroup:
return None, value
subgroup = group
result = cls.subgroup_lookup().get(subgroup)
return result, subgroup or None
@dataclass
class Commit:
hash: str | None
short: str
authors: list[str]
def __str__(self):
result = f'{self.short!r}'
if self.hash:
result += f' ({self.hash[:HASH_LENGTH]})'
if self.authors:
authors = ', '.join(self.authors)
result += f' by {authors}'
return result
@dataclass
class CommitInfo:
details: str | None
sub_details: tuple[str, ...]
message: str
issues: list[str]
commit: Commit
fixes: list[Commit]
def key(self):
return ((self.details or '').lower(), self.sub_details, self.message)
def unique(items):
return sorted({item.strip().lower(): item for item in items if item}.values())
class Changelog:
MISC_RE = re.compile(r'(?:^|\b)(?:lint(?:ing)?|misc|format(?:ting)?|fixes)(?:\b|$)', re.IGNORECASE)
ALWAYS_SHOWN = (CommitGroup.PRIORITY,)
def __init__(self, groups, repo, collapsible=False):
self._groups = groups
self._repo = repo
self._collapsible = collapsible
def __str__(self):
return '\n'.join(self._format_groups(self._groups)).replace('\t', ' ')
def _format_groups(self, groups):
first = True
for item in CommitGroup:
if self._collapsible and item not in self.ALWAYS_SHOWN and first:
first = False
yield '\n<details><summary><h3>Changelog</h3></summary>\n'
group = groups[item]
if group:
yield self.format_module(item.value, group)
if self._collapsible:
yield '\n</details>'
def format_module(self, name, group):
result = f'\n#### {name} changes\n' if name else '\n'
return result + '\n'.join(self._format_group(group))
def _format_group(self, group):
sorted_group = sorted(group, key=CommitInfo.key)
detail_groups = itertools.groupby(sorted_group, lambda item: (item.details or '').lower())
for _, items in detail_groups:
items = list(items)
details = items[0].details
if details == 'cleanup':
items = self._prepare_cleanup_misc_items(items)
prefix = '-'
if details:
if len(items) == 1:
prefix = f'- **{details}**:'
else:
yield f'- **{details}**'
prefix = '\t-'
sub_detail_groups = itertools.groupby(items, lambda item: tuple(map(str.lower, item.sub_details)))
for sub_details, entries in sub_detail_groups:
if not sub_details:
for entry in entries:
yield f'{prefix} {self.format_single_change(entry)}'
continue
entries = list(entries)
sub_prefix = f'{prefix} {", ".join(entries[0].sub_details)}'
if len(entries) == 1:
yield f'{sub_prefix}: {self.format_single_change(entries[0])}'
continue
yield sub_prefix
for entry in entries:
yield f'\t{prefix} {self.format_single_change(entry)}'
def _prepare_cleanup_misc_items(self, items):
cleanup_misc_items = defaultdict(list)
sorted_items = []
for item in items:
if self.MISC_RE.search(item.message):
cleanup_misc_items[tuple(item.commit.authors)].append(item)
else:
sorted_items.append(item)
for commit_infos in cleanup_misc_items.values():
sorted_items.append(CommitInfo(
'cleanup', ('Miscellaneous',), ', '.join(
self._format_message_link(None, info.commit.hash)
for info in sorted(commit_infos, key=lambda item: item.commit.hash or '')),
[], Commit(None, '', commit_infos[0].commit.authors), []))
return sorted_items
def format_single_change(self, info: CommitInfo):
message, sep, rest = info.message.partition('\n')
if '[' not in message:
# If the message doesn't already contain markdown links, try to add a link to the commit
message = self._format_message_link(message, info.commit.hash)
if info.issues:
message = f'{message} ({self._format_issues(info.issues)})'
if info.commit.authors:
message = f'{message} by {self._format_authors(info.commit.authors)}'
if info.fixes:
fix_message = ', '.join(f'{self._format_message_link(None, fix.hash)}' for fix in info.fixes)
authors = sorted({author for fix in info.fixes for author in fix.authors}, key=str.casefold)
if authors != info.commit.authors:
fix_message = f'{fix_message} by {self._format_authors(authors)}'
message = f'{message} (With fixes in {fix_message})'
return message if not sep else f'{message}{sep}{rest}'
def _format_message_link(self, message, hash):
assert message or hash, 'Improperly defined commit message or override'
message = message if message else hash[:HASH_LENGTH]
return f'[{message}]({self.repo_url}/commit/{hash})' if hash else message
def _format_issues(self, issues):
return ', '.join(f'[#{issue}]({self.repo_url}/issues/{issue})' for issue in issues)
@staticmethod
def _format_authors(authors):
return ', '.join(f'[{author}]({BASE_URL}/{author})' for author in authors)
@property
def repo_url(self):
return f'{BASE_URL}/{self._repo}'
class CommitRange:
COMMAND = 'git'
COMMIT_SEPARATOR = '-----'
AUTHOR_INDICATOR_RE = re.compile(r'Authored by:? ', re.IGNORECASE)
MESSAGE_RE = re.compile(r'''
(?:\[(?P<prefix>[^\]]+)\]\ )?
(?:(?P<sub_details>`?[\w.-]+`?): )?
(?P<message>.+?)
(?:\ \((?P<issues>\#\d+(?:,\ \#\d+)*)\))?
''', re.VERBOSE | re.DOTALL)
EXTRACTOR_INDICATOR_RE = re.compile(r'(?:Fix|Add)\s+Extractors?', re.IGNORECASE)
REVERT_RE = re.compile(r'(?:\[[^\]]+\]\s+)?(?i:Revert)\s+([\da-f]{40})')
FIXES_RE = re.compile(r'(?i:Fix(?:es)?(?:\s+bugs?)?(?:\s+in|\s+for)?|Revert|Improve)\s+([\da-f]{40})')
UPSTREAM_MERGE_RE = re.compile(r'Update to ytdl-commit-([\da-f]+)')
def __init__(self, start, end, default_author=None):
self._start, self._end = start, end
self._commits, self._fixes = self._get_commits_and_fixes(default_author)
self._commits_added = []
def __iter__(self):
return iter(itertools.chain(self._commits.values(), self._commits_added))
def __len__(self):
return len(self._commits) + len(self._commits_added)
def __contains__(self, commit):
if isinstance(commit, Commit):
if not commit.hash:
return False
commit = commit.hash
return commit in self._commits
def _get_commits_and_fixes(self, default_author):
result = run_process(
self.COMMAND, 'log', f'--format=%H%n%s%n%b%n{self.COMMIT_SEPARATOR}',
f'{self._start}..{self._end}' if self._start else self._end).stdout
commits, reverts = {}, {}
fixes = defaultdict(list)
lines = iter(result.splitlines(False))
for i, commit_hash in enumerate(lines):
short = next(lines)
skip = short.startswith('Release ') or short == '[version] update'
authors = [default_author] if default_author else []
for line in iter(lambda: next(lines), self.COMMIT_SEPARATOR):
match = self.AUTHOR_INDICATOR_RE.match(line)
if match:
authors = sorted(map(str.strip, line[match.end():].split(',')), key=str.casefold)
commit = Commit(commit_hash, short, authors)
if skip and (self._start or not i):
logger.debug(f'Skipped commit: {commit}')
continue
elif skip:
logger.debug(f'Reached Release commit, breaking: {commit}')
break
revert_match = self.REVERT_RE.fullmatch(commit.short)
if revert_match:
reverts[revert_match.group(1)] = commit
continue
fix_match = self.FIXES_RE.search(commit.short)
if fix_match:
commitish = fix_match.group(1)
fixes[commitish].append(commit)
commits[commit.hash] = commit
for commitish, revert_commit in reverts.items():
reverted = commits.pop(commitish, None)
if reverted:
logger.debug(f'{commitish} fully reverted {reverted}')
else:
commits[revert_commit.hash] = revert_commit
for commitish, fix_commits in fixes.items():
if commitish in commits:
hashes = ', '.join(commit.hash[:HASH_LENGTH] for commit in fix_commits)
logger.info(f'Found fix(es) for {commitish[:HASH_LENGTH]}: {hashes}')
for fix_commit in fix_commits:
del commits[fix_commit.hash]
else:
logger.debug(f'Commit with fixes not in changes: {commitish[:HASH_LENGTH]}')
return commits, fixes
def apply_overrides(self, overrides):
for override in overrides:
when = override.get('when')
if when and when not in self and when != self._start:
logger.debug(f'Ignored {when!r} override')
continue
override_hash = override.get('hash') or when
if override['action'] == 'add':
commit = Commit(override.get('hash'), override['short'], override.get('authors') or [])
logger.info(f'ADD {commit}')
self._commits_added.append(commit)
elif override['action'] == 'remove':
if override_hash in self._commits:
logger.info(f'REMOVE {self._commits[override_hash]}')
del self._commits[override_hash]
elif override['action'] == 'change':
if override_hash not in self._commits:
continue
commit = Commit(override_hash, override['short'], override.get('authors') or [])
logger.info(f'CHANGE {self._commits[commit.hash]} -> {commit}')
self._commits[commit.hash] = commit
self._commits = {key: value for key, value in reversed(self._commits.items())}
def groups(self):
group_dict = defaultdict(list)
for commit in self:
upstream_re = self.UPSTREAM_MERGE_RE.search(commit.short)
if upstream_re:
commit.short = f'[upstream] Merged with youtube-dl {upstream_re.group(1)}'
match = self.MESSAGE_RE.fullmatch(commit.short)
if not match:
logger.error(f'Error parsing short commit message: {commit.short!r}')
continue
prefix, sub_details_alt, message, issues = match.groups()
issues = [issue.strip()[1:] for issue in issues.split(',')] if issues else []
if prefix:
groups, details, sub_details = zip(*map(self.details_from_prefix, prefix.split(',')))
group = next(iter(filter(None, groups)), None)
details = ', '.join(unique(details))
sub_details = list(itertools.chain.from_iterable(sub_details))
else:
group = CommitGroup.CORE
details = None
sub_details = []
if sub_details_alt:
sub_details.append(sub_details_alt)
sub_details = tuple(unique(sub_details))
if not group:
if self.EXTRACTOR_INDICATOR_RE.search(commit.short):
group = CommitGroup.EXTRACTOR
logger.error(f'Assuming [ie] group for {commit.short!r}')
else:
group = CommitGroup.CORE
commit_info = CommitInfo(
details, sub_details, message.strip(),
issues, commit, self._fixes[commit.hash])
logger.debug(f'Resolved {commit.short!r} to {commit_info!r}')
group_dict[group].append(commit_info)
return group_dict
@staticmethod
def details_from_prefix(prefix):
if not prefix:
return CommitGroup.CORE, None, ()
prefix, *sub_details = prefix.split(':')
group, details = CommitGroup.get(prefix)
if group is CommitGroup.PRIORITY and details:
details = details.partition('/')[2].strip()
if details and '/' in details:
logger.error(f'Prefix is overnested, using first part: {prefix}')
details = details.partition('/')[0].strip()
if details == 'common':
details = None
elif group is CommitGroup.NETWORKING and details == 'rh':
details = 'Request Handler'
return group, details, sub_details
def get_new_contributors(contributors_path, commits):
contributors = set()
if contributors_path.exists():
for line in read_file(contributors_path).splitlines():
author, _, _ = line.strip().partition(' (')
authors = author.split('/')
contributors.update(map(str.casefold, authors))
new_contributors = set()
for commit in commits:
for author in commit.authors:
author_folded = author.casefold()
if author_folded not in contributors:
contributors.add(author_folded)
new_contributors.add(author)
return sorted(new_contributors, key=str.casefold)
def create_changelog(args):
logging.basicConfig(
datefmt='%Y-%m-%d %H-%M-%S', format='{asctime} | {levelname:<8} | {message}',
level=logging.WARNING - 10 * args.verbosity, style='{', stream=sys.stderr)
commits = CommitRange(None, args.commitish, args.default_author)
if not args.no_override:
if args.override_path.exists():
overrides = json.loads(read_file(args.override_path))
commits.apply_overrides(overrides)
else:
logger.warning(f'File {args.override_path.as_posix()} does not exist')
logger.info(f'Loaded {len(commits)} commits')
new_contributors = get_new_contributors(args.contributors_path, commits)
if new_contributors:
if args.contributors:
write_file(args.contributors_path, '\n'.join(new_contributors) + '\n', mode='a')
logger.info(f'New contributors: {", ".join(new_contributors)}')
return Changelog(commits.groups(), args.repo, args.collapsible)
def create_parser():
import argparse
parser = argparse.ArgumentParser(
description='Create a changelog markdown from a git commit range')
parser.add_argument(
'commitish', default='HEAD', nargs='?',
help='The commitish to create the range from (default: %(default)s)')
parser.add_argument(
'-v', '--verbosity', action='count', default=0,
help='increase verbosity (can be used twice)')
parser.add_argument(
'-c', '--contributors', action='store_true',
help='update CONTRIBUTORS file (default: %(default)s)')
parser.add_argument(
'--contributors-path', type=Path, default=LOCATION_PATH.parent / 'CONTRIBUTORS',
help='path to the CONTRIBUTORS file')
parser.add_argument(
'--no-override', action='store_true',
help='skip override json in commit generation (default: %(default)s)')
parser.add_argument(
'--override-path', type=Path, default=LOCATION_PATH / 'changelog_override.json',
help='path to the changelog_override.json file')
parser.add_argument(
'--default-author', default='pukkandan',
help='the author to use without a author indicator (default: %(default)s)')
parser.add_argument(
'--repo', default='yt-dlp/yt-dlp',
help='the github repository to use for the operations (default: %(default)s)')
parser.add_argument(
'--collapsible', action='store_true',
help='make changelog collapsible (default: %(default)s)')
return parser
if __name__ == '__main__':
print(create_changelog(create_parser().parse_args()))

@ -1,4 +1,5 @@
#!/usr/bin/env python3
import optparse
import re

@ -1,28 +1,71 @@
#!/usr/bin/env python3
import optparse
# Allow direct execution
import os
import sys
def read(fname):
with open(fname, encoding='utf-8') as f:
return f.read()
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Get the version from yt_dlp/version.py without importing the package
def read_version(fname):
exec(compile(read(fname), fname, 'exec'))
return locals()['__version__']
import re
from devscripts.utils import get_filename_args, read_file, write_file
VERBOSE_TMPL = '''
- type: checkboxes
id: verbose
attributes:
label: Provide verbose output that clearly demonstrates the problem
options:
- label: Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
required: true
- label: "If using API, add `'verbose': True` to `YoutubeDL` params instead"
required: false
- label: Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below
required: true
- type: textarea
id: log
attributes:
label: Complete Verbose Output
description: |
It should start like this:
placeholder: |
[debug] Command-line config: ['-vU', 'https://www.youtube.com/watch?v=BaW_jenozKc']
[debug] Encodings: locale cp65001, fs utf-8, pref cp65001, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@... from yt-dlp/yt-dlp [b634ba742] (win_exe)
[debug] Python 3.8.10 (CPython 64bit) - Windows-10-10.0.22000-SP0
[debug] exe versions: ffmpeg N-106550-g072101bd52-20220410 (fdk,setts), ffprobe N-106624-g391ce570c8-20220415, phantomjs 2.1.1
[debug] Optional libraries: Cryptodome-3.15.0, brotli-1.0.9, certifi-2022.06.15, mutagen-1.45.1, sqlite3-2.6.0, websockets-10.3
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests
[debug] Loaded 1893 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
yt-dlp is up to date (nightly@... from yt-dlp/yt-dlp-nightly-builds)
[youtube] Extracting URL: https://www.youtube.com/watch?v=BaW_jenozKc
<more lines>
render: shell
validations:
required: true
'''.strip()
NO_SKIP = '''
- type: checkboxes
attributes:
label: DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE
description: Fill all fields even if you think it is irrelevant for the issue
options:
- label: I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\\* field
required: true
'''.strip()
def main():
parser = optparse.OptionParser(usage='%prog INFILE OUTFILE')
options, args = parser.parse_args()
if len(args) != 2:
parser.error('Expected an input and an output filename')
infile, outfile = args
with open(outfile, 'w', encoding='utf-8') as outf:
outf.write(
read(infile) % {'version': read_version('yt_dlp/version.py')})
fields = {'no_skip': NO_SKIP}
fields['verbose'] = VERBOSE_TMPL % fields
fields['verbose_optional'] = re.sub(r'(\n\s+validations:)?\n\s+required: true', '', fields['verbose'])
infile, outfile = get_filename_args(has_infile=True)
write_file(outfile, read_file(infile) % fields)
if __name__ == '__main__':

@ -1,39 +1,51 @@
#!/usr/bin/env python3
import optparse
# Allow direct execution
import os
import shutil
import sys
from inspect import getsource
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from inspect import getsource
from devscripts.utils import get_filename_args, read_file, write_file
NO_ATTR = object()
STATIC_CLASS_PROPERTIES = ['IE_NAME', 'IE_DESC', 'SEARCH_KEY', '_WORKING', '_NETRC_MACHINE', 'age_limit']
STATIC_CLASS_PROPERTIES = [
'IE_NAME', '_ENABLED', '_VALID_URL', # Used for URL matching
'_WORKING', 'IE_DESC', '_NETRC_MACHINE', 'SEARCH_KEY', # Used for --extractor-descriptions
'age_limit', # Used for --age-limit (evaluated)
'_RETURN_TYPE', # Accessed in CLI only with instance (evaluated)
]
CLASS_METHODS = [
'ie_key', 'working', 'description', 'suitable', '_match_valid_url', '_match_id', 'get_temp_id', 'is_suitable'
'ie_key', 'suitable', '_match_valid_url', # Used for URL matching
'working', 'get_temp_id', '_match_id', # Accessed just before instance creation
'description', # Used for --extractor-descriptions
'is_suitable', # Used for --age-limit
'supports_login', 'is_single_video', # Accessed in CLI only with instance
]
IE_TEMPLATE = '''
class {name}({bases}):
_module = {module!r}
'''
with open('devscripts/lazy_load_template.py', encoding='utf-8') as f:
MODULE_TEMPLATE = f.read()
MODULE_TEMPLATE = read_file('devscripts/lazy_load_template.py')
def main():
parser = optparse.OptionParser(usage='%prog [OUTFILE.py]')
args = parser.parse_args()[1] or ['yt_dlp/extractor/lazy_extractors.py']
if len(args) != 1:
parser.error('Expected only an output filename')
lazy_extractors_filename = args[0]
lazy_extractors_filename = get_filename_args(default_outfile='yt_dlp/extractor/lazy_extractors.py')
if os.path.exists(lazy_extractors_filename):
os.remove(lazy_extractors_filename)
_ALL_CLASSES = get_all_ies() # Must be before import
import yt_dlp.plugins
from yt_dlp.extractor.common import InfoExtractor, SearchInfoExtractor
# Filter out plugins
_ALL_CLASSES = [cls for cls in _ALL_CLASSES if not cls.__module__.startswith(f'{yt_dlp.plugins.PACKAGE_NAME}.')]
DummyInfoExtractor = type('InfoExtractor', (InfoExtractor,), {'IE_NAME': NO_ATTR})
module_src = '\n'.join((
MODULE_TEMPLATE,
@ -43,20 +55,20 @@ def main():
*build_ies(_ALL_CLASSES, (InfoExtractor, SearchInfoExtractor), DummyInfoExtractor),
))
with open(lazy_extractors_filename, 'wt', encoding='utf-8') as f:
f.write(f'{module_src}\n')
write_file(lazy_extractors_filename, f'{module_src}\n')
def get_all_ies():
PLUGINS_DIRNAME = 'ytdlp_plugins'
BLOCKED_DIRNAME = f'{PLUGINS_DIRNAME}_blocked'
if os.path.exists(PLUGINS_DIRNAME):
os.rename(PLUGINS_DIRNAME, BLOCKED_DIRNAME)
# os.rename cannot be used, e.g. in Docker. See https://github.com/yt-dlp/yt-dlp/pull/4958
shutil.move(PLUGINS_DIRNAME, BLOCKED_DIRNAME)
try:
from yt_dlp.extractor.extractors import _ALL_CLASSES
finally:
if os.path.exists(BLOCKED_DIRNAME):
os.rename(BLOCKED_DIRNAME, PLUGINS_DIRNAME)
shutil.move(BLOCKED_DIRNAME, PLUGINS_DIRNAME)
return _ALL_CLASSES
@ -91,7 +103,7 @@ def sort_ies(ies, ignored_bases):
for c in classes[:]:
bases = set(c.__bases__) - {object, *ignored_bases}
restart = False
for b in bases:
for b in sorted(bases, key=lambda x: x.__name__):
if b not in classes and b not in returned_classes:
assert b.__name__ != 'GenericIE', 'Cannot inherit from GenericIE'
classes.insert(0, b)
@ -113,11 +125,6 @@ def build_lazy_ie(ie, name, attr_base):
}.get(base.__name__, base.__name__) for base in ie.__bases__)
s = IE_TEMPLATE.format(name=name, module=ie.__module__, bases=bases)
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'
return s + '\n'.join(extra_ie_code(ie, attr_base))

@ -1,10 +1,21 @@
#!/usr/bin/env python3
# yt-dlp --help | make_readme.py
# This must be run in a console of correct width
"""
yt-dlp --help | make_readme.py
This must be run in a console of correct width
"""
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import functools
import re
import sys
from devscripts.utils import read_file, write_file
README_FILE = 'README.md'
@ -34,37 +45,49 @@ switch_col_width = len(re.search(r'(?m)^\s{5,}', options).group())
delim = f'\n{" " * switch_col_width}'
PATCHES = (
( # Headings
( # Standardize `--update` message
r'(?m)^( -U, --update\s+).+(\n \s.+)*$',
r'\1Update this program to the latest version',
),
( # Headings
r'(?m)^ (\w.+\n)( (?=\w))?',
r'## \1'
),
( # Do not split URLs
( # Fixup `--date` formatting
rf'(?m)( --date DATE.+({delim}[^\[]+)*)\[.+({delim}.+)*$',
(rf'\1[now|today|yesterday][-N[day|week|month|year]].{delim}'
f'E.g. "--date today-2weeks" downloads only{delim}'
'videos uploaded on the same day two weeks ago'),
),
( # Do not split URLs
rf'({delim[:-1]})? (?P<label>\[\S+\] )?(?P<url>https?({delim})?:({delim})?/({delim})?/(({delim})?\S+)+)\s',
lambda mobj: ''.join((delim, mobj.group('label') or '', re.sub(r'\s+', '', mobj.group('url')), '\n'))
),
( # Do not split "words"
( # Do not split "words"
rf'(?m)({delim}\S+)+$',
lambda mobj: ''.join((delim, mobj.group(0).replace(delim, '')))
),
( # Allow overshooting last line
( # Allow overshooting last line
rf'(?m)^(?P<prev>.+)${delim}(?P<current>.+)$(?!{delim})',
lambda mobj: (mobj.group().replace(delim, ' ')
if len(mobj.group()) - len(delim) + 1 <= max_width + ALLOWED_OVERSHOOT
else mobj.group())
),
( # Avoid newline when a space is available b/w switch and description
( # Avoid newline when a space is available b/w switch and description
DISABLE_PATCH, # This creates issues with prepare_manpage
r'(?m)^(\s{4}-.{%d})(%s)' % (switch_col_width - 6, delim),
r'\1 '
),
( # Replace brackets with a Markdown link
r'SponsorBlock API \((http.+)\)',
r'[SponsorBlock API](\1)'
),
)
with open(README_FILE, encoding='utf-8') as f:
readme = f.read()
readme = read_file(README_FILE)
with open(README_FILE, 'w', encoding='utf-8') as f:
f.write(''.join((
take_section(readme, end=f'## {OPTIONS_START}'),
functools.reduce(apply_patch, PATCHES, options),
take_section(readme, f'# {OPTIONS_END}'),
)))
write_file(README_FILE, ''.join((
take_section(readme, end=f'## {OPTIONS_START}'),
functools.reduce(apply_patch, PATCHES, options),
take_section(readme, f'# {OPTIONS_END}'),
)))

@ -1,23 +1,19 @@
#!/usr/bin/env python3
import optparse
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from devscripts.utils import get_filename_args, write_file
from yt_dlp.extractor import list_extractor_classes
def main():
parser = optparse.OptionParser(usage='%prog OUTFILE.md')
_, args = parser.parse_args()
if len(args) != 1:
parser.error('Expected an output filename')
out = '\n'.join(ie.description() for ie in list_extractor_classes() if ie.IE_DESC is not False)
with open(args[0], 'w', encoding='utf-8') as outf:
outf.write(f'# Supported sites\n{out}\n')
write_file(get_filename_args(), f'# Supported sites\n{out}\n')
if __name__ == '__main__':

@ -1,8 +1,22 @@
#!/usr/bin/env python3
import optparse
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import os.path
import re
from devscripts.utils import (
compose_functions,
get_filename_args,
read_file,
write_file,
)
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
README_FILE = os.path.join(ROOT_DIR, 'README.md')
@ -10,7 +24,7 @@ PREFIX = r'''%yt-dlp(1)
# NAME
yt\-dlp \- A youtube-dl fork with additional features and patches
yt\-dlp \- A feature\-rich command\-line audio/video downloader
# SYNOPSIS
@ -21,25 +35,6 @@ yt\-dlp \- A youtube-dl fork with additional features and patches
'''
def main():
parser = optparse.OptionParser(usage='%prog OUTFILE.md')
options, args = parser.parse_args()
if len(args) != 1:
parser.error('Expected an output filename')
outfile, = args
with open(README_FILE, encoding='utf-8') as f:
readme = f.read()
readme = filter_excluded_sections(readme)
readme = move_sections(readme)
readme = filter_options(readme)
with open(outfile, 'w', encoding='utf-8') as outf:
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 -->')
@ -48,6 +43,27 @@ def filter_excluded_sections(readme):
'', readme)
def _convert_code_blocks(readme):
current_code_block = None
for line in readme.splitlines(True):
if current_code_block:
if line == current_code_block:
current_code_block = None
yield '\n'
else:
yield f' {line}'
elif line.startswith('```'):
current_code_block = line.count('`') * '`' + '\n'
yield '\n'
else:
yield line
def convert_code_blocks(readme):
return ''.join(_convert_code_blocks(readme))
def move_sections(readme):
MOVE_TAG_TEMPLATE = '<!-- MANPAGE: MOVE "%s" SECTION HERE -->'
sections = re.findall(r'(?m)^%s$' % (
@ -70,8 +86,10 @@ def move_sections(readme):
def filter_options(readme):
section = re.search(r'(?sm)^# USAGE AND OPTIONS\n.+?(?=^# )', readme).group(0)
section_new = section.replace('*', R'\*')
options = '# OPTIONS\n'
for line in section.split('\n')[1:]:
for line in section_new.split('\n')[1:]:
mobj = re.fullmatch(r'''(?x)
\s{4}(?P<opt>-(?:,\s|[^\s])+)
(?:\s(?P<meta>(?:[^\s]|\s(?!\s))+))?
@ -91,5 +109,12 @@ def filter_options(readme):
return readme.replace(section, options, 1)
TRANSFORM = compose_functions(filter_excluded_sections, convert_code_blocks, move_sections, filter_options)
def main():
write_file(get_filename_args(), PREFIX + TRANSFORM(read_file(README_FILE)))
if __name__ == '__main__':
main()

@ -1,17 +1,4 @@
@setlocal
@echo off
cd /d %~dp0..
if ["%~1"]==[""] (
set "test_set="test""
) else if ["%~1"]==["core"] (
set "test_set="-m not download""
) else if ["%~1"]==["download"] (
set "test_set="-m "download""
) else (
echo.Invalid test type "%~1". Use "core" ^| "download"
exit /b 1
)
set PYTHONWARNINGS=error
pytest %test_set%
>&2 echo run_tests.bat is deprecated. Please use `devscripts/run_tests.py` instead
python %~dp0run_tests.py %~1

@ -0,0 +1,71 @@
#!/usr/bin/env python3
import argparse
import functools
import os
import re
import subprocess
import sys
from pathlib import Path
fix_test_name = functools.partial(re.compile(r'IE(_all|_\d+)?$').sub, r'\1')
def parse_args():
parser = argparse.ArgumentParser(description='Run selected yt-dlp tests')
parser.add_argument(
'test', help='a extractor tests, or one of "core" or "download"', nargs='*')
parser.add_argument(
'-k', help='run a test matching EXPRESSION. Same as "pytest -k"', metavar='EXPRESSION')
return parser.parse_args()
def run_tests(*tests, pattern=None, ci=False):
run_core = 'core' in tests or (not pattern and not tests)
run_download = 'download' in tests
tests = list(map(fix_test_name, tests))
arguments = ['pytest', '-Werror', '--tb=short']
if ci:
arguments.append('--color=yes')
if run_core:
arguments.extend(['-m', 'not download'])
elif run_download:
arguments.extend(['-m', 'download'])
elif pattern:
arguments.extend(['-k', pattern])
else:
arguments.extend(
f'test/test_download.py::TestDownload::test_{test}' for test in tests)
print(f'Running {arguments}', flush=True)
try:
return subprocess.call(arguments)
except FileNotFoundError:
pass
arguments = [sys.executable, '-Werror', '-m', 'unittest']
if run_core:
print('"pytest" needs to be installed to run core tests', file=sys.stderr, flush=True)
return 1
elif run_download:
arguments.append('test.test_download')
elif pattern:
arguments.extend(['-k', pattern])
else:
arguments.extend(
f'test.test_download.TestDownload.test_{test}' for test in tests)
print(f'Running {arguments}', flush=True)
return subprocess.call(arguments)
if __name__ == '__main__':
try:
args = parse_args()
os.chdir(Path(__file__).parent.parent)
sys.exit(run_tests(*args.test, pattern=args.k, ci=bool(os.getenv('CI'))))
except KeyboardInterrupt:
pass

@ -1,14 +1,4 @@
#!/usr/bin/env sh
if [ -z $1 ]; then
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
python3 -bb -Werror -m pytest "$test_set"
>&2 echo 'run_tests.sh is deprecated. Please use `devscripts/run_tests.py` instead'
python3 devscripts/run_tests.py "$1"

@ -0,0 +1,36 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import functools
import re
from devscripts.utils import compose_functions, read_file, write_file
VERSION_FILE = 'yt_dlp/version.py'
def parse_options():
parser = argparse.ArgumentParser(description='Set the build variant of the package')
parser.add_argument('variant', help='Name of the variant')
parser.add_argument('-M', '--update-message', default=None, help='Message to show in -U')
return parser.parse_args()
def property_setter(name, value):
return functools.partial(re.sub, rf'(?m)^{name}\s*=\s*.+$', f'{name} = {value!r}')
opts = parse_options()
transform = compose_functions(
property_setter('VARIANT', opts.variant),
property_setter('UPDATE_HINT', opts.update_message)
)
write_file(VERSION_FILE, transform(read_file(VERSION_FILE)))

@ -0,0 +1,189 @@
#!/usr/bin/env python3
"""
Simple parser for spec compliant toml files
A simple toml parser for files that comply with the spec.
Should only be used to parse `pyproject.toml` for `install_deps.py`.
IMPORTANT: INVALID FILES OR MULTILINE STRINGS ARE NOT SUPPORTED!
"""
from __future__ import annotations
import datetime as dt
import json
import re
WS = r'(?:[\ \t]*)'
STRING_RE = re.compile(r'"(?:\\.|[^\\"\n])*"|\'[^\'\n]*\'')
SINGLE_KEY_RE = re.compile(rf'{STRING_RE.pattern}|[A-Za-z0-9_-]+')
KEY_RE = re.compile(rf'{WS}(?:{SINGLE_KEY_RE.pattern}){WS}(?:\.{WS}(?:{SINGLE_KEY_RE.pattern}){WS})*')
EQUALS_RE = re.compile(rf'={WS}')
WS_RE = re.compile(WS)
_SUBTABLE = rf'(?P<subtable>^\[(?P<is_list>\[)?(?P<path>{KEY_RE.pattern})\]\]?)'
EXPRESSION_RE = re.compile(rf'^(?:{_SUBTABLE}|{KEY_RE.pattern}=)', re.MULTILINE)
LIST_WS_RE = re.compile(rf'{WS}((#[^\n]*)?\n{WS})*')
LEFTOVER_VALUE_RE = re.compile(r'[^,}\]\t\n#]+')
def parse_key(value: str):
for match in SINGLE_KEY_RE.finditer(value):
if match[0][0] == '"':
yield json.loads(match[0])
elif match[0][0] == '\'':
yield match[0][1:-1]
else:
yield match[0]
def get_target(root: dict, paths: list[str], is_list=False):
target = root
for index, key in enumerate(paths, 1):
use_list = is_list and index == len(paths)
result = target.get(key)
if result is None:
result = [] if use_list else {}
target[key] = result
if isinstance(result, dict):
target = result
elif use_list:
target = {}
result.append(target)
else:
target = result[-1]
assert isinstance(target, dict)
return target
def parse_enclosed(data: str, index: int, end: str, ws_re: re.Pattern):
index += 1
if match := ws_re.match(data, index):
index = match.end()
while data[index] != end:
index = yield True, index
if match := ws_re.match(data, index):
index = match.end()
if data[index] == ',':
index += 1
if match := ws_re.match(data, index):
index = match.end()
assert data[index] == end
yield False, index + 1
def parse_value(data: str, index: int):
if data[index] == '[':
result = []
indices = parse_enclosed(data, index, ']', LIST_WS_RE)
valid, index = next(indices)
while valid:
index, value = parse_value(data, index)
result.append(value)
valid, index = indices.send(index)
return index, result
if data[index] == '{':
result = {}
indices = parse_enclosed(data, index, '}', WS_RE)
valid, index = next(indices)
while valid:
valid, index = indices.send(parse_kv_pair(data, index, result))
return index, result
if match := STRING_RE.match(data, index):
return match.end(), json.loads(match[0]) if match[0][0] == '"' else match[0][1:-1]
match = LEFTOVER_VALUE_RE.match(data, index)
assert match
value = match[0].strip()
for func in [
int,
float,
dt.time.fromisoformat,
dt.date.fromisoformat,
dt.datetime.fromisoformat,
{'true': True, 'false': False}.get,
]:
try:
value = func(value)
break
except Exception:
pass
return match.end(), value
def parse_kv_pair(data: str, index: int, target: dict):
match = KEY_RE.match(data, index)
if not match:
return None
*keys, key = parse_key(match[0])
match = EQUALS_RE.match(data, match.end())
assert match
index = match.end()
index, value = parse_value(data, index)
get_target(target, keys)[key] = value
return index
def parse_toml(data: str):
root = {}
target = root
index = 0
while True:
match = EXPRESSION_RE.search(data, index)
if not match:
break
if match.group('subtable'):
index = match.end()
path, is_list = match.group('path', 'is_list')
target = get_target(root, list(parse_key(path)), bool(is_list))
continue
index = parse_kv_pair(data, match.start(), target)
assert index is not None
return root
def main():
import argparse
from pathlib import Path
parser = argparse.ArgumentParser()
parser.add_argument('infile', type=Path, help='The TOML file to read as input')
args = parser.parse_args()
with args.infile.open('r', encoding='utf-8') as file:
data = file.read()
def default(obj):
if isinstance(obj, (dt.date, dt.time, dt.datetime)):
return obj.isoformat()
print(json.dumps(parse_toml(data), default=default))
if __name__ == '__main__':
main()

@ -1,34 +0,0 @@
#!/usr/bin/env python3
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())
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) 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,41 +1,82 @@
#!/usr/bin/env python3
import subprocess
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import contextlib
import datetime as dt
import sys
from datetime import datetime
with open('yt_dlp/version.py') as f:
exec(compile(f.read(), 'yt_dlp/version.py', 'exec'))
old_version = locals()['__version__']
from devscripts.utils import read_version, run_process, write_file
old_version_list = old_version.split('.')
def get_new_version(version, revision):
if not version:
version = dt.datetime.now(dt.timezone.utc).strftime('%Y.%m.%d')
old_ver = '.'.join(old_version_list[:3])
old_rev = old_version_list[3] if len(old_version_list) > 3 else ''
if revision:
assert revision.isdecimal(), 'Revision must be a number'
else:
old_version = read_version().split('.')
if version.split('.') == old_version[:3]:
revision = str(int((old_version + [0])[3]) + 1)
ver = datetime.utcnow().strftime("%Y.%m.%d")
return f'{version}.{revision}' if revision else version
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
def get_git_head():
with contextlib.suppress(Exception):
return run_process('git', 'rev-parse', 'HEAD').stdout.strip()
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'''\
VERSION_TEMPLATE = '''\
# Autogenerated by devscripts/update-version.py
__version__ = {VERSION!r}
__version__ = {version!r}
RELEASE_GIT_HEAD = {GIT_HEAD!r}
RELEASE_GIT_HEAD = {git_head!r}
VARIANT = None
UPDATE_HINT = None
CHANNEL = {channel!r}
ORIGIN = {origin!r}
_pkg_version = {package_version!r}
'''
with open('yt_dlp/version.py', 'wt') as f:
f.write(VERSION_FILE)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Update the version.py file')
parser.add_argument(
'-c', '--channel', default='stable',
help='Select update channel (default: %(default)s)')
parser.add_argument(
'-r', '--origin', default='local',
help='Select origin/repository (default: %(default)s)')
parser.add_argument(
'-s', '--suffix', default='',
help='Add an alphanumeric suffix to the package version, e.g. "dev"')
parser.add_argument(
'-o', '--output', default='yt_dlp/version.py',
help='The output file to write to (default: %(default)s)')
parser.add_argument(
'version', nargs='?', default=None,
help='A version or revision to use instead of generating one')
args = parser.parse_args()
git_head = get_git_head()
version = (
args.version if args.version and '.' in args.version
else get_new_version(None, args.version))
write_file(args.output, VERSION_TEMPLATE.format(
version=version, git_head=git_head, channel=args.channel, origin=args.origin,
package_version=f'{version}{args.suffix}'))
print('::set-output name=ytdlp_version::' + VERSION)
print(f'\nVersion = {VERSION}, Git HEAD = {GIT_HEAD}')
print(f'version={version} ({args.channel}), head={git_head}')

@ -0,0 +1,26 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from pathlib import Path
from devscripts.make_changelog import create_changelog, create_parser
from devscripts.utils import read_file, read_version, write_file
# Always run after devscripts/update-version.py, and run before `make doc|pypi-files|tar|all`
if __name__ == '__main__':
parser = create_parser()
parser.description = 'Update an existing changelog file with an entry for a new release'
parser.add_argument(
'--changelog-path', type=Path, default=Path(__file__).parent.parent / 'Changelog.md',
help='path to the Changelog file')
args = parser.parse_args()
new_entry = create_changelog(args)
header, sep, changelog = read_file(args.changelog_path).partition('\n### ')
write_file(args.changelog_path, f'{header}{sep}{read_version()}\n{new_entry}\n{sep}{changelog}')

@ -0,0 +1,47 @@
import argparse
import functools
import subprocess
def read_file(fname):
with open(fname, encoding='utf-8') as f:
return f.read()
def write_file(fname, content, mode='w'):
with open(fname, mode, encoding='utf-8') as f:
return f.write(content)
def read_version(fname='yt_dlp/version.py', varname='__version__'):
"""Get the version without importing the package"""
items = {}
exec(compile(read_file(fname), fname, 'exec'), items)
return items[varname]
def get_filename_args(has_infile=False, default_outfile=None):
parser = argparse.ArgumentParser()
if has_infile:
parser.add_argument('infile', help='Input file')
kwargs = {'nargs': '?', 'default': default_outfile} if default_outfile else {}
parser.add_argument('outfile', **kwargs, help='Output file')
opts = parser.parse_args()
if has_infile:
return opts.infile, opts.outfile
return opts.outfile
def compose_functions(*functions):
return lambda x: functools.reduce(lambda y, f: f(y), functions, x)
def run_process(*args, **kwargs):
kwargs.setdefault('text', True)
kwargs.setdefault('check', True)
kwargs.setdefault('capture_output', True)
if kwargs['text']:
kwargs.setdefault('encoding', 'utf-8')
kwargs.setdefault('errors', 'replace')
return subprocess.run(args, **kwargs)

@ -1,9 +1,12 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import yt_dlp
ZSH_COMPLETION_FILE = "completions/zsh/_yt-dlp"

@ -0,0 +1,29 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGP78C4BEAD0rF9zjGPAt0thlt5C1ebzccAVX7Nb1v+eqQjk+WEZdTETVCg3
WAM5ngArlHdm/fZqzUgO+pAYrB60GKeg7ffUDf+S0XFKEZdeRLYeAaqqKhSibVal
DjvOBOztu3W607HLETQAqA7wTPuIt2WqmpL60NIcyr27LxqmgdN3mNvZ2iLO+bP0
nKR/C+PgE9H4ytywDa12zMx6PmZCnVOOOu6XZEFmdUxxdQ9fFDqd9LcBKY2LDOcS
Yo1saY0YWiZWHtzVoZu1kOzjnS5Fjq/yBHJLImDH7pNxHm7s/PnaurpmQFtDFruk
t+2lhDnpKUmGr/I/3IHqH/X+9nPoS4uiqQ5HpblB8BK+4WfpaiEg75LnvuOPfZIP
KYyXa/0A7QojMwgOrD88ozT+VCkKkkJ+ijXZ7gHNjmcBaUdKK7fDIEOYI63Lyc6Q
WkGQTigFffSUXWHDCO9aXNhP3ejqFWgGMtCUsrbkcJkWuWY7q5ARy/05HbSM3K4D
U9eqtnxmiV1WQ8nXuI9JgJQRvh5PTkny5LtxqzcmqvWO9TjHBbrs14BPEO9fcXxK
L/CFBbzXDSvvAgArdqqlMoncQ/yicTlfL6qzJ8EKFiqW14QMTdAn6SuuZTodXCTi
InwoT7WjjuFPKKdvfH1GP4bnqdzTnzLxCSDIEtfyfPsIX+9GI7Jkk/zZjQARAQAB
tDdTaW1vbiBTYXdpY2tpICh5dC1kbHAgc2lnbmluZyBrZXkpIDxjb250YWN0QGdy
dWI0ay54eXo+iQJOBBMBCgA4FiEErAy75oSNaoc0ZK9OV89lkztadYEFAmP78C4C
GwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQV89lkztadYEVqQ//cW7TxhXg
7Xbh2EZQzXml0egn6j8QaV9KzGragMiShrlvTO2zXfLXqyizrFP4AspgjSn/4NrI
8mluom+Yi+qr7DXT4BjQqIM9y3AjwZPdywe912Lxcw52NNoPZCm24I9T7ySc8lmR
FQvZC0w4H/VTNj/2lgJ1dwMflpwvNRiWa5YzcFGlCUeDIPskLx9++AJE+xwU3LYm
jQQsPBqpHHiTBEJzMLl+rfd9Fg4N+QNzpFkTDW3EPerLuvJniSBBwZthqxeAtw4M
UiAXh6JvCc2hJkKCoygRfM281MeolvmsGNyQm+axlB0vyldiPP6BnaRgZlx+l6MU
cPqgHblb7RW5j9lfr6OYL7SceBIHNv0CFrt1OnkGo/tVMwcs8LH3Ae4a7UJlIceL
V54aRxSsZU7w4iX+PB79BWkEsQzwKrUuJVOeL4UDwWajp75OFaUqbS/slDDVXvK5
OIeuth3mA/adjdvgjPxhRQjA3l69rRWIJDrqBSHldmRsnX6cvXTDy8wSXZgy51lP
m4IVLHnCy9m4SaGGoAsfTZS0cC9FgjUIyTyrq9M67wOMpUxnuB0aRZgJE1DsI23E
qdvcSNVlO+39xM/KPWUEh6b83wMn88QeW+DCVGWACQq5N3YdPnAJa50617fGbY6I
gXIoRHXkDqe23PZ/jURYCv0sjVtjPoVC+bg=
=bJkn
-----END PGP PUBLIC KEY BLOCK-----

@ -1,154 +1,17 @@
#!/usr/bin/env python3
# Allow execution from anywhere
import os
import platform
import sys
from PyInstaller.__main__ import run as run_pyinstaller
OS_NAME, ARCH = sys.platform, platform.architecture()[0][:2]
def main():
opts = parse_options()
version = read_version('yt_dlp/version.py')
onedir = '--onedir' in opts or '-D' in opts
if not onedir and '-F' not in opts and '--onefile' not in opts:
opts.append('--onefile')
name, final_file = exe(onedir)
print(f'Building yt-dlp v{version} {ARCH}bit for {OS_NAME} with options {opts}')
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')
opts = [
f'--name={name}',
'--icon=devscripts/logo.ico',
'--upx-exclude=vcruntime140.dll',
'--noconfirm',
# NB: Modules that are only imported dynamically must be added here.
# --collect-submodules may not work correctly if user has a yt-dlp installed via PIP
'--hidden-import=yt_dlp.compat._legacy',
*dependency_options(),
*opts,
'yt_dlp/__main__.py',
]
print(f'Running PyInstaller with {opts}')
run_pyinstaller(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
# Get the version from yt_dlp/version.py without importing the package
def read_version(fname):
with open(fname, encoding='utf-8') as f:
exec(compile(f.read(), fname, 'exec'))
return locals()['__version__']
def exe(onedir):
"""@returns (name, path)"""
name = '_'.join(filter(None, (
'yt-dlp',
{'win32': '', 'darwin': 'macos'}.get(OS_NAME, OS_NAME),
ARCH == '32' and 'x86'
)))
return name, ''.join(filter(None, (
'dist/',
onedir and f'{name}/',
name,
OS_NAME == 'win32' and '.exe'
)))
def version_to_list(version):
version_list = version.split('.')
return list(map(int, version_list)) + [0] * (4 - len(version_list))
def dependency_options():
# Due to the current implementation, these are auto-detected, but explicitly add them just in case
dependencies = [pycryptodome_module(), 'mutagen', 'brotli', 'certifi', 'websockets']
excluded_modules = ['test', 'ytdlp_plugins', 'youtube_dl', 'youtube_dlc']
yield from (f'--hidden-import={module}' for module in dependencies)
yield '--collect-submodules=websockets'
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 == 'win32':
windows_set_version(exe, version)
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
def windows_set_version(exe, version):
from PyInstaller.utils.win32.versioninfo import (
FixedFileInfo,
SetVersion,
StringFileInfo,
StringStruct,
StringTable,
VarFileInfo,
VarStruct,
VSVersionInfo,
)
import warnings
version_list = version_to_list(version)
suffix = '_x86' if ARCH == '32' else ''
SetVersion(exe, VSVersionInfo(
ffi=FixedFileInfo(
filevers=version_list,
prodvers=version_list,
mask=0x3F,
flags=0x0,
OS=0x4,
fileType=0x1,
subtype=0x0,
date=(0, 0),
),
kids=[
StringFileInfo([StringTable('040904B0', [
StringStruct('Comments', 'yt-dlp%s Command Line Interface.' % suffix),
StringStruct('CompanyName', 'https://github.com/yt-dlp'),
StringStruct('FileDescription', 'yt-dlp%s' % (' (32 Bit)' if ARCH == '32' else '')),
StringStruct('FileVersion', version),
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(
'ProductVersion', f'{version}{suffix} on Python {platform.python_version()}'),
])]), VarFileInfo([VarStruct('Translation', [0, 1200])])
]
))
from bundle.pyinstaller import main
warnings.warn(DeprecationWarning('`pyinst.py` is deprecated and will be removed in a future version. '
'Use `bundle.pyinstaller` instead'))
if __name__ == '__main__':
main()

@ -0,0 +1,124 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "yt-dlp"
maintainers = [
{name = "pukkandan", email = "pukkandan.ytdlp@gmail.com"},
{name = "Grub4K", email = "contact@grub4k.xyz"},
{name = "bashonly", email = "bashonly@protonmail.com"},
{name = "coletdjnz", email = "coletdjnz@protonmail.com"},
]
description = "A feature-rich command-line audio/video downloader"
readme = "README.md"
requires-python = ">=3.8"
keywords = [
"youtube-dl",
"video-downloader",
"youtube-downloader",
"sponsorblock",
"youtube-dlc",
"yt-dlp",
]
license = {file = "LICENSE"}
classifiers = [
"Topic :: Multimedia :: Video",
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"License :: OSI Approved :: The Unlicense (Unlicense)",
"Operating System :: OS Independent",
]
dynamic = ["version"]
dependencies = [
"brotli; implementation_name=='cpython'",
"brotlicffi; implementation_name!='cpython'",
"certifi",
"mutagen",
"pycryptodomex",
"requests>=2.31.0,<3",
"urllib3>=1.26.17,<3",
"websockets>=12.0",
]
[project.optional-dependencies]
default = []
curl-cffi = ["curl-cffi==0.5.10; implementation_name=='cpython'"]
secretstorage = [
"cffi",
"secretstorage",
]
build = [
"build",
"hatchling",
"pip",
"wheel",
]
dev = [
"flake8",
"isort",
"pytest",
]
pyinstaller = [
"pyinstaller>=6.3; sys_platform!='darwin'",
"pyinstaller==5.13.2; sys_platform=='darwin'", # needed for curl_cffi
]
py2exe = ["py2exe>=0.12"]
[project.urls]
Documentation = "https://github.com/yt-dlp/yt-dlp#readme"
Repository = "https://github.com/yt-dlp/yt-dlp"
Tracker = "https://github.com/yt-dlp/yt-dlp/issues"
Funding = "https://github.com/yt-dlp/yt-dlp/blob/master/Collaborators.md#collaborators"
[project.scripts]
yt-dlp = "yt_dlp:main"
[project.entry-points.pyinstaller40]
hook-dirs = "yt_dlp.__pyinstaller:get_hook_dirs"
[tool.hatch.build.targets.sdist]
include = [
"/yt_dlp",
"/devscripts",
"/test",
"/.gitignore", # included by default, needed for auto-excludes
"/Changelog.md",
"/LICENSE", # included as license
"/pyproject.toml", # included by default
"/README.md", # included as readme
"/setup.cfg",
"/supportedsites.md",
]
artifacts = [
"/yt_dlp/extractor/lazy_extractors.py",
"/completions",
"/AUTHORS", # included by default
"/README.txt",
"/yt-dlp.1",
]
[tool.hatch.build.targets.wheel]
packages = ["yt_dlp"]
artifacts = ["/yt_dlp/extractor/lazy_extractors.py"]
[tool.hatch.build.targets.wheel.shared-data]
"completions/bash/yt-dlp" = "share/bash-completion/completions/yt-dlp"
"completions/zsh/_yt-dlp" = "share/zsh/site-functions/_yt-dlp"
"completions/fish/yt-dlp.fish" = "share/fish/vendor_completions.d/yt-dlp.fish"
"README.txt" = "share/doc/yt_dlp/README.txt"
"yt-dlp.1" = "share/man/man1/yt-dlp.1"
[tool.hatch.version]
path = "yt_dlp/version.py"
pattern = "_pkg_version = '(?P<version>[^']+)'"

@ -1,6 +0,0 @@
mutagen
pycryptodomex
websockets
brotli; platform_python_implementation=='CPython'
brotlicffi; platform_python_implementation!='CPython'
certifi

@ -1,7 +1,3 @@
[wheel]
universal = true
[flake8]
exclude = build,venv,.tox,.git,.pytest_cache
ignore = E402,E501,E731,E741,W503
@ -10,6 +6,14 @@ per_file_ignores =
devscripts/lazy_load_template.py: F401
[autoflake]
ignore-init-module-imports = true
ignore-pass-after-docstring = true
remove-all-unused-imports = true
remove-duplicate-keys = true
remove-unused-variables = true
[tool:pytest]
addopts = -ra -v --strict-markers
markers =
@ -18,12 +22,12 @@ markers =
[tox:tox]
skipsdist = true
envlist = py{36,37,38,39,310},pypy{36,37,38,39}
envlist = py{38,39,310,311,312},pypy{38,39,310}
skip_missing_interpreters = true
[testenv] # tox
deps =
pytest
pytest
commands = pytest {posargs:"-m not download"}
passenv = HOME # For test_compat_expanduser
setenv =
@ -31,9 +35,11 @@ setenv =
[isort]
py_version = 36
py_version = 38
multi_line_output = VERTICAL_HANGING_INDENT
line_length = 80
reverse_relative = true
ensure_newline_before_comments = true
include_trailing_comma = true
known_first_party =
test

@ -1,156 +1,36 @@
#!/usr/bin/env python3
import os.path
import sys
import warnings
try:
from setuptools import Command, find_packages, setup
setuptools_available = True
except ImportError:
from distutils.core import Command, setup
setuptools_available = False
from distutils.spawn import spawn
def read(fname):
with open(fname, encoding='utf-8') as f:
return f.read()
# Get the version from yt_dlp/version.py without importing the package
def read_version(fname):
exec(compile(read(fname), fname, 'exec'))
return locals()['__version__']
VERSION = read_version('yt_dlp/version.py')
DESCRIPTION = 'A youtube-dl fork with additional features and patches'
# Allow execution from anywhere
import os
import sys
LONG_DESCRIPTION = '\n\n'.join((
'Official repository: <https://github.com/yt-dlp/yt-dlp>',
'**PS**: Some links in this document will not work since this is a copy of the README.md from Github',
read('README.md')))
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
REQUIREMENTS = read('requirements.txt').splitlines()
import warnings
if sys.argv[1:2] == ['py2exe']:
import py2exe # noqa: F401
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'],
# Modules that are only imported dynamically must be added here
'includes': ['yt_dlp.compat._legacy'],
}
},
'zipfile': None
}
else:
files_spec = [
('share/bash-completion/completions', ['completions/bash/yt-dlp']),
('share/zsh/site-functions', ['completions/zsh/_yt-dlp']),
('share/fish/vendor_completions.d', ['completions/fish/yt-dlp.fish']),
('share/doc/yt_dlp', ['README.txt']),
('share/man/man1', ['yt-dlp.1'])
]
root = os.path.dirname(os.path.abspath(__file__))
data_files = []
for dirname, files in files_spec:
resfiles = []
for fn in files:
if not os.path.exists(fn):
warnings.warn('Skipping file %s since it is not present. Try running `make pypi-files` first' % fn)
else:
resfiles.append(fn)
data_files.append((dirname, resfiles))
params = {
'data_files': data_files,
}
warnings.warn(DeprecationWarning('`setup.py py2exe` is deprecated and will be removed in a future version. '
'Use `bundle.py2exe` instead'))
if setuptools_available:
params['entry_points'] = {'console_scripts': ['yt-dlp = yt_dlp:main']}
else:
params['scripts'] = ['yt-dlp']
import bundle.py2exe
bundle.py2exe.main()
class build_lazy_extractors(Command):
description = 'Build the extractor lazy loading module'
user_options = []
elif 'build_lazy_extractors' in sys.argv:
warnings.warn(DeprecationWarning('`setup.py build_lazy_extractors` is deprecated and will be removed in a future version. '
'Use `devscripts.make_lazy_extractors` instead'))
def initialize_options(self):
pass
import subprocess
def finalize_options(self):
pass
os.chdir(sys.path[0])
print('running build_lazy_extractors')
subprocess.run([sys.executable, 'devscripts/make_lazy_extractors.py'])
def run(self):
spawn([sys.executable, 'devscripts/make_lazy_extractors.py', 'yt_dlp/extractor/lazy_extractors.py'],
dry_run=self.dry_run)
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(
name='yt-dlp',
version=VERSION,
maintainer='pukkandan',
maintainer_email='pukkandan.ytdlp@gmail.com',
description=DESCRIPTION,
long_description=LONG_DESCRIPTION,
long_description_content_type='text/markdown',
url='https://github.com/yt-dlp/yt-dlp',
packages=packages,
install_requires=REQUIREMENTS,
project_urls={
'Documentation': 'https://github.com/yt-dlp/yt-dlp#readme',
'Source': 'https://github.com/yt-dlp/yt-dlp',
'Tracker': 'https://github.com/yt-dlp/yt-dlp/issues',
'Funding': 'https://github.com/yt-dlp/yt-dlp/blob/master/Collaborators.md#collaborators',
},
classifiers=[
'Topic :: Multimedia :: Video',
'Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Programming Language :: Python',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: Implementation',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'License :: Public Domain',
'Operating System :: OS Independent',
],
python_requires='>=3.6',
cmdclass={'build_lazy_extractors': build_lazy_extractors},
**params
)
print(
'ERROR: Building by calling `setup.py` is deprecated. '
'Use a build frontend like `build` instead. ',
'Refer to https://build.pypa.io for more info', file=sys.stderr)
sys.exit(1)

File diff suppressed because it is too large Load Diff

@ -0,0 +1,64 @@
import inspect
import pytest
from yt_dlp.networking import RequestHandler
from yt_dlp.networking.common import _REQUEST_HANDLERS
from yt_dlp.utils._utils import _YDLLogger as FakeLogger
@pytest.fixture
def handler(request):
RH_KEY = getattr(request, 'param', None)
if not RH_KEY:
return
if inspect.isclass(RH_KEY) and issubclass(RH_KEY, RequestHandler):
handler = RH_KEY
elif RH_KEY in _REQUEST_HANDLERS:
handler = _REQUEST_HANDLERS[RH_KEY]
else:
pytest.skip(f'{RH_KEY} request handler is not available')
class HandlerWrapper(handler):
RH_KEY = handler.RH_KEY
def __init__(self, *args, **kwargs):
super().__init__(logger=FakeLogger, *args, **kwargs)
return HandlerWrapper
@pytest.fixture(autouse=True)
def skip_handler(request, handler):
"""usage: pytest.mark.skip_handler('my_handler', 'reason')"""
for marker in request.node.iter_markers('skip_handler'):
if marker.args[0] == handler.RH_KEY:
pytest.skip(marker.args[1] if len(marker.args) > 1 else '')
@pytest.fixture(autouse=True)
def skip_handler_if(request, handler):
"""usage: pytest.mark.skip_handler_if('my_handler', lambda request: True, 'reason')"""
for marker in request.node.iter_markers('skip_handler_if'):
if marker.args[0] == handler.RH_KEY and marker.args[1](request):
pytest.skip(marker.args[2] if len(marker.args) > 2 else '')
@pytest.fixture(autouse=True)
def skip_handlers_if(request, handler):
"""usage: pytest.mark.skip_handlers_if(lambda request, handler: True, 'reason')"""
for marker in request.node.iter_markers('skip_handlers_if'):
if handler and marker.args[0](request, handler):
pytest.skip(marker.args[1] if len(marker.args) > 1 else '')
def pytest_configure(config):
config.addinivalue_line(
"markers", "skip_handler(handler): skip test for the given handler",
)
config.addinivalue_line(
"markers", "skip_handler_if(handler): skip test for the given handler if condition is true"
)
config.addinivalue_line(
"markers", "skip_handlers_if(handler): skip test for handlers when the condition is true"
)

@ -9,8 +9,8 @@ import types
import yt_dlp.extractor
from yt_dlp import YoutubeDL
from yt_dlp.compat import compat_os_name, compat_str
from yt_dlp.utils import preferredencoding, write_string
from yt_dlp.compat import compat_os_name
from yt_dlp.utils import preferredencoding, try_call, write_string, find_available_port
if 'pytest' in sys.modules:
import pytest
@ -92,33 +92,40 @@ def gettestcases(include_onlymatching=False):
yield from ie.get_testcases(include_onlymatching)
def getwebpagetestcases():
for ie in yt_dlp.extractor.gen_extractors():
for tc in ie.get_webpage_testcases():
tc.setdefault('add_ie', []).append('Generic')
yield tc
md5 = lambda s: hashlib.md5(s.encode()).hexdigest()
def expect_value(self, got, expected, field):
if isinstance(expected, compat_str) and expected.startswith('re:'):
if isinstance(expected, str) and expected.startswith('re:'):
match_str = expected[len('re:'):]
match_rex = re.compile(match_str)
self.assertTrue(
isinstance(got, compat_str),
f'Expected a {compat_str.__name__} object, but got {type(got).__name__} for field {field}')
isinstance(got, str),
f'Expected a {str.__name__} object, but got {type(got).__name__} for field {field}')
self.assertTrue(
match_rex.match(got),
f'field {field} (value: {got!r}) should match {match_str!r}')
elif isinstance(expected, compat_str) and expected.startswith('startswith:'):
elif isinstance(expected, str) and expected.startswith('startswith:'):
start_str = expected[len('startswith:'):]
self.assertTrue(
isinstance(got, compat_str),
f'Expected a {compat_str.__name__} object, but got {type(got).__name__} for field {field}')
isinstance(got, str),
f'Expected a {str.__name__} object, but got {type(got).__name__} for field {field}')
self.assertTrue(
got.startswith(start_str),
f'field {field} (value: {got!r}) should start with {start_str!r}')
elif isinstance(expected, compat_str) and expected.startswith('contains:'):
elif isinstance(expected, str) and expected.startswith('contains:'):
contains_str = expected[len('contains:'):]
self.assertTrue(
isinstance(got, compat_str),
f'Expected a {compat_str.__name__} object, but got {type(got).__name__} for field {field}')
isinstance(got, str),
f'Expected a {str.__name__} object, but got {type(got).__name__} for field {field}')
self.assertTrue(
contains_str in got,
f'field {field} (value: {got!r}) should contain {contains_str!r}')
@ -142,12 +149,12 @@ def expect_value(self, got, expected, field):
index, field, type_expected, type_got))
expect_value(self, item_got, item_expected, field)
else:
if isinstance(expected, compat_str) and expected.startswith('md5:'):
if isinstance(expected, str) and expected.startswith('md5:'):
self.assertTrue(
isinstance(got, compat_str),
isinstance(got, str),
f'Expected field {field} to be a unicode object, but got value {got!r} of type {type(got)!r}')
got = 'md5:' + md5(got)
elif isinstance(expected, compat_str) and re.match(r'^(?:min|max)?count:\d+', expected):
elif isinstance(expected, str) and re.match(r'^(?:min|max)?count:\d+', expected):
self.assertTrue(
isinstance(got, (list, dict)),
f'Expected field {field} to be a list or a dict, but it is of type {type(got).__name__}')
@ -187,8 +194,8 @@ def sanitize_got_info_dict(got_dict):
'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',
'autonumber', 'playlist', 'format_index', 'video_ext', 'audio_ext', 'duration_string', 'epoch', 'n_entries',
'fulltitle', 'extractor', 'extractor_key', 'filename', 'filepath', 'infojson_filename', 'original_url',
# Only live_status needs to be checked
'is_live', 'was_live',
@ -207,14 +214,27 @@ def sanitize_got_info_dict(got_dict):
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)
if value is not None and key not in IGNORED_FIELDS and (
not any(key.startswith(f'{prefix}_') for prefix in IGNORED_PREFIXES)
or key == '_old_archive_ids')
}
# 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')
# Remove deprecated fields
for old in YoutubeDL._deprecated_multivalue_fields.keys():
test_info_dict.pop(old, None)
# release_year may be generated from release_date
if try_call(lambda: test_info_dict['release_year'] == int(test_info_dict['release_date'][:4])):
test_info_dict.pop('release_year')
# Check url for flat entries
if got_dict.get('_type', 'video') != 'video' and got_dict.get('url'):
test_info_dict['url'] = got_dict['url']
return test_info_dict
@ -228,33 +248,31 @@ def expect_info_dict(self, got_dict, expected_dict):
for key in mandatory_fields:
self.assertTrue(got_dict.get(key), 'Missing mandatory field %s' % key)
# Check for mandatory fields that are automatically set by YoutubeDL
for key in ['webpage_url', 'extractor', 'extractor_key']:
self.assertTrue(got_dict.get(key), 'Missing field: %s' % key)
if got_dict.get('_type', 'video') == 'video':
for key in ['webpage_url', 'extractor', 'extractor_key']:
self.assertTrue(got_dict.get(key), 'Missing field: %s' % key)
test_info_dict = sanitize_got_info_dict(got_dict)
missing_keys = set(test_info_dict.keys()) - set(expected_dict.keys())
if missing_keys:
def _repr(v):
if isinstance(v, compat_str):
if isinstance(v, str):
return "'%s'" % v.replace('\\', '\\\\').replace("'", "\\'").replace('\n', '\\n')
elif isinstance(v, type):
return v.__name__
else:
return repr(v)
info_dict_str = ''
if len(missing_keys) != len(expected_dict):
info_dict_str += ''.join(
f' {_repr(k)}: {_repr(v)},\n'
for k, v in test_info_dict.items() if k not in missing_keys)
if info_dict_str:
info_dict_str += '\n'
info_dict_str = ''.join(
f' {_repr(k)}: {_repr(v)},\n'
for k, v in test_info_dict.items() if k not in missing_keys)
if info_dict_str:
info_dict_str += '\n'
info_dict_str += ''.join(
f' {_repr(k)}: {_repr(test_info_dict[k])},\n'
for k in missing_keys)
write_string(
'\n\'info_dict\': {\n' + info_dict_str + '},\n', out=sys.stderr)
info_dict_str = '\n\'info_dict\': {\n' + info_dict_str + '},\n'
write_string(info_dict_str.replace('\n', '\n '), out=sys.stderr)
self.assertFalse(
missing_keys,
'Missing keys in test definition: %s' % (
@ -315,3 +333,13 @@ def http_server_port(httpd):
else:
sock = httpd.socket
return sock.getsockname()[1]
def verify_address_availability(address):
if find_available_port(address) is None:
pytest.skip(f'Unable to bind to source address {address} (address may not exist)')
def validate_and_send(rh, req):
rh.validate(req)
return rh.send(req)

@ -44,5 +44,6 @@
"writesubtitles": false,
"allsubtitles": false,
"listsubtitles": false,
"fixup": "never"
"fixup": "never",
"allow_playlist_files": false
}

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
@ -6,10 +7,12 @@ import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import http.server
import threading
from test.helper import FakeYDL, expect_dict, expect_value, http_server_port
from yt_dlp.compat import compat_etree_fromstring, compat_http_server
from test.helper import FakeYDL, expect_dict, expect_value, http_server_port
from yt_dlp.compat import compat_etree_fromstring
from yt_dlp.extractor import YoutubeIE, get_info_extractor
from yt_dlp.extractor.common import InfoExtractor
from yt_dlp.utils import (
@ -23,7 +26,7 @@ TEAPOT_RESPONSE_STATUS = 418
TEAPOT_RESPONSE_BODY = "<h1>418 I'm a teapot</h1>"
class InfoExtractorTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
class InfoExtractorTestRequestHandler(http.server.BaseHTTPRequestHandler):
def log_message(self, format, *args):
pass
@ -38,7 +41,9 @@ class InfoExtractorTestRequestHandler(compat_http_server.BaseHTTPRequestHandler)
class DummyIE(InfoExtractor):
pass
def _sort_formats(self, formats, field_preference=[]):
self._downloader.sort_formats(
{'formats': formats, '_format_sort_fields': field_preference})
class TestInfoExtractor(unittest.TestCase):
@ -64,6 +69,7 @@ class TestInfoExtractor(unittest.TestCase):
<meta name="og:test1" content='foo > < bar'/>
<meta name="og:test2" content="foo >//< bar"/>
<meta property=og-test3 content='Ill-formatted opengraph'/>
<meta property=og:test4 content=unquoted-value/>
'''
self.assertEqual(ie._og_search_title(html), 'Foo')
self.assertEqual(ie._og_search_description(html), 'Some video\'s description ')
@ -76,6 +82,7 @@ class TestInfoExtractor(unittest.TestCase):
self.assertEqual(ie._og_search_property(('test0', 'test1'), html), 'foo > < bar')
self.assertRaises(RegexNotFoundError, ie._og_search_property, 'test0', html, None, fatal=True)
self.assertRaises(RegexNotFoundError, ie._og_search_property, ('test0', 'test00'), html, None, fatal=True)
self.assertEqual(ie._og_search_property('test4', html), 'unquoted-value')
def test_html_search_meta(self):
ie = self.ie
@ -910,8 +917,6 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'acodec': 'mp4a.40.2',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 263.851,
'abr': 0,
}, {
'format_id': '577',
'format_index': None,
@ -929,8 +934,6 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'acodec': 'mp4a.40.2',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 577.61,
'abr': 0,
}, {
'format_id': '915',
'format_index': None,
@ -948,8 +951,6 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'acodec': 'mp4a.40.2',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 915.905,
'abr': 0,
}, {
'format_id': '1030',
'format_index': None,
@ -967,8 +968,6 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'acodec': 'mp4a.40.2',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 1030.138,
'abr': 0,
}, {
'format_id': '1924',
'format_index': None,
@ -986,8 +985,6 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'acodec': 'mp4a.40.2',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 1924.009,
'abr': 0,
}],
{
'en': [{
@ -1399,6 +1396,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'vcodec': 'none',
'acodec': 'AACL',
'protocol': 'ism',
'audio_channels': 2,
'_download_params': {
'stream_type': 'audio',
'duration': 8880746666,
@ -1412,9 +1410,6 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'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',
@ -1438,9 +1433,6 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'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',
@ -1464,9 +1456,6 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'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',
@ -1490,9 +1479,6 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'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',
@ -1516,9 +1502,6 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'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',
@ -1542,9 +1525,6 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
'video_ext': 'ismv',
'audio_ext': 'none',
'vbr': 4482,
}],
{
'eng': [
@ -1564,6 +1544,265 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
]
},
),
(
'ec-3_test',
'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
[{
'format_id': 'audio_deu-127',
'url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'manifest_url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'ext': 'isma',
'tbr': 127,
'asr': 48000,
'vcodec': 'none',
'acodec': 'AACL',
'protocol': 'ism',
'language': 'deu',
'audio_channels': 2,
'_download_params': {
'stream_type': 'audio',
'duration': 370000000,
'timescale': 10000000,
'width': 0,
'height': 0,
'fourcc': 'AACL',
'language': 'deu',
'codec_private_data': '1190',
'sampling_rate': 48000,
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
}, {
'format_id': 'audio_deu_1-224',
'url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'manifest_url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'ext': 'isma',
'tbr': 224,
'asr': 48000,
'vcodec': 'none',
'acodec': 'EC-3',
'protocol': 'ism',
'language': 'deu',
'audio_channels': 6,
'_download_params': {
'stream_type': 'audio',
'duration': 370000000,
'timescale': 10000000,
'width': 0,
'height': 0,
'fourcc': 'EC-3',
'language': 'deu',
'codec_private_data': '00063F000000AF87FBA7022DFB42A4D405CD93843BDD0700200F00',
'sampling_rate': 48000,
'channels': 6,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
}, {
'format_id': 'video_deu-23',
'url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'manifest_url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'ext': 'ismv',
'width': 384,
'height': 216,
'tbr': 23,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'language': 'deu',
'_download_params': {
'stream_type': 'video',
'duration': 370000000,
'timescale': 10000000,
'width': 384,
'height': 216,
'fourcc': 'AVC1',
'language': 'deu',
'codec_private_data': '000000016742C00CDB06077E5C05A808080A00000300020000030009C0C02EE0177CC6300F142AE00000000168CA8DC8',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
}, {
'format_id': 'video_deu-403',
'url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'manifest_url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'ext': 'ismv',
'width': 400,
'height': 224,
'tbr': 403,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'language': 'deu',
'_download_params': {
'stream_type': 'video',
'duration': 370000000,
'timescale': 10000000,
'width': 400,
'height': 224,
'fourcc': 'AVC1',
'language': 'deu',
'codec_private_data': '00000001674D4014E98323B602D4040405000003000100000300320F1429380000000168EAECF2',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
}, {
'format_id': 'video_deu-680',
'url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'manifest_url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'ext': 'ismv',
'width': 640,
'height': 360,
'tbr': 680,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'language': 'deu',
'_download_params': {
'stream_type': 'video',
'duration': 370000000,
'timescale': 10000000,
'width': 640,
'height': 360,
'fourcc': 'AVC1',
'language': 'deu',
'codec_private_data': '00000001674D401EE981405FF2E02D4040405000000300100000030320F162D3800000000168EAECF2',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
}, {
'format_id': 'video_deu-1253',
'url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'manifest_url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'ext': 'ismv',
'width': 640,
'height': 360,
'tbr': 1253,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'vbr': 1253,
'language': 'deu',
'_download_params': {
'stream_type': 'video',
'duration': 370000000,
'timescale': 10000000,
'width': 640,
'height': 360,
'fourcc': 'AVC1',
'language': 'deu',
'codec_private_data': '00000001674D401EE981405FF2E02D4040405000000300100000030320F162D3800000000168EAECF2',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
}, {
'format_id': 'video_deu-2121',
'url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'manifest_url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'ext': 'ismv',
'width': 768,
'height': 432,
'tbr': 2121,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'language': 'deu',
'_download_params': {
'stream_type': 'video',
'duration': 370000000,
'timescale': 10000000,
'width': 768,
'height': 432,
'fourcc': 'AVC1',
'language': 'deu',
'codec_private_data': '00000001674D401EECA0601BD80B50101014000003000400000300C83C58B6580000000168E93B3C80',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
}, {
'format_id': 'video_deu-3275',
'url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'manifest_url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'ext': 'ismv',
'width': 1280,
'height': 720,
'tbr': 3275,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'language': 'deu',
'_download_params': {
'stream_type': 'video',
'duration': 370000000,
'timescale': 10000000,
'width': 1280,
'height': 720,
'fourcc': 'AVC1',
'language': 'deu',
'codec_private_data': '00000001674D4020ECA02802DD80B501010140000003004000000C83C60C65800000000168E93B3C80',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
}, {
'format_id': 'video_deu-5300',
'url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'manifest_url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'ext': 'ismv',
'width': 1920,
'height': 1080,
'tbr': 5300,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'language': 'deu',
'_download_params': {
'stream_type': 'video',
'duration': 370000000,
'timescale': 10000000,
'width': 1920,
'height': 1080,
'fourcc': 'AVC1',
'language': 'deu',
'codec_private_data': '00000001674D4028ECA03C0113F2E02D4040405000000300100000030320F18319600000000168E93B3C80',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
}, {
'format_id': 'video_deu-8079',
'url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'manifest_url': 'https://smstr01.dmm.t-online.de/smooth24/smoothstream_m1/streaming/sony/9221438342941275747/636887760842957027/25_km_h-Trailer-9221571562372022953_deu_20_1300k_HD_H_264_ISMV.ism/Manifest',
'ext': 'ismv',
'width': 1920,
'height': 1080,
'tbr': 8079,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'language': 'deu',
'_download_params': {
'stream_type': 'video',
'duration': 370000000,
'timescale': 10000000,
'width': 1920,
'height': 1080,
'fourcc': 'AVC1',
'language': 'deu',
'codec_private_data': '00000001674D4028ECA03C0113F2E02D4040405000000300100000030320F18319600000000168E93B3C80',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
}],
{},
),
]
for ism_file, ism_url, expected_formats, expected_subtitles in _TEST_CASES:
@ -1655,7 +1894,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
# or the underlying `_download_webpage_handle` returning no content
# when a response matches `expected_status`.
httpd = compat_http_server.HTTPServer(
httpd = http.server.HTTPServer(
('127.0.0.1', 0), InfoExtractorTestRequestHandler)
port = http_server_port(httpd)
server_thread = threading.Thread(target=httpd.serve_forever)
@ -1667,6 +1906,15 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
expected_status=TEAPOT_RESPONSE_STATUS)
self.assertEqual(content, TEAPOT_RESPONSE_BODY)
def test_search_nextjs_data(self):
data = '<script id="__NEXT_DATA__" type="application/json">{"props":{}}</script>'
self.assertEqual(self.ie._search_nextjs_data(data, None), {'props': {}})
self.assertEqual(self.ie._search_nextjs_data('', None, fatal=False), {})
self.assertEqual(self.ie._search_nextjs_data('', None, default=None), None)
self.assertEqual(self.ie._search_nextjs_data('', None, default={}), {})
with self.assertRaises(DeprecationWarning):
self.assertEqual(self.ie._search_nextjs_data('', None, default='{}'), {})
if __name__ == '__main__':
unittest.main()

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
@ -6,17 +7,13 @@ import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import copy
import json
from test.helper import FakeYDL, assertRegexpMatches
from test.helper import FakeYDL, assertRegexpMatches, try_rm
from yt_dlp import YoutubeDL
from yt_dlp.compat import (
compat_os_name,
compat_setenv,
compat_str,
compat_urllib_error,
)
from yt_dlp.compat import compat_os_name
from yt_dlp.extractor import YoutubeIE
from yt_dlp.extractor.common import InfoExtractor
from yt_dlp.postprocessor.common import PostProcessor
@ -27,6 +24,7 @@ from yt_dlp.utils import (
int_or_none,
match_filter_func,
)
from yt_dlp.utils.traversal import traverse_obj
TEST_URL = 'http://localhost/sample.mp4'
@ -70,8 +68,7 @@ class TestFormatSelection(unittest.TestCase):
{'ext': 'mp4', 'height': 460, 'url': TEST_URL},
]
info_dict = _make_result(formats)
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['ext'], 'webm')
@ -84,8 +81,7 @@ class TestFormatSelection(unittest.TestCase):
{'ext': 'mp4', 'height': 1080, 'url': TEST_URL},
]
info_dict['formats'] = formats
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['ext'], 'mp4')
@ -99,8 +95,7 @@ class TestFormatSelection(unittest.TestCase):
{'ext': 'flv', 'height': 720, 'url': TEST_URL},
]
info_dict['formats'] = formats
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['ext'], 'mp4')
@ -112,15 +107,14 @@ class TestFormatSelection(unittest.TestCase):
{'ext': 'webm', 'height': 720, 'url': TEST_URL},
]
info_dict['formats'] = formats
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['ext'], 'webm')
def test_format_selection(self):
formats = [
{'format_id': '35', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
{'format_id': '35', 'ext': 'mp4', 'preference': 0, 'url': TEST_URL},
{'format_id': 'example-with-dashes', 'ext': 'webm', 'preference': 1, 'url': TEST_URL},
{'format_id': '45', 'ext': 'webm', 'preference': 2, 'url': TEST_URL},
{'format_id': '47', 'ext': 'webm', 'preference': 3, 'url': TEST_URL},
@ -146,6 +140,8 @@ class TestFormatSelection(unittest.TestCase):
test('example-with-dashes', 'example-with-dashes')
test('all', '2', '47', '45', 'example-with-dashes', '35')
test('mergeall', '2+47+45+example-with-dashes+35', multi=True)
# See: https://github.com/yt-dlp/yt-dlp/pulls/8797
test('7_a/worst', '35')
def test_format_selection_audio(self):
formats = [
@ -187,23 +183,20 @@ class TestFormatSelection(unittest.TestCase):
]
info_dict = _make_result(formats)
ydl = YDL({'format': 'best'})
ie = YoutubeIE(ydl)
ie._sort_formats(info_dict['formats'])
ydl = YDL({'format': 'best', 'format_sort': ['abr', 'ext']})
ydl.sort_formats(info_dict)
ydl.process_ie_result(copy.deepcopy(info_dict))
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], 'aac-64')
ydl = YDL({'format': 'mp3'})
ie = YoutubeIE(ydl)
ie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(copy.deepcopy(info_dict))
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], 'mp3-64')
ydl = YDL({'prefer_free_formats': True})
ie = YoutubeIE(ydl)
ie._sort_formats(info_dict['formats'])
ydl = YDL({'prefer_free_formats': True, 'format_sort': ['abr', 'ext']})
ydl.sort_formats(info_dict)
ydl.process_ie_result(copy.deepcopy(info_dict))
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], 'ogg-64')
@ -348,8 +341,7 @@ class TestFormatSelection(unittest.TestCase):
info_dict = _make_result(list(formats_order), extractor='youtube')
ydl = YDL({'format': 'bestvideo+bestaudio'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], '248+172')
@ -357,40 +349,35 @@ class TestFormatSelection(unittest.TestCase):
info_dict = _make_result(list(formats_order), extractor='youtube')
ydl = YDL({'format': 'bestvideo[height>=999999]+bestaudio/best'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], '38')
info_dict = _make_result(list(formats_order), extractor='youtube')
ydl = YDL({'format': 'bestvideo/best,bestaudio'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(info_dict)
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
self.assertEqual(downloaded_ids, ['137', '141'])
info_dict = _make_result(list(formats_order), extractor='youtube')
ydl = YDL({'format': '(bestvideo[ext=mp4],bestvideo[ext=webm])+bestaudio'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(info_dict)
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
self.assertEqual(downloaded_ids, ['137+141', '248+141'])
info_dict = _make_result(list(formats_order), extractor='youtube')
ydl = YDL({'format': '(bestvideo[ext=mp4],bestvideo[ext=webm])[height<=720]+bestaudio'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(info_dict)
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
self.assertEqual(downloaded_ids, ['136+141', '247+141'])
info_dict = _make_result(list(formats_order), extractor='youtube')
ydl = YDL({'format': '(bestvideo[ext=none]/bestvideo[ext=webm])+bestaudio'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(info_dict)
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
self.assertEqual(downloaded_ids, ['248+141'])
@ -398,16 +385,14 @@ class TestFormatSelection(unittest.TestCase):
for f1, f2 in zip(formats_order, formats_order[1:]):
info_dict = _make_result([f1, f2], extractor='youtube')
ydl = YDL({'format': 'best/bestvideo'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], f1['format_id'])
info_dict = _make_result([f2, f1], extractor='youtube')
ydl = YDL({'format': 'best/bestvideo'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.sort_formats(info_dict)
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], f1['format_id'])
@ -482,7 +467,7 @@ class TestFormatSelection(unittest.TestCase):
for f in formats:
f['url'] = 'http://_/'
f['ext'] = 'unknown'
info_dict = _make_result(formats)
info_dict = _make_result(formats, _format_sort_fields=('id', ))
ydl = YDL({'format': 'best[filesize<3000]'})
ydl.process_ie_result(info_dict)
@ -664,13 +649,17 @@ class TestYoutubeDL(unittest.TestCase):
'playlist_autonumber': 2,
'__last_playlist_index': 100,
'n_entries': 10,
'formats': [{'id': 'id 1'}, {'id': 'id 2'}, {'id': 'id 3'}]
'formats': [
{'id': 'id 1', 'height': 1080, 'width': 1920},
{'id': 'id 2', 'height': 720},
{'id': 'id 3'}
]
}
def test_prepare_outtmpl_and_filename(self):
def test(tmpl, expected, *, info=None, **params):
params['outtmpl'] = tmpl
ydl = YoutubeDL(params)
ydl = FakeYDL(params)
ydl._num_downloads = 1
self.assertEqual(ydl.validate_outtmpl(tmpl), None)
@ -682,7 +671,7 @@ class TestYoutubeDL(unittest.TestCase):
for (name, got), expect in zip((('outtmpl', out), ('filename', fname)), expected):
if callable(expect):
self.assertTrue(expect(got), f'Wrong {name} from {tmpl}')
else:
elif expect is not None:
self.assertEqual(got, expect, f'Wrong {name} from {tmpl}')
# Side-effects
@ -697,7 +686,8 @@ class TestYoutubeDL(unittest.TestCase):
test('%(id)s.%(ext)s', '1234.mp4')
test('%(duration_string)s', ('27:46:40', '27-46-40'))
test('%(resolution)s', '1080p')
test('%(playlist_index)s', '001')
test('%(playlist_index|)s', '001')
test('%(playlist_index&{}!)s', '1!')
test('%(playlist_autonumber)s', '02')
test('%(autonumber)s', '00001')
test('%(autonumber+2)03d', '005', autonumber_start=3)
@ -724,13 +714,14 @@ class TestYoutubeDL(unittest.TestCase):
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)s', ('ab:cd', 'abcd'), 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')
test('%(formats.{id)s', 'NA')
# Entire info_dict
def expect_same_infodict(out):
@ -739,7 +730,7 @@ class TestYoutubeDL(unittest.TestCase):
self.assertEqual(got_dict.get(info_field), expected, info_field)
return True
test('%()j', (expect_same_infodict, str))
test('%()j', (expect_same_infodict, None))
# NA placeholder
NA_TEST_OUTTMPL = '%(uploader_date)s-%(width)d-%(x|def)s-%(id)s.%(ext)s'
@ -767,20 +758,23 @@ class TestYoutubeDL(unittest.TestCase):
test('%(ext)c', 'm')
test('%(id)d %(id)r', "1234 '1234'")
test('%(id)r %(height)r', "'1234' 1080")
test('%(title5)a %(height)a', (R"'\xe1\xe9\xed \U0001d400' 1080", None))
test('%(ext)s-%(ext|def)d', 'mp4-def')
test('%(width|0)04d', '0000')
test('a%(width|)d', 'a', outtmpl_na_placeholder='none')
test('%(width|0)04d', '0')
test('a%(width|b)d', 'ab', 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('%(formats)j', (json.dumps(FORMATS), None))
test('%(formats)#j', (
json.dumps(FORMATS, indent=4),
json.dumps(FORMATS, indent=4).replace(':', '').replace('"', "").replace('\n', ' ')
))
test('%(title5).3B', 'á')
test('%(title5)U', 'áéí 𝐀')
test('%(title5)#U', 'a\u0301e\u0301i\u0301 𝐀')
@ -790,13 +784,13 @@ class TestYoutubeDL(unittest.TestCase):
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 ' ')))
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'"))
test('%(title4)q', ('"foo ""bar"" test"', None))
test('%(formats.:.id)#q', ('"id 1" "id 2" "id 3"', None))
test('%(formats.0.id)#q', ('"id 1"', None))
else:
test('%(title4)q', ('\'foo "bar" test\'', "'foo 'bar' test'"))
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'")
@ -805,8 +799,9 @@ class TestYoutubeDL(unittest.TestCase):
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('%(filesize*8)d', '8192')
test('%(formats.0) 15s', ('% 15s' % FORMATS[0], None))
test('%(formats.0)r', (repr(FORMATS[0]), None))
test('%(height.0)03d', '001')
test('%(-height.0)04d', '-001')
test('%(formats.-1.id)s', FORMATS[-1]['id'])
@ -815,6 +810,12 @@ class TestYoutubeDL(unittest.TestCase):
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')
out = json.dumps([{'id': f['id'], 'height.:2': str(f['height'])[:2]}
if 'height' in f else {'id': f['id']}
for f in FORMATS])
test('%(formats.:.{id,height.:2})j', (out, None))
test('%(formats.:.{id,height}.id)l', ', '.join(f['id'] for f in FORMATS))
test('%(.{id,title})j', ('{"id": "1234"}', '{id 1234}'))
# Alternates
test('%(title,id)s', '1234')
@ -828,6 +829,11 @@ class TestYoutubeDL(unittest.TestCase):
test('%(title&foo|baz)s.bar', 'baz.bar')
test('%(x,id&foo|baz)s.bar', 'foo.bar')
test('%(x,title&foo|baz)s.bar', 'baz.bar')
test('%(id&a\nb|)s', ('a\nb', 'a b'))
test('%(id&hi {:>10} {}|)s', 'hi 1234 1234')
test(R'%(id&{0} {}|)s', 'NA')
test(R'%(id&{0.1}|)s', 'NA')
test('%(height&{:,d})S', '1,080')
# Laziness
def gen():
@ -841,21 +847,21 @@ class TestYoutubeDL(unittest.TestCase):
# test('%(foo|)s', ('', '_')) # fixme
# Environment variable expansion for prepare_filename
compat_setenv('__yt_dlp_var', 'expanded')
os.environ['__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')
os.environ['s'] = 'expanded'
test('%s%', ('%s%', 'expanded')) # %s% should be expanded before escaping %s
compat_setenv('(test)s', 'expanded')
os.environ['(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))
test('%(title3)s', ('foo/bar\\test', 'foobartest'))
test('folder/%(title3)s', ('folder/foo/bar\\test', 'folder%sfoobartest' % os.path.sep))
def test_format_note(self):
ydl = YoutubeDL()
@ -873,12 +879,12 @@ class TestYoutubeDL(unittest.TestCase):
class SimplePP(PostProcessor):
def run(self, info):
with open(audiofile, 'wt') as f:
with open(audiofile, 'w') as f:
f.write('EXAMPLE')
return [info['filepath']], info
def run_pp(params, PP):
with open(filename, 'wt') as f:
with open(filename, 'w') as f:
f.write('EXAMPLE')
ydl = YoutubeDL(params)
ydl.add_post_processor(PP())
@ -897,7 +903,7 @@ class TestYoutubeDL(unittest.TestCase):
class ModifierPP(PostProcessor):
def run(self, info):
with open(info['filepath'], 'wt') as f:
with open(info['filepath'], 'w') as f:
f.write('MODIFIED')
return [], info
@ -935,7 +941,7 @@ class TestYoutubeDL(unittest.TestCase):
def get_videos(filter_=None):
ydl = YDL({'match_filter': filter_, 'simulate': True})
for v in videos:
ydl.process_ie_result(v, download=True)
ydl.process_ie_result(v.copy(), download=True)
return [v['id'] for v in ydl.downloaded_info_dicts]
res = get_videos()
@ -1055,6 +1061,7 @@ class TestYoutubeDL(unittest.TestCase):
for v in get_downloaded_info_dicts(params, entries)]
self.assertEqual(results, list(enumerate(zip(expected_ids, expected_ids))), f'Entries of {name} for {params}')
self.assertEqual(sorted(evaluated), expected_eval, f'Evaluation of {name} for {params}')
test_selection({}, INDICES)
test_selection({'playlistend': 20}, INDICES, True)
test_selection({'playlistend': 2}, INDICES[:2])
@ -1098,11 +1105,6 @@ class TestYoutubeDL(unittest.TestCase):
test_selection({'playlist_items': '-15::2'}, INDICES[1::2], True)
test_selection({'playlist_items': '-15::15'}, [], True)
def test_urlopen_no_file_protocol(self):
# see https://github.com/ytdl-org/youtube-dl/issues/8227
ydl = YDL()
self.assertRaises(compat_urllib_error.URLError, ydl.urlopen, 'file:///etc/passwd')
def test_do_not_override_ie_key_in_url_transparent(self):
ydl = YDL()
@ -1187,7 +1189,7 @@ class TestYoutubeDL(unittest.TestCase):
def _entries(self):
for n in range(3):
video_id = compat_str(n)
video_id = str(n)
yield {
'_type': 'url_transparent',
'ie_key': VideoIE.ie_key(),
@ -1216,6 +1218,129 @@ class TestYoutubeDL(unittest.TestCase):
self.assertEqual(downloaded['extractor'], 'Video')
self.assertEqual(downloaded['extractor_key'], 'Video')
def test_header_cookies(self):
from http.cookiejar import Cookie
ydl = FakeYDL()
ydl.report_warning = lambda *_, **__: None
def cookie(name, value, version=None, domain='', path='', secure=False, expires=None):
return Cookie(
version or 0, name, value, None, False,
domain, bool(domain), bool(domain), path, bool(path),
secure, expires, False, None, None, rest={})
_test_url = 'https://yt.dlp/test'
def test(encoded_cookies, cookies, *, headers=False, round_trip=None, error_re=None):
def _test():
ydl.cookiejar.clear()
ydl._load_cookies(encoded_cookies, autoscope=headers)
if headers:
ydl._apply_header_cookies(_test_url)
data = {'url': _test_url}
ydl._calc_headers(data)
self.assertCountEqual(
map(vars, ydl.cookiejar), map(vars, cookies),
'Extracted cookiejar.Cookie is not the same')
if not headers:
self.assertEqual(
data.get('cookies'), round_trip or encoded_cookies,
'Cookie is not the same as round trip')
ydl.__dict__['_YoutubeDL__header_cookies'] = []
with self.subTest(msg=encoded_cookies):
if not error_re:
_test()
return
with self.assertRaisesRegex(Exception, error_re):
_test()
test('test=value; Domain=.yt.dlp', [cookie('test', 'value', domain='.yt.dlp')])
test('test=value', [cookie('test', 'value')], error_re=r'Unscoped cookies are not allowed')
test('cookie1=value1; Domain=.yt.dlp; Path=/test; cookie2=value2; Domain=.yt.dlp; Path=/', [
cookie('cookie1', 'value1', domain='.yt.dlp', path='/test'),
cookie('cookie2', 'value2', domain='.yt.dlp', path='/')])
test('test=value; Domain=.yt.dlp; Path=/test; Secure; Expires=9999999999', [
cookie('test', 'value', domain='.yt.dlp', path='/test', secure=True, expires=9999999999)])
test('test="value; "; path=/test; domain=.yt.dlp', [
cookie('test', 'value; ', domain='.yt.dlp', path='/test')],
round_trip='test="value\\073 "; Domain=.yt.dlp; Path=/test')
test('name=; Domain=.yt.dlp', [cookie('name', '', domain='.yt.dlp')],
round_trip='name=""; Domain=.yt.dlp')
test('test=value', [cookie('test', 'value', domain='.yt.dlp')], headers=True)
test('cookie1=value; Domain=.yt.dlp; cookie2=value', [], headers=True, error_re=r'Invalid syntax')
ydl.deprecated_feature = ydl.report_error
test('test=value', [], headers=True, error_re=r'Passing cookies as a header is a potential security risk')
def test_infojson_cookies(self):
TEST_FILE = 'test_infojson_cookies.info.json'
TEST_URL = 'https://example.com/example.mp4'
COOKIES = 'a=b; Domain=.example.com; c=d; Domain=.example.com'
COOKIE_HEADER = {'Cookie': 'a=b; c=d'}
ydl = FakeYDL()
ydl.process_info = lambda x: ydl._write_info_json('test', x, TEST_FILE)
def make_info(info_header_cookies=False, fmts_header_cookies=False, cookies_field=False):
fmt = {'url': TEST_URL}
if fmts_header_cookies:
fmt['http_headers'] = COOKIE_HEADER
if cookies_field:
fmt['cookies'] = COOKIES
return _make_result([fmt], http_headers=COOKIE_HEADER if info_header_cookies else None)
def test(initial_info, note):
result = {}
result['processed'] = ydl.process_ie_result(initial_info)
self.assertTrue(ydl.cookiejar.get_cookies_for_url(TEST_URL),
msg=f'No cookies set in cookiejar after initial process when {note}')
ydl.cookiejar.clear()
with open(TEST_FILE) as infojson:
result['loaded'] = ydl.sanitize_info(json.load(infojson), True)
result['final'] = ydl.process_ie_result(result['loaded'].copy(), download=False)
self.assertTrue(ydl.cookiejar.get_cookies_for_url(TEST_URL),
msg=f'No cookies set in cookiejar after final process when {note}')
ydl.cookiejar.clear()
for key in ('processed', 'loaded', 'final'):
info = result[key]
self.assertIsNone(
traverse_obj(info, ((None, ('formats', 0)), 'http_headers', 'Cookie'), casesense=False, get_all=False),
msg=f'Cookie header not removed in {key} result when {note}')
self.assertEqual(
traverse_obj(info, ((None, ('formats', 0)), 'cookies'), get_all=False), COOKIES,
msg=f'No cookies field found in {key} result when {note}')
test({'url': TEST_URL, 'http_headers': COOKIE_HEADER, 'id': '1', 'title': 'x'}, 'no formats field')
test(make_info(info_header_cookies=True), 'info_dict header cokies')
test(make_info(fmts_header_cookies=True), 'format header cookies')
test(make_info(info_header_cookies=True, fmts_header_cookies=True), 'info_dict and format header cookies')
test(make_info(info_header_cookies=True, fmts_header_cookies=True, cookies_field=True), 'all cookies fields')
test(make_info(cookies_field=True), 'cookies format field')
test({'url': TEST_URL, 'cookies': COOKIES, 'id': '1', 'title': 'x'}, 'info_dict cookies field only')
try_rm(TEST_FILE)
def test_add_headers_cookie(self):
def check_for_cookie_header(result):
return traverse_obj(result, ((None, ('formats', 0)), 'http_headers', 'Cookie'), casesense=False, get_all=False)
ydl = FakeYDL({'http_headers': {'Cookie': 'a=b'}})
ydl._apply_header_cookies(_make_result([])['webpage_url']) # Scope to input webpage URL: .example.com
fmt = {'url': 'https://example.com/video.mp4'}
result = ydl.process_ie_result(_make_result([fmt]), download=False)
self.assertIsNone(check_for_cookie_header(result), msg='http_headers cookies in result info_dict')
self.assertEqual(result.get('cookies'), 'a=b; Domain=.example.com', msg='No cookies were set in cookies field')
self.assertIn('a=b', ydl.cookiejar.get_cookie_header(fmt['url']), msg='No cookies were set in cookiejar')
fmt = {'url': 'https://wrong.com/video.mp4'}
result = ydl.process_ie_result(_make_result([fmt]), download=False)
self.assertIsNone(check_for_cookie_header(result), msg='http_headers cookies for wrong domain')
self.assertFalse(result.get('cookies'), msg='Cookies set in cookies field for wrong domain')
self.assertFalse(ydl.cookiejar.get_cookie_header(fmt['url']), msg='Cookies set in cookiejar for wrong domain')
if __name__ == '__main__':
unittest.main()

@ -1,22 +1,26 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import re
import sys
import tempfile
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from yt_dlp.utils import YoutubeDLCookieJar
import re
import tempfile
from yt_dlp.cookies import YoutubeDLCookieJar
class TestYoutubeDLCookieJar(unittest.TestCase):
def test_keep_session_cookies(self):
cookiejar = YoutubeDLCookieJar('./test/testdata/cookies/session_cookies.txt')
cookiejar.load(ignore_discard=True, ignore_expires=True)
cookiejar.load()
tf = tempfile.NamedTemporaryFile(delete=False)
try:
cookiejar.save(filename=tf.name, ignore_discard=True, ignore_expires=True)
cookiejar.save(filename=tf.name)
temp = tf.read().decode()
self.assertTrue(re.search(
r'www\.foobar\.foobar\s+FALSE\s+/\s+TRUE\s+0\s+YoutubeDLExpiresEmpty\s+YoutubeDLExpiresEmptyValue', temp))
@ -28,7 +32,7 @@ class TestYoutubeDLCookieJar(unittest.TestCase):
def test_strip_httponly_prefix(self):
cookiejar = YoutubeDLCookieJar('./test/testdata/cookies/httponly_cookies.txt')
cookiejar.load(ignore_discard=True, ignore_expires=True)
cookiejar.load()
def assert_cookie_has_value(key):
self.assertEqual(cookiejar._cookies['www.foobar.foobar']['/'][key].value, key + '_VALUE')
@ -38,11 +42,25 @@ class TestYoutubeDLCookieJar(unittest.TestCase):
def test_malformed_cookies(self):
cookiejar = YoutubeDLCookieJar('./test/testdata/cookies/malformed_cookies.txt')
cookiejar.load(ignore_discard=True, ignore_expires=True)
cookiejar.load()
# Cookies should be empty since all malformed cookie file entries
# will be ignored
self.assertFalse(cookiejar._cookies)
def test_get_cookie_header(self):
cookiejar = YoutubeDLCookieJar('./test/testdata/cookies/httponly_cookies.txt')
cookiejar.load()
header = cookiejar.get_cookie_header('https://www.foobar.foobar')
self.assertIn('HTTPONLY_COOKIE', header)
def test_get_cookies_for_url(self):
cookiejar = YoutubeDLCookieJar('./test/testdata/cookies/session_cookies.txt')
cookiejar.load()
cookies = cookiejar.get_cookies_for_url('https://www.foobar.foobar/')
self.assertEqual(len(cookies), 2)
cookies = cookiejar.get_cookies_for_url('https://foobar.foobar/')
self.assertFalse(cookies)
if __name__ == '__main__':
unittest.main()

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
@ -6,10 +7,10 @@ import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import base64
from yt_dlp.aes import (
BLOCK_SIZE_BYTES,
aes_cbc_decrypt,
aes_cbc_decrypt_bytes,
aes_cbc_encrypt,
@ -22,8 +23,10 @@ from yt_dlp.aes import (
aes_encrypt,
aes_gcm_decrypt_and_verify,
aes_gcm_decrypt_and_verify_bytes,
key_expansion,
pad_block,
)
from yt_dlp.dependencies import Cryptodome_AES
from yt_dlp.dependencies import Cryptodome
from yt_dlp.utils import bytes_to_intlist, intlist_to_bytes
# the encrypted data can be generate with 'devscripts/generate_aes_testdata.py'
@ -45,7 +48,7 @@ class TestAES(unittest.TestCase):
data = b'\x97\x92+\xe5\x0b\xc3\x18\x91ky9m&\xb3\xb5@\xe6\x27\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)
if Cryptodome_AES:
if Cryptodome.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)
@ -75,7 +78,7 @@ class TestAES(unittest.TestCase):
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 Cryptodome_AES:
if Cryptodome.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)
@ -99,8 +102,7 @@ class TestAES(unittest.TestCase):
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))
encrypted = intlist_to_bytes(aes_ecb_encrypt(data, self.key))
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:')
@ -110,6 +112,41 @@ class TestAES(unittest.TestCase):
decrypted = intlist_to_bytes(aes_ecb_decrypt(data, self.key, self.iv))
self.assertEqual(decrypted.rstrip(b'\x08'), self.secret_msg)
def test_key_expansion(self):
key = '4f6bdaa39e2f8cb07f5e722d9edef314'
self.assertEqual(key_expansion(bytes_to_intlist(bytearray.fromhex(key))), [
0x4F, 0x6B, 0xDA, 0xA3, 0x9E, 0x2F, 0x8C, 0xB0, 0x7F, 0x5E, 0x72, 0x2D, 0x9E, 0xDE, 0xF3, 0x14,
0x53, 0x66, 0x20, 0xA8, 0xCD, 0x49, 0xAC, 0x18, 0xB2, 0x17, 0xDE, 0x35, 0x2C, 0xC9, 0x2D, 0x21,
0x8C, 0xBE, 0xDD, 0xD9, 0x41, 0xF7, 0x71, 0xC1, 0xF3, 0xE0, 0xAF, 0xF4, 0xDF, 0x29, 0x82, 0xD5,
0x2D, 0xAD, 0xDE, 0x47, 0x6C, 0x5A, 0xAF, 0x86, 0x9F, 0xBA, 0x00, 0x72, 0x40, 0x93, 0x82, 0xA7,
0xF9, 0xBE, 0x82, 0x4E, 0x95, 0xE4, 0x2D, 0xC8, 0x0A, 0x5E, 0x2D, 0xBA, 0x4A, 0xCD, 0xAF, 0x1D,
0x54, 0xC7, 0x26, 0x98, 0xC1, 0x23, 0x0B, 0x50, 0xCB, 0x7D, 0x26, 0xEA, 0x81, 0xB0, 0x89, 0xF7,
0x93, 0x60, 0x4E, 0x94, 0x52, 0x43, 0x45, 0xC4, 0x99, 0x3E, 0x63, 0x2E, 0x18, 0x8E, 0xEA, 0xD9,
0xCA, 0xE7, 0x7B, 0x39, 0x98, 0xA4, 0x3E, 0xFD, 0x01, 0x9A, 0x5D, 0xD3, 0x19, 0x14, 0xB7, 0x0A,
0xB0, 0x4E, 0x1C, 0xED, 0x28, 0xEA, 0x22, 0x10, 0x29, 0x70, 0x7F, 0xC3, 0x30, 0x64, 0xC8, 0xC9,
0xE8, 0xA6, 0xC1, 0xE9, 0xC0, 0x4C, 0xE3, 0xF9, 0xE9, 0x3C, 0x9C, 0x3A, 0xD9, 0x58, 0x54, 0xF3,
0xB4, 0x86, 0xCC, 0xDC, 0x74, 0xCA, 0x2F, 0x25, 0x9D, 0xF6, 0xB3, 0x1F, 0x44, 0xAE, 0xE7, 0xEC])
def test_pad_block(self):
block = [0x21, 0xA0, 0x43, 0xFF]
self.assertEqual(pad_block(block, 'pkcs7'),
block + [0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C])
self.assertEqual(pad_block(block, 'iso7816'),
block + [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
self.assertEqual(pad_block(block, 'whitespace'),
block + [0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20])
self.assertEqual(pad_block(block, 'zero'),
block + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
block = list(range(16))
for mode in ('pkcs7', 'iso7816', 'whitespace', 'zero'):
self.assertEqual(pad_block(block, mode), block, mode)
if __name__ == '__main__':
unittest.main()

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
@ -6,9 +7,10 @@ import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from test.helper import is_download_test, try_rm
from test.helper import is_download_test, try_rm
from yt_dlp import YoutubeDL
from yt_dlp.utils import DownloadError
def _download_restricted(url, filename, age):
@ -24,10 +26,14 @@ def _download_restricted(url, filename, age):
ydl.add_default_info_extractors()
json_filename = os.path.splitext(filename)[0] + '.info.json'
try_rm(json_filename)
ydl.download([url])
res = os.path.exists(json_filename)
try_rm(json_filename)
return res
try:
ydl.download([url])
except DownloadError:
pass
else:
return os.path.exists(json_filename)
finally:
try_rm(json_filename)
@is_download_test
@ -37,12 +43,12 @@ class TestAgeRestriction(unittest.TestCase):
self.assertFalse(_download_restricted(url, filename, age))
def test_youtube(self):
self._assert_restricted('07FYdnEawAQ', '07FYdnEawAQ.mp4', 10)
self._assert_restricted('HtVdAasjOgU', 'HtVdAasjOgU.mp4', 10)
def test_youporn(self):
self._assert_restricted(
'http://www.youporn.com/watch/505835/sex-ed-is-it-safe-to-masturbate-daily/',
'505835.mp4', 2, old_age=25)
'https://www.youporn.com/watch/16715086/sex-ed-in-detention-18-asmr/',
'16715086.mp4', 2, old_age=25)
if __name__ == '__main__':

@ -1,6 +1,6 @@
#!/usr/bin/env python3
# Allow direct execution
import collections
import os
import sys
import unittest
@ -8,8 +8,9 @@ import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from test.helper import gettestcases
import collections
from test.helper import gettestcases
from yt_dlp.extractor import FacebookIE, YoutubeIE, gen_extractors

@ -1,15 +1,16 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import shutil
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from test.helper import FakeYDL
import shutil
from test.helper import FakeYDL
from yt_dlp.cache import Cache

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
@ -7,18 +8,17 @@ import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import struct
from yt_dlp import compat
from yt_dlp.compat import urllib # isort: split
from yt_dlp.compat import (
compat_etree_fromstring,
compat_expanduser,
compat_getenv,
compat_setenv,
compat_str,
compat_struct_unpack,
compat_urllib_parse_unquote,
compat_urllib_parse_unquote_plus,
compat_urllib_parse_urlencode,
)
from yt_dlp.compat.urllib.request import getproxies
class TestCompat(unittest.TestCase):
@ -26,28 +26,22 @@ class TestCompat(unittest.TestCase):
with self.assertWarns(DeprecationWarning):
compat.compat_basestring
compat.asyncio.events # Must not raise error
with self.assertWarns(DeprecationWarning):
compat.WINDOWS_VT_MODE
def test_compat_getenv(self):
test_str = 'тест'
compat_setenv('yt_dlp_COMPAT_GETENV', test_str)
self.assertEqual(compat_getenv('yt_dlp_COMPAT_GETENV'), test_str)
self.assertEqual(urllib.request.getproxies, getproxies)
def test_compat_setenv(self):
test_var = 'yt_dlp_COMPAT_SETENV'
test_str = 'тест'
compat_setenv(test_var, test_str)
compat_getenv(test_var)
self.assertEqual(compat_getenv(test_var), test_str)
with self.assertWarns(DeprecationWarning):
compat.compat_pycrypto_AES # Must not raise error
def test_compat_expanduser(self):
old_home = os.environ.get('HOME')
test_str = R'C:\Documents and Settings\тест\Application Data'
try:
compat_setenv('HOME', test_str)
os.environ['HOME'] = test_str
self.assertEqual(compat_expanduser('~'), test_str)
finally:
compat_setenv('HOME', old_home or '')
os.environ['HOME'] = old_home or ''
def test_compat_urllib_parse_unquote(self):
self.assertEqual(compat_urllib_parse_unquote('abc%20def'), 'abc def')
@ -69,8 +63,8 @@ class TestCompat(unittest.TestCase):
'''(^◣_◢^)っ︻デ═一 ⇀ ⇀ ⇀ ⇀ ⇀ ↶%I%Break%Things%''')
def test_compat_urllib_parse_unquote_plus(self):
self.assertEqual(compat_urllib_parse_unquote_plus('abc%20def'), 'abc def')
self.assertEqual(compat_urllib_parse_unquote_plus('%7e/abc+def'), '~/abc def')
self.assertEqual(urllib.parse.unquote_plus('abc%20def'), 'abc def')
self.assertEqual(urllib.parse.unquote_plus('%7e/abc+def'), '~/abc def')
def test_compat_urllib_parse_urlencode(self):
self.assertEqual(compat_urllib_parse_urlencode({'abc': 'def'}), 'abc=def')
@ -91,11 +85,11 @@ class TestCompat(unittest.TestCase):
</root>
'''
doc = compat_etree_fromstring(xml.encode())
self.assertTrue(isinstance(doc.attrib['foo'], compat_str))
self.assertTrue(isinstance(doc.attrib['spam'], compat_str))
self.assertTrue(isinstance(doc.find('normal').text, compat_str))
self.assertTrue(isinstance(doc.find('chinese').text, compat_str))
self.assertTrue(isinstance(doc.find('foo/bar').text, compat_str))
self.assertTrue(isinstance(doc.attrib['foo'], str))
self.assertTrue(isinstance(doc.attrib['spam'], str))
self.assertTrue(isinstance(doc.find('normal').text, str))
self.assertTrue(isinstance(doc.find('chinese').text, str))
self.assertTrue(isinstance(doc.find('foo/bar').text, str))
def test_compat_etree_fromstring_doctype(self):
xml = '''<?xml version="1.0"?>
@ -104,7 +98,7 @@ class TestCompat(unittest.TestCase):
compat_etree_fromstring(xml)
def test_struct_unpack(self):
self.assertEqual(compat_struct_unpack('!B', b'\x00'), (0,))
self.assertEqual(struct.unpack('!B', b'\x00'), (0,))
if __name__ == '__main__':

@ -0,0 +1,227 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
import unittest
import unittest.mock
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import contextlib
import itertools
from pathlib import Path
from yt_dlp.compat import compat_expanduser
from yt_dlp.options import create_parser, parseOpts
from yt_dlp.utils import Config, get_executable_path
ENVIRON_DEFAULTS = {
'HOME': None,
'XDG_CONFIG_HOME': '/_xdg_config_home/',
'USERPROFILE': 'C:/Users/testing/',
'APPDATA': 'C:/Users/testing/AppData/Roaming/',
'HOMEDRIVE': 'C:/',
'HOMEPATH': 'Users/testing/',
}
@contextlib.contextmanager
def set_environ(**kwargs):
saved_environ = os.environ.copy()
for name, value in {**ENVIRON_DEFAULTS, **kwargs}.items():
if value is None:
os.environ.pop(name, None)
else:
os.environ[name] = value
yield
os.environ.clear()
os.environ.update(saved_environ)
def _generate_expected_groups():
xdg_config_home = os.getenv('XDG_CONFIG_HOME') or compat_expanduser('~/.config')
appdata_dir = os.getenv('appdata')
home_dir = compat_expanduser('~')
return {
'Portable': [
Path(get_executable_path(), 'yt-dlp.conf'),
],
'Home': [
Path('yt-dlp.conf'),
],
'User': [
Path(xdg_config_home, 'yt-dlp.conf'),
Path(xdg_config_home, 'yt-dlp', 'config'),
Path(xdg_config_home, 'yt-dlp', 'config.txt'),
*((
Path(appdata_dir, 'yt-dlp.conf'),
Path(appdata_dir, 'yt-dlp', 'config'),
Path(appdata_dir, 'yt-dlp', 'config.txt'),
) if appdata_dir else ()),
Path(home_dir, 'yt-dlp.conf'),
Path(home_dir, 'yt-dlp.conf.txt'),
Path(home_dir, '.yt-dlp', 'config'),
Path(home_dir, '.yt-dlp', 'config.txt'),
],
'System': [
Path('/etc/yt-dlp.conf'),
Path('/etc/yt-dlp/config'),
Path('/etc/yt-dlp/config.txt'),
]
}
class TestConfig(unittest.TestCase):
maxDiff = None
@set_environ()
def test_config__ENVIRON_DEFAULTS_sanity(self):
expected = make_expected()
self.assertCountEqual(
set(expected), expected,
'ENVIRON_DEFAULTS produces non unique names')
def test_config_all_environ_values(self):
for name, value in ENVIRON_DEFAULTS.items():
for new_value in (None, '', '.', value or '/some/dir'):
with set_environ(**{name: new_value}):
self._simple_grouping_test()
def test_config_default_expected_locations(self):
files, _ = self._simple_config_test()
self.assertEqual(
files, make_expected(),
'Not all expected locations have been checked')
def test_config_default_grouping(self):
self._simple_grouping_test()
def _simple_grouping_test(self):
expected_groups = make_expected_groups()
for name, group in expected_groups.items():
for index, existing_path in enumerate(group):
result, opts = self._simple_config_test(existing_path)
expected = expected_from_expected_groups(expected_groups, existing_path)
self.assertEqual(
result, expected,
f'The checked locations do not match the expected ({name}, {index})')
self.assertEqual(
opts.outtmpl['default'], '1',
f'The used result value was incorrect ({name}, {index})')
def _simple_config_test(self, *stop_paths):
encountered = 0
paths = []
def read_file(filename, default=[]):
nonlocal encountered
path = Path(filename)
paths.append(path)
if path in stop_paths:
encountered += 1
return ['-o', f'{encountered}']
with ConfigMock(read_file):
_, opts, _ = parseOpts([], False)
return paths, opts
@set_environ()
def test_config_early_exit_commandline(self):
self._early_exit_test(0, '--ignore-config')
@set_environ()
def test_config_early_exit_files(self):
for index, _ in enumerate(make_expected(), 1):
self._early_exit_test(index)
def _early_exit_test(self, allowed_reads, *args):
reads = 0
def read_file(filename, default=[]):
nonlocal reads
reads += 1
if reads > allowed_reads:
self.fail('The remaining config was not ignored')
elif reads == allowed_reads:
return ['--ignore-config']
with ConfigMock(read_file):
parseOpts(args, False)
@set_environ()
def test_config_override_commandline(self):
self._override_test(0, '-o', 'pass')
@set_environ()
def test_config_override_files(self):
for index, _ in enumerate(make_expected(), 1):
self._override_test(index)
def _override_test(self, start_index, *args):
index = 0
def read_file(filename, default=[]):
nonlocal index
index += 1
if index > start_index:
return ['-o', 'fail']
elif index == start_index:
return ['-o', 'pass']
with ConfigMock(read_file):
_, opts, _ = parseOpts(args, False)
self.assertEqual(
opts.outtmpl['default'], 'pass',
'The earlier group did not override the later ones')
@contextlib.contextmanager
def ConfigMock(read_file=None):
with unittest.mock.patch('yt_dlp.options.Config') as mock:
mock.return_value = Config(create_parser())
if read_file is not None:
mock.read_file = read_file
yield mock
def make_expected(*filepaths):
return expected_from_expected_groups(_generate_expected_groups(), *filepaths)
def make_expected_groups(*filepaths):
return _filter_expected_groups(_generate_expected_groups(), filepaths)
def expected_from_expected_groups(expected_groups, *filepaths):
return list(itertools.chain.from_iterable(
_filter_expected_groups(expected_groups, filepaths).values()))
def _filter_expected_groups(expected, filepaths):
if not filepaths:
return expected
result = {}
for group, paths in expected.items():
new_paths = []
for path in paths:
new_paths.append(path)
if path in filepaths:
break
result[group] = new_paths
return result
if __name__ == '__main__':
unittest.main()

@ -1,8 +1,9 @@
import datetime as dt
import unittest
from datetime import datetime, timezone
from yt_dlp import cookies
from yt_dlp.cookies import (
LenientSimpleCookie,
LinuxChromeCookieDecryptor,
MacChromeCookieDecryptor,
WindowsChromeCookieDecryptor,
@ -48,32 +49,38 @@ class TestCookies(unittest.TestCase):
""" based on https://chromium.googlesource.com/chromium/src/+/refs/heads/main/base/nix/xdg_util_unittest.cc """
test_cases = [
({}, _LinuxDesktopEnvironment.OTHER),
({'DESKTOP_SESSION': 'my_custom_de'}, _LinuxDesktopEnvironment.OTHER),
({'XDG_CURRENT_DESKTOP': 'my_custom_de'}, _LinuxDesktopEnvironment.OTHER),
({'DESKTOP_SESSION': 'gnome'}, _LinuxDesktopEnvironment.GNOME),
({'DESKTOP_SESSION': 'mate'}, _LinuxDesktopEnvironment.GNOME),
({'DESKTOP_SESSION': 'kde4'}, _LinuxDesktopEnvironment.KDE),
({'DESKTOP_SESSION': 'kde'}, _LinuxDesktopEnvironment.KDE),
({'DESKTOP_SESSION': 'kde4'}, _LinuxDesktopEnvironment.KDE4),
({'DESKTOP_SESSION': 'kde'}, _LinuxDesktopEnvironment.KDE3),
({'DESKTOP_SESSION': 'xfce'}, _LinuxDesktopEnvironment.XFCE),
({'GNOME_DESKTOP_SESSION_ID': 1}, _LinuxDesktopEnvironment.GNOME),
({'KDE_FULL_SESSION': 1}, _LinuxDesktopEnvironment.KDE),
({'KDE_FULL_SESSION': 1}, _LinuxDesktopEnvironment.KDE3),
({'KDE_FULL_SESSION': 1, 'DESKTOP_SESSION': 'kde4'}, _LinuxDesktopEnvironment.KDE4),
({'XDG_CURRENT_DESKTOP': 'X-Cinnamon'}, _LinuxDesktopEnvironment.CINNAMON),
({'XDG_CURRENT_DESKTOP': 'Deepin'}, _LinuxDesktopEnvironment.DEEPIN),
({'XDG_CURRENT_DESKTOP': 'GNOME'}, _LinuxDesktopEnvironment.GNOME),
({'XDG_CURRENT_DESKTOP': 'GNOME:GNOME-Classic'}, _LinuxDesktopEnvironment.GNOME),
({'XDG_CURRENT_DESKTOP': 'GNOME : GNOME-Classic'}, _LinuxDesktopEnvironment.GNOME),
({'XDG_CURRENT_DESKTOP': 'Unity', 'DESKTOP_SESSION': 'gnome-fallback'}, _LinuxDesktopEnvironment.GNOME),
({'XDG_CURRENT_DESKTOP': 'KDE', 'KDE_SESSION_VERSION': '5'}, _LinuxDesktopEnvironment.KDE),
({'XDG_CURRENT_DESKTOP': 'KDE'}, _LinuxDesktopEnvironment.KDE),
({'XDG_CURRENT_DESKTOP': 'KDE', 'KDE_SESSION_VERSION': '5'}, _LinuxDesktopEnvironment.KDE5),
({'XDG_CURRENT_DESKTOP': 'KDE', 'KDE_SESSION_VERSION': '6'}, _LinuxDesktopEnvironment.KDE6),
({'XDG_CURRENT_DESKTOP': 'KDE'}, _LinuxDesktopEnvironment.KDE4),
({'XDG_CURRENT_DESKTOP': 'Pantheon'}, _LinuxDesktopEnvironment.PANTHEON),
({'XDG_CURRENT_DESKTOP': 'UKUI'}, _LinuxDesktopEnvironment.UKUI),
({'XDG_CURRENT_DESKTOP': 'Unity'}, _LinuxDesktopEnvironment.UNITY),
({'XDG_CURRENT_DESKTOP': 'Unity:Unity7'}, _LinuxDesktopEnvironment.UNITY),
({'XDG_CURRENT_DESKTOP': 'Unity:Unity8'}, _LinuxDesktopEnvironment.UNITY),
]
for env, expected_desktop_environment in test_cases:
self.assertEqual(_get_linux_desktop_environment(env), expected_desktop_environment)
self.assertEqual(_get_linux_desktop_environment(env, Logger()), expected_desktop_environment)
def test_chrome_cookie_decryptor_linux_derive_key(self):
key = LinuxChromeCookieDecryptor.derive_key(b'abc')
@ -131,9 +138,169 @@ class TestCookies(unittest.TestCase):
self.assertEqual(cookie.name, 'foo')
self.assertEqual(cookie.value, 'test%20%3Bcookie')
self.assertFalse(cookie.secure)
expected_expiration = datetime(2021, 6, 18, 21, 39, 19, tzinfo=timezone.utc)
expected_expiration = dt.datetime(2021, 6, 18, 21, 39, 19, tzinfo=dt.timezone.utc)
self.assertEqual(cookie.expires, int(expected_expiration.timestamp()))
def test_pbkdf2_sha1(self):
key = pbkdf2_sha1(b'peanuts', b' ' * 16, 1, 16)
self.assertEqual(key, b'g\xe1\x8e\x0fQ\x1c\x9b\xf3\xc9`!\xaa\x90\xd9\xd34')
class TestLenientSimpleCookie(unittest.TestCase):
def _run_tests(self, *cases):
for message, raw_cookie, expected in cases:
cookie = LenientSimpleCookie(raw_cookie)
with self.subTest(message, expected=expected):
self.assertEqual(cookie.keys(), expected.keys(), message)
for key, expected_value in expected.items():
morsel = cookie[key]
if isinstance(expected_value, tuple):
expected_value, expected_attributes = expected_value
else:
expected_attributes = {}
attributes = {
key: value
for key, value in dict(morsel).items()
if value != ""
}
self.assertEqual(attributes, expected_attributes, message)
self.assertEqual(morsel.value, expected_value, message)
def test_parsing(self):
self._run_tests(
# Copied from https://github.com/python/cpython/blob/v3.10.7/Lib/test/test_http_cookies.py
(
"Test basic cookie",
"chips=ahoy; vienna=finger",
{"chips": "ahoy", "vienna": "finger"},
),
(
"Test quoted cookie",
'keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"',
{"keebler": 'E=mc2; L="Loves"; fudge=\012;'},
),
(
"Allow '=' in an unquoted value",
"keebler=E=mc2",
{"keebler": "E=mc2"},
),
(
"Allow cookies with ':' in their name",
"key:term=value:term",
{"key:term": "value:term"},
),
(
"Allow '[' and ']' in cookie values",
"a=b; c=[; d=r; f=h",
{"a": "b", "c": "[", "d": "r", "f": "h"},
),
(
"Test basic cookie attributes",
'Customer="WILE_E_COYOTE"; Version=1; Path=/acme',
{"Customer": ("WILE_E_COYOTE", {"version": "1", "path": "/acme"})},
),
(
"Test flag only cookie attributes",
'Customer="WILE_E_COYOTE"; HttpOnly; Secure',
{"Customer": ("WILE_E_COYOTE", {"httponly": True, "secure": True})},
),
(
"Test flag only attribute with values",
"eggs=scrambled; httponly=foo; secure=bar; Path=/bacon",
{"eggs": ("scrambled", {"httponly": "foo", "secure": "bar", "path": "/bacon"})},
),
(
"Test special case for 'expires' attribute, 4 digit year",
'Customer="W"; expires=Wed, 01 Jan 2010 00:00:00 GMT',
{"Customer": ("W", {"expires": "Wed, 01 Jan 2010 00:00:00 GMT"})},
),
(
"Test special case for 'expires' attribute, 2 digit year",
'Customer="W"; expires=Wed, 01 Jan 98 00:00:00 GMT',
{"Customer": ("W", {"expires": "Wed, 01 Jan 98 00:00:00 GMT"})},
),
(
"Test extra spaces in keys and values",
"eggs = scrambled ; secure ; path = bar ; foo=foo ",
{"eggs": ("scrambled", {"secure": True, "path": "bar"}), "foo": "foo"},
),
(
"Test quoted attributes",
'Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"',
{"Customer": ("WILE_E_COYOTE", {"version": "1", "path": "/acme"})}
),
# Our own tests that CPython passes
(
"Allow ';' in quoted value",
'chips="a;hoy"; vienna=finger',
{"chips": "a;hoy", "vienna": "finger"},
),
(
"Keep only the last set value",
"a=c; a=b",
{"a": "b"},
),
)
def test_lenient_parsing(self):
self._run_tests(
(
"Ignore and try to skip invalid cookies",
'chips={"ahoy;": 1}; vienna="finger;"',
{"vienna": "finger;"},
),
(
"Ignore cookies without a name",
"a=b; unnamed; c=d",
{"a": "b", "c": "d"},
),
(
"Ignore '\"' cookie without name",
'a=b; "; c=d',
{"a": "b", "c": "d"},
),
(
"Skip all space separated values",
"x a=b c=d x; e=f",
{"a": "b", "c": "d", "e": "f"},
),
(
"Skip all space separated values",
'x a=b; data={"complex": "json", "with": "key=value"}; x c=d x',
{"a": "b", "c": "d"},
),
(
"Expect quote mending",
'a=b; invalid="; c=d',
{"a": "b", "c": "d"},
),
(
"Reset morsel after invalid to not capture attributes",
"a=b; invalid; Version=1; c=d",
{"a": "b", "c": "d"},
),
(
"Reset morsel after invalid to not capture attributes",
"a=b; $invalid; $Version=1; c=d",
{"a": "b", "c": "d"},
),
(
"Continue after non-flag attribute without value",
"a=b; path; Version=1; c=d",
{"a": "b", "c": "d"},
),
(
"Allow cookie attributes with `$` prefix",
'Customer="WILE_E_COYOTE"; $Version=1; $Secure; $Path=/acme',
{"Customer": ("WILE_E_COYOTE", {"version": "1", "secure": True, "path": "/acme"})},
),
(
"Invalid Morsel keys should not result in an error",
"Key=Value; [Invalid]=Value; Another=Value",
{"Key": "Value", "Another": "Value"},
),
)

@ -1,37 +1,39 @@
#!/usr/bin/env python3
# Allow direct execution
import hashlib
import json
import os
import socket
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import collections
import hashlib
import json
from test.helper import (
assertGreaterEqual,
expect_info_dict,
expect_warnings,
get_params,
gettestcases,
getwebpagetestcases,
is_download_test,
report_warning,
try_rm,
)
import yt_dlp.YoutubeDL
from yt_dlp.compat import (
compat_http_client,
compat_HTTPError,
compat_urllib_error,
)
import yt_dlp.YoutubeDL # isort: split
from yt_dlp.extractor import get_info_extractor
from yt_dlp.networking.exceptions import HTTPError, TransportError
from yt_dlp.utils import (
DownloadError,
ExtractorError,
UnavailableVideoError,
YoutubeDLError,
format_bytes,
join_nonempty,
)
RETRIES = 3
@ -57,7 +59,9 @@ def _file_md5(fn):
return hashlib.md5(f.read()).hexdigest()
defs = gettestcases()
normal_test_cases = gettestcases()
webpage_test_cases = getwebpagetestcases()
tests_counter = collections.defaultdict(collections.Counter)
@is_download_test
@ -72,24 +76,13 @@ class TestDownload(unittest.TestCase):
def __str__(self):
"""Identify each test with the `add_ie` attribute, if available."""
cls, add_ie = type(self), getattr(self, self._testMethodName).add_ie
return f'{self._testMethodName} ({cls.__module__}.{cls.__name__}){f" [{add_ie}]" if add_ie else ""}:'
def strclass(cls):
"""From 2.7's unittest; 2.6 had _strclass so we can't import it."""
return f'{cls.__module__}.{cls.__name__}'
add_ie = getattr(self, self._testMethodName).add_ie
return '%s (%s)%s:' % (self._testMethodName,
strclass(self.__class__),
' [%s]' % add_ie if add_ie else '')
def setUp(self):
self.defs = defs
# Dynamically generate tests
def generator(test_case, tname):
def test_template(self):
if self.COMPLETED_TESTS.get(tname):
return
@ -108,14 +101,16 @@ def generator(test_case, tname):
print_skipping('IE marked as not _WORKING')
for tc in test_cases:
if tc.get('expected_exception'):
continue
info_dict = tc.get('info_dict', {})
params = tc.get('params', {})
if not info_dict.get('id'):
raise Exception('Test definition incorrect. \'id\' key is not present')
elif not info_dict.get('ext'):
raise Exception(f'Test {tname} definition incorrect - "id" key is not present')
elif not info_dict.get('ext') and info_dict.get('_type', 'video') == 'video':
if params.get('skip_download') and params.get('ignore_no_formats_error'):
continue
raise Exception('Test definition incorrect. The output file cannot be known. \'ext\' key is not present')
raise Exception(f'Test {tname} definition incorrect - "ext" key must be present to define the output file')
if 'skip' in test_case:
print_skipping(test_case['skip'])
@ -128,7 +123,8 @@ def generator(test_case, tname):
params['outtmpl'] = tname + '_' + params['outtmpl']
if is_playlist and 'playlist' not in test_case:
params.setdefault('extract_flat', 'in_playlist')
params.setdefault('playlistend', test_case.get('playlist_mincount'))
params.setdefault('playlistend', test_case.get(
'playlist_mincount', test_case.get('playlist_count', -2) + 1))
params.setdefault('skip_download', True)
ydl = YoutubeDL(params, auto_init=False)
@ -146,6 +142,17 @@ def generator(test_case, tname):
res_dict = None
def match_exception(err):
expected_exception = test_case.get('expected_exception')
if not expected_exception:
return False
if err.__class__.__name__ == expected_exception:
return True
for exc in err.exc_info:
if exc.__class__.__name__ == expected_exception:
return True
return False
def try_rm_tcs_files(tcs=None):
if tcs is None:
tcs = test_cases
@ -167,7 +174,10 @@ def generator(test_case, tname):
force_generic_extractor=params.get('force_generic_extractor', False))
except (DownloadError, ExtractorError) as err:
# Check if the exception is not a network related one
if not err.exc_info[0] in (compat_urllib_error.URLError, socket.timeout, UnavailableVideoError, compat_http_client.BadStatusLine) or (err.exc_info[0] == compat_HTTPError and err.exc_info[1].code == 503):
if not isinstance(err.exc_info[1], (TransportError, UnavailableVideoError)) or (isinstance(err.exc_info[1], HTTPError) and err.exc_info[1].status == 503):
if match_exception(err):
return
err.msg = f'{getattr(err, "msg", err)} ({tname})'
raise
if try_num == RETRIES:
@ -177,6 +187,10 @@ def generator(test_case, tname):
print(f'Retrying: {try_num} failed tries\n\n##########\n\n')
try_num += 1
except YoutubeDLError as err:
if match_exception(err):
return
raise
else:
break
@ -216,6 +230,8 @@ def generator(test_case, tname):
tc_res_dict = res_dict['entries'][tc_num]
# First, check test cases' data against extracted data alone
expect_info_dict(self, tc_res_dict, tc.get('info_dict', {}))
if tc_res_dict.get('_type', 'video') != 'video':
continue
# Now, check downloaded file consistency
tc_filename = get_tc_filename(tc)
if not test_case.get('params', {}).get('skip_download', False):
@ -250,40 +266,48 @@ def generator(test_case, tname):
# extractor returns full results even with extract_flat
res_tcs = [{'info_dict': e} for e in res_dict['entries']]
try_rm_tcs_files(res_tcs)
ydl.close()
return test_template
# And add them to TestDownload
tests_counter = {}
for test_case in defs:
name = test_case['name']
i = tests_counter.get(name, 0)
tests_counter[name] = i + 1
tname = f'test_{name}_{i}' if i else f'test_{name}'
test_method = generator(test_case, tname)
test_method.__name__ = str(tname)
ie_list = test_case.get('add_ie')
test_method.add_ie = ie_list and ','.join(ie_list)
setattr(TestDownload, test_method.__name__, test_method)
del test_method
def inject_tests(test_cases, label=''):
for test_case in test_cases:
name = test_case['name']
tname = join_nonempty('test', name, label, tests_counter[name][label], delim='_')
tests_counter[name][label] += 1
test_method = generator(test_case, tname)
test_method.__name__ = tname
test_method.add_ie = ','.join(test_case.get('add_ie', []))
setattr(TestDownload, test_method.__name__, test_method)
inject_tests(normal_test_cases)
def batch_generator(name, num_tests):
# TODO: disable redirection to the IE to ensure we are actually testing the webpage extraction
inject_tests(webpage_test_cases, 'webpage')
def batch_generator(name):
def test_template(self):
for i in range(num_tests):
getattr(self, f'test_{name}_{i}' if i else f'test_{name}')()
for label, num_tests in tests_counter[name].items():
for i in range(num_tests):
test_name = join_nonempty('test', name, label, i, delim='_')
try:
getattr(self, test_name)()
except unittest.SkipTest:
print(f'Skipped {test_name}')
return test_template
for name, num_tests in tests_counter.items():
test_method = batch_generator(name, num_tests)
for name in tests_counter:
test_method = batch_generator(name)
test_method.__name__ = f'test_{name}_all'
test_method.add_ie = ''
setattr(TestDownload, test_method.__name__, test_method)
del test_method
del test_method
if __name__ == '__main__':

@ -0,0 +1,139 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import http.cookiejar
from test.helper import FakeYDL
from yt_dlp.downloader.external import (
Aria2cFD,
AxelFD,
CurlFD,
FFmpegFD,
HttpieFD,
WgetFD,
)
TEST_COOKIE = {
'version': 0,
'name': 'test',
'value': 'ytdlp',
'port': None,
'port_specified': False,
'domain': '.example.com',
'domain_specified': True,
'domain_initial_dot': False,
'path': '/',
'path_specified': True,
'secure': False,
'expires': None,
'discard': False,
'comment': None,
'comment_url': None,
'rest': {},
}
TEST_INFO = {'url': 'http://www.example.com/'}
class TestHttpieFD(unittest.TestCase):
def test_make_cmd(self):
with FakeYDL() as ydl:
downloader = HttpieFD(ydl, {})
self.assertEqual(
downloader._make_cmd('test', TEST_INFO),
['http', '--download', '--output', 'test', 'http://www.example.com/'])
# Test cookie header is added
ydl.cookiejar.set_cookie(http.cookiejar.Cookie(**TEST_COOKIE))
self.assertEqual(
downloader._make_cmd('test', TEST_INFO),
['http', '--download', '--output', 'test', 'http://www.example.com/', 'Cookie:test=ytdlp'])
class TestAxelFD(unittest.TestCase):
def test_make_cmd(self):
with FakeYDL() as ydl:
downloader = AxelFD(ydl, {})
self.assertEqual(
downloader._make_cmd('test', TEST_INFO),
['axel', '-o', 'test', '--', 'http://www.example.com/'])
# Test cookie header is added
ydl.cookiejar.set_cookie(http.cookiejar.Cookie(**TEST_COOKIE))
self.assertEqual(
downloader._make_cmd('test', TEST_INFO),
['axel', '-o', 'test', '-H', 'Cookie: test=ytdlp', '--max-redirect=0', '--', 'http://www.example.com/'])
class TestWgetFD(unittest.TestCase):
def test_make_cmd(self):
with FakeYDL() as ydl:
downloader = WgetFD(ydl, {})
self.assertNotIn('--load-cookies', downloader._make_cmd('test', TEST_INFO))
# Test cookiejar tempfile arg is added
ydl.cookiejar.set_cookie(http.cookiejar.Cookie(**TEST_COOKIE))
self.assertIn('--load-cookies', downloader._make_cmd('test', TEST_INFO))
class TestCurlFD(unittest.TestCase):
def test_make_cmd(self):
with FakeYDL() as ydl:
downloader = CurlFD(ydl, {})
self.assertNotIn('--cookie', downloader._make_cmd('test', TEST_INFO))
# Test cookie header is added
ydl.cookiejar.set_cookie(http.cookiejar.Cookie(**TEST_COOKIE))
self.assertIn('--cookie', downloader._make_cmd('test', TEST_INFO))
self.assertIn('test=ytdlp', downloader._make_cmd('test', TEST_INFO))
class TestAria2cFD(unittest.TestCase):
def test_make_cmd(self):
with FakeYDL() as ydl:
downloader = Aria2cFD(ydl, {})
downloader._make_cmd('test', TEST_INFO)
self.assertFalse(hasattr(downloader, '_cookies_tempfile'))
# Test cookiejar tempfile arg is added
ydl.cookiejar.set_cookie(http.cookiejar.Cookie(**TEST_COOKIE))
cmd = downloader._make_cmd('test', TEST_INFO)
self.assertIn(f'--load-cookies={downloader._cookies_tempfile}', cmd)
@unittest.skipUnless(FFmpegFD.available(), 'ffmpeg not found')
class TestFFmpegFD(unittest.TestCase):
_args = []
def _test_cmd(self, args):
self._args = args
def test_make_cmd(self):
with FakeYDL() as ydl:
downloader = FFmpegFD(ydl, {})
downloader._debug_cmd = self._test_cmd
downloader._call_downloader('test', {**TEST_INFO, 'ext': 'mp4'})
self.assertEqual(self._args, [
'ffmpeg', '-y', '-hide_banner', '-i', 'http://www.example.com/',
'-c', 'copy', '-f', 'mp4', 'file:test'])
# Test cookies arg is added
ydl.cookiejar.set_cookie(http.cookiejar.Cookie(**TEST_COOKIE))
downloader._call_downloader('test', {**TEST_INFO, 'ext': 'mp4'})
self.assertEqual(self._args, [
'ffmpeg', '-y', '-hide_banner', '-cookies', 'test=ytdlp; path=/; domain=.example.com;\r\n',
'-i', 'http://www.example.com/', '-c', 'copy', '-f', 'mp4', 'file:test'])
# Test with non-url input (ffmpeg reads from stdin '-' for websockets)
downloader._call_downloader('test', {'url': 'x', 'ext': 'mp4'})
self.assertEqual(self._args, [
'ffmpeg', '-y', '-hide_banner', '-i', 'x', '-c', 'copy', '-f', 'mp4', 'file:test'])
if __name__ == '__main__':
unittest.main()

@ -1,19 +1,22 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import re
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import http.server
import re
import threading
from test.helper import http_server_port, try_rm
from test.helper import http_server_port, try_rm
from yt_dlp import YoutubeDL
from yt_dlp.compat import compat_http_server
from yt_dlp.downloader.http import HttpFD
from yt_dlp.utils import encodeFilename
from yt_dlp.utils._utils import _YDLLogger as FakeLogger
TEST_DIR = os.path.dirname(os.path.abspath(__file__))
@ -21,7 +24,7 @@ TEST_DIR = os.path.dirname(os.path.abspath(__file__))
TEST_SIZE = 10 * 1024
class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
class HTTPTestRequestHandler(http.server.BaseHTTPRequestHandler):
def log_message(self, format, *args):
pass
@ -65,20 +68,9 @@ class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
assert False
class FakeLogger:
def debug(self, msg):
pass
def warning(self, msg):
pass
def error(self, msg):
pass
class TestHttpFD(unittest.TestCase):
def setUp(self):
self.httpd = compat_http_server.HTTPServer(
self.httpd = http.server.HTTPServer(
('127.0.0.1', 0), HTTPTestRequestHandler)
self.port = http_server_port(self.httpd)
self.server_thread = threading.Thread(target=self.httpd.serve_forever)
@ -93,8 +85,8 @@ class TestHttpFD(unittest.TestCase):
try_rm(encodeFilename(filename))
self.assertTrue(downloader.real_download(filename, {
'url': 'http://127.0.0.1:%d/%s' % (self.port, ep),
}))
self.assertEqual(os.path.getsize(encodeFilename(filename)), TEST_SIZE)
}), ep)
self.assertEqual(os.path.getsize(encodeFilename(filename)), TEST_SIZE, ep)
try_rm(encodeFilename(filename))
def download_all(self, params):

@ -1,47 +1,59 @@
#!/usr/bin/env python3
import contextlib
# Allow direct execution
import os
import subprocess
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from yt_dlp.utils import encodeArgument
rootDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
import contextlib
import subprocess
from yt_dlp.utils import Popen
try:
_DEV_NULL = subprocess.DEVNULL
except AttributeError:
_DEV_NULL = open(os.devnull, 'wb')
rootDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
LAZY_EXTRACTORS = 'yt_dlp/extractor/lazy_extractors.py'
class TestExecution(unittest.TestCase):
def run_yt_dlp(self, exe=(sys.executable, 'yt_dlp/__main__.py'), opts=('--version', )):
stdout, stderr, returncode = Popen.run(
[*exe, '--ignore-config', *opts], cwd=rootDir, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(stderr, file=sys.stderr)
self.assertEqual(returncode, 0)
return stdout.strip(), stderr.strip()
def test_main_exec(self):
self.run_yt_dlp()
def test_import(self):
subprocess.check_call([sys.executable, '-c', 'import yt_dlp'], cwd=rootDir)
self.run_yt_dlp(exe=(sys.executable, '-c', 'import yt_dlp'))
def test_module_exec(self):
subprocess.check_call([sys.executable, '-m', 'yt_dlp', '--ignore-config', '--version'], cwd=rootDir, stdout=_DEV_NULL)
def test_main_exec(self):
subprocess.check_call([sys.executable, 'yt_dlp/__main__.py', '--ignore-config', '--version'], cwd=rootDir, stdout=_DEV_NULL)
self.run_yt_dlp(exe=(sys.executable, '-m', 'yt_dlp'))
def test_cmdline_umlauts(self):
p = subprocess.Popen(
[sys.executable, 'yt_dlp/__main__.py', '--ignore-config', encodeArgument('ä'), '--version'],
cwd=rootDir, stdout=_DEV_NULL, stderr=subprocess.PIPE)
_, stderr = p.communicate()
_, stderr = self.run_yt_dlp(opts=('ä', '--version'))
self.assertFalse(stderr)
def test_lazy_extractors(self):
try:
subprocess.check_call([sys.executable, 'devscripts/make_lazy_extractors.py', 'yt_dlp/extractor/lazy_extractors.py'], cwd=rootDir, stdout=_DEV_NULL)
subprocess.check_call([sys.executable, 'test/test_all_urls.py'], cwd=rootDir, stdout=_DEV_NULL)
subprocess.check_call([sys.executable, 'devscripts/make_lazy_extractors.py', LAZY_EXTRACTORS],
cwd=rootDir, stdout=subprocess.DEVNULL)
self.assertTrue(os.path.exists(LAZY_EXTRACTORS))
_, stderr = self.run_yt_dlp(opts=('-s', 'test:'))
# `MIN_RECOMMENDED` emits a deprecated feature warning for deprecated Python versions
if stderr and stderr.startswith('Deprecated Feature: Support for Python'):
stderr = ''
self.assertFalse(stderr)
subprocess.check_call([sys.executable, 'test/test_all_urls.py'], cwd=rootDir, stdout=subprocess.DEVNULL)
finally:
with contextlib.suppress(OSError):
os.remove('yt_dlp/extractor/lazy_extractors.py')
os.remove(LAZY_EXTRACTORS)
if __name__ == '__main__':

@ -1,189 +0,0 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import ssl
import threading
from test.helper import http_server_port
from yt_dlp import YoutubeDL
from yt_dlp.compat import compat_http_server, compat_urllib_request
TEST_DIR = os.path.dirname(os.path.abspath(__file__))
class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
def log_message(self, format, *args):
pass
def do_GET(self):
if self.path == '/video.html':
self.send_response(200)
self.send_header('Content-Type', 'text/html; charset=utf-8')
self.end_headers()
self.wfile.write(b'<html><video src="/vid.mp4" /></html>')
elif self.path == '/vid.mp4':
self.send_response(200)
self.send_header('Content-Type', 'video/mp4')
self.end_headers()
self.wfile.write(b'\x00\x00\x00\x00\x20\x66\x74[video]')
elif self.path == '/%E4%B8%AD%E6%96%87.html':
self.send_response(200)
self.send_header('Content-Type', 'text/html; charset=utf-8')
self.end_headers()
self.wfile.write(b'<html><video src="/vid.mp4" /></html>')
else:
assert False
class FakeLogger:
def debug(self, msg):
pass
def warning(self, msg):
pass
def error(self, msg):
pass
class TestHTTP(unittest.TestCase):
def setUp(self):
self.httpd = compat_http_server.HTTPServer(
('127.0.0.1', 0), HTTPTestRequestHandler)
self.port = http_server_port(self.httpd)
self.server_thread = threading.Thread(target=self.httpd.serve_forever)
self.server_thread.daemon = True
self.server_thread.start()
class TestHTTPS(unittest.TestCase):
def setUp(self):
certfn = os.path.join(TEST_DIR, 'testcert.pem')
self.httpd = compat_http_server.HTTPServer(
('127.0.0.1', 0), HTTPTestRequestHandler)
sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
sslctx.load_cert_chain(certfn, None)
self.httpd.socket = sslctx.wrap_socket(self.httpd.socket, server_side=True)
self.port = http_server_port(self.httpd)
self.server_thread = threading.Thread(target=self.httpd.serve_forever)
self.server_thread.daemon = True
self.server_thread.start()
def test_nocheckcertificate(self):
ydl = YoutubeDL({'logger': FakeLogger()})
self.assertRaises(
Exception,
ydl.extract_info, 'https://127.0.0.1:%d/video.html' % self.port)
ydl = YoutubeDL({'logger': FakeLogger(), 'nocheckcertificate': True})
r = ydl.extract_info('https://127.0.0.1:%d/video.html' % self.port)
self.assertEqual(r['entries'][0]['url'], 'https://127.0.0.1:%d/vid.mp4' % self.port)
class TestClientCert(unittest.TestCase):
def setUp(self):
certfn = os.path.join(TEST_DIR, 'testcert.pem')
self.certdir = os.path.join(TEST_DIR, 'testdata', 'certificate')
cacertfn = os.path.join(self.certdir, 'ca.crt')
self.httpd = compat_http_server.HTTPServer(('127.0.0.1', 0), HTTPTestRequestHandler)
sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
sslctx.verify_mode = ssl.CERT_REQUIRED
sslctx.load_verify_locations(cafile=cacertfn)
sslctx.load_cert_chain(certfn, None)
self.httpd.socket = sslctx.wrap_socket(self.httpd.socket, server_side=True)
self.port = http_server_port(self.httpd)
self.server_thread = threading.Thread(target=self.httpd.serve_forever)
self.server_thread.daemon = True
self.server_thread.start()
def _run_test(self, **params):
ydl = YoutubeDL({
'logger': FakeLogger(),
# Disable client-side validation of unacceptable self-signed testcert.pem
# The test is of a check on the server side, so unaffected
'nocheckcertificate': True,
**params,
})
r = ydl.extract_info('https://127.0.0.1:%d/video.html' % self.port)
self.assertEqual(r['entries'][0]['url'], 'https://127.0.0.1:%d/vid.mp4' % self.port)
def test_certificate_combined_nopass(self):
self._run_test(client_certificate=os.path.join(self.certdir, 'clientwithkey.crt'))
def test_certificate_nocombined_nopass(self):
self._run_test(client_certificate=os.path.join(self.certdir, 'client.crt'),
client_certificate_key=os.path.join(self.certdir, 'client.key'))
def test_certificate_combined_pass(self):
self._run_test(client_certificate=os.path.join(self.certdir, 'clientwithencryptedkey.crt'),
client_certificate_password='foobar')
def test_certificate_nocombined_pass(self):
self._run_test(client_certificate=os.path.join(self.certdir, 'client.crt'),
client_certificate_key=os.path.join(self.certdir, 'clientencrypted.key'),
client_certificate_password='foobar')
def _build_proxy_handler(name):
class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
proxy_name = name
def log_message(self, format, *args):
pass
def do_GET(self):
self.send_response(200)
self.send_header('Content-Type', 'text/plain; charset=utf-8')
self.end_headers()
self.wfile.write(f'{self.proxy_name}: {self.path}'.encode())
return HTTPTestRequestHandler
class TestProxy(unittest.TestCase):
def setUp(self):
self.proxy = compat_http_server.HTTPServer(
('127.0.0.1', 0), _build_proxy_handler('normal'))
self.port = http_server_port(self.proxy)
self.proxy_thread = threading.Thread(target=self.proxy.serve_forever)
self.proxy_thread.daemon = True
self.proxy_thread.start()
self.geo_proxy = compat_http_server.HTTPServer(
('127.0.0.1', 0), _build_proxy_handler('geo'))
self.geo_port = http_server_port(self.geo_proxy)
self.geo_proxy_thread = threading.Thread(target=self.geo_proxy.serve_forever)
self.geo_proxy_thread.daemon = True
self.geo_proxy_thread.start()
def test_proxy(self):
geo_proxy = f'127.0.0.1:{self.geo_port}'
ydl = YoutubeDL({
'proxy': f'127.0.0.1:{self.port}',
'geo_verification_proxy': geo_proxy,
})
url = 'http://foo.com/bar'
response = ydl.urlopen(url).read().decode()
self.assertEqual(response, f'normal: {url}')
req = compat_urllib_request.Request(url)
req.add_header('Ytdl-request-proxy', geo_proxy)
response = ydl.urlopen(req).read().decode()
self.assertEqual(response, f'geo: {url}')
def test_proxy_with_idn(self):
ydl = YoutubeDL({
'proxy': f'127.0.0.1:{self.port}',
})
url = 'http://中文.tw/'
response = ydl.urlopen(url).read().decode()
# b'xn--fiq228c' is '中文'.encode('idna')
self.assertEqual(response, 'normal: http://xn--fiq228c.tw/')
if __name__ == '__main__':
unittest.main()

@ -0,0 +1,379 @@
import abc
import base64
import contextlib
import functools
import json
import os
import random
import ssl
import threading
from http.server import BaseHTTPRequestHandler
from socketserver import ThreadingTCPServer
import pytest
from test.helper import http_server_port, verify_address_availability
from test.test_networking import TEST_DIR
from test.test_socks import IPv6ThreadingTCPServer
from yt_dlp.dependencies import urllib3
from yt_dlp.networking import Request
from yt_dlp.networking.exceptions import HTTPError, ProxyError, SSLError
class HTTPProxyAuthMixin:
def proxy_auth_error(self):
self.send_response(407)
self.send_header('Proxy-Authenticate', 'Basic realm="test http proxy"')
self.end_headers()
return False
def do_proxy_auth(self, username, password):
if username is None and password is None:
return True
proxy_auth_header = self.headers.get('Proxy-Authorization', None)
if proxy_auth_header is None:
return self.proxy_auth_error()
if not proxy_auth_header.startswith('Basic '):
return self.proxy_auth_error()
auth = proxy_auth_header[6:]
try:
auth_username, auth_password = base64.b64decode(auth).decode().split(':', 1)
except Exception:
return self.proxy_auth_error()
if auth_username != (username or '') or auth_password != (password or ''):
return self.proxy_auth_error()
return True
class HTTPProxyHandler(BaseHTTPRequestHandler, HTTPProxyAuthMixin):
def __init__(self, *args, proxy_info=None, username=None, password=None, request_handler=None, **kwargs):
self.username = username
self.password = password
self.proxy_info = proxy_info
super().__init__(*args, **kwargs)
def do_GET(self):
if not self.do_proxy_auth(self.username, self.password):
self.server.close_request(self.request)
return
if self.path.endswith('/proxy_info'):
payload = json.dumps(self.proxy_info or {
'client_address': self.client_address,
'connect': False,
'connect_host': None,
'connect_port': None,
'headers': dict(self.headers),
'path': self.path,
'proxy': ':'.join(str(y) for y in self.connection.getsockname()),
})
self.send_response(200)
self.send_header('Content-Type', 'application/json; charset=utf-8')
self.send_header('Content-Length', str(len(payload)))
self.end_headers()
self.wfile.write(payload.encode())
else:
self.send_response(404)
self.end_headers()
self.server.close_request(self.request)
if urllib3:
import urllib3.util.ssltransport
class SSLTransport(urllib3.util.ssltransport.SSLTransport):
"""
Modified version of urllib3 SSLTransport to support server side SSL
This allows us to chain multiple TLS connections.
"""
def __init__(self, socket, ssl_context, server_hostname=None, suppress_ragged_eofs=True, server_side=False):
self.incoming = ssl.MemoryBIO()
self.outgoing = ssl.MemoryBIO()
self.suppress_ragged_eofs = suppress_ragged_eofs
self.socket = socket
self.sslobj = ssl_context.wrap_bio(
self.incoming,
self.outgoing,
server_hostname=server_hostname,
server_side=server_side
)
self._ssl_io_loop(self.sslobj.do_handshake)
@property
def _io_refs(self):
return self.socket._io_refs
@_io_refs.setter
def _io_refs(self, value):
self.socket._io_refs = value
def shutdown(self, *args, **kwargs):
self.socket.shutdown(*args, **kwargs)
else:
SSLTransport = None
class HTTPSProxyHandler(HTTPProxyHandler):
def __init__(self, request, *args, **kwargs):
certfn = os.path.join(TEST_DIR, 'testcert.pem')
sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
sslctx.load_cert_chain(certfn, None)
if isinstance(request, ssl.SSLSocket):
request = SSLTransport(request, ssl_context=sslctx, server_side=True)
else:
request = sslctx.wrap_socket(request, server_side=True)
super().__init__(request, *args, **kwargs)
class HTTPConnectProxyHandler(BaseHTTPRequestHandler, HTTPProxyAuthMixin):
protocol_version = 'HTTP/1.1'
default_request_version = 'HTTP/1.1'
def __init__(self, *args, username=None, password=None, request_handler=None, **kwargs):
self.username = username
self.password = password
self.request_handler = request_handler
super().__init__(*args, **kwargs)
def do_CONNECT(self):
if not self.do_proxy_auth(self.username, self.password):
self.server.close_request(self.request)
return
self.send_response(200)
self.end_headers()
proxy_info = {
'client_address': self.client_address,
'connect': True,
'connect_host': self.path.split(':')[0],
'connect_port': int(self.path.split(':')[1]),
'headers': dict(self.headers),
'path': self.path,
'proxy': ':'.join(str(y) for y in self.connection.getsockname()),
}
self.request_handler(self.request, self.client_address, self.server, proxy_info=proxy_info)
self.server.close_request(self.request)
class HTTPSConnectProxyHandler(HTTPConnectProxyHandler):
def __init__(self, request, *args, **kwargs):
certfn = os.path.join(TEST_DIR, 'testcert.pem')
sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
sslctx.load_cert_chain(certfn, None)
request = sslctx.wrap_socket(request, server_side=True)
self._original_request = request
super().__init__(request, *args, **kwargs)
def do_CONNECT(self):
super().do_CONNECT()
self.server.close_request(self._original_request)
@contextlib.contextmanager
def proxy_server(proxy_server_class, request_handler, bind_ip=None, **proxy_server_kwargs):
server = server_thread = None
try:
bind_address = bind_ip or '127.0.0.1'
server_type = ThreadingTCPServer if '.' in bind_address else IPv6ThreadingTCPServer
server = server_type(
(bind_address, 0), functools.partial(proxy_server_class, request_handler=request_handler, **proxy_server_kwargs))
server_port = http_server_port(server)
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
if '.' not in bind_address:
yield f'[{bind_address}]:{server_port}'
else:
yield f'{bind_address}:{server_port}'
finally:
server.shutdown()
server.server_close()
server_thread.join(2.0)
class HTTPProxyTestContext(abc.ABC):
REQUEST_HANDLER_CLASS = None
REQUEST_PROTO = None
def http_server(self, server_class, *args, **kwargs):
return proxy_server(server_class, self.REQUEST_HANDLER_CLASS, *args, **kwargs)
@abc.abstractmethod
def proxy_info_request(self, handler, target_domain=None, target_port=None, **req_kwargs) -> dict:
"""return a dict of proxy_info"""
class HTTPProxyHTTPTestContext(HTTPProxyTestContext):
# Standard HTTP Proxy for http requests
REQUEST_HANDLER_CLASS = HTTPProxyHandler
REQUEST_PROTO = 'http'
def proxy_info_request(self, handler, target_domain=None, target_port=None, **req_kwargs):
request = Request(f'http://{target_domain or "127.0.0.1"}:{target_port or "40000"}/proxy_info', **req_kwargs)
handler.validate(request)
return json.loads(handler.send(request).read().decode())
class HTTPProxyHTTPSTestContext(HTTPProxyTestContext):
# HTTP Connect proxy, for https requests
REQUEST_HANDLER_CLASS = HTTPSProxyHandler
REQUEST_PROTO = 'https'
def proxy_info_request(self, handler, target_domain=None, target_port=None, **req_kwargs):
request = Request(f'https://{target_domain or "127.0.0.1"}:{target_port or "40000"}/proxy_info', **req_kwargs)
handler.validate(request)
return json.loads(handler.send(request).read().decode())
CTX_MAP = {
'http': HTTPProxyHTTPTestContext,
'https': HTTPProxyHTTPSTestContext,
}
@pytest.fixture(scope='module')
def ctx(request):
return CTX_MAP[request.param]()
@pytest.mark.parametrize(
'handler', ['Urllib', 'Requests', 'CurlCFFI'], indirect=True)
@pytest.mark.parametrize('ctx', ['http'], indirect=True) # pure http proxy can only support http
class TestHTTPProxy:
def test_http_no_auth(self, handler, ctx):
with ctx.http_server(HTTPProxyHandler) as server_address:
with handler(proxies={ctx.REQUEST_PROTO: f'http://{server_address}'}) as rh:
proxy_info = ctx.proxy_info_request(rh)
assert proxy_info['proxy'] == server_address
assert proxy_info['connect'] is False
assert 'Proxy-Authorization' not in proxy_info['headers']
def test_http_auth(self, handler, ctx):
with ctx.http_server(HTTPProxyHandler, username='test', password='test') as server_address:
with handler(proxies={ctx.REQUEST_PROTO: f'http://test:test@{server_address}'}) as rh:
proxy_info = ctx.proxy_info_request(rh)
assert proxy_info['proxy'] == server_address
assert 'Proxy-Authorization' in proxy_info['headers']
def test_http_bad_auth(self, handler, ctx):
with ctx.http_server(HTTPProxyHandler, username='test', password='test') as server_address:
with handler(proxies={ctx.REQUEST_PROTO: f'http://test:bad@{server_address}'}) as rh:
with pytest.raises(HTTPError) as exc_info:
ctx.proxy_info_request(rh)
assert exc_info.value.response.status == 407
exc_info.value.response.close()
def test_http_source_address(self, handler, ctx):
with ctx.http_server(HTTPProxyHandler) as server_address:
source_address = f'127.0.0.{random.randint(5, 255)}'
verify_address_availability(source_address)
with handler(proxies={ctx.REQUEST_PROTO: f'http://{server_address}'},
source_address=source_address) as rh:
proxy_info = ctx.proxy_info_request(rh)
assert proxy_info['proxy'] == server_address
assert proxy_info['client_address'][0] == source_address
@pytest.mark.skip_handler('Urllib', 'urllib does not support https proxies')
def test_https(self, handler, ctx):
with ctx.http_server(HTTPSProxyHandler) as server_address:
with handler(verify=False, proxies={ctx.REQUEST_PROTO: f'https://{server_address}'}) as rh:
proxy_info = ctx.proxy_info_request(rh)
assert proxy_info['proxy'] == server_address
assert proxy_info['connect'] is False
assert 'Proxy-Authorization' not in proxy_info['headers']
@pytest.mark.skip_handler('Urllib', 'urllib does not support https proxies')
def test_https_verify_failed(self, handler, ctx):
with ctx.http_server(HTTPSProxyHandler) as server_address:
with handler(verify=True, proxies={ctx.REQUEST_PROTO: f'https://{server_address}'}) as rh:
# Accept SSLError as may not be feasible to tell if it is proxy or request error.
# note: if request proto also does ssl verification, this may also be the error of the request.
# Until we can support passing custom cacerts to handlers, we cannot properly test this for all cases.
with pytest.raises((ProxyError, SSLError)):
ctx.proxy_info_request(rh)
def test_http_with_idn(self, handler, ctx):
with ctx.http_server(HTTPProxyHandler) as server_address:
with handler(proxies={ctx.REQUEST_PROTO: f'http://{server_address}'}) as rh:
proxy_info = ctx.proxy_info_request(rh, target_domain='中文.tw')
assert proxy_info['proxy'] == server_address
assert proxy_info['path'].startswith('http://xn--fiq228c.tw')
assert proxy_info['headers']['Host'].split(':', 1)[0] == 'xn--fiq228c.tw'
@pytest.mark.parametrize(
'handler,ctx', [
('Requests', 'https'),
('CurlCFFI', 'https'),
], indirect=True)
class TestHTTPConnectProxy:
def test_http_connect_no_auth(self, handler, ctx):
with ctx.http_server(HTTPConnectProxyHandler) as server_address:
with handler(verify=False, proxies={ctx.REQUEST_PROTO: f'http://{server_address}'}) as rh:
proxy_info = ctx.proxy_info_request(rh)
assert proxy_info['proxy'] == server_address
assert proxy_info['connect'] is True
assert 'Proxy-Authorization' not in proxy_info['headers']
def test_http_connect_auth(self, handler, ctx):
with ctx.http_server(HTTPConnectProxyHandler, username='test', password='test') as server_address:
with handler(verify=False, proxies={ctx.REQUEST_PROTO: f'http://test:test@{server_address}'}) as rh:
proxy_info = ctx.proxy_info_request(rh)
assert proxy_info['proxy'] == server_address
assert 'Proxy-Authorization' in proxy_info['headers']
@pytest.mark.skip_handler(
'Requests',
'bug in urllib3 causes unclosed socket: https://github.com/urllib3/urllib3/issues/3374'
)
def test_http_connect_bad_auth(self, handler, ctx):
with ctx.http_server(HTTPConnectProxyHandler, username='test', password='test') as server_address:
with handler(verify=False, proxies={ctx.REQUEST_PROTO: f'http://test:bad@{server_address}'}) as rh:
with pytest.raises(ProxyError):
ctx.proxy_info_request(rh)
def test_http_connect_source_address(self, handler, ctx):
with ctx.http_server(HTTPConnectProxyHandler) as server_address:
source_address = f'127.0.0.{random.randint(5, 255)}'
verify_address_availability(source_address)
with handler(proxies={ctx.REQUEST_PROTO: f'http://{server_address}'},
source_address=source_address,
verify=False) as rh:
proxy_info = ctx.proxy_info_request(rh)
assert proxy_info['proxy'] == server_address
assert proxy_info['client_address'][0] == source_address
@pytest.mark.skipif(urllib3 is None, reason='requires urllib3 to test')
def test_https_connect_proxy(self, handler, ctx):
with ctx.http_server(HTTPSConnectProxyHandler) as server_address:
with handler(verify=False, proxies={ctx.REQUEST_PROTO: f'https://{server_address}'}) as rh:
proxy_info = ctx.proxy_info_request(rh)
assert proxy_info['proxy'] == server_address
assert proxy_info['connect'] is True
assert 'Proxy-Authorization' not in proxy_info['headers']
@pytest.mark.skipif(urllib3 is None, reason='requires urllib3 to test')
def test_https_connect_verify_failed(self, handler, ctx):
with ctx.http_server(HTTPSConnectProxyHandler) as server_address:
with handler(verify=True, proxies={ctx.REQUEST_PROTO: f'https://{server_address}'}) as rh:
# Accept SSLError as may not be feasible to tell if it is proxy or request error.
# note: if request proto also does ssl verification, this may also be the error of the request.
# Until we can support passing custom cacerts to handlers, we cannot properly test this for all cases.
with pytest.raises((ProxyError, SSLError)):
ctx.proxy_info_request(rh)
@pytest.mark.skipif(urllib3 is None, reason='requires urllib3 to test')
def test_https_connect_proxy_auth(self, handler, ctx):
with ctx.http_server(HTTPSConnectProxyHandler, username='test', password='test') as server_address:
with handler(verify=False, proxies={ctx.REQUEST_PROTO: f'https://test:test@{server_address}'}) as rh:
proxy_info = ctx.proxy_info_request(rh)
assert proxy_info['proxy'] == server_address
assert 'Proxy-Authorization' in proxy_info['headers']

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
@ -6,8 +7,8 @@ import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from test.helper import FakeYDL, is_download_test
from test.helper import FakeYDL, is_download_test
from yt_dlp.extractor import IqiyiIE

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
@ -6,174 +7,373 @@ import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from yt_dlp.jsinterp import JSInterpreter
import math
from yt_dlp.jsinterp import JS_Undefined, JSInterpreter
class TestJSInterpreter(unittest.TestCase):
def test_basic(self):
jsi = JSInterpreter('function x(){;}')
self.assertEqual(jsi.call_function('x'), None)
jsi = JSInterpreter('function x3(){return 42;}')
self.assertEqual(jsi.call_function('x3'), 42)
class NaN:
pass
jsi = JSInterpreter('var x5 = function(){return 42;}')
self.assertEqual(jsi.call_function('x5'), 42)
class TestJSInterpreter(unittest.TestCase):
def _test(self, jsi_or_code, expected, func='f', args=()):
if isinstance(jsi_or_code, str):
jsi_or_code = JSInterpreter(jsi_or_code)
got = jsi_or_code.call_function(func, *args)
if expected is NaN:
self.assertTrue(math.isnan(got), f'{got} is not NaN')
else:
self.assertEqual(got, expected)
def test_basic(self):
jsi = JSInterpreter('function f(){;}')
self.assertEqual(repr(jsi.extract_function('f')), 'F<f>')
self._test(jsi, None)
self._test('function f(){return 42;}', 42)
self._test('function f(){42}', None)
self._test('var f = function(){return 42;}', 42)
def test_add(self):
self._test('function f(){return 42 + 7;}', 49)
self._test('function f(){return 42 + undefined;}', NaN)
self._test('function f(){return 42 + null;}', 42)
def test_sub(self):
self._test('function f(){return 42 - 7;}', 35)
self._test('function f(){return 42 - undefined;}', NaN)
self._test('function f(){return 42 - null;}', 42)
def test_mul(self):
self._test('function f(){return 42 * 7;}', 294)
self._test('function f(){return 42 * undefined;}', NaN)
self._test('function f(){return 42 * null;}', 0)
def test_div(self):
jsi = JSInterpreter('function f(a, b){return a / b;}')
self._test(jsi, NaN, args=(0, 0))
self._test(jsi, NaN, args=(JS_Undefined, 1))
self._test(jsi, float('inf'), args=(2, 0))
self._test(jsi, 0, args=(0, 3))
def test_mod(self):
self._test('function f(){return 42 % 7;}', 0)
self._test('function f(){return 42 % 0;}', NaN)
self._test('function f(){return 42 % undefined;}', NaN)
def test_exp(self):
self._test('function f(){return 42 ** 2;}', 1764)
self._test('function f(){return 42 ** undefined;}', NaN)
self._test('function f(){return 42 ** null;}', 1)
self._test('function f(){return undefined ** 42;}', NaN)
def test_calc(self):
jsi = JSInterpreter('function x4(a){return 2*a+1;}')
self.assertEqual(jsi.call_function('x4', 3), 7)
self._test('function f(a){return 2*a+1;}', 7, args=[3])
def test_empty_return(self):
jsi = JSInterpreter('function f(){return; y()}')
self.assertEqual(jsi.call_function('f'), None)
self._test('function f(){return; y()}', None)
def test_morespace(self):
jsi = JSInterpreter('function x (a) { return 2 * a + 1 ; }')
self.assertEqual(jsi.call_function('x', 3), 7)
jsi = JSInterpreter('function f () { x = 2 ; return x; }')
self.assertEqual(jsi.call_function('f'), 2)
self._test('function f (a) { return 2 * a + 1 ; }', 7, args=[3])
self._test('function f () { x = 2 ; return x; }', 2)
def test_strange_chars(self):
jsi = JSInterpreter('function $_xY1 ($_axY1) { var $_axY2 = $_axY1 + 1; return $_axY2; }')
self.assertEqual(jsi.call_function('$_xY1', 20), 21)
self._test('function $_xY1 ($_axY1) { var $_axY2 = $_axY1 + 1; return $_axY2; }',
21, args=[20], func='$_xY1')
def test_operators(self):
jsi = JSInterpreter('function f(){return 1 << 5;}')
self.assertEqual(jsi.call_function('f'), 32)
jsi = JSInterpreter('function f(){return 19 & 21;}')
self.assertEqual(jsi.call_function('f'), 17)
jsi = JSInterpreter('function f(){return 11 >> 2;}')
self.assertEqual(jsi.call_function('f'), 2)
self._test('function f(){return 1 << 5;}', 32)
self._test('function f(){return 2 ** 5}', 32)
self._test('function f(){return 19 & 21;}', 17)
self._test('function f(){return 11 >> 2;}', 2)
self._test('function f(){return []? 2+3: 4;}', 5)
self._test('function f(){return 1 == 2}', False)
self._test('function f(){return 0 && 1 || 2;}', 2)
self._test('function f(){return 0 ?? 42;}', 0)
self._test('function f(){return "life, the universe and everything" < 42;}', False)
def test_array_access(self):
jsi = JSInterpreter('function f(){var x = [1,2,3]; x[0] = 4; x[0] = 5; x[2] = 7; return x;}')
self.assertEqual(jsi.call_function('f'), [5, 2, 7])
self._test('function f(){var x = [1,2,3]; x[0] = 4; x[0] = 5; x[2.0] = 7; return x;}', [5, 2, 7])
def test_parens(self):
jsi = JSInterpreter('function f(){return (1) + (2) * ((( (( (((((3)))))) )) ));}')
self.assertEqual(jsi.call_function('f'), 7)
self._test('function f(){return (1) + (2) * ((( (( (((((3)))))) )) ));}', 7)
self._test('function f(){return (1 + 2) * 3;}', 9)
jsi = JSInterpreter('function f(){return (1 + 2) * 3;}')
self.assertEqual(jsi.call_function('f'), 9)
def test_quotes(self):
self._test(R'function f(){return "a\"\\("}', R'a"\(')
def test_assignments(self):
jsi = JSInterpreter('function f(){var x = 20; x = 30 + 1; return x;}')
self.assertEqual(jsi.call_function('f'), 31)
jsi = JSInterpreter('function f(){var x = 20; x += 30 + 1; return x;}')
self.assertEqual(jsi.call_function('f'), 51)
jsi = JSInterpreter('function f(){var x = 20; x -= 30 + 1; return x;}')
self.assertEqual(jsi.call_function('f'), -11)
self._test('function f(){var x = 20; x = 30 + 1; return x;}', 31)
self._test('function f(){var x = 20; x += 30 + 1; return x;}', 51)
self._test('function f(){var x = 20; x -= 30 + 1; return x;}', -11)
@unittest.skip('Not implemented')
def test_comments(self):
'Skipping: Not yet fully implemented'
return
jsi = JSInterpreter('''
function x() {
var x = /* 1 + */ 2;
var y = /* 30
* 40 */ 50;
return x + y;
}
''')
self.assertEqual(jsi.call_function('x'), 52)
jsi = JSInterpreter('''
function f() {
var x = "/*";
var y = 1 /* comment */ + 2;
return y;
}
''')
self.assertEqual(jsi.call_function('f'), 3)
self._test('''
function f() {
var x = /* 1 + */ 2;
var y = /* 30
* 40 */ 50;
return x + y;
}
''', 52)
self._test('''
function f() {
var x = "/*";
var y = 1 /* comment */ + 2;
return y;
}
''', 3)
def test_precedence(self):
jsi = JSInterpreter('''
function x() {
var a = [10, 20, 30, 40, 50];
var b = 6;
a[0]=a[b%a.length];
return a;
}''')
self.assertEqual(jsi.call_function('x'), [20, 20, 30, 40, 50])
self._test('''
function f() {
var a = [10, 20, 30, 40, 50];
var b = 6;
a[0]=a[b%a.length];
return a;
}
''', [20, 20, 30, 40, 50])
def test_builtins(self):
self._test('function f() { return NaN }', NaN)
def test_date(self):
self._test('function f() { return new Date("Wednesday 31 December 1969 18:01:26 MDT") - 0; }', 86000)
jsi = JSInterpreter('function f(dt) { return new Date(dt) - 0; }')
self._test(jsi, 86000, args=['Wednesday 31 December 1969 18:01:26 MDT'])
self._test(jsi, 86000, args=['12/31/1969 18:01:26 MDT']) # m/d/y
self._test(jsi, 0, args=['1 January 1970 00:00:00 UTC'])
def test_call(self):
jsi = JSInterpreter('''
function x() { return 2; }
function y(a) { return x() + a; }
function z() { return y(3); }
function x() { return 2; }
function y(a) { return x() + (a?a:0); }
function z() { return y(3); }
''')
self.assertEqual(jsi.call_function('z'), 5)
self._test(jsi, 5, func='z')
self._test(jsi, 2, func='y')
def test_if(self):
self._test('''
function f() {
let a = 9;
if (0==0) {a++}
return a
}
''', 10)
self._test('''
function f() {
if (0==0) {return 10}
}
''', 10)
self._test('''
function f() {
if (0!=0) {return 1}
else {return 10}
}
''', 10)
""" # Unsupported
self._test('''
function f() {
if (0!=0) {return 1}
else if (1==0) {return 2}
else {return 10}
}
''', 10)
"""
def test_for_loop(self):
jsi = JSInterpreter('''
function x() { a=0; for (i=0; i-10; i++) {a++} a }
''')
self.assertEqual(jsi.call_function('x'), 10)
self._test('function f() { a=0; for (i=0; i-10; i++) {a++} return a }', 10)
def test_switch(self):
jsi = JSInterpreter('''
function x(f) { switch(f){
case 1:f+=1;
case 2:f+=2;
case 3:f+=3;break;
case 4:f+=4;
default:f=0;
} return f }
function f(x) { switch(x){
case 1:x+=1;
case 2:x+=2;
case 3:x+=3;break;
case 4:x+=4;
default:x=0;
} return x }
''')
self.assertEqual(jsi.call_function('x', 1), 7)
self.assertEqual(jsi.call_function('x', 3), 6)
self.assertEqual(jsi.call_function('x', 5), 0)
self._test(jsi, 7, args=[1])
self._test(jsi, 6, args=[3])
self._test(jsi, 0, args=[5])
def test_switch_default(self):
jsi = JSInterpreter('''
function x(f) { switch(f){
case 2: f+=2;
default: f-=1;
case 5:
case 6: f+=6;
case 0: break;
case 1: f+=1;
} return f }
function f(x) { switch(x){
case 2: x+=2;
default: x-=1;
case 5:
case 6: x+=6;
case 0: break;
case 1: x+=1;
} return x }
''')
self.assertEqual(jsi.call_function('x', 1), 2)
self.assertEqual(jsi.call_function('x', 5), 11)
self.assertEqual(jsi.call_function('x', 9), 14)
self._test(jsi, 2, args=[1])
self._test(jsi, 11, args=[5])
self._test(jsi, 14, args=[9])
def test_try(self):
jsi = JSInterpreter('''
function x() { try{return 10} catch(e){return 5} }
''')
self.assertEqual(jsi.call_function('x'), 10)
self._test('function f() { try{return 10} catch(e){return 5} }', 10)
def test_catch(self):
self._test('function f() { try{throw 10} catch(e){return 5} }', 5)
def test_finally(self):
self._test('function f() { try{throw 10} finally {return 42} }', 42)
self._test('function f() { try{throw 10} catch(e){return 5} finally {return 42} }', 42)
def test_nested_try(self):
self._test('''
function f() {try {
try{throw 10} finally {throw 42}
} catch(e){return 5} }
''', 5)
def test_for_loop_continue(self):
jsi = JSInterpreter('''
function x() { a=0; for (i=0; i-10; i++) { continue; a++ } a }
''')
self.assertEqual(jsi.call_function('x'), 0)
self._test('function f() { a=0; for (i=0; i-10; i++) { continue; a++ } return a }', 0)
def test_for_loop_break(self):
jsi = JSInterpreter('''
function x() { a=0; for (i=0; i-10; i++) { break; a++ } a }
''')
self.assertEqual(jsi.call_function('x'), 0)
self._test('function f() { a=0; for (i=0; i-10; i++) { break; a++ } return a }', 0)
def test_for_loop_try(self):
self._test('''
function f() {
for (i=0; i-10; i++) { try { if (i == 5) throw i} catch {return 10} finally {break} };
return 42 }
''', 42)
def test_literal_list(self):
self._test('function f() { return [1, 2, "asdf", [5, 6, 7]][3] }', [5, 6, 7])
def test_comma(self):
self._test('function f() { a=5; a -= 1, a+=3; return a }', 7)
self._test('function f() { a=5; return (a -= 1, a+=3, a); }', 7)
self._test('function f() { return (l=[0,1,2,3], function(a, b){return a+b})((l[1], l[2]), l[3]) }', 5)
def test_void(self):
self._test('function f() { return void 42; }', None)
def test_return_function(self):
jsi = JSInterpreter('''
function x() { [1, 2, "asdf", [5, 6, 7]][3] }
function f() { return [1, function(){return 1}][1] }
''')
self.assertEqual(jsi.call_function('x'), [5, 6, 7])
self.assertEqual(jsi.call_function('f')([]), 1)
def test_null(self):
self._test('function f() { return null; }', None)
self._test('function f() { return [null > 0, null < 0, null == 0, null === 0]; }',
[False, False, False, False])
self._test('function f() { return [null >= 0, null <= 0]; }', [True, True])
def test_undefined(self):
self._test('function f() { return undefined === undefined; }', True)
self._test('function f() { return undefined; }', JS_Undefined)
self._test('function f() {return undefined ?? 42; }', 42)
self._test('function f() { let v; return v; }', JS_Undefined)
self._test('function f() { let v; return v**0; }', 1)
self._test('function f() { let v; return [v>42, v<=42, v&&42, 42&&v]; }',
[False, False, JS_Undefined, JS_Undefined])
self._test('''
function f() { return [
undefined === undefined,
undefined == undefined,
undefined == null,
undefined < undefined,
undefined > undefined,
undefined === 0,
undefined == 0,
undefined < 0,
undefined > 0,
undefined >= 0,
undefined <= 0,
undefined > null,
undefined < null,
undefined === null
]; }
''', list(map(bool, (1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))))
def test_comma(self):
jsi = JSInterpreter('''
function x() { a=5; a -= 1, a+=3; return a }
function f() { let v; return [42+v, v+42, v**42, 42**v, 0**v]; }
''')
self.assertEqual(jsi.call_function('x'), 7)
for y in jsi.call_function('f'):
self.assertTrue(math.isnan(y))
def test_object(self):
self._test('function f() { return {}; }', {})
self._test('function f() { let a = {m1: 42, m2: 0 }; return [a["m1"], a.m2]; }', [42, 0])
self._test('function f() { let a; return a?.qq; }', JS_Undefined)
self._test('function f() { let a = {m1: 42, m2: 0 }; return a?.qq; }', JS_Undefined)
def test_regex(self):
self._test('function f() { let a=/,,[/,913,/](,)}/; }', None)
self._test('function f() { let a=/,,[/,913,/](,)}/; return a; }', R'/,,[/,913,/](,)}/0')
R''' # We are not compiling regex
jsi = JSInterpreter('function f() { let a=/,,[/,913,/](,)}/; return a; }')
self.assertIsInstance(jsi.call_function('f'), re.Pattern)
jsi = JSInterpreter('function f() { let a=/,,[/,913,/](,)}/i; return a; }')
self.assertEqual(jsi.call_function('f').flags & re.I, re.I)
jsi = JSInterpreter(R'function f() { let a=/,][}",],()}(\[)/; return a; }')
self.assertEqual(jsi.call_function('f').pattern, r',][}",],()}(\[)')
jsi = JSInterpreter(R'function f() { let a=[/[)\\]/]; return a[0]; }')
self.assertEqual(jsi.call_function('f').pattern, r'[)\\]')
'''
@unittest.skip('Not implemented')
def test_replace(self):
self._test('function f() { let a="data-name".replace("data-", ""); return a }',
'name')
self._test('function f() { let a="data-name".replace(new RegExp("^.+-"), ""); return a; }',
'name')
self._test('function f() { let a="data-name".replace(/^.+-/, ""); return a; }',
'name')
self._test('function f() { let a="data-name".replace(/a/g, "o"); return a; }',
'doto-nome')
self._test('function f() { let a="data-name".replaceAll("a", "o"); return a; }',
'doto-nome')
def test_char_code_at(self):
jsi = JSInterpreter('function f(i){return "test".charCodeAt(i)}')
self._test(jsi, 116, args=[0])
self._test(jsi, 101, args=[1])
self._test(jsi, 115, args=[2])
self._test(jsi, 116, args=[3])
self._test(jsi, None, args=[4])
self._test(jsi, 116, args=['not_a_number'])
def test_bitwise_operators_overflow(self):
self._test('function f(){return -524999584 << 5}', 379882496)
self._test('function f(){return 1236566549 << 5}', 915423904)
def test_bitwise_operators_typecast(self):
self._test('function f(){return null << 5}', 0)
self._test('function f(){return undefined >> 5}', 0)
self._test('function f(){return 42 << NaN}', 42)
def test_negative(self):
self._test('function f(){return 2 * -2.0 ;}', -4)
self._test('function f(){return 2 - - -2 ;}', 0)
self._test('function f(){return 2 - - - -2 ;}', 4)
self._test('function f(){return 2 - + + - -2;}', 0)
self._test('function f(){return 2 + - + - -2;}', 0)
@unittest.skip('Not implemented')
def test_packed(self):
jsi = JSInterpreter('''function f(p,a,c,k,e,d){while(c--)if(k[c])p=p.replace(new RegExp('\\b'+c.toString(a)+'\\b','g'),k[c]);return p}''')
self.assertEqual(jsi.call_function('f', '''h 7=g("1j");7.7h({7g:[{33:"w://7f-7e-7d-7c.v.7b/7a/79/78/77/76.74?t=73&s=2s&e=72&f=2t&71=70.0.0.1&6z=6y&6x=6w"}],6v:"w://32.v.u/6u.31",16:"r%",15:"r%",6t:"6s",6r:"",6q:"l",6p:"l",6o:"6n",6m:\'6l\',6k:"6j",9:[{33:"/2u?b=6i&n=50&6h=w://32.v.u/6g.31",6f:"6e"}],1y:{6d:1,6c:\'#6b\',6a:\'#69\',68:"67",66:30,65:r,},"64":{63:"%62 2m%m%61%5z%5y%5x.u%5w%5v%5u.2y%22 2k%m%1o%22 5t%m%1o%22 5s%m%1o%22 2j%m%5r%22 16%m%5q%22 15%m%5p%22 5o%2z%5n%5m%2z",5l:"w://v.u/d/1k/5k.2y",5j:[]},\'5i\':{"5h":"5g"},5f:"5e",5d:"w://v.u",5c:{},5b:l,1x:[0.25,0.50,0.75,1,1.25,1.5,2]});h 1m,1n,5a;h 59=0,58=0;h 7=g("1j");h 2x=0,57=0,56=0;$.55({54:{\'53-52\':\'2i-51\'}});7.j(\'4z\',6(x){c(5>0&&x.1l>=5&&1n!=1){1n=1;$(\'q.4y\').4x(\'4w\')}});7.j(\'13\',6(x){2x=x.1l});7.j(\'2g\',6(x){2w(x)});7.j(\'4v\',6(){$(\'q.2v\').4u()});6 2w(x){$(\'q.2v\').4t();c(1m)19;1m=1;17=0;c(4s.4r===l){17=1}$.4q(\'/2u?b=4p&2l=1k&4o=2t-4n-4m-2s-4l&4k=&4j=&4i=&17=\'+17,6(2r){$(\'#4h\').4g(2r)});$(\'.3-8-4f-4e:4d("4c")\').2h(6(e){2q();g().4b(0);g().4a(l)});6 2q(){h $14=$("<q />").2p({1l:"49",16:"r%",15:"r%",48:0,2n:0,2o:47,46:"45(10%, 10%, 10%, 0.4)","44-43":"42"});$("<41 />").2p({16:"60%",15:"60%",2o:40,"3z-2n":"3y"}).3x({\'2m\':\'/?b=3w&2l=1k\',\'2k\':\'0\',\'2j\':\'2i\'}).2f($14);$14.2h(6(){$(3v).3u();g().2g()});$14.2f($(\'#1j\'))}g().13(0);}6 3t(){h 9=7.1b(2e);2d.2c(9);c(9.n>1){1r(i=0;i<9.n;i++){c(9[i].1a==2e){2d.2c(\'!!=\'+i);7.1p(i)}}}}7.j(\'3s\',6(){g().1h("/2a/3r.29","3q 10 28",6(){g().13(g().27()+10)},"2b");$("q[26=2b]").23().21(\'.3-20-1z\');g().1h("/2a/3p.29","3o 10 28",6(){h 12=g().27()-10;c(12<0)12=0;g().13(12)},"24");$("q[26=24]").23().21(\'.3-20-1z\');});6 1i(){}7.j(\'3n\',6(){1i()});7.j(\'3m\',6(){1i()});7.j("k",6(y){h 9=7.1b();c(9.n<2)19;$(\'.3-8-3l-3k\').3j(6(){$(\'#3-8-a-k\').1e(\'3-8-a-z\');$(\'.3-a-k\').p(\'o-1f\',\'11\')});7.1h("/3i/3h.3g","3f 3e",6(){$(\'.3-1w\').3d(\'3-8-1v\');$(\'.3-8-1y, .3-8-1x\').p(\'o-1g\',\'11\');c($(\'.3-1w\').3c(\'3-8-1v\')){$(\'.3-a-k\').p(\'o-1g\',\'l\');$(\'.3-a-k\').p(\'o-1f\',\'l\');$(\'.3-8-a\').1e(\'3-8-a-z\');$(\'.3-8-a:1u\').3b(\'3-8-a-z\')}3a{$(\'.3-a-k\').p(\'o-1g\',\'11\');$(\'.3-a-k\').p(\'o-1f\',\'11\');$(\'.3-8-a:1u\').1e(\'3-8-a-z\')}},"39");7.j("38",6(y){1d.37(\'1c\',y.9[y.36].1a)});c(1d.1t(\'1c\')){35("1s(1d.1t(\'1c\'));",34)}});h 18;6 1s(1q){h 9=7.1b();c(9.n>1){1r(i=0;i<9.n;i++){c(9[i].1a==1q){c(i==18){19}18=i;7.1p(i)}}}}',36,270,'|||jw|||function|player|settings|tracks|submenu||if||||jwplayer|var||on|audioTracks|true|3D|length|aria|attr|div|100|||sx|filemoon|https||event|active||false|tt|seek|dd|height|width|adb|current_audio|return|name|getAudioTracks|default_audio|localStorage|removeClass|expanded|checked|addButton|callMeMaybe|vplayer|0fxcyc2ajhp1|position|vvplay|vvad|220|setCurrentAudioTrack|audio_name|for|audio_set|getItem|last|open|controls|playbackRates|captions|rewind|icon|insertAfter||detach|ff00||button|getPosition|sec|png|player8|ff11|log|console|track_name|appendTo|play|click|no|scrolling|frameborder|file_code|src|top|zIndex|css|showCCform|data|1662367683|383371|dl|video_ad|doPlay|prevt|mp4|3E||jpg|thumbs|file|300|setTimeout|currentTrack|setItem|audioTrackChanged|dualSound|else|addClass|hasClass|toggleClass|Track|Audio|svg|dualy|images|mousedown|buttons|topbar|playAttemptFailed|beforePlay|Rewind|fr|Forward|ff|ready|set_audio_track|remove|this|upload_srt|prop|50px|margin|1000001|iframe|center|align|text|rgba|background|1000000|left|absolute|pause|setCurrentCaptions|Upload|contains|item|content|html|fviews|referer|prem|embed|3e57249ef633e0d03bf76ceb8d8a4b65|216|83|hash|view|get|TokenZir|window|hide|show|complete|slow|fadeIn|video_ad_fadein|time||cache|Cache|Content|headers|ajaxSetup|v2done|tott|vastdone2|vastdone1|vvbefore|playbackRateControls|cast|aboutlink|FileMoon|abouttext|UHD|1870|qualityLabels|sites|GNOME_POWER|link|2Fiframe|3C|allowfullscreen|22360|22640|22no|marginheight|marginwidth|2FGNOME_POWER|2F0fxcyc2ajhp1|2Fe|2Ffilemoon|2F|3A||22https|3Ciframe|code|sharing|fontOpacity|backgroundOpacity|Tahoma|fontFamily|303030|backgroundColor|FFFFFF|color|userFontScale|thumbnails|kind|0fxcyc2ajhp10000|url|get_slides|start|startparam|none|preload|html5|primary|hlshtml|androidhls|duration|uniform|stretching|0fxcyc2ajhp1_xt|image|2048|sp|6871|asn|127|srv|43200|_g3XlBcu2lmD9oDexD2NLWSmah2Nu3XcDrl93m9PwXY|m3u8||master|0fxcyc2ajhp1_x|00076|01|hls2|to|s01|delivery|storage|moon|sources|setup'''.split('|')))
if __name__ == '__main__':

@ -1,3 +1,6 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
import unittest

File diff suppressed because it is too large Load Diff

@ -0,0 +1,208 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
import pytest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import io
import random
import ssl
from yt_dlp.cookies import YoutubeDLCookieJar
from yt_dlp.dependencies import certifi
from yt_dlp.networking import Response
from yt_dlp.networking._helper import (
InstanceStoreMixin,
add_accept_encoding_header,
get_redirect_method,
make_socks_proxy_opts,
select_proxy,
ssl_load_certs,
)
from yt_dlp.networking.exceptions import (
HTTPError,
IncompleteRead,
)
from yt_dlp.socks import ProxyType
from yt_dlp.utils.networking import HTTPHeaderDict
TEST_DIR = os.path.dirname(os.path.abspath(__file__))
class TestNetworkingUtils:
def test_select_proxy(self):
proxies = {
'all': 'socks5://example.com',
'http': 'http://example.com:1080',
'no': 'bypass.example.com,yt-dl.org'
}
assert select_proxy('https://example.com', proxies) == proxies['all']
assert select_proxy('http://example.com', proxies) == proxies['http']
assert select_proxy('http://bypass.example.com', proxies) is None
assert select_proxy('https://yt-dl.org', proxies) is None
@pytest.mark.parametrize('socks_proxy,expected', [
('socks5h://example.com', {
'proxytype': ProxyType.SOCKS5,
'addr': 'example.com',
'port': 1080,
'rdns': True,
'username': None,
'password': None
}),
('socks5://user:@example.com:5555', {
'proxytype': ProxyType.SOCKS5,
'addr': 'example.com',
'port': 5555,
'rdns': False,
'username': 'user',
'password': ''
}),
('socks4://u%40ser:pa%20ss@127.0.0.1:1080', {
'proxytype': ProxyType.SOCKS4,
'addr': '127.0.0.1',
'port': 1080,
'rdns': False,
'username': 'u@ser',
'password': 'pa ss'
}),
('socks4a://:pa%20ss@127.0.0.1', {
'proxytype': ProxyType.SOCKS4A,
'addr': '127.0.0.1',
'port': 1080,
'rdns': True,
'username': '',
'password': 'pa ss'
})
])
def test_make_socks_proxy_opts(self, socks_proxy, expected):
assert make_socks_proxy_opts(socks_proxy) == expected
def test_make_socks_proxy_unknown(self):
with pytest.raises(ValueError, match='Unknown SOCKS proxy version: socks'):
make_socks_proxy_opts('socks://127.0.0.1')
@pytest.mark.skipif(not certifi, reason='certifi is not installed')
def test_load_certifi(self):
context_certifi = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context_certifi.load_verify_locations(cafile=certifi.where())
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_load_certs(context, use_certifi=True)
assert context.get_ca_certs() == context_certifi.get_ca_certs()
context_default = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context_default.load_default_certs()
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_load_certs(context, use_certifi=False)
assert context.get_ca_certs() == context_default.get_ca_certs()
if context_default.get_ca_certs() == context_certifi.get_ca_certs():
pytest.skip('System uses certifi as default. The test is not valid')
@pytest.mark.parametrize('method,status,expected', [
('GET', 303, 'GET'),
('HEAD', 303, 'HEAD'),
('PUT', 303, 'GET'),
('POST', 301, 'GET'),
('HEAD', 301, 'HEAD'),
('POST', 302, 'GET'),
('HEAD', 302, 'HEAD'),
('PUT', 302, 'PUT'),
('POST', 308, 'POST'),
('POST', 307, 'POST'),
('HEAD', 308, 'HEAD'),
('HEAD', 307, 'HEAD'),
])
def test_get_redirect_method(self, method, status, expected):
assert get_redirect_method(method, status) == expected
@pytest.mark.parametrize('headers,supported_encodings,expected', [
({'Accept-Encoding': 'br'}, ['gzip', 'br'], {'Accept-Encoding': 'br'}),
({}, ['gzip', 'br'], {'Accept-Encoding': 'gzip, br'}),
({'Content-type': 'application/json'}, [], {'Content-type': 'application/json', 'Accept-Encoding': 'identity'}),
])
def test_add_accept_encoding_header(self, headers, supported_encodings, expected):
headers = HTTPHeaderDict(headers)
add_accept_encoding_header(headers, supported_encodings)
assert headers == HTTPHeaderDict(expected)
class TestInstanceStoreMixin:
class FakeInstanceStoreMixin(InstanceStoreMixin):
def _create_instance(self, **kwargs):
return random.randint(0, 1000000)
def _close_instance(self, instance):
pass
def test_mixin(self):
mixin = self.FakeInstanceStoreMixin()
assert mixin._get_instance(d={'a': 1, 'b': 2, 'c': {'d', 4}}) == mixin._get_instance(d={'a': 1, 'b': 2, 'c': {'d', 4}})
assert mixin._get_instance(d={'a': 1, 'b': 2, 'c': {'e', 4}}) != mixin._get_instance(d={'a': 1, 'b': 2, 'c': {'d', 4}})
assert mixin._get_instance(d={'a': 1, 'b': 2, 'c': {'d', 4}} != mixin._get_instance(d={'a': 1, 'b': 2, 'g': {'d', 4}}))
assert mixin._get_instance(d={'a': 1}, e=[1, 2, 3]) == mixin._get_instance(d={'a': 1}, e=[1, 2, 3])
assert mixin._get_instance(d={'a': 1}, e=[1, 2, 3]) != mixin._get_instance(d={'a': 1}, e=[1, 2, 3, 4])
cookiejar = YoutubeDLCookieJar()
assert mixin._get_instance(b=[1, 2], c=cookiejar) == mixin._get_instance(b=[1, 2], c=cookiejar)
assert mixin._get_instance(b=[1, 2], c=cookiejar) != mixin._get_instance(b=[1, 2], c=YoutubeDLCookieJar())
# Different order
assert mixin._get_instance(c=cookiejar, b=[1, 2]) == mixin._get_instance(b=[1, 2], c=cookiejar)
m = mixin._get_instance(t=1234)
assert mixin._get_instance(t=1234) == m
mixin._clear_instances()
assert mixin._get_instance(t=1234) != m
class TestNetworkingExceptions:
@staticmethod
def create_response(status):
return Response(fp=io.BytesIO(b'test'), url='http://example.com', headers={'tesT': 'test'}, status=status)
def test_http_error(self):
response = self.create_response(403)
error = HTTPError(response)
assert error.status == 403
assert str(error) == error.msg == 'HTTP Error 403: Forbidden'
assert error.reason == response.reason
assert error.response is response
data = error.response.read()
assert data == b'test'
assert repr(error) == '<HTTPError 403: Forbidden>'
def test_redirect_http_error(self):
response = self.create_response(301)
error = HTTPError(response, redirect_loop=True)
assert str(error) == error.msg == 'HTTP Error 301: Moved Permanently (redirect loop detected)'
assert error.reason == 'Moved Permanently'
def test_incomplete_read_error(self):
error = IncompleteRead(4, 3, cause='test')
assert isinstance(error, IncompleteRead)
assert repr(error) == '<IncompleteRead: 4 bytes read, 3 more expected>'
assert str(error) == error.msg == '4 bytes read, 3 more expected'
assert error.partial == 4
assert error.expected == 3
assert error.cause == 'test'
error = IncompleteRead(3)
assert repr(error) == '<IncompleteRead: 3 bytes read>'
assert str(error) == '3 bytes read'

@ -1,11 +1,15 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import subprocess
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import subprocess
from test.helper import is_download_test, try_rm
root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

@ -0,0 +1,73 @@
import importlib
import os
import shutil
import sys
import unittest
from pathlib import Path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
TEST_DATA_DIR = Path(os.path.dirname(os.path.abspath(__file__)), 'testdata')
sys.path.append(str(TEST_DATA_DIR))
importlib.invalidate_caches()
from yt_dlp.plugins import PACKAGE_NAME, directories, load_plugins
class TestPlugins(unittest.TestCase):
TEST_PLUGIN_DIR = TEST_DATA_DIR / PACKAGE_NAME
def test_directories_containing_plugins(self):
self.assertIn(self.TEST_PLUGIN_DIR, map(Path, directories()))
def test_extractor_classes(self):
for module_name in tuple(sys.modules):
if module_name.startswith(f'{PACKAGE_NAME}.extractor'):
del sys.modules[module_name]
plugins_ie = load_plugins('extractor', 'IE')
self.assertIn(f'{PACKAGE_NAME}.extractor.normal', sys.modules.keys())
self.assertIn('NormalPluginIE', plugins_ie.keys())
# don't load modules with underscore prefix
self.assertFalse(
f'{PACKAGE_NAME}.extractor._ignore' in sys.modules.keys(),
'loaded module beginning with underscore')
self.assertNotIn('IgnorePluginIE', plugins_ie.keys())
# Don't load extractors with underscore prefix
self.assertNotIn('_IgnoreUnderscorePluginIE', plugins_ie.keys())
# Don't load extractors not specified in __all__ (if supplied)
self.assertNotIn('IgnoreNotInAllPluginIE', plugins_ie.keys())
self.assertIn('InAllPluginIE', plugins_ie.keys())
def test_postprocessor_classes(self):
plugins_pp = load_plugins('postprocessor', 'PP')
self.assertIn('NormalPluginPP', plugins_pp.keys())
def test_importing_zipped_module(self):
zip_path = TEST_DATA_DIR / 'zipped_plugins.zip'
shutil.make_archive(str(zip_path)[:-4], 'zip', str(zip_path)[:-4])
sys.path.append(str(zip_path)) # add zip to search paths
importlib.invalidate_caches() # reset the import caches
try:
for plugin_type in ('extractor', 'postprocessor'):
package = importlib.import_module(f'{PACKAGE_NAME}.{plugin_type}')
self.assertIn(zip_path / PACKAGE_NAME / plugin_type, map(Path, package.__path__))
plugins_ie = load_plugins('extractor', 'IE')
self.assertIn('ZippedPluginIE', plugins_ie.keys())
plugins_pp = load_plugins('postprocessor', 'PP')
self.assertIn('ZippedPluginPP', plugins_pp.keys())
finally:
sys.path.remove(str(zip_path))
os.remove(zip_path)
importlib.invalidate_caches() # reset the import caches
if __name__ == '__main__':
unittest.main()

@ -1,13 +1,15 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from test.helper import get_params, is_download_test, try_rm
import yt_dlp.YoutubeDL
from test.helper import get_params, is_download_test, try_rm
import yt_dlp.YoutubeDL # isort: split
from yt_dlp.utils import DownloadError

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# Allow direct execution
import os
import sys
@ -6,6 +7,7 @@ import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from yt_dlp import YoutubeDL
from yt_dlp.compat import compat_shlex_quote
from yt_dlp.postprocessor import (
@ -14,6 +16,7 @@ from yt_dlp.postprocessor import (
MetadataFromFieldPP,
MetadataParserPP,
ModifyChaptersPP,
SponsorBlockPP,
)
@ -74,11 +77,15 @@ class TestModifyChaptersPP(unittest.TestCase):
self._pp = ModifyChaptersPP(YoutubeDL())
@staticmethod
def _sponsor_chapter(start, end, cat, remove=False):
c = {'start_time': start, 'end_time': end, '_categories': [(cat, start, end)]}
if remove:
c['remove'] = True
return c
def _sponsor_chapter(start, end, cat, remove=False, title=None):
if title is None:
title = SponsorBlockPP.CATEGORIES[cat]
return {
'start_time': start,
'end_time': end,
'_categories': [(cat, start, end, title)],
**({'remove': True} if remove else {}),
}
@staticmethod
def _chapter(start, end, title=None, remove=False):
@ -128,6 +135,19 @@ class TestModifyChaptersPP(unittest.TestCase):
'c', '[SponsorBlock]: Filler Tangent', 'c'])
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
def test_remove_marked_arrange_sponsors_SponsorBlockChapters(self):
chapters = self._chapters([70], ['c']) + [
self._sponsor_chapter(10, 20, 'chapter', title='sb c1'),
self._sponsor_chapter(15, 16, 'chapter', title='sb c2'),
self._sponsor_chapter(30, 40, 'preview'),
self._sponsor_chapter(50, 60, 'filler')]
expected = self._chapters(
[10, 15, 16, 20, 30, 40, 50, 60, 70],
['c', '[SponsorBlock]: sb c1', '[SponsorBlock]: sb c1, sb c2', '[SponsorBlock]: sb c1',
'c', '[SponsorBlock]: Preview/Recap',
'c', '[SponsorBlock]: Filler Tangent', 'c'])
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
def test_remove_marked_arrange_sponsors_UniqueNamesForOverlappingSponsors(self):
chapters = self._chapters([120], ['c']) + [
self._sponsor_chapter(10, 45, 'sponsor'), self._sponsor_chapter(20, 40, 'selfpromo'),
@ -171,7 +191,7 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts)
def test_remove_marked_arrange_sponsors_ChapterWithCutHidingSponsor(self):
cuts = [self._sponsor_chapter(20, 50, 'selpromo', remove=True)]
cuts = [self._sponsor_chapter(20, 50, 'selfpromo', remove=True)]
chapters = self._chapters([60], ['c']) + [
self._sponsor_chapter(10, 20, 'intro'),
self._sponsor_chapter(30, 40, 'sponsor'),
@ -197,7 +217,7 @@ class TestModifyChaptersPP(unittest.TestCase):
self._sponsor_chapter(10, 20, 'sponsor'),
self._sponsor_chapter(20, 30, 'interaction', remove=True),
self._chapter(30, 40, remove=True),
self._sponsor_chapter(40, 50, 'selpromo', remove=True),
self._sponsor_chapter(40, 50, 'selfpromo', remove=True),
self._sponsor_chapter(50, 60, 'interaction')]
expected = self._chapters([10, 20, 30, 40],
['c', '[SponsorBlock]: Sponsor',
@ -280,7 +300,7 @@ class TestModifyChaptersPP(unittest.TestCase):
chapters = self._chapters([70], ['c']) + [
self._sponsor_chapter(10, 30, 'sponsor'),
self._sponsor_chapter(20, 50, 'interaction'),
self._sponsor_chapter(30, 50, 'selpromo', remove=True),
self._sponsor_chapter(30, 50, 'selfpromo', remove=True),
self._sponsor_chapter(40, 60, 'sponsor'),
self._sponsor_chapter(50, 60, 'interaction')]
expected = self._chapters(

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save