├── test ├── __init__.py ├── swftests │ ├── .gitignore │ ├── EqualsOperator.as │ ├── DictCall.as │ ├── ConstantInt.as │ ├── StringBasics.as │ ├── StringConversion.as │ ├── StaticAssignment.as │ ├── ClassConstruction.as │ ├── StringCharCodeAt.as │ ├── LocalVars.as │ ├── StaticRetrieval.as │ ├── ClassCall.as │ ├── PrivateCall.as │ ├── ConstArrayAccess.as │ ├── PrivateVoidCall.as │ ├── MemberAssignment.as │ ├── ArrayAccess.as │ └── NeOperator.as ├── testdata │ ├── cookies │ │ ├── session_cookies.txt │ │ ├── httponly_cookies.txt │ │ └── malformed_cookies.txt │ ├── m3u8 │ │ ├── vidio.m3u8 │ │ ├── toggle_mobile_12211.m3u8 │ │ └── teamcoco_11995.m3u8 │ ├── f4m │ │ └── custom_base_url.f4m │ ├── xspf │ │ └── foo_xspf.xspf │ └── mpd │ │ ├── float_duration.mpd │ │ └── unfragmented.mpd ├── test_postprocessors.py ├── test_netrc.py ├── test_options.py ├── test_update.py ├── parameters.json ├── test_iqiyi_sdk_interpreter.py ├── test_execution.py ├── test_age_restriction.py ├── versions.json └── test_cache.py ├── docs ├── .gitignore └── index.rst ├── youtube_dl ├── version.py ├── __main__.py ├── extractor │ ├── spiegeltv.py │ ├── ufctv.py │ ├── gigya.py │ ├── usanetwork.py │ ├── embedly.py │ ├── engadget.py │ ├── m6.py │ ├── videodetective.py │ ├── myvidster.py │ ├── lci.py │ ├── cinemax.py │ ├── outsidetv.py │ ├── ku6.py │ ├── nrl.py │ ├── vodpl.py │ ├── cliprs.py │ ├── freespeech.py │ ├── stretchinternet.py │ ├── teachingchannel.py │ ├── ebaumsworld.py │ ├── savefrom.py │ ├── foxsports.py │ ├── uktvplay.py │ ├── people.py │ ├── nerdcubed.py │ ├── nonktube.py │ ├── lovehomeporn.py │ ├── formula1.py │ ├── gputechconf.py │ ├── unity.py │ ├── hentaistigma.py │ ├── nuevo.py │ ├── defense.py │ ├── rottentomatoes.py │ ├── __init__.py │ ├── dropbox.py │ ├── bfi.py │ ├── echomsk.py │ ├── adobeconnect.py │ ├── screencastomatic.py │ ├── worldstarhiphop.py │ ├── bild.py │ ├── helsinki.py │ ├── restudy.py │ ├── howcast.py │ ├── thestar.py │ ├── thesun.py │ ├── thescene.py │ ├── academicearth.py │ ├── nzz.py │ ├── moviezine.py │ ├── hgtv.py │ ├── yourupload.py │ ├── trunews.py │ ├── tvland.py │ ├── aljazeera.py │ ├── ro220.py │ ├── xbef.py │ ├── fox9.py │ ├── skylinewebcams.py │ ├── tastytrade.py │ ├── miaopai.py │ ├── cbssports.py │ ├── filmweb.py │ ├── rtvs.py │ ├── ehow.py │ ├── discoverynetworks.py │ ├── livejournal.py │ ├── phoenix.py │ ├── sonyliv.py │ ├── vh1.py │ ├── odatv.py │ ├── oktoberfesttv.py │ ├── vodplatform.py │ ├── glide.py │ ├── ruhd.py │ ├── thisamericanlife.py │ ├── hornbunny.py │ ├── hypem.py │ ├── mychannels.py │ ├── commonmistakes.py │ ├── goshgay.py │ ├── historicfilms.py │ ├── tvnoe.py │ ├── aliexpress.py │ ├── streetvoice.py │ ├── sztvhu.py │ ├── parliamentliveuk.py │ ├── behindkink.py │ ├── lenta.py │ ├── reverbnation.py │ └── weiqitv.py ├── postprocessor │ ├── execafterdownload.py │ ├── __init__.py │ └── metadatafromtitle.py └── downloader │ ├── rtsp.py │ └── __init__.py ├── devscripts ├── SizeOfImage.patch ├── SizeOfImage_w.patch ├── fish-completion.in ├── posix-locale.sh ├── install_jython.sh ├── lazy_load_template.py ├── run_tests.sh ├── gh-pages │ ├── update-copyright.py │ ├── generate-download.py │ ├── sign-versions.py │ ├── update-sites.py │ └── add-version.py ├── make_readme.py ├── zsh-completion.in ├── make_issue_template.py ├── make_contributing.py ├── bash-completion.in ├── bash-completion.py ├── generate_aes_testdata.py ├── make_supportedsites.py ├── show-downloads-statistics.py ├── zsh-completion.py └── fish-completion.py ├── bin └── youtube-dl ├── setup.cfg ├── MANIFEST.in ├── tox.ini ├── .gitignore ├── youtube-dl.plugin.zsh ├── LICENSE ├── .github ├── ISSUE_TEMPLATE │ ├── 6_question.md │ ├── 3_site_feature_request.md │ └── 5_feature_request.md ├── ISSUE_TEMPLATE_tmpl │ ├── 3_site_feature_request.md │ └── 5_feature_request.md └── PULL_REQUEST_TEMPLATE.md └── .travis.yml /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | -------------------------------------------------------------------------------- /test/swftests/.gitignore: -------------------------------------------------------------------------------- 1 | *.swf 2 | -------------------------------------------------------------------------------- /youtube_dl/version.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | __version__ = '2020.11.17' 4 | -------------------------------------------------------------------------------- /devscripts/SizeOfImage.patch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skyme5/youtube-dl-1/master/devscripts/SizeOfImage.patch -------------------------------------------------------------------------------- /devscripts/SizeOfImage_w.patch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skyme5/youtube-dl-1/master/devscripts/SizeOfImage_w.patch -------------------------------------------------------------------------------- /bin/youtube-dl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import youtube_dl 4 | 5 | if __name__ == '__main__': 6 | youtube_dl.main() 7 | -------------------------------------------------------------------------------- /devscripts/fish-completion.in: -------------------------------------------------------------------------------- 1 | 2 | {{commands}} 3 | 4 | 5 | complete --command youtube-dl --arguments ":ytfavorites :ytrecommended :ytsubscriptions :ytwatchlater :ythistory" 6 | -------------------------------------------------------------------------------- /devscripts/posix-locale.sh: -------------------------------------------------------------------------------- 1 | 2 | # source this file in your shell to get a POSIX locale (which will break many programs, but that's kind of the point) 3 | 4 | export LC_ALL=POSIX 5 | export LANG=POSIX 6 | export LANGUAGE=POSIX 7 | -------------------------------------------------------------------------------- /test/swftests/EqualsOperator.as: -------------------------------------------------------------------------------- 1 | // input: [] 2 | // output: false 3 | 4 | package { 5 | public class EqualsOperator { 6 | public static function main():Boolean{ 7 | return 1 == 2; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/swftests/DictCall.as: -------------------------------------------------------------------------------- 1 | // input: [{"x": 1, "y": 2}] 2 | // output: 3 3 | 4 | package { 5 | public class DictCall { 6 | public static function main(d:Object):int{ 7 | return d.x + d.y; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/swftests/ConstantInt.as: -------------------------------------------------------------------------------- 1 | // input: [] 2 | // output: 2 3 | 4 | package { 5 | public class ConstantInt { 6 | private static const x:int = 2; 7 | 8 | public static function main():int{ 9 | return x; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/swftests/StringBasics.as: -------------------------------------------------------------------------------- 1 | // input: [] 2 | // output: 3 3 | 4 | package { 5 | public class StringBasics { 6 | public static function main():int{ 7 | var s:String = "abc"; 8 | return s.length; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /devscripts/install_jython.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | wget http://central.maven.org/maven2/org/python/jython-installer/2.7.1/jython-installer-2.7.1.jar 4 | java -jar jython-installer-2.7.1.jar -s -d "$HOME/jython" 5 | $HOME/jython/bin/jython -m pip install nose 6 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [wheel] 2 | universal = True 3 | 4 | [flake8] 5 | exclude = youtube_dl/extractor/__init__.py,devscripts/buildserver.py,devscripts/lazy_load_template.py,devscripts/make_issue_template.py,setup.py,build,.git,venv 6 | ignore = E402,E501,E731,E741,W503 7 | -------------------------------------------------------------------------------- /test/swftests/StringConversion.as: -------------------------------------------------------------------------------- 1 | // input: [] 2 | // output: 2 3 | 4 | package { 5 | public class StringConversion { 6 | public static function main():int{ 7 | var s:String = String(99); 8 | return s.length; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include LICENSE 3 | include AUTHORS 4 | include ChangeLog 5 | include youtube-dl.bash-completion 6 | include youtube-dl.fish 7 | include youtube-dl.1 8 | recursive-include docs Makefile conf.py *.rst 9 | recursive-include test * 10 | -------------------------------------------------------------------------------- /test/swftests/StaticAssignment.as: -------------------------------------------------------------------------------- 1 | // input: [1] 2 | // output: 1 3 | 4 | package { 5 | public class StaticAssignment { 6 | public static var v:int; 7 | 8 | public static function main(a:int):int{ 9 | v = a; 10 | return v; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/swftests/ClassConstruction.as: -------------------------------------------------------------------------------- 1 | // input: [] 2 | // output: 0 3 | 4 | package { 5 | public class ClassConstruction { 6 | public static function main():int{ 7 | var f:Foo = new Foo(); 8 | return 0; 9 | } 10 | } 11 | } 12 | 13 | class Foo { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /test/swftests/StringCharCodeAt.as: -------------------------------------------------------------------------------- 1 | // input: [] 2 | // output: 9897 3 | 4 | package { 5 | public class StringCharCodeAt { 6 | public static function main():int{ 7 | var s:String = "abc"; 8 | return s.charCodeAt(1) * 100 + s.charCodeAt(); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/swftests/LocalVars.as: -------------------------------------------------------------------------------- 1 | // input: [1, 2] 2 | // output: 3 3 | 4 | package { 5 | public class LocalVars { 6 | public static function main(a:int, b:int):int{ 7 | var c:int = a + b + b; 8 | var d:int = c - b; 9 | var e:int = d; 10 | return e; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/testdata/cookies/session_cookies.txt: -------------------------------------------------------------------------------- 1 | # Netscape HTTP Cookie File 2 | # http://curl.haxx.se/rfc/cookie_spec.html 3 | # This is a generated file! Do not edit. 4 | 5 | www.foobar.foobar FALSE / TRUE YoutubeDLExpiresEmpty YoutubeDLExpiresEmptyValue 6 | www.foobar.foobar FALSE / TRUE 0 YoutubeDLExpires0 YoutubeDLExpires0Value 7 | -------------------------------------------------------------------------------- /test/swftests/StaticRetrieval.as: -------------------------------------------------------------------------------- 1 | // input: [] 2 | // output: 1 3 | 4 | package { 5 | public class StaticRetrieval { 6 | public static var v:int; 7 | 8 | public static function main():int{ 9 | if (v) { 10 | return 0; 11 | } else { 12 | return 1; 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/testdata/cookies/httponly_cookies.txt: -------------------------------------------------------------------------------- 1 | # Netscape HTTP Cookie File 2 | # http://curl.haxx.se/rfc/cookie_spec.html 3 | # This is a generated file! Do not edit. 4 | 5 | #HttpOnly_www.foobar.foobar FALSE / TRUE 2147483647 HTTPONLY_COOKIE HTTPONLY_COOKIE_VALUE 6 | www.foobar.foobar FALSE / TRUE 2147483647 JS_ACCESSIBLE_COOKIE JS_ACCESSIBLE_COOKIE_VALUE 7 | -------------------------------------------------------------------------------- /test/swftests/ClassCall.as: -------------------------------------------------------------------------------- 1 | // input: [] 2 | // output: 121 3 | 4 | package { 5 | public class ClassCall { 6 | public static function main():int{ 7 | var f:OtherClass = new OtherClass(); 8 | return f.func(100,20); 9 | } 10 | } 11 | } 12 | 13 | class OtherClass { 14 | public function func(x: int, y: int):int { 15 | return x+y+1; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/testdata/cookies/malformed_cookies.txt: -------------------------------------------------------------------------------- 1 | # Netscape HTTP Cookie File 2 | # http://curl.haxx.se/rfc/cookie_spec.html 3 | # This is a generated file! Do not edit. 4 | 5 | # Cookie file entry with invalid number of fields - 6 instead of 7 6 | www.foobar.foobar FALSE / FALSE 0 COOKIE 7 | 8 | # Cookie file entry with invalid expires at 9 | www.foobar.foobar FALSE / FALSE 1.7976931348623157e+308 COOKIE VALUE 10 | -------------------------------------------------------------------------------- /test/swftests/PrivateCall.as: -------------------------------------------------------------------------------- 1 | // input: [] 2 | // output: 9 3 | 4 | package { 5 | public class PrivateCall { 6 | public static function main():int{ 7 | var f:OtherClass = new OtherClass(); 8 | return f.func(); 9 | } 10 | } 11 | } 12 | 13 | class OtherClass { 14 | private function pf():int { 15 | return 9; 16 | } 17 | 18 | public function func():int { 19 | return this.pf(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/swftests/ConstArrayAccess.as: -------------------------------------------------------------------------------- 1 | // input: [] 2 | // output: 4 3 | 4 | package { 5 | public class ConstArrayAccess { 6 | private static const x:int = 2; 7 | private static const ar:Array = ["42", "3411"]; 8 | 9 | public static function main():int{ 10 | var c:ConstArrayAccess = new ConstArrayAccess(); 11 | return c.f(); 12 | } 13 | 14 | public function f(): int { 15 | return ar[1].length; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/swftests/PrivateVoidCall.as: -------------------------------------------------------------------------------- 1 | // input: [] 2 | // output: 9 3 | 4 | package { 5 | public class PrivateVoidCall { 6 | public static function main():int{ 7 | var f:OtherClass = new OtherClass(); 8 | f.func(); 9 | return 9; 10 | } 11 | } 12 | } 13 | 14 | class OtherClass { 15 | private function pf():void { 16 | ; 17 | } 18 | 19 | public function func():void { 20 | this.pf(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/swftests/MemberAssignment.as: -------------------------------------------------------------------------------- 1 | // input: [1] 2 | // output: 2 3 | 4 | package { 5 | public class MemberAssignment { 6 | public var v:int; 7 | 8 | public function g():int { 9 | return this.v; 10 | } 11 | 12 | public function f(a:int):int{ 13 | this.v = a; 14 | return this.v + this.g(); 15 | } 16 | 17 | public static function main(a:int): int { 18 | var v:MemberAssignment = new MemberAssignment(); 19 | return v.f(a); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/swftests/ArrayAccess.as: -------------------------------------------------------------------------------- 1 | // input: [["a", "b", "c", "d"]] 2 | // output: ["c", "b", "a", "d"] 3 | 4 | package { 5 | public class ArrayAccess { 6 | public static function main(ar:Array):Array { 7 | var aa:ArrayAccess = new ArrayAccess(); 8 | return aa.f(ar, 2); 9 | } 10 | 11 | private function f(ar:Array, num:Number):Array{ 12 | var x:String = ar[0]; 13 | var y:String = ar[num % ar.length]; 14 | ar[0] = y; 15 | ar[num] = x; 16 | return ar; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/swftests/NeOperator.as: -------------------------------------------------------------------------------- 1 | // input: [] 2 | // output: 123 3 | 4 | package { 5 | public class NeOperator { 6 | public static function main(): int { 7 | var res:int = 0; 8 | if (1 != 2) { 9 | res += 3; 10 | } else { 11 | res += 4; 12 | } 13 | if (2 != 2) { 14 | res += 10; 15 | } else { 16 | res += 20; 17 | } 18 | if (9 == 9) { 19 | res += 100; 20 | } 21 | return res; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /devscripts/lazy_load_template.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals 3 | 4 | import re 5 | 6 | 7 | class LazyLoadExtractor(object): 8 | _module = None 9 | 10 | @classmethod 11 | def ie_key(cls): 12 | return cls.__name__[:-2] 13 | 14 | def __new__(cls, *args, **kwargs): 15 | mod = __import__(cls._module, fromlist=(cls.__name__,)) 16 | real_cls = getattr(mod, cls.__name__) 17 | instance = real_cls.__new__(real_cls) 18 | instance.__init__(*args, **kwargs) 19 | return instance 20 | -------------------------------------------------------------------------------- /youtube_dl/__main__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import unicode_literals 3 | 4 | # Execute with 5 | # $ python youtube_dl/__main__.py (2.6+) 6 | # $ python -m youtube_dl (2.7+) 7 | 8 | import sys 9 | 10 | if __package__ is None and not hasattr(sys, 'frozen'): 11 | # direct call of __main__.py 12 | import os.path 13 | path = os.path.realpath(os.path.abspath(__file__)) 14 | sys.path.insert(0, os.path.dirname(os.path.dirname(path))) 15 | 16 | import youtube_dl 17 | 18 | if __name__ == '__main__': 19 | youtube_dl.main() 20 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to youtube-dl's documentation! 2 | ====================================== 3 | 4 | *youtube-dl* is a command-line program to download videos from YouTube.com and more sites. 5 | It can also be used in Python code. 6 | 7 | Developer guide 8 | --------------- 9 | 10 | This section contains information for using *youtube-dl* from Python programs. 11 | 12 | .. toctree:: 13 | :maxdepth: 2 14 | 15 | module_guide 16 | 17 | Indices and tables 18 | ================== 19 | 20 | * :ref:`genindex` 21 | * :ref:`modindex` 22 | * :ref:`search` 23 | 24 | -------------------------------------------------------------------------------- /test/test_postprocessors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import unicode_literals 4 | 5 | # Allow direct execution 6 | import os 7 | import sys 8 | import unittest 9 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 10 | 11 | from youtube_dl.postprocessor import MetadataFromTitlePP 12 | 13 | 14 | class TestMetadataFromTitle(unittest.TestCase): 15 | def test_format_to_regex(self): 16 | pp = MetadataFromTitlePP(None, '%(title)s - %(artist)s') 17 | self.assertEqual(pp._titleregex, r'(?P