├── .gitignore
├── ansible
├── .gitignore
├── Vagrantfile
├── ansible.cfg
├── dbservers.yml
├── env_vars
│ ├── base.yml
│ ├── production.yml
│ └── vagrant.yml
├── local
├── production
├── roles
│ ├── base
│ │ ├── tasks
│ │ │ ├── create_swap_file.yml
│ │ │ └── main.yml
│ │ └── vars
│ │ │ └── main.yml
│ ├── celery
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ ├── copy_scripts.yml
│ │ │ ├── main.yml
│ │ │ └── setup_supervisor.yml
│ │ ├── templates
│ │ │ ├── celery_start.j2
│ │ │ ├── flower_start.j2
│ │ │ ├── supervisor_celery.conf.j2
│ │ │ └── supervisor_flower.conf.j2
│ │ └── vars
│ │ │ └── main.yml
│ ├── db
│ │ ├── handlers
│ │ │ └── main.yml
│ │ └── tasks
│ │ │ └── main.yml
│ ├── memcached
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ └── main.yml
│ │ ├── templates
│ │ │ └── memcached.conf.j2
│ │ └── vars
│ │ │ └── main.yml
│ ├── rabbitmq
│ │ ├── handlers
│ │ │ └── main.yml
│ │ └── tasks
│ │ │ ├── main.yml
│ │ │ ├── setup_users.yml
│ │ │ └── setup_vhosts.yml
│ └── web
│ │ ├── handlers
│ │ └── main.yml
│ │ ├── tasks
│ │ ├── create_users_and_groups.yml
│ │ ├── main.yml
│ │ ├── set_file_permissions.yml
│ │ ├── setup_cron_jobs.yml
│ │ ├── setup_django_app.yml
│ │ ├── setup_git_repo.yml
│ │ ├── setup_nginx.yml
│ │ ├── setup_supervisor.yml
│ │ └── setup_virtualenv.yml
│ │ ├── templates
│ │ ├── gunicorn_start.j2
│ │ ├── maintenance_off.html
│ │ ├── nginx_site_config.j2
│ │ ├── supervisor_config.j2
│ │ └── virtualenv_postactivate.j2
│ │ └── vars
│ │ └── main.yml
├── site.yml
├── vagrant.yml
└── webservers.yml
├── django
├── Dockerfile
└── requirements.txt
├── docker-compose.yml
├── ipython_config.py
├── manage.py
├── scripts
└── deploy_youtubeadl.sh
├── tor-hidden-service
├── Dockerfile
├── get-tor-hostname
├── start-tor
└── torrc
└── youtubeadl
├── __init__.py
├── apps
├── __init__.py
├── core
│ ├── __init__.py
│ ├── admin.py
│ ├── context_processors.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── utils.py
│ └── views.py
└── downloader
│ ├── __init__.py
│ ├── admin.py
│ ├── migrations
│ ├── 0001_initial.py
│ └── __init__.py
│ ├── models.py
│ ├── tasks.py
│ ├── tests.py
│ ├── urls.py
│ ├── utils.py
│ └── views.py
├── celery.py
├── settings
├── __init__.py
├── base.py
├── local.py
└── production.py
├── static
├── js
│ └── main.js
└── vendor
│ ├── bootstrap
│ ├── config.json
│ ├── css
│ │ ├── bootstrap-theme.css
│ │ ├── bootstrap-theme.min.css
│ │ ├── bootstrap.css
│ │ └── bootstrap.min.css
│ └── js
│ │ ├── bootstrap.js
│ │ └── bootstrap.min.js
│ ├── font-awesome
│ ├── css
│ │ ├── font-awesome.css
│ │ └── font-awesome.min.css
│ ├── fonts
│ │ ├── FontAwesome.otf
│ │ ├── fontawesome-webfont.eot
│ │ ├── fontawesome-webfont.svg
│ │ ├── fontawesome-webfont.ttf
│ │ ├── fontawesome-webfont.woff
│ │ └── fontawesome-webfont.woff2
│ ├── less
│ │ ├── animated.less
│ │ ├── bordered-pulled.less
│ │ ├── core.less
│ │ ├── fixed-width.less
│ │ ├── font-awesome.less
│ │ ├── icons.less
│ │ ├── larger.less
│ │ ├── list.less
│ │ ├── mixins.less
│ │ ├── path.less
│ │ ├── rotated-flipped.less
│ │ ├── stacked.less
│ │ └── variables.less
│ └── scss
│ │ ├── _animated.scss
│ │ ├── _bordered-pulled.scss
│ │ ├── _core.scss
│ │ ├── _fixed-width.scss
│ │ ├── _icons.scss
│ │ ├── _larger.scss
│ │ ├── _list.scss
│ │ ├── _mixins.scss
│ │ ├── _path.scss
│ │ ├── _rotated-flipped.scss
│ │ ├── _stacked.scss
│ │ ├── _variables.scss
│ │ └── font-awesome.scss
│ └── jquery
│ └── jquery.min.js
├── templates
├── 403.html
├── 404.html
├── 500.html
├── base.html
└── home.html
├── urls.py
└── wsgi.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # C extensions
6 | *.so
7 |
8 | # Distribution / packaging
9 | .Python
10 | env/
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | *.egg-info/
23 | .installed.cfg
24 | *.egg
25 |
26 | # PyInstaller
27 | # Usually these files are written by a python script from a template
28 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
29 | *.manifest
30 | *.spec
31 |
32 | # Installer logs
33 | pip-log.txt
34 | pip-delete-this-directory.txt
35 |
36 | # Unit test / coverage reports
37 | htmlcov/
38 | .tox/
39 | .coverage
40 | .coverage.*
41 | .cache
42 | nosetests.xml
43 | coverage.xml
44 | *,cover
45 |
46 | # Translations
47 | *.mo
48 | *.pot
49 |
50 | # Django stuff:
51 | *.log
52 | media/
53 |
54 | # Sphinx documentation
55 | docs/_build/
56 |
57 | # PyBuilder
58 | target/
59 |
60 | # PyCharm IDE
61 | .idea
62 |
--------------------------------------------------------------------------------
/ansible/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .vagrant
3 | vagrant_ansible_inventory_default
4 |
--------------------------------------------------------------------------------
/ansible/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
5 | VAGRANTFILE_API_VERSION = "2"
6 |
7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
8 | config.vm.box = "precise64"
9 | config.vm.box_url = "http://files.vagrantup.com/precise64.box"
10 |
11 | config.vm.network :private_network, ip: "192.168.33.15"
12 |
13 | config.vm.provider :virtualbox do |vb|
14 | vb.customize ["modifyvm", :id, "--name", "MyCoolApp", "--memory", "512"]
15 | end
16 |
17 | # Shared folder from the host machine to the guest machine. Uncomment the line
18 | # below to enable it.
19 | config.vm.synced_folder "../../youtube-audio-dl", "/webapps/youtube-audio-dl/youtubeadl"
20 |
21 | # Ansible provisioner.
22 | config.vm.provision "ansible" do |ansible|
23 | ansible.playbook = "vagrant.yml"
24 | ansible.host_key_checking = false
25 | ansible.verbose = "v"
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/ansible/ansible.cfg:
--------------------------------------------------------------------------------
1 | [defaults]
2 | host_key_checking=False
--------------------------------------------------------------------------------
/ansible/dbservers.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Provision a {{ application_name }} db server
4 | hosts: dbservers
5 | sudo: yes
6 | sudo_user: root
7 | remote_user: root
8 | vars:
9 | - update_apt_cache: yes
10 | vars_files:
11 | - env_vars/base.yml
12 | - env_vars/{{ env }}.yml
13 |
14 | roles:
15 | - base
16 | - db
--------------------------------------------------------------------------------
/ansible/env_vars/base.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | git_repo: https://github.com/jcalazan/youtube-audio-dl.git
4 |
5 | project_name: youtube-audio-dl
6 | application_name: youtubeadl
--------------------------------------------------------------------------------
/ansible/env_vars/production.yml:
--------------------------------------------------------------------------------
1 | $ANSIBLE_VAULT;1.1;AES256
2 | 64633232656537663937386564333666303265643532313731666234383635356239306463666637
3 | 6633396164393939396635633533376334623464633164640a336331343962326537656530303133
4 | 39316137623434636331333132343862626632353933613766316134313332313536313638623861
5 | 6665353762383033330a623932303837356130323633383666393335343066336365313363663461
6 | 36346566383965623262306664383466613633333932393230313534316335653435633234383264
7 | 33613833663565346637393437386564363331646136313065663065623138626163663566323362
8 | 34653062366665616364383565366562363561333335623531323362373564316531656435623237
9 | 37303337626235306534633761393238373563326432656237666233613166343137623661323662
10 | 32383239393038356130303231306132353436343566303162353966343134653265613362613763
11 | 34656639616133363734306637393261393461633334323833626637663636323238306234336663
12 | 36333735626634663962623736343530353737356564323437633632666133633461383464343366
13 | 31306565373836333732333632346239613032356333363331626537316439336431353065663961
14 | 66313561386666323261616139613734633235323966323561623066373735313531383930626633
15 | 36623662356539636561386439333034373030396130323537376235316437363562393565613232
16 | 37393662663063303063393034343135643665626466613931393637383162343237633331616463
17 | 61346530343466636634303263303637626237383164303938323133353833623263333033313630
18 | 62333835306462663365656138373031366664313661393164323230646264616262323537326438
19 | 33626662353436646563346535663662343063363835633834313165646135393462613739353132
20 | 36643165336663366439326436393435313163316366383434613962353065333232346439356132
21 | 31646330633030333439663030373034383231386631383538313931303764656664353939653834
22 | 66373937316139393061373361396437633132343864316534323665353966346365346464626134
23 | 32626138653734336436613564313739396137636530373230323836376434316631326239616563
24 | 66353465346130613938346237616462636234646436373561343661646330623237366465613864
25 | 34333831663734653131653431666264626465383463383365646161356434373637303933653731
26 | 66313562393031343336353834396638386138356335303966623363646661656239613436626662
27 | 35636237306162626135643263356530373661626538353564363165613633646530353138333462
28 | 37353033383238396164623939613235306538373164316163383536393231353763616163636439
29 | 61393336616332396436393534343630316339303131383332366531323462613962663038656662
30 | 32663038363938313235363165333965393265306461383635313334623435346333373361383766
31 | 65323638333635633836623338346235373637343731646261366331373030323637623739386537
32 | 62393932316363366433356131373038656436383536356433383863396234616164333530383165
33 | 39353232333336326630353234343266313336373335303633656335633839646335396262346366
34 | 61653433326138613263373336353564353064323964383732346261663839343761366631333938
35 | 65616132636135333332333737626463333462386664353738663038326530303164633563626634
36 | 63366133373463373866323633336533653036376166663139373535363438396334303735616138
37 | 33623830363463613637336362343462666634636438656134323264303939396632366234633830
38 | 66643534306130656338303362323565643961333630363464363366343638623763333861626364
39 | 61366637663439623138316339366566383036306633323738313166363538616536396238623830
40 | 64353835633634363330663739346464376637356332363866303364343761303737666334363366
41 | 62666362313166356238396633353561393735663361346262366631633135633737656136343661
42 | 32336233633236323132633762653939333639373032623161383632663033343262613337643236
43 | 65333530623837383964333936623731323932333634656666623935666566626365303039616539
44 | 37306631306538373363373131346139343832666161346631316438313365363438333634386636
45 | 36643564353031323132646364373239343035623464616435613164663931303164656463626530
46 | 32326465303832323961663066633938323332353961633665376133613234323430373065353231
47 | 63366333666333633165313932383465376237333365646231656438303930316231333666303065
48 | 38343764613135383261613439386435313731303565373062343630353038386235363931353661
49 | 65373537643537636638373735333563383631626137623665363765366436316137373533623836
50 | 65633063356231333730313765663462373662353938383531306161666666383636396634336663
51 | 31633262323064366539633334386564623164306564636166633736623436623533663435323363
52 | 64636662336136653933363435353033373965363038323336396130633538663039336632373035
53 | 65383465646638303739613338346134633437306464363735393961316531386534386335656632
54 | 65323435336630376234373638656139633733393464383639323737323030353836396166626163
55 | 34333462663634383734393061663061353230396131633663353963393936613534636364326532
56 | 61633739383361646531303136383437333063656334656463323362386562353161623837646232
57 | 31343464346464393562313463613161653065383663373363336462333135623464643635636336
58 | 34663234363463393935666530636463336430373031643733656230613965326165343939303937
59 | 64316539323932346536646530666463343964636136643061353538313239656239323566373833
60 | 65643463316363336635303039366530333037383131396538356230303534653838326561373361
61 | 34663563376233326433623837323835366432666539313638393630626362623866343065373265
62 | 31623664343331373733613164653663623137656333353961333636666534616638653163326162
63 | 66303937366565643633313662663139336639373231313230353531313731326230313663336237
64 | 32343362316336613738333637316236363035383330323239653037646639303331316634613736
65 | 33616136386165646634333131396564313331383032386665633233643534383466663362323234
66 | 61376436646364653832663464393037393833633033353132646139383338373563613334626133
67 | 63333765613737343630633834616462346236303264656235643663303964313438663361353231
68 | 34666261303661393533623534353631326432373263646331656662363731346136373638633138
69 | 38343164376463656638323534333734303662333865343064363663386534363866336565396234
70 | 31626265303637376564656331623363643734363936616233666361653236386438623630613562
71 | 38613439373834613730393065343139316339323463306234393336353164356263616564643730
72 | 33356633333230333761306633333466396163363035633564306131386537393035393963633934
73 | 61323730316331376534363865663438343331386434383665383033626132306163343730373666
74 | 61656265393834373339646664313238613739386537306663383731646238666463663365333462
75 | 38316664326238326135353631623438393538643833666464333039323561353766356132633633
76 | 63633463393661316661336634363534616665336530363766313661616439333334643937383466
77 | 34643064643437336335396237633337316637366562663237636466353839373865313964336539
78 | 66336239306632633931633365323239383934346461363462323739333266316361633137356534
79 | 65633935343430393131363333663364336564333838353939666361346366323561313233346439
80 | 38666539346162326536346634303233376566313762363831396437326530633031316163656433
81 | 32653531313966653539333364386431343334366637353938326662343339373233613339643166
82 | 65396335326330396163383434353934303632336532373663666463343539323435623138353961
83 | 66653735613765656537346238633530623732656439626463356334633131326535653734313938
84 | 64626432316539383430373733366130656335346636613061383536656634366231643437383339
85 | 36613436613765616564613435333833303661636663393961663839336638303039313837623564
86 | 33386263366566336565323235646330366566383237353032393131663363303032376666323731
87 | 61646630356435656565313865653464306561636139323137313561396537666332386565643861
88 | 30373639323462323464363463316532333132356364633134353364343865363464326139326532
89 | 30396336343864613161666536613362623931643763393664666561366638396233373364666130
90 | 36316437653834383862616338366264363936373836383235373434353930323232363037613964
91 | 32656666303166356335646139336435313136646531356362653139356664373233643734326466
92 | 65613363336534323538613865326165663333646137613365316263383635316561663038343966
93 | 37303637613433633863356263643537613639393533343738663266306263383565373233376437
94 | 65303662373135336239356239386135336564653535333066643030316233633038653830313565
95 | 39666661636531646638613262623833323335373065333134646466653732663964383336656365
96 | 32616466346362393935363965633862646130303561386139396665356162333863633263326233
97 | 35363233643966353034386439303262366539613331306436383261366635626535663432613730
98 | 62643431333461616533376131353933616663393633653961376263373031316433316337336637
99 | 31623163633863363462306132343862636634383530383432343432653937623436306636336562
100 | 61326163633862396132383134336666336235653962386162616363393730616134383431346466
101 | 37633736326338313733363234363838383339343236616631303833643138663464653534313835
102 | 30393665613938383962336231626666383962383638663065363834643265616262333330393136
103 | 64663136343433336265646566326637616431653636376137343338313531373363643833333733
104 | 33343430653930656431353632633737333630333235653435373462363438643935303739383330
105 | 32636432646461363066653630613437306265323031656165666663393234396236356165643064
106 | 34643164383938613134383834356331386637373066316363646336383233373031666561636337
107 | 38306536663063626639306436343033313364306536396138343061613765336536346564326130
108 | 31323230313033323532663235313833356561356265376136393537663436376533393232343164
109 | 61386235313665623964646431313234643132663730376266313632306630623932663839306135
110 | 38366333316566643161613166383638356462343036656461383961326365383065326337366539
111 | 37313032336438643961346464383763616238393936366331623561313864333363376163616336
112 | 35333362646266656235333365386165373638393866323762366339326366353066303230623036
113 | 36326161613463643338303236326236613864613664326637613563313839653135383661613133
114 | 33313038376234636630333232623133306366386466663066326466313465626562663365326334
115 | 33333933356537386338393832343733396633663236386134643163393736363030643331393932
116 | 61353864333638333433323436633766653764386332633461616362373063646335303839643233
117 | 34646436626333323834653239353031396366653238383865343933333733313663326263636130
118 | 63346438626566393834383737376464363664613130663330663566616263393832623061633436
119 | 65353431373238623532323465333462666165626435393462663963353761636634336430653762
120 | 63366439366261333432393830636461356465313035303135333333353065303062363761663439
121 | 30616261396363393732353161396564306238316632306131633534326461316366363566333662
122 | 34303833323464366336326536623866396163336565363436633838353235663837386632326136
123 | 30356637313839303131353065626533656332636534386437643434333332386138343837643864
124 | 66313634306636636331626532396163343361633434663034303561323361386436633639636439
125 | 32653464303065393963373862396236373232343336306332643837653939323634663039323831
126 | 31623131383361323963336339383564353336643837373539653939373130376430613765303831
127 | 65333736636434626663323935366333356161363132366435303765346333633536666334303930
128 | 66343537383139376137626630633531663436386363363539306536633638333865363636643364
129 | 36313937363633623964653330646136383132333933333961333131636361633161306436653936
130 | 61353535306234633938653462316233383434623430316138303964343732663432303035363735
131 | 66623266343336386365386563393734636461343666326635613737333130303764376338653635
132 | 31616637376465646461316138653530313536633262306166316636633837663632376234653866
133 | 30363832663763353435623430633131353538333731353835303239373363316465353136323962
134 | 61376535613036303938653236393338613737326564333339356134653962316563323333623164
135 | 64643333633030313838353839343632323631663339376135386338316531363931356262393362
136 | 33616434323030303436313035373834313565363637326266363461646435373032353765653638
137 | 34646136323765636436353762636138306361373461396663353766643465333461383738326437
138 | 38386561626562363462346365643833393265643439653861393662643366316332353032633839
139 | 36386262333036656132623038333364653932653034663332356436363637653636353764623136
140 | 35386366343638346466316437663762396331393539613136396635363862333037663132623765
141 | 30323261306633633463376135303861396430656662616339373364653666646130633065636162
142 | 65316236643635386262663431363266633936663733313231386431653436393330616538316333
143 | 63396266653730653335393836663064363838346632376636383233383261366638346532633264
144 | 33663635343662633030396534383761623463353936623165663361633939636336366334303532
145 | 35386435643939396233643837363363353066373633396464636231656264623938623134393666
146 | 30343739643536343363393536626135613733343061666539643262326237326631653736633939
147 | 34383861393364656461356237376530653830396666663764306630633035333337343561343531
148 | 64383538393738303865366466383834356263323537646364306633646161636536366235306465
149 | 33613066653365376430383136396232636332303034376235656161636434353836623363633033
150 | 61316334306631623866643730376565336262333535656364393430313838306163653561396337
151 | 61343665333931306136663635356239633836333061376361316230346232366434303665663839
152 | 32613636383333653336366563633231613935383737383837613031396530663636313736666666
153 | 31363738396634393731656434366664323666323439393865323130653430313532363065663537
154 | 33376139353231653438393565393037626631313539653237313338336161633034643638333363
155 | 37313866393064366435373734663636666561333734663138373164333637313632346666366630
156 | 39373139323466316531666464373065343339376532353931396364353134343035316165643435
157 | 37373936393065646136613037353961623131333835643438383537613366363034623638653635
158 | 61323637393366613665623066613531393630316262386366343262393061353564643732393066
159 | 31323239616231663730636231353334326263346163373833396263323838613438323430396264
160 | 65313433623638306634363038353365626263626335643436656462373631386135643735396236
161 | 36663966633634386339393036373435313636353031333566393861353230336235303666663539
162 | 66613862366332653338643964363233326633363738353930363563663130373936343866306135
163 | 32663335653764326433633637636333386535623065336561306330313536623365366431613235
164 | 63323733343839313033636564343635393935393366363661373866366639373365363636643030
165 | 64656534633762646661313938363534316535356564383465383761373435363762323261363338
166 | 33373233383339373466643633653730386233363064336531336363343165643962633336376337
167 | 64356337393762376236323239393730373864356237666533353366306361313330363938373361
168 | 30313330383931666562666337643535613764356366306430363634313435653066313233616436
169 | 33373238376266303537396463316430646261666466393964356331636133303934383264656633
170 | 30346433343266346333393264633266396439616433303931643536643361643130343761366163
171 | 34356362646136313537336662623666353762396238396432646162386634353161396330666533
172 | 38393839633861343966623731393938306163393665643138386463373061393236626233616563
173 | 64303237643934313436326663663130386465396163393931653836383332396364303464396265
174 | 66313536633661326439373938373464613838336537313533353637316266393362643764353966
175 | 34396266386161303830333339363933373438633538626638646636343963373330313635643336
176 | 38386637363464656537383139376633653439353831366238333138373161306533653039666464
177 | 64643832613232356430376438383763346339366263623164656538353534376137323636623164
178 | 37633239646566623431653237653338383636343331343736386332626633383962366439653361
179 | 63333565313436626365616466386637353039396338323331343664393031656235383336636138
180 | 38353439316564323437396563326363623061333531393061346463306433373530396630343536
181 | 31313437663938386537303031366233346162653462303563613865653532386464366666636265
182 | 32666263373262373235663964656464666463626132663038343461336230393161376133616663
183 | 61323236393764663133653064323865306564633066326430323738616539316539363964343764
184 | 37353931393062363764343732666631636535373462333262363663653563383064306462336438
185 | 32616263623835633937373966393538393734353866366362636630376538613766343032353661
186 | 34383365323434666532313062343334626139393762656631353566336161363066643839363565
187 | 39656634363439653233633130613434646536353634633135363634376363356265383163356530
188 | 34323366313664663634363261613836616239383962396532316139303330333634343364623431
189 | 32643865333863393362313566303961383337383835663666303165386436373461613038336138
190 | 35383632346139646631336162306664323932636466653333353938393438336563353962353566
191 | 63326461316563633866653562316365316239326461386566336430323962303966636632636130
192 | 37643939373030343035326134373662363235623436393839653263636137333531653630363334
193 | 38653430643731346363613632393330396336663763376431343833376561306136643465316533
194 | 34376639656538636535316362323634366634303630313464383062323766666465663066316363
195 | 66343961356161663864373362316135306133306332323236333966396536623630353163646333
196 | 39633339626665313930626464316338633935316535393937356339636435386465363838386331
197 | 35623933626239636435656533323532643230623634393762666434303761616562326165626331
198 | 36356537326264373662313039633463626534626432333436653532336462623365633565633233
199 | 66363835623766663838663365643738393533663038323461383838323636376433386135643966
200 | 31336462353162646432333735383237623734333134386663616234316466353837343336386233
201 | 65356239353639626631653637313461316432666665616364656466376638313964393364363164
202 | 38376134326666636635633661383232313862386435663464356434386536633966376139643634
203 | 66623665633932346661636637323831633665396537646163383938626363333263623063323162
204 | 66376139356665313462393563626532363065343238306432613131663739643236336337653932
205 | 63306133353166633762356534313233616664383230316234393137363230326337666561643830
206 | 66643761633934326164653066633332633935616238643238306139333635313433333265666464
207 | 64396432653732333963326339653766313834376637373930313461636663393966613133326237
208 | 66646231393737646336366439366634663235303365626461316532353766653566323066626239
209 | 38356330363062336662373166633261373534626534303961623933666634323064343364663936
210 | 31313265393730323536343036303164393265343062643331386363386661666662343166343932
211 | 30653633393262643537376366643638613039343936353764613132333132346165323662356135
212 | 65653831623536663238616561313661393562383836343237653637633930303063333331313933
213 | 30306435316139386663383064323138303862613431313731313462633263613531356134323331
214 | 63393634653334393966373137653033613232383333383262393731393137643937636235353137
215 | 38353437353434363337623231333132373939323537633033393161333135393133653931613237
216 | 39623434346663346131623361366538313433353036643664633466386238393536316638623365
217 | 66353332313265386137636130316430363038366335383761363330663036663534623435396166
218 | 39393234333762353066613363393230656465613231313563623466366631333039366233343865
219 | 35636136383730336663633137386264323363383937366130643765396233393761623232663739
220 | 61656130393061636161663037303061366561373864353963303265333339643035323433386334
221 | 38386534313037333665396563663864373831356361353038393735623161643563666534643835
222 | 36643432653635666263616439666234656664343966653033343863316462666234643161373938
223 | 37383332386463373737353865333963636130346136633466623634343565346536336634356534
224 | 38316363316164393261663133653232306530323566623365333361626535303930353461393235
225 | 64366465633132636233343530323935303933623062643331383832316335613863653665396336
226 | 62663138653931653165363935633630343834393261633065313538366332353838366335316337
227 | 66393632346437653066636263633630613963316331656630653334393638653664366265643530
228 | 63653463666533613863393632393163353533616364643166353762656630303335633563336133
229 | 63386434373731366463306361613163396465626566303935643165656330363137303664616538
230 | 37663133613561656333363436343039313131323439346231373638383239636534353430336661
231 | 34656436333336336362306263383037653337643530653330616337633235323636616135383865
232 | 65666264373966613536323864653330396561653661623330613731373230613061636534323466
233 | 64336465663636396464383634323964363966356465616664613066353730626466383534383864
234 | 31363663386262316165626338343365343565303339386630386261656166613336346139326635
235 | 36383939323162376432326135323230373335316139623432376434363737633238613734623831
236 | 36396431343864396536626163393733616366333364346638376139383364646235313665613963
237 | 37326531333663353065643135333336343831336361353933666230396162633337343865663337
238 | 33323265613737613364643432313961353364386636333961653636386463316133666439393331
239 | 35663333306661343361323737353638626539353963616330373036353433393334363437623261
240 | 64653838396263636166623431383964633634353433383637613565393739336131636532636535
241 | 32316436363633353261303963626632653332383233626639393362303337643638306231633861
242 | 38393832643561623938666566623436373736346565663038313261343534623766393835623230
243 | 33333637366133636639636339383930323137333630633431363365343062646566336435643830
244 | 613331383632356166626332366431663664
245 |
--------------------------------------------------------------------------------
/ansible/env_vars/vagrant.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | # Git settings.
4 | setup_git_repo: no
5 | git_branch: master
6 |
7 |
8 | # Database settings.
9 | db_user: "{{ application_name }}"
10 | db_name: "{{ application_name }}"
11 | db_password: password
12 |
13 |
14 | # Gunicorn settings. For the number of workers, a good rule to follow is
15 | # 2 x number of CPUs + 1
16 | gunicorn_num_workers: 3
17 |
18 | # Setting this to 1 will restart the Gunicorn process each time
19 | # you make a request, basically reloading the code. Very handy
20 | # when developing. Set to 0 for unlimited requests (default).
21 | gunicorn_max_requests: 0
22 |
23 |
24 | # Nginx settings.
25 | nginx_server_name: "{{ inventory_hostname }}"
26 | ssl_src_dir: ssl_self_signed
27 | ssl_dest_dir: /etc/ssl
28 | ssl_key_password: password
29 |
30 |
31 | # RabbitMQ settings.
32 | rabbitmq_server_name: "{{ inventory_hostname }}"
33 |
34 | rabbitmq_admin_user: admin
35 | rabbitmq_admin_password: password
36 |
37 | rabbitmq_application_vhost: "{{ application_name }}"
38 | rabbitmq_application_user: "{{ application_name }}"
39 | rabbitmq_application_password: password
40 |
41 |
42 | # Celery settings.
43 | celery_num_workers: 2
44 | flower_admin_password: password
45 |
46 |
47 | # Application settings.
48 | django_settings_file: "{{ application_name }}.settings.local"
49 | django_secret_key: "akr2icmg1n8%z^3fe3c+)5d0(t^cy-2_25rrl35a7@!scna^1#"
50 |
51 | broker_url: "amqp://{{ rabbitmq_application_user }}:{{ rabbitmq_application_password }}@localhost/{{ rabbitmq_application_vhost }}"
52 |
53 | run_django_db_migrations: yes
54 | run_django_collectstatic: yes
55 |
56 |
57 | # SSL certs settings.
58 | ssl_dest_dir: /etc/ssl
59 |
60 | ssl_crt: |
61 | -----BEGIN CERTIFICATE-----
62 | MIIDjTCCAnWgAwIBAgIJAMazeCBLPAeCMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
63 | BAYTAlVTMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
64 | aWRnaXRzIFB0eSBMdGQxFjAUBgNVBAMMDSouZXhhbXBsZS5jb20wHhcNMTQwNjE4
65 | MjI0MjU0WhcNMjQwNjE1MjI0MjU0WjBdMQswCQYDVQQGEwJVUzETMBEGA1UECAwK
66 | U29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRYw
67 | FAYDVQQDDA0qLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
68 | CgKCAQEAuTyvpgw5iC7vHGr9cpCa1yVW3rTc/81PWqMPL3lKmV4IzHd7+50QKOFC
69 | QE6nfhYS+jVM/3dk8DQgaaTdo1BVF9kT/p1SQE2aE4AFHfPKXP1M+MFBoqK6uuje
70 | jns4sItZg5yj6QTyTBNOHkaXeCObYpAnp+HokqT5Nmrr/uzPZc7jNZ41ehM2mL3n
71 | J7Zgl40nQj4UqFLsXmlG4g6DKEKilRIpJClLdRm6lydgdVi2HApE4adkDOcIXXY6
72 | 87Y/LFoPFrgpztWv/O0/oJguV7LHttjS9b6LzjF8k7rWqCT4muHy1fYcJXLIOaUr
73 | WEru9FQegppwIo6tQjoZuy09lLOztQIDAQABo1AwTjAdBgNVHQ4EFgQUbYkM8ZEK
74 | +5GbEw1Bx7DHBqbJ6G0wHwYDVR0jBBgwFoAUbYkM8ZEK+5GbEw1Bx7DHBqbJ6G0w
75 | DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAuBfBeTXulSb9dNCMvxzN
76 | XAEIxw1s+Rdlup8v25Otj+5mUAq0LNWDmNID7gA4NcJ/GiCzA7+ojE6g6vFj4weU
77 | LPHnAKN+XbyGyG/Jeqk30qWdWw/3E3bPrJBt4dTT9QwojasHbkIP0/qtzy3UFW9V
78 | 32wScQV1aMXQtip5o5ANidXuTOgz2u+DCWWZmSMb0r1vn8/XV/X39n4iC/7H9TrQ
79 | DFrdr8kCgVJ7UxXDFvx7g6HxDfh0UudkjSxH5L4aQEmdXQAZjDY015lq2mp58LjE
80 | /2gucKfZufEhaPL159OVt5fctnRrFySyDmzQX5z2oVWTrTE83huTRc87XQK1QcYH
81 | +w==
82 | -----END CERTIFICATE-----
83 |
84 | ssl_key: |
85 | -----BEGIN PRIVATE KEY-----
86 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC5PK+mDDmILu8c
87 | av1ykJrXJVbetNz/zU9aow8veUqZXgjMd3v7nRAo4UJATqd+FhL6NUz/d2TwNCBp
88 | pN2jUFUX2RP+nVJATZoTgAUd88pc/Uz4wUGiorq66N6Oeziwi1mDnKPpBPJME04e
89 | Rpd4I5tikCen4eiSpPk2auv+7M9lzuM1njV6EzaYvecntmCXjSdCPhSoUuxeaUbi
90 | DoMoQqKVEikkKUt1GbqXJ2B1WLYcCkThp2QM5whddjrztj8sWg8WuCnO1a/87T+g
91 | mC5Xsse22NL1vovOMXyTutaoJPia4fLV9hwlcsg5pStYSu70VB6CmnAijq1COhm7
92 | LT2Us7O1AgMBAAECggEAHjQU9+A6aUgt2NZhKRMHDFmcRof7GQKjE8ZOrZD7ZvJ8
93 | QMqivq4nemLwaIfqq5Zx1bZnLaiMHtaBCnjFYuGwXkkZB4UjajS9ELzpGK8tqefr
94 | awwn5ZrfE6bw0w6oebDfEaSy3UXfNCRZsnoULJSxu2qB7M/bGj4oHIVmoZR/ZLwG
95 | LRItoK0wB2Bok5bmF9mAfW9EkoCOwkQP6uEynJ7z1f03teGJhSWu8xfjJv7XkLxG
96 | vIFbSSeGKZdEHK5fz5nHyr8RCkF5DNPagrs5gz0o1clDeG3VcQhCUgE1y8Ly8iSR
97 | LvDhk6KcfTscvdvxXNKPYPtqpFZfnJTt4qVM5rGaAQKBgQDd94EiefLVPxei/gqB
98 | cfhmtsDAdeQRqdJedg/PE4KDzlAqzOY/Bd4klVASwA0yxXepqf2ZRT1vhMkjFmSM
99 | kproc+gzKFQxxUSmJ//Jl2csaR3+UTAiBiv3b5BuCptG9WaHxRwx/jwHyslANrHP
100 | D+33ybLTOjlMbktrwIkqR1JzwQKBgQDVo31EYOQ7fDt4DYLRVHMoKJpErbwDH9jt
101 | hqfloKrV+UfrAWtn4mMcrCb6LKWTiv5T52gPbV/sSM5+7U97W3goffJShCPKobd3
102 | 6vhn2rowPjQd3IkZEygUuw4xTOHWUl1MB6Z9zyUd3hM1/wlO1CiHtaCpnEVgX66b
103 | yEF7IVXs9QKBgBIrscmVvBhS6udv7oI8Rz55VXwr6ni7szoCZjbofPW3TP7D+VFN
104 | dKsAAicWy73NRoeAH/+NGINplmGl8qNDWSUQYADYG1Rbtsv3WEwzdcG/9TGdidgv
105 | Myg1XNh1S9LaQgN5Ul6RVm643hLAp3uw7SUswNPj307vdIMkptXsMsbBAoGAdfuI
106 | 9ZdQ0+0i5oUHptUtl5L8x0rvFwaihWKlHHJjhjHZ3tX02/UxaSdFi0nW0ymilPGq
107 | DUMJA3Od3ojuKSD1td8AUUO6hHBU4zv3nVs1Eel4XLlrWVaz/ubiyqU732GzNobP
108 | EpGwXNNE5sAHAuq1y2Sp6qFryvJseonYZ8icLHUCgYBHSWGgjhOA7KyZdcTdmpu+
109 | fGAwN2Coj2l+PKvQEJkX96IOboHDkd7N8mwyfjb30FcD1uVkEwjp55PpHmYph8xD
110 | GhN+yDgmf5OjDia0mFhv1nA/Nh16rQZd2NV7qYx0npPabOfud/8imdgOFr78HCjS
111 | MoqV6aeRY/7uwLiviaIUJg==
112 | -----END PRIVATE KEY-----
--------------------------------------------------------------------------------
/ansible/local:
--------------------------------------------------------------------------------
1 | [webservers]
2 | 192.168.33.15
3 |
4 | [dbservers]
5 | 192.168.33.15
6 |
7 | [memcachedservers]
8 | 192.168.33.15
9 |
--------------------------------------------------------------------------------
/ansible/production:
--------------------------------------------------------------------------------
1 | [all:vars]
2 | env=production
3 |
4 | [webservers]
5 | www.youtubeadl.com
6 |
7 | [dbservers]
8 | www.youtubeadl.com
--------------------------------------------------------------------------------
/ansible/roles/base/tasks/create_swap_file.yml:
--------------------------------------------------------------------------------
1 | - name: Create swap file
2 | command: dd if=/dev/zero of={{ swap_file_path }} bs=1024 count={{ swap_file_size_kb }}k
3 | creates="{{ swap_file_path }}"
4 | tags: swap.file.create
5 |
6 | - name: Change swap file permissions
7 | file: path="{{ swap_file_path }}"
8 | owner=root
9 | group=root
10 | mode=0600
11 | tags: swap.file.permissions
12 |
13 | - name: Check swap file type
14 | command: file {{ swap_file_path }}
15 | register: swapfile
16 | tags: swap.file.mkswap
17 |
18 | - name: Make swap file
19 | command: "sudo mkswap {{ swap_file_path }}"
20 | when: swapfile.stdout.find('swap file') == -1
21 | tags: swap.file.mkswap
22 |
23 | - name: Write swap entry in fstab
24 | mount: name=none
25 | src={{ swap_file_path }}
26 | fstype=swap
27 | opts=sw
28 | passno=0
29 | dump=0
30 | state=present
31 | tags: swap.fstab
32 |
33 | - name: Mount swap
34 | command: "swapon {{ swap_file_path }}"
35 | when: ansible_swaptotal_mb < 1
36 | tags: swap.file.swapon
--------------------------------------------------------------------------------
/ansible/roles/base/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - include: create_swap_file.yml
4 | when: create_swap_file
5 | tags: swap
6 |
7 | - name: Ensure bash, OpenSSl, and libssl are the latest versions
8 | apt: name={{ item }} update_cache={{ update_apt_cache }} state=latest
9 | with_items:
10 | - bash
11 | - openssl
12 | - libssl-dev
13 | - libssl-doc
14 | tags: packages
15 |
16 | - name: Install base packages
17 | apt: name={{ item }} update_cache={{ update_apt_cache }} force=yes state=installed
18 | with_items:
19 | - build-essential
20 | - ntp
21 | - htop
22 | - git
23 | - libpq-dev
24 | - python-dev
25 | - python-pip
26 | - python-pycurl
27 | - supervisor
28 | tags: packages
29 |
30 | - name: Install newrelic
31 | pip: name=newrelic
32 | tags: packages
33 |
34 | - name: Install virtualenv
35 | pip: name=virtualenv
36 | tags: packages
37 |
--------------------------------------------------------------------------------
/ansible/roles/base/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | create_swap_file: yes
4 | swap_file_path: /swapfile
5 | swap_file_size_kb: 512
--------------------------------------------------------------------------------
/ansible/roles/celery/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: restart {{ celery_application_name }}
4 | supervisorctl: name={{ celery_application_name }} state=restarted
5 |
6 | - name: restart flower
7 | supervisorctl: name=flower state=restarted
--------------------------------------------------------------------------------
/ansible/roles/celery/tasks/copy_scripts.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Create the folder for the celery scripts
4 | file: path={{ celery_scripts_dir }}
5 | owner={{ celery_user }}
6 | group={{ celery_group }}
7 | mode=0774
8 | state=directory
9 | tags:
10 | - celery
11 |
12 | - name: Create the {{ celery_application_name }} script file
13 | template: src={{ celery_template_file }}
14 | dest={{ celery_scripts_dir }}/{{ celery_application_name }}_start
15 | owner={{ celery_user }}
16 | group={{ celery_group }}
17 | mode=0755
18 | tags:
19 | - celery
20 |
21 | - name: Create the flower script file
22 | template: src=flower_start.j2
23 | dest={{ celery_scripts_dir }}/flower_start
24 | owner={{ celery_user }}
25 | group={{ celery_group }}
26 | mode=0755
27 | tags:
28 | - celery
29 | - flower
--------------------------------------------------------------------------------
/ansible/roles/celery/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - include: copy_scripts.yml
4 |
5 | - include: setup_supervisor.yml
6 |
7 | - name: Check running applications managed by supervisor
8 | shell: supervisorctl status
9 | register: supervisor_applications
10 | tags:
11 | - celery
12 | - deploy
13 |
14 | - name: Restart the {{ celery_application_name }} app
15 | supervisorctl: name={{ celery_application_name }} state=restarted
16 | when: supervisor_applications.stdout.find('{{ celery_application_name }}') != -1
17 | tags:
18 | - celery
19 | - deploy
20 |
21 | - name: Restart the flower app
22 | supervisorctl: name=flower state=restarted
23 | when: supervisor_applications.stdout.find('flower') != -1
24 | tags:
25 | - flower
26 | - deploy
--------------------------------------------------------------------------------
/ansible/roles/celery/tasks/setup_supervisor.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Install Supervisor
4 | apt: name=supervisor update_cache={{ update_apt_cache }} state=installed
5 | tags:
6 | - celery
7 | - flower
8 |
9 | - name: Ensure supervisor service is started
10 | service: name=supervisor state=started enabled=yes
11 | tags:
12 | - celery
13 | - flower
14 |
15 | - name: Create the Supervisor config file for {{ celery_application_name }}
16 | template: src=supervisor_{{ celery_application_name }}.conf.j2
17 | dest=/etc/supervisor/conf.d/{{ celery_application_name }}.conf
18 | tags:
19 | - celery
20 |
21 | - name: Create the Supervisor config file for flower
22 | template: src=supervisor_flower.conf.j2
23 | dest=/etc/supervisor/conf.d/flower.conf
24 | tags:
25 | - flower
26 |
27 | - name: Create the {{ celery_application_name }} log directory
28 | file: path={{ celery_log_dir }}
29 | owner={{ celery_user }}
30 | group={{ celery_group }}
31 | state=directory
32 | tags:
33 | - celery
34 | - flower
35 |
36 | - name: Create the {{ celery_application_name }} log file
37 | file: path={{ celery_log_file }}
38 | owner={{ celery_user }}
39 | group={{ celery_group }}
40 | state=touch
41 | tags:
42 | - celery
43 |
44 | - name: Create the flower log file
45 | file: path={{ flower_log_file }}
46 | owner={{ celery_user }}
47 | group={{ celery_group }}
48 | state=touch
49 | tags:
50 | - flower
51 |
52 | - name: Re-read the Supervisor config files
53 | command: supervisorctl reread
54 | tags:
55 | - celery
56 | - flower
57 |
58 | - name: Update Supervisor to add the apps in the process group
59 | command: supervisorctl update
60 | tags:
61 | - celery
62 | - flower
--------------------------------------------------------------------------------
/ansible/roles/celery/templates/celery_start.j2:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | DJANGODIR={{ project_path }}
4 |
5 | # Activate the virtual environment.
6 | cd $DJANGODIR
7 | . {{ virtualenv_path }}/bin/activate
8 | . {{ virtualenv_path }}/bin/postactivate
9 |
10 | # Programs meant to be run under supervisor should not daemonize themselves
11 | # (do not use --daemon).
12 | exec celery -A {{ application_name }} worker -E -l info --concurrency={{ celery_num_workers }}
13 |
--------------------------------------------------------------------------------
/ansible/roles/celery/templates/flower_start.j2:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | DJANGODIR={{ project_path }}
4 |
5 | # Activate the virtual environment.
6 | cd $DJANGODIR
7 | . {{ virtualenv_path }}/bin/activate
8 | . {{ virtualenv_path }}/bin/postactivate
9 |
10 | # Programs meant to be run under supervisor should not daemonize themselves
11 | # (do not use --daemon).
12 | exec celery -A youtubeadl flower --port=5555 --basic_auth=admin:{{ flower_admin_password }}
--------------------------------------------------------------------------------
/ansible/roles/celery/templates/supervisor_celery.conf.j2:
--------------------------------------------------------------------------------
1 | [program:{{ celery_application_name }}]
2 | command={{ celery_scripts_dir }}/{{ celery_application_name }}_start
3 |
4 | autostart=true
5 | autorestart=true
6 |
7 | user={{ celery_user }}
8 |
9 | stdout_logfile={{ celery_log_file }}
10 | redirect_stderr = true
--------------------------------------------------------------------------------
/ansible/roles/celery/templates/supervisor_flower.conf.j2:
--------------------------------------------------------------------------------
1 | [program:flower]
2 | command={{ celery_scripts_dir }}/flower_start
3 |
4 | autostart=true
5 | autorestart=true
6 |
7 | user={{ celery_user }}
8 |
9 | stdout_logfile={{ flower_log_file }}
10 | redirect_stderr = true
--------------------------------------------------------------------------------
/ansible/roles/celery/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | server_root_dir: /webapps
4 |
5 | virtualenv_path: "/webapps/{{ application_name }}"
6 | project_path: "{{ virtualenv_path }}/{{ project_name }}"
7 |
8 | celery_user: "{{ application_name }}"
9 | celery_group: webapps
10 |
11 | celery_application_name: celery
12 | celery_scripts_dir: "{{ virtualenv_path }}/scripts/celery"
13 | celery_template_file: "{{ celery_application_name }}_start.j2"
14 |
15 | celery_log_dir: "{{ virtualenv_path }}/logs"
16 | celery_log_file: "{{ celery_log_dir }}/{{ celery_application_name }}.log"
17 | flower_log_file: "{{ celery_log_dir }}/flower.log"
--------------------------------------------------------------------------------
/ansible/roles/db/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: restart postgresql
4 | service: name=postgresql state=restarted enabled=yes
5 |
--------------------------------------------------------------------------------
/ansible/roles/db/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Install PostgreSQL
4 | apt: name={{ item }} update_cache={{ update_apt_cache }} state=installed
5 | with_items:
6 | - postgresql
7 | - postgresql-contrib
8 | - python-psycopg2
9 | tags: packages
10 |
11 | - name: Ensure the PostgreSQL service is running
12 | service: name=postgresql state=started enabled=yes
13 |
14 | - name: Ensure database is created
15 | sudo_user: postgres
16 | postgresql_db: name={{ db_name }}
17 | encoding='UTF-8'
18 | lc_collate='en_US.UTF-8'
19 | lc_ctype='en_US.UTF-8'
20 | template='template0'
21 | state=present
22 |
23 | - name: Ensure user has access to the database
24 | sudo_user: postgres
25 | postgresql_user: db={{ db_name }}
26 | name={{ db_user }}
27 | password={{ db_password }}
28 | priv=ALL
29 | state=present
30 |
31 | - name: Ensure user does not have unnecessary privileges
32 | sudo_user: postgres
33 | postgresql_user: name={{ db_user }}
34 | role_attr_flags=NOSUPERUSER,NOCREATEDB
35 | state=present
--------------------------------------------------------------------------------
/ansible/roles/memcached/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: restart memcached
4 | service: name=memcached state=restarted enabled=yes
5 |
--------------------------------------------------------------------------------
/ansible/roles/memcached/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Install Memcached
4 | apt: name=memcached update_cache={{ update_apt_cache }} state=installed
5 | tags: packages
6 |
7 | - name: Create the Memcached configuration file
8 | template: src=memcached.conf.j2
9 | dest=/etc/memcached.conf
10 | mode=0644
11 | backup=yes
12 | notify:
13 | - restart memcached
14 |
15 | - name: Ensure the Memcached service is running
16 | service: name=memcached state=started enabled=yes
--------------------------------------------------------------------------------
/ansible/roles/memcached/templates/memcached.conf.j2:
--------------------------------------------------------------------------------
1 | # 2003 - Jay Bonci
2 | # This configuration file is read by the start-memcached script provided as
3 | # part of the Debian GNU/Linux distribution.
4 |
5 | # Run memcached as a daemon. This command is implied, and is not needed for the
6 | # daemon to run. See the README.Debian that comes with this package for more
7 | # information.
8 | -d
9 |
10 | # Log memcached's output to /var/log/memcached
11 | logfile /var/log/memcached.log
12 |
13 | # Be verbose
14 | # -v
15 |
16 | # Be even more verbose (print client commands as well)
17 | # -vv
18 |
19 | # Start with a cap of 64 megs of memory. It's reasonable, and the daemon default
20 | # Note that the daemon will grow to this size, but does not start out holding this much
21 | # memory
22 | -m {{ memcached_max_memory_mb }}
23 |
24 | # Default connection port is 11211
25 | -p {{ memcached_port }}
26 |
27 | # Run the daemon as root. The start-memcached will default to running as root if no
28 | # -u command is present in this config file
29 | -u {{ memcached_user }}
30 |
31 | # Specify which IP address to listen on. The default is to listen on all IP addresses
32 | # This parameter is one of the only security measures that memcached has, so make sure
33 | # it's listening on a firewalled interface.
34 | -l {{ memcached_listen }}
35 |
36 | # Limit the number of simultaneous incoming connections. The daemon default is 1024
37 | -c {{ memcached_max_connections }}
38 |
39 | # Lock down all paged memory. Consult with the README and homepage before you do this
40 | # -k
41 |
42 | # Return error when memory is exhausted (rather than removing items)
43 | # -M
44 |
45 | # Maximize core file limit
46 | # -r
--------------------------------------------------------------------------------
/ansible/roles/memcached/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | memcached_listen: 127.0.0.1
4 | memcached_port: 11211
5 | memcached_user: nobody
6 | memcached_max_memory_mb: 64
7 | memcached_max_connections: 1024
8 |
--------------------------------------------------------------------------------
/ansible/roles/rabbitmq/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: restart rabbitmq-server
4 | service: name=rabbitmq-server state=restarted
--------------------------------------------------------------------------------
/ansible/roles/rabbitmq/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Add the RabbitMQ public GPG key to the apt repo
4 | apt_key: url=http://www.rabbitmq.com/rabbitmq-signing-key-public.asc
5 | state=present
6 |
7 | - name: Add RabbitMQ to the sources list
8 | apt_repository: repo='deb http://www.rabbitmq.com/debian/ testing main'
9 | update_cache={{ update_apt_cache }}
10 | state=present
11 |
12 | - name: Install RabbitMQ server
13 | apt: name={{ item }} update_cache={{ update_apt_cache }} force=yes state=installed
14 | with_items:
15 | - rabbitmq-server
16 |
17 | - name: Enable the RabbitMQ Management Console
18 | rabbitmq_plugin: names=rabbitmq_management state=enabled
19 | notify: restart rabbitmq-server
20 |
21 | - include: setup_vhosts.yml
22 |
23 | - include: setup_users.yml
24 |
25 | - name: Ensure that the RabbitMQ service is running
26 | service: name=rabbitmq-server state=started enabled=yes
--------------------------------------------------------------------------------
/ansible/roles/rabbitmq/tasks/setup_users.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Create default admin user
4 | rabbitmq_user: user={{ rabbitmq_admin_user }}
5 | password={{ rabbitmq_admin_password }}
6 | vhost=/
7 | tags=administrator
8 | state=present
9 |
10 | - name: Create application user
11 | rabbitmq_user: user={{ rabbitmq_application_user }}
12 | password={{ rabbitmq_application_password }}
13 | vhost={{ rabbitmq_application_vhost }}
14 | configure_priv=.*
15 | read_priv=.*
16 | write_priv=.*
17 | state=present
18 |
19 | - name: Ensure the default 'guest' user doesn't exist
20 | rabbitmq_user: user=guest
21 | state=absent
22 |
23 |
--------------------------------------------------------------------------------
/ansible/roles/rabbitmq/tasks/setup_vhosts.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Create a vhost for the application
4 | rabbitmq_vhost: name={{ rabbitmq_application_vhost }} state=present
--------------------------------------------------------------------------------
/ansible/roles/web/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: restart application
4 | supervisorctl: name={{ application_name }} state=restarted
5 |
6 | - name: restart nginx
7 | service: name=nginx state=restarted enabled=yes
8 |
9 | - name: reload nginx
10 | service: name=nginx state=reloaded
11 |
--------------------------------------------------------------------------------
/ansible/roles/web/tasks/create_users_and_groups.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Create the application user
4 | user: name={{ gunicorn_user }} state=present
5 |
6 | - name: Create the application group
7 | group: name={{ gunicorn_group }} system=yes state=present
8 |
9 | - name: Add the application user to the application group
10 | user: name={{ gunicorn_user }} group={{ gunicorn_group }} state=present
--------------------------------------------------------------------------------
/ansible/roles/web/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Install additional packages
4 | apt: name={{ item }} update_cache={{ update_apt_cache }} force=yes state=installed
5 | with_items:
6 | - ffmpeg
7 | - libavcodec-extra-53
8 | tags: packages
9 |
10 | - include: create_users_and_groups.yml
11 |
12 | - include: setup_virtualenv.yml
13 | tags: virtualenv
14 |
15 | - include: setup_git_repo.yml
16 | tags: deploy
17 |
18 | - include: setup_django_app.yml
19 | tags: deploy
20 |
21 | - include: setup_supervisor.yml
22 | tags: supervisor
23 |
24 | - include: set_file_permissions.yml
25 | tags: deploy
26 |
27 | - include: setup_nginx.yml
28 | tags: nginx
29 |
30 | - include: setup_cron_jobs.yml
31 | tags: cron
--------------------------------------------------------------------------------
/ansible/roles/web/tasks/set_file_permissions.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Ensure that the application file permissions are set properly
4 | file: path={{ virtualenv_path }}
5 | recurse=yes
6 | owner={{ gunicorn_user }}
7 | group={{ gunicorn_group }}
8 | state=directory
9 | notify: restart application
10 |
--------------------------------------------------------------------------------
/ansible/roles/web/tasks/setup_cron_jobs.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Ensure that a daily youtube-dl package update job exists
4 | cron: name="daily youtube-dl update"
5 | special_time=daily
6 | user=root
7 | job=". /webapps/youtubeadl/bin/activate && pip install -U youtube-dl && supervisorctl restart all"
8 | state=present
9 |
10 | - name: Ensure that a daily file cleanup job exists
11 | cron: name="daily file cleanup"
12 | special_time=daily
13 | user=root
14 | job="cd /webapps/youtubeadl/media && rm -rf *.mp3"
15 | state=present
--------------------------------------------------------------------------------
/ansible/roles/web/tasks/setup_django_app.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Install packages required by the Django app inside virtualenv
4 | pip: virtualenv={{ virtualenv_path }} requirements={{ requirements_file }}
5 |
6 | - name: Run the Django syncdb command
7 | django_manage:
8 | command: syncdb
9 | app_path: "{{ project_path }}"
10 | virtualenv: "{{ virtualenv_path }}"
11 | settings: "{{ django_settings_file }}"
12 | environment: django_environment
13 | when: run_django_syncdb is defined and run_django_sync_db
14 | tags: django.syncdb
15 |
16 | - name: Run Django database migrations
17 | django_manage:
18 | command: migrate
19 | app_path: "{{ project_path }}"
20 | virtualenv: "{{ virtualenv_path }}"
21 | settings: "{{ django_settings_file }}"
22 | environment: django_environment
23 | when: run_django_db_migrations is defined and run_django_db_migrations
24 | tags: django.migrate
25 |
26 | - name: Run Django collectstatic
27 | django_manage:
28 | command: collectstatic
29 | app_path: "{{ project_path }}"
30 | virtualenv: "{{ virtualenv_path }}"
31 | settings: "{{ django_settings_file }}"
32 | environment: django_environment
33 | when: run_django_collectstatic is defined and run_django_collectstatic
34 | tags: django.collectstatic
--------------------------------------------------------------------------------
/ansible/roles/web/tasks/setup_git_repo.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Setup the Git repo
4 | git: repo={{ git_repo }}
5 | version="{{ git_branch }}"
6 | dest={{ project_path }}
7 | accept_hostkey=yes
8 | when: setup_git_repo
9 | tags: git
10 |
11 | - name: Delete all .pyc files
12 | command: find . -name '*.pyc' -delete
13 | args:
14 | chdir: "{{ project_path }}"
15 | tags: git
--------------------------------------------------------------------------------
/ansible/roles/web/tasks/setup_nginx.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Install Nginx
4 | apt: name=nginx update_cache={{ update_apt_cache }} state=installed
5 | tags: packages
6 |
7 | - name: Copy the SSL certificate to the remote server
8 | copy: content="{{ ssl_crt }}" dest={{ ssl_dest_dir }}/{{ application_name }}.crt
9 | notify: restart nginx
10 |
11 | - name: Copy the SSL private key to the remote server
12 | copy: content="{{ ssl_key }}" dest={{ ssl_dest_dir }}/{{ application_name }}.key
13 | notify: restart nginx
14 |
15 | - name: Create the Nginx configuration file
16 | template: src=nginx_site_config.j2
17 | dest=/etc/nginx/sites-available/{{ application_name }}
18 | backup=yes
19 | notify: reload nginx
20 |
21 | - name: Ensure that the default site is disabled
22 | command: rm /etc/nginx/sites-enabled/default
23 | removes=/etc/nginx/sites-enabled/default
24 | notify: reload nginx
25 |
26 | - name: Ensure that the application site is enabled
27 | command: ln -s /etc/nginx/sites-available/{{ application_name }}
28 | /etc/nginx/sites-enabled/{{ application_name }}
29 | creates=/etc/nginx/sites-enabled/{{ application_name }}
30 | notify: reload nginx
31 |
32 | - name: Ensure Nginx service is started
33 | service: name=nginx state=started enabled=yes
--------------------------------------------------------------------------------
/ansible/roles/web/tasks/setup_supervisor.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Create the Supervisor config file
4 | template: src=supervisor_config.j2
5 | dest=/etc/supervisor/conf.d/{{ application_name }}.conf
6 | backup=yes
7 |
8 | - name: Re-read the Supervisor config files
9 | supervisorctl: name={{ application_name }} state=present
10 |
11 | - name: Restart Supervisor
12 | supervisorctl: name={{ application_name }} state=restarted
13 |
--------------------------------------------------------------------------------
/ansible/roles/web/tasks/setup_virtualenv.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Create the virtualenv
4 | command: virtualenv {{ virtualenv_path }} --no-site-packages
5 | creates={{ virtualenv_path }}/bin/activate
6 |
7 | - name: Ensure gunicorn is installed
8 | pip: virtualenv={{ virtualenv_path }} name=gunicorn
9 |
10 | - name: Create the Gunicorn script file
11 | template: src=gunicorn_start.j2
12 | dest={{ virtualenv_path }}/bin/gunicorn_start
13 | owner={{ gunicorn_user }}
14 | group={{ gunicorn_group }}
15 | mode=0755
16 | backup=yes
17 | tags: deploy
18 |
19 | - name: Create the application log folder
20 | file: path={{ application_log_dir }}
21 | owner={{ gunicorn_user }}
22 | group={{ gunicorn_group }}
23 | mode=0774
24 | state=directory
25 |
26 | - name: Create the application log file
27 | command: touch {{ application_log_file }}
28 | creates={{ application_log_file }}
29 |
30 | - name: Create the virtualenv postactivate script to set environment variables
31 | template: src=virtualenv_postactivate.j2
32 | dest={{ virtualenv_path }}/bin/postactivate
33 | owner={{ gunicorn_user }}
34 | group={{ gunicorn_group }}
35 | mode=0640
36 | backup=yes
37 | tags: deploy
38 |
39 | - name: Set permission to the application log file
40 | file: path={{ application_log_file }}
41 | owner={{ gunicorn_user }}
42 | group={{ gunicorn_group }}
43 | mode=0664
44 | state=file
45 |
46 | - name: Create the maintenance page
47 | template: src=maintenance_off.html
48 | dest={{ virtualenv_path }}/maintenance_off.html
49 | mode=0664
50 |
--------------------------------------------------------------------------------
/ansible/roles/web/templates/gunicorn_start.j2:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | NAME="{{ application_name }}"
4 | DJANGODIR="{{ project_path }}"
5 | SOCKFILE={{ virtualenv_path }}/run/gunicorn.sock
6 | USER={{ gunicorn_user }}
7 | GROUP={{ gunicorn_group }}
8 | NUM_WORKERS={{ gunicorn_num_workers }}
9 |
10 | # Set this to 0 for unlimited requests. During development, you might want to
11 | # set this to 1 to automatically restart the process on each request (i.e. your
12 | # code will be reloaded on every request).
13 | MAX_REQUESTS={{ gunicorn_max_requests }}
14 |
15 | echo "Starting $NAME as `whoami`"
16 |
17 | # Activate the virtual environment.
18 | cd $DJANGODIR
19 | . {{ virtualenv_path }}/bin/activate
20 |
21 | # Set additional environment variables.
22 | . {{ virtualenv_path }}/bin/postactivate
23 |
24 | # Create the run directory if it doesn't exist.
25 | RUNDIR=$(dirname $SOCKFILE)
26 | test -d $RUNDIR || mkdir -p $RUNDIR
27 |
28 | # Programs meant to be run under supervisor should not daemonize themselves
29 | # (do not use --daemon). Also note that the timeout is set to 5 minutes as we're
30 | # currently waiting for the celery task to finish before returning a response, which
31 | # could sometimes take a while. We should remove this later once we fixed the Ajax call
32 | # to check for the task status as this could tie up all the Gunicorn workers if the
33 | # site gets busy.
34 | exec gunicorn \
35 | --name $NAME \
36 | --workers $NUM_WORKERS \
37 | --max-requests $MAX_REQUESTS \
38 | --timeout 300 \
39 | --user $USER --group $GROUP \
40 | --log-level debug \
41 | --bind unix:$SOCKFILE \
42 | {{ application_name }}.wsgi
43 |
--------------------------------------------------------------------------------
/ansible/roles/web/templates/maintenance_off.html:
--------------------------------------------------------------------------------
1 |
2 | Site Maintenance
3 |
11 |
12 |
13 | We’ll be back soon!
14 |
15 |
Sorry for the inconvenience but we’re performing some maintenance at the moment. If you need to you can always contact us , otherwise we’ll be back online shortly!
16 |
— The Team
17 |
18 |
19 |
--------------------------------------------------------------------------------
/ansible/roles/web/templates/nginx_site_config.j2:
--------------------------------------------------------------------------------
1 | upstream wsgi_server {
2 | # fail_timeout=0 means we always retry an upstream even if it failed
3 | # to return a good HTTP response (in case the Unicorn master nukes a
4 | # single worker for timing out).
5 |
6 | server unix:{{ virtualenv_path }}/run/gunicorn.sock fail_timeout=0;
7 | }
8 |
9 | server {
10 | listen 80;
11 | server_name {{ nginx_server_name }};
12 | rewrite ^/admin/ https://$server_name$request_uri? permanent;
13 |
14 | client_max_body_size 4G;
15 |
16 | access_log {{ nginx_access_log_file }};
17 | error_log {{ nginx_error_log_file }};
18 |
19 | location /static/ {
20 | alias {{ nginx_static_dir }};
21 | }
22 |
23 | location /media/ {
24 | alias {{ nginx_media_dir }};
25 | }
26 |
27 | location / {
28 | if (-f {{ virtualenv_path }}/maintenance_on.html) {
29 | return 503;
30 | }
31 |
32 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
33 | proxy_set_header Host $http_host;
34 | proxy_redirect off;
35 | proxy_read_timeout 300;
36 |
37 | # Try to serve static files from nginx, no point in making an
38 | # *application* server like Unicorn/Rainbows! serve static files.
39 | if (!-f $request_filename) {
40 | proxy_pass http://wsgi_server;
41 | break;
42 | }
43 | }
44 |
45 | # Error pages
46 | error_page 500 502 504 /500.html;
47 | location = /500.html {
48 | root {{ project_path }}/{{ application_name }}/templates/;
49 | }
50 |
51 | error_page 503 /maintenance_on.html;
52 | location = /maintenance_on.html {
53 | root {{ virtualenv_path }}/;
54 | }
55 | }
56 |
57 | server {
58 | listen 443;
59 | server_name {{ nginx_server_name }};
60 | ssl on;
61 | ssl_certificate {{ ssl_dest_dir }}/{{ application_name }}.crt;
62 | ssl_certificate_key {{ ssl_dest_dir }}/{{ application_name }}.key;
63 |
64 | client_max_body_size 4G;
65 |
66 | access_log {{ nginx_access_log_file }};
67 | error_log {{ nginx_error_log_file }};
68 |
69 | location /static/ {
70 | alias {{ nginx_static_dir }};
71 | }
72 |
73 | location /media/ {
74 | alias {{ nginx_media_dir }};
75 | }
76 |
77 | location / {
78 | if (-f {{ virtualenv_path }}/maintenance_on.html) {
79 | return 503;
80 | }
81 |
82 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
83 | proxy_set_header X-Forwarded-Proto https;
84 | proxy_set_header Host $http_host;
85 | proxy_redirect off;
86 | proxy_read_timeout 300;
87 |
88 | # Try to serve static files from nginx, no point in making an
89 | # *application* server like Unicorn/Rainbows! serve static files.
90 | if (!-f $request_filename) {
91 | proxy_pass http://wsgi_server;
92 | break;
93 | }
94 | }
95 |
96 | # Error pages
97 | error_page 500 502 504 /500.html;
98 | location = /500.html {
99 | root {{ project_path }}/{{ application_name }}/templates/;
100 | }
101 |
102 | error_page 503 /maintenance_on.html;
103 | location = /maintenance_on.html {
104 | root {{ virtualenv_path }}/;
105 | }
106 | }
107 |
108 |
109 | ### DOMAIN REDIRECTS ###
110 |
111 | # Redirect non-www top-level domain to www
112 | server {
113 | listen 80;
114 | listen 443;
115 | server_name youtubeadl.com;
116 | return 301 http://www.youtubeadl.com$request_uri;
117 | }
--------------------------------------------------------------------------------
/ansible/roles/web/templates/supervisor_config.j2:
--------------------------------------------------------------------------------
1 | [program:{{ application_name }}]
2 | command = {{ virtualenv_path }}/bin/gunicorn_start
3 | user = {{ gunicorn_user }}
4 | stdout_logfile = {{ application_log_file }}
5 | redirect_stderr = true
--------------------------------------------------------------------------------
/ansible/roles/web/templates/virtualenv_postactivate.j2:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | {% for variable_name, value in django_environment.iteritems() %}
4 | export {{ variable_name }}="{{ value }}"
5 | {% endfor %}
6 |
--------------------------------------------------------------------------------
/ansible/roles/web/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | # Application settings.
4 | virtualenv_path: "/webapps/{{ application_name }}"
5 | project_path: "{{ virtualenv_path }}/{{ project_name }}"
6 | application_log_dir: "{{ virtualenv_path }}/logs"
7 | application_log_file: "{{ application_log_dir }}/gunicorn_supervisor.log"
8 | requirements_file: "{{ project_path }}/requirements.txt"
9 |
10 |
11 | # Gunicorn settings
12 | gunicorn_user: "{{ application_name }}"
13 | gunicorn_group: webapps
14 |
15 |
16 | # Nginx settings
17 | nginx_http_port: 80
18 | nginx_https_port: 443
19 | nginx_access_log_file: "{{ application_log_dir }}/nginx_access.log"
20 | nginx_error_log_file: "{{ application_log_dir }}/nginx_error.log"
21 | nginx_static_dir: "{{ virtualenv_path }}/static/"
22 | nginx_media_dir: "{{ virtualenv_path }}/media/"
23 |
24 |
25 | # Django Environment variables
26 | django_environment:
27 | DJANGO_SETTINGS_MODULE: "{{ django_settings_file }}"
28 | DJANGO_SECRET_KEY: "{{ django_secret_key }}"
29 | MEDIA_ROOT: "{{ nginx_media_dir }}"
30 | STATIC_ROOT: "{{ nginx_static_dir }}"
31 | DATABASE_USER: "{{ db_user }}"
32 | DATABASE_PASSWORD: "{{ db_password }}"
33 | BROKER_URL: "{{ broker_url }}"
34 | EMAIL_HOST: "{{ email_host }}"
35 | EMAIL_HOST_USER: "{{ email_host_user }}"
36 | EMAIL_HOST_PASSWORD: "{{ email_host_password }}"
37 | GOOGLE_ANALYTICS_TRACKING_ID: "{{ google_analytics_tracking_id }}"
38 | ADDTHIS_PUBLISHER_ID: "{{ addthis_publisher_id }}"
39 |
--------------------------------------------------------------------------------
/ansible/site.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - include: dbservers.yml
4 |
5 | - include: webservers.yml
--------------------------------------------------------------------------------
/ansible/vagrant.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Create a {{ application_name }} virtual machine via vagrant
4 | hosts: all
5 | sudo: yes
6 | sudo_user: root
7 | remote_user: vagrant
8 | vars:
9 | - update_apt_cache: yes
10 | vars_files:
11 | - env_vars/base.yml
12 | - env_vars/vagrant.yml
13 |
14 | roles:
15 | - base
16 | - db
17 | - rabbitmq
18 | - web
19 | - celery
--------------------------------------------------------------------------------
/ansible/webservers.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: Provision a {{ application_name }} web server
4 | hosts: webservers
5 | sudo: yes
6 | sudo_user: root
7 | remote_user: root
8 | vars:
9 | - setup_git_repo: yes
10 | - update_apt_cache: yes
11 | vars_files:
12 | - env_vars/base.yml
13 | - env_vars/{{ env }}.yml
14 |
15 | roles:
16 | - base
17 | - rabbitmq
18 | - web
19 | - celery
--------------------------------------------------------------------------------
/django/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM jcalazan/django
2 |
3 | ADD ./requirements.txt ./requirements.txt
4 |
5 | RUN pip install -r requirements.txt
6 |
--------------------------------------------------------------------------------
/django/requirements.txt:
--------------------------------------------------------------------------------
1 | django ~> 1.11.18
2 |
3 | django-braces==1.4.0
4 | django-compressor==1.4
5 | django-debug-toolbar>=1.11.1
6 | django-extensions==1.5.5
7 | django-grappelli==2.6.4
8 | celery==3.1.18
9 | flower ~> 0.9.2
10 | gunicorn ~> 19.5.0
11 | ipdb==0.8
12 | ipython[notebook]==3.2.1
13 | psycopg2==2.6
14 | werkzeug>=0.15.3
15 | youtube-dl>=2014.06.26
16 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | postgresql:
2 | image: sameersbn/postgresql:9.4-11
3 | environment:
4 | - DB_NAME=youtubeadl
5 | - DB_USER=youtubeadl
6 | - DB_PASS=password
7 | volumes:
8 | - ~/dockerfiles/youtube-audio-dl/postgresql:/var/lib/postgresql
9 | expose:
10 | - "5432"
11 |
12 | rabbitmq:
13 | image: jcalazan/rabbitmq
14 | expose:
15 | - "15672"
16 |
17 | # NOTES:
18 | # - The C_FORCE_ROOT variable allows celery to run as the root user.
19 | celery:
20 | build: django/
21 | environment:
22 | - C_FORCE_ROOT=true
23 | - DATABASE_HOST=postgresql
24 | - BROKER_URL=amqp://guest:guest@rabbitmq//
25 | working_dir: /youtube-audio-dl
26 | command: bash -c "sleep 3 && celery -A youtubeadl worker -E -l info --concurrency=3"
27 | volumes:
28 | - .:/youtube-audio-dl
29 | links:
30 | - postgresql
31 | - rabbitmq
32 |
33 | # NOTES:
34 | # - The C_FORCE_ROOT variable allows celery to run as the root user.
35 | flower:
36 | build: django/
37 | environment:
38 | - C_FORCE_ROOT=true
39 | - DATABASE_HOST=postgresql
40 | - BROKER_URL=amqp://guest:guest@rabbitmq//
41 | working_dir: /youtube-audio-dl
42 | command: bash -c "sleep 3 && celery -A youtubeadl flower --port=5555"
43 | volumes:
44 | - .:/youtube-audio-dl
45 | expose:
46 | - "5555"
47 | links:
48 | - postgresql
49 | - rabbitmq
50 |
51 | django:
52 | build: django/
53 | environment:
54 | - DATABASE_HOST=postgresql
55 | - BROKER_URL=amqp://guest:guest@rabbitmq//
56 | working_dir: /youtube-audio-dl
57 | command: bash -c "sleep 3 && python manage.py migrate --noinput && python manage.py runserver_plus 0.0.0.0:80"
58 | volumes:
59 | - .:/youtube-audio-dl
60 | expose:
61 | - "80"
62 | links:
63 | - postgresql
64 | - rabbitmq
65 |
66 | tor:
67 | build: tor-hidden-service/
68 | links:
69 | - django:web
70 |
--------------------------------------------------------------------------------
/ipython_config.py:
--------------------------------------------------------------------------------
1 | c = get_config()
2 |
3 | # Allow all IP addresses to use the service and run it on port 80.
4 | c.NotebookApp.ip = '0.0.0.0'
5 | c.NotebookApp.port = 80
6 |
7 | # Don't load the browser on startup.
8 | c.NotebookApp.open_browser = False
9 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 |
6 | if __name__ == '__main__':
7 | os.environ.setdefault('DJANGO_SETTINGS_MODULE',
8 | 'youtubeadl.settings.local')
9 |
10 | from django.core.management import execute_from_command_line
11 |
12 | execute_from_command_line(sys.argv)
13 |
--------------------------------------------------------------------------------
/scripts/deploy_youtubeadl.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd ../ansible
4 |
5 | ansible-playbook -i ../ansible/production ../ansible/site.yml --tags="deploy" --ask-vault-pass
6 |
--------------------------------------------------------------------------------
/tor-hidden-service/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM patrickod/tor-hidden-service
2 |
3 | ADD ./start-tor /bin/start-tor
4 |
5 | RUN chmod +x /bin/start-tor
6 |
7 | ADD ./get-tor-hostname /bin/get-tor-hostname
8 |
9 | RUN chmod +x /bin/get-tor-hostname
10 |
11 |
--------------------------------------------------------------------------------
/tor-hidden-service/get-tor-hostname:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | HOSTNAME='/var/lib/tor/hidden-service/hostname'
4 |
5 | while [ ! -f $HOSTNAME ]; do sleep 1; done
6 |
7 | echo 'Your onion address is' $(cat $HOSTNAME)
8 |
--------------------------------------------------------------------------------
/tor-hidden-service/start-tor:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 |
4 | REGEX='\([0-9]*\)_TCP=tcp://\([0-9]\{1,3\}\.\)\{3\}\([0-9]\)\{1,3\}\:\([0-9]*\)'
5 |
6 | env | grep -o $REGEX | sed -e "s/_TCP=tcp:\/\// /" -e "s/:/ /" | awk '{ printf "HiddenServicePort %s %s:%s\n", $1, $2, $3 }' >> /etc/torrc
7 |
8 | /bin/get-tor-hostname &
9 |
10 | /usr/local/bin/tor -f /etc/torrc
11 |
--------------------------------------------------------------------------------
/tor-hidden-service/torrc:
--------------------------------------------------------------------------------
1 | ## Configuration file for a typical Tor user
2 | ## Last updated 22 April 2012 for Tor 0.2.3.14-alpha.
3 | ## (may or may not work for much older or much newer versions of Tor.)
4 | ##
5 | ## Lines that begin with "## " try to explain what's going on. Lines
6 | ## that begin with just "#" are disabled commands: you can enable them
7 | ## by removing the "#" symbol.
8 | ##
9 | ## See 'man tor', or https://www.torproject.org/docs/tor-manual.html,
10 | ## for more options you can use in this file.
11 | ##
12 | ## Tor will look for this file in various places based on your platform:
13 | ## https://www.torproject.org/docs/faq#torrc
14 |
15 | ## Tor opens a socks proxy on port 9050 by default -- even if you don't
16 | ## configure one below. Set "SocksPort 0" if you plan to run Tor only
17 | ## as a relay, and not make any local application connections yourself.
18 | #SocksPort 9050 # Default: Bind to localhost:9050 for local connections.
19 | #SocksPort 192.168.0.1:9100 # Bind to this adddress:port too.
20 |
21 | ## Logs go to stdout at level "notice" unless redirected by something
22 | ## else, like one of the below lines. You can have as many Log lines as
23 | ## you want.
24 | ##
25 | ## We advise using "notice" in most cases, since anything more verbose
26 | ## may provide sensitive information to an attacker who obtains the logs.
27 | ##
28 | ## Send all messages of level 'notice' or higher to /var/log/tor/notices.log
29 | #Log notice file /var/log/tor/notices.log
30 | ## Send every possible message to /var/log/tor/debug.log
31 | #Log debug file /var/log/tor/debug.log
32 | ## Use the system log instead of Tor's logfiles
33 | Log notice syslog
34 | ## To send all messages to stderr:
35 | #Log debug stderr
36 |
37 | ## Uncomment this to start the process in the background... or use
38 | ## --runasdaemon 1 on the command line. This is ignored on Windows;
39 | ## see the FAQ entry if you want Tor to run as an NT service.
40 | #RunAsDaemon 1
41 |
42 | ## The directory for keeping all the keys/etc. By default, we store
43 | ## things in $HOME/.tor on Unix, and in Application Data\tor on Windows.
44 | DataDirectory /var/lib/tor
45 |
46 | ############### This section is just for location-hidden services ###
47 |
48 | ## Once you have configured a hidden service, you can look at the
49 | ## contents of the file ".../hidden_service/hostname" for the address
50 | ## to tell people.
51 | ##
52 | ## HiddenServicePort x y:z says to redirect requests on port x to the
53 | ## address y:z.
54 |
55 | #HiddenServiceDir /var/lib/tor/hidden_service/
56 | #HiddenServicePort 80 127.0.0.1:80
57 |
58 | #HiddenServiceDir /var/lib/tor/other_hidden_service/
59 | #HiddenServicePort 80 127.0.0.1:80
60 | #HiddenServicePort 22 127.0.0.1:22
61 |
62 | HiddenServiceDir /var/lib/tor/hidden-service
63 |
--------------------------------------------------------------------------------
/youtubeadl/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 |
3 | # This will make sure the app is always imported when
4 | # Django starts so that shared_task will use this app.
5 | from youtubeadl.celery import app as celery_app
--------------------------------------------------------------------------------
/youtubeadl/apps/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'jonathan'
2 |
--------------------------------------------------------------------------------
/youtubeadl/apps/core/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwestergren/docker-compose-tor-demo/5f0795e74b534b33a14a86c98f29a34b7ca0227d/youtubeadl/apps/core/__init__.py
--------------------------------------------------------------------------------
/youtubeadl/apps/core/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from youtubeadl.apps.core.models import Ad
4 |
5 |
6 | @admin.register(Ad)
7 | class AdAdmin(admin.ModelAdmin):
8 | list_display = ('description', 'position', 'created', 'modified')
--------------------------------------------------------------------------------
/youtubeadl/apps/core/context_processors.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 |
3 |
4 | def third_party_tracking_ids(request):
5 | """
6 | Retrieve 3rd-party tracking IDs from the settings file and add them to the
7 | request context.
8 | """
9 | return {
10 | 'google_analytics_tracking_id': settings.GOOGLE_ANALYTICS_TRACKING_ID,
11 | 'addthis_publisher_id': settings.ADDTHIS_PUBLISHER_ID,
12 | }
--------------------------------------------------------------------------------
/youtubeadl/apps/core/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 | import django.utils.timezone
6 | import django_extensions.db.fields
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='Ad',
17 | fields=[
18 | ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
19 | ('created', django_extensions.db.fields.CreationDateTimeField(default=django.utils.timezone.now, verbose_name='created', editable=False, blank=True)),
20 | ('modified', django_extensions.db.fields.ModificationDateTimeField(default=django.utils.timezone.now, verbose_name='modified', editable=False, blank=True)),
21 | ('description', models.CharField(max_length=255, null=True, blank=True)),
22 | ('code', models.TextField()),
23 | ('position', models.CharField(blank=True, max_length=10, null=True, choices=[(b'top', b'Top'), (b'bottom', b'Bottom')])),
24 | ],
25 | options={
26 | 'ordering': ('-modified', '-created'),
27 | 'abstract': False,
28 | 'get_latest_by': 'modified',
29 | },
30 | ),
31 | ]
32 |
--------------------------------------------------------------------------------
/youtubeadl/apps/core/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwestergren/docker-compose-tor-demo/5f0795e74b534b33a14a86c98f29a34b7ca0227d/youtubeadl/apps/core/migrations/__init__.py
--------------------------------------------------------------------------------
/youtubeadl/apps/core/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | from django_extensions.db.models import TimeStampedModel
4 |
5 |
6 | class Ad(TimeStampedModel):
7 | TOP = 'top'
8 | BOTTOM = 'bottom'
9 | POSITION_CHOICES = (
10 | (TOP, 'Top'),
11 | (BOTTOM, 'Bottom'),
12 | )
13 |
14 | description = models.CharField(max_length=255, null=True, blank=True)
15 | code = models.TextField()
16 | position = models.CharField(max_length=10,
17 | null=True,
18 | blank=True,
19 | choices=POSITION_CHOICES)
20 |
21 | def __unicode__(self):
22 | return self.description
--------------------------------------------------------------------------------
/youtubeadl/apps/core/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/youtubeadl/apps/core/utils.py:
--------------------------------------------------------------------------------
1 | import re
2 | from unicodedata import normalize
3 |
4 |
5 | def slugify(text, delim=u'-'):
6 | """
7 | Slugifies a string.
8 |
9 | This is slightly different from the built-in one in Django.
10 |
11 | Source: http://stackoverflow.com/questions/9042515/normalizing-unicode-\
12 | text-to-filenames-etc-in-python
13 | """
14 | result = []
15 |
16 | re_obj = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.:]+')
17 | for word in re_obj.split(text):
18 | word = normalize('NFKD', word).encode('ascii', 'ignore')
19 | if word:
20 | result.append(word)
21 | return unicode(delim.join(result))
22 |
23 |
24 | def get_client_ip(request):
25 | """
26 | Retrieve the client's IPv4 address from the request object.
27 | """
28 | x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
29 |
30 | if x_forwarded_for:
31 | ip = x_forwarded_for.split(',')[0]
32 | else:
33 | ip = request.META.get('REMOTE_ADDR')
34 | return ip
35 |
--------------------------------------------------------------------------------
/youtubeadl/apps/core/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 |
3 | # Create your views here.
--------------------------------------------------------------------------------
/youtubeadl/apps/downloader/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwestergren/docker-compose-tor-demo/5f0795e74b534b33a14a86c98f29a34b7ca0227d/youtubeadl/apps/downloader/__init__.py
--------------------------------------------------------------------------------
/youtubeadl/apps/downloader/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from django.utils.text import Truncator
3 |
4 | from youtubeadl.apps.downloader import models
5 |
6 |
7 | class ActivityLogInline(admin.TabularInline):
8 | model = models.ActivityLog
9 | readonly_fields = ('created',)
10 |
11 |
12 | @admin.register(models.ActivityLog)
13 | class ActivityLogAdmin(admin.ModelAdmin):
14 | list_display = (
15 | 'video',
16 | 'video_title',
17 | 'client_ip',
18 | 'action',
19 | 'created',
20 | )
21 | list_filter = ('action', 'client_ip')
22 |
23 | def video_title(self, obj):
24 | return Truncator(obj.video.title).chars(50)
25 | video_title.admin_order_field = 'video__title'
26 |
27 |
28 | @admin.register(models.Video)
29 | class VideoAdmin(admin.ModelAdmin):
30 | list_display = (
31 | 'youtube_id',
32 | 'title',
33 | 'audio_filename',
34 | 'duration',
35 | 'download_count',
36 | 'last_download_date',
37 | )
38 | list_filter = ('last_download_date',)
39 | search_fields = (
40 | 'youtube_id',
41 | 'title',
42 | 'audio_filename',
43 | )
44 |
45 | inlines = [ActivityLogInline]
46 |
--------------------------------------------------------------------------------
/youtubeadl/apps/downloader/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 | import django.utils.timezone
6 | import django_extensions.db.fields
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='ActivityLog',
17 | fields=[
18 | ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
19 | ('created', django_extensions.db.fields.CreationDateTimeField(default=django.utils.timezone.now, verbose_name='created', editable=False, blank=True)),
20 | ('modified', django_extensions.db.fields.ModificationDateTimeField(default=django.utils.timezone.now, verbose_name='modified', editable=False, blank=True)),
21 | ('client_ip', models.GenericIPAddressField(null=True)),
22 | ('action', models.CharField(max_length=50, choices=[(b'convert', b'Convert'), (b'download', b'Download')])),
23 | ],
24 | options={
25 | 'ordering': ('-modified', '-created'),
26 | 'abstract': False,
27 | 'get_latest_by': 'modified',
28 | },
29 | ),
30 | migrations.CreateModel(
31 | name='Video',
32 | fields=[
33 | ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
34 | ('created', django_extensions.db.fields.CreationDateTimeField(default=django.utils.timezone.now, verbose_name='created', editable=False, blank=True)),
35 | ('modified', django_extensions.db.fields.ModificationDateTimeField(default=django.utils.timezone.now, verbose_name='modified', editable=False, blank=True)),
36 | ('youtube_id', models.CharField(unique=True, max_length=100)),
37 | ('url', models.URLField(max_length=255)),
38 | ('title', models.TextField()),
39 | ('duration', models.IntegerField(null=True)),
40 | ('audio_filename', models.CharField(max_length=255, null=True, blank=True)),
41 | ('audio_filesize', models.IntegerField(null=True)),
42 | ('download_count', models.IntegerField(default=0, null=True)),
43 | ('last_download_date', models.DateTimeField(null=True)),
44 | ],
45 | options={
46 | 'ordering': ('-modified', '-created'),
47 | 'abstract': False,
48 | 'get_latest_by': 'modified',
49 | },
50 | ),
51 | migrations.AddField(
52 | model_name='activitylog',
53 | name='video',
54 | field=models.ForeignKey(to='downloader.Video'),
55 | ),
56 | ]
57 |
--------------------------------------------------------------------------------
/youtubeadl/apps/downloader/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwestergren/docker-compose-tor-demo/5f0795e74b534b33a14a86c98f29a34b7ca0227d/youtubeadl/apps/downloader/migrations/__init__.py
--------------------------------------------------------------------------------
/youtubeadl/apps/downloader/models.py:
--------------------------------------------------------------------------------
1 | import datetime
2 |
3 | from django.db import models
4 |
5 | from django_extensions.db.models import TimeStampedModel
6 |
7 |
8 | class Video(TimeStampedModel):
9 | youtube_id = models.CharField(max_length=100, unique=True)
10 | url = models.URLField(max_length=255)
11 | title = models.TextField()
12 | duration = models.IntegerField(null=True)
13 | audio_filename = models.CharField(max_length=255, null=True, blank=True)
14 | audio_filesize = models.IntegerField(null=True)
15 | download_count = models.IntegerField(null=True, default=0)
16 | last_download_date = models.DateTimeField(null=True)
17 |
18 | def __unicode__(self):
19 | return self.youtube_id
20 |
21 |
22 | class ActivityLogManager(models.Manager):
23 |
24 | def get_current_day_convert_count_by_ip(self, client_ip):
25 | today = datetime.datetime.today()
26 | return self.select_related().filter(
27 | client_ip=client_ip,
28 | action=ActivityLog.CONVERT,
29 | created__year=today.year,
30 | created__month=today.month,
31 | created__day=today.day).count()
32 |
33 |
34 | class ActivityLog(TimeStampedModel):
35 | """
36 | Store user activity.
37 | """
38 | CONVERT = 'convert'
39 | DOWNLOAD = 'download'
40 | ACTION_CHOICES = (
41 | (CONVERT, 'Convert'),
42 | (DOWNLOAD, 'Download'),
43 | )
44 |
45 | video = models.ForeignKey(Video)
46 | client_ip = models.GenericIPAddressField(null=True)
47 | action = models.CharField(max_length=50, choices=ACTION_CHOICES)
48 |
49 | objects = ActivityLogManager()
--------------------------------------------------------------------------------
/youtubeadl/apps/downloader/tasks.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 |
3 | import os
4 | import shutil
5 | import uuid
6 |
7 | from django.conf import settings
8 |
9 | import youtube_dl
10 | from celery import shared_task
11 |
12 | from youtubeadl.apps.downloader.models import Video, ActivityLog
13 | from youtubeadl.apps.downloader.utils import create_filename, get_video_info
14 |
15 |
16 | @shared_task
17 | def convert(url, client_ip=None):
18 | """
19 | Convert the YouTube video to MP3 audio.
20 |
21 | Steps:
22 | 1. Get the video's information to make sure the provided url is valid.
23 | 2. If info is returned and the duration is no more than
24 | MAX_DURATION_SECONDS, log the request and start the conversion.
25 | 3. Return the download link if conversion completes successfully.
26 | """
27 | info = get_video_info(url)
28 |
29 | result = None
30 | if info and info['duration'] <= settings.MAX_DURATION_SECONDS:
31 | youtube_id = info['id']
32 | title = info['title']
33 |
34 | audio_filename = create_filename(info['title'])
35 |
36 | video, created = Video.objects.get_or_create(youtube_id=youtube_id)
37 | video.url = url
38 | video.title = title
39 | video.duration = int(info['duration'])
40 | video.save()
41 |
42 | ActivityLog.objects.create(
43 | video=video,
44 | client_ip=client_ip,
45 | action=ActivityLog.CONVERT,
46 | )
47 |
48 | result = {
49 | 'youtube_id': youtube_id,
50 | 'title': title
51 | }
52 |
53 | # Simply return the filename and update the video object if the file
54 | # already exists, otherwise, start the conversion.
55 | output_filepath = os.path.join(settings.MEDIA_ROOT, audio_filename)
56 | if os.path.exists(output_filepath):
57 | result['filename'] = audio_filename
58 |
59 | # Update the video object.
60 | video.audio_filename = audio_filename
61 | video.audio_filesize = os.path.getsize(output_filepath)
62 | video.save()
63 | else:
64 | conversion_result = start_conversion(url, audio_filename, video)
65 |
66 | # If extraction result is 0, extraction is successful.
67 | if conversion_result == 0:
68 | result['filename'] = audio_filename
69 |
70 | return result
71 |
72 |
73 | def start_conversion(url, audio_filename, video):
74 | # We're creating a temporary file in case multiple workers are in the
75 | # process of converting the same video.
76 | temp_filepath = os.path.join(settings.MEDIA_ROOT,
77 | '{0}.{1}'.format(uuid.uuid4(), '%(ext)s'))
78 | output_filepath = os.path.join(settings.MEDIA_ROOT, audio_filename)
79 |
80 | ydl_opts = {
81 | 'format': 'bestaudio/best',
82 | 'extractaudio': True,
83 | 'audioformat': 'mp3',
84 | 'outtmpl': temp_filepath,
85 | 'noplaylist': True,
86 | 'postprocessors': [
87 | {
88 | 'key': 'FFmpegMetadata'
89 | },
90 | {
91 | 'key': 'FFmpegExtractAudio',
92 | 'preferredcodec': 'mp3',
93 | 'preferredquality': '192',
94 | },
95 | ]
96 | }
97 |
98 | with youtube_dl.YoutubeDL(ydl_opts) as ydl:
99 | result = ydl.download([url])
100 |
101 | # Status code 0 is successful.
102 | if result == 0:
103 | # Move the temporary file to the proper location.
104 | temp_filepath = temp_filepath.replace('.%(ext)s', '.mp3')
105 | shutil.move(temp_filepath, output_filepath)
106 |
107 | # Update the video object.
108 | video.audio_filename = audio_filename
109 | video.audio_filesize = os.path.getsize(output_filepath)
110 | video.save()
111 |
112 | return result
--------------------------------------------------------------------------------
/youtubeadl/apps/downloader/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/youtubeadl/apps/downloader/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import patterns, url
2 |
3 | from youtubeadl.apps.downloader import views
4 |
5 |
6 | urlpatterns = patterns('',
7 | url(
8 | regex=r'^convert/$',
9 | view=views.ConvertAjaxView.as_view(),
10 | name='convert_ajax_view',
11 | ),
12 | url(
13 | regex=r'^download/(?P.*)/(?P.*)$',
14 | view=views.download,
15 | name='download_view',
16 | ),
17 | )
--------------------------------------------------------------------------------
/youtubeadl/apps/downloader/utils.py:
--------------------------------------------------------------------------------
1 | import uuid
2 |
3 | import youtube_dl
4 |
5 | from youtubeadl.apps.core.utils import slugify
6 |
7 |
8 | def create_filename(value):
9 | """
10 | Generate a valid filename.
11 |
12 | Non-ASCII characters will be deleted from the value and replace spaces with
13 | underscores. Slashes and percent signs are also stripped.
14 | """
15 | filename = slugify(value, u'_')
16 |
17 | # Generate a random filename if the title only contains non-ASCII
18 | # characters (i.e. slugifying it deletes everything).
19 | if not filename:
20 | filename = uuid.uuid4()
21 |
22 | return '{}.mp3'.format(filename)
23 |
24 |
25 | def get_video_info(url):
26 | """
27 | Retrieve the YouTube videos' information without downloading it.
28 |
29 | Source: http://stackoverflow.com/questions/18054500/how-to-use-youtube-dl-\
30 | from-a-python-programm/18947879#18947879
31 | """
32 | ydl = youtube_dl.YoutubeDL()
33 | ydl.add_default_info_extractors()
34 |
35 | try:
36 | return ydl.extract_info(url, download=False)
37 | except youtube_dl.DownloadError:
38 | return None
--------------------------------------------------------------------------------
/youtubeadl/apps/downloader/views.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import logging
3 | import os
4 | import urllib
5 | from urlparse import urlparse, parse_qs, urlsplit, urlunsplit
6 |
7 | from django.conf import settings
8 | from django.core.urlresolvers import reverse
9 | from django.http import HttpResponse, HttpResponseRedirect
10 | from django.utils.encoding import smart_str
11 | from django.views.generic import TemplateView, View
12 |
13 | from braces.views import JSONResponseMixin, AjaxResponseMixin
14 | from celery.result import AsyncResult
15 |
16 | from youtubeadl.apps.core.utils import get_client_ip
17 |
18 | from youtubeadl.apps.core.models import Ad
19 | from youtubeadl.apps.downloader import tasks
20 | from youtubeadl.apps.downloader.models import ActivityLog, Video
21 |
22 |
23 | logger = logging.getLogger(__name__)
24 |
25 |
26 | def download(request, youtube_id, filename):
27 | """
28 | Serves the audio file.
29 | """
30 | filepath = os.path.join(settings.MEDIA_ROOT, filename)
31 | file_exists = os.path.exists(filepath)
32 |
33 | video = None
34 | try:
35 | # We need to filter by both the youtube_id and audio_filename as the
36 | # record might exists but the video is still being converted.
37 | video = Video.objects.get(youtube_id=youtube_id, audio_filename=filename)
38 | except Video.DoesNotExist:
39 | pass
40 |
41 | if video and file_exists:
42 | ActivityLog.objects.create(
43 | video=video,
44 | action=ActivityLog.DOWNLOAD,
45 | client_ip=get_client_ip(request),
46 | )
47 |
48 | video.download_count += 1
49 | video.last_download_date = datetime.datetime.now()
50 | video.save()
51 |
52 | if settings.DEBUG:
53 | with open(filepath, 'rb') as file_data:
54 | response = HttpResponse(file_data.read(),
55 | content_type='audio/mpeg')
56 |
57 | response['Content-Disposition'] = 'attachment; filename={}'.format(
58 | smart_str(filename))
59 | response['Content-Length'] = os.path.getsize(filepath)
60 |
61 | return response
62 | else:
63 | # Have Nginx serve the file in production.
64 | response = HttpResponse(content_type='application/force-download')
65 | response['Content-Length'] = os.path.getsize(filepath)
66 | response['X-Accel-Redirect'] = os.path.join(settings.MEDIA_URL,
67 | smart_str(filename))
68 |
69 | return response
70 |
71 | return HttpResponseRedirect(reverse('home'))
72 |
73 |
74 | class DownloadFormView(TemplateView):
75 | template_name = 'home.html'
76 |
77 | def get_context_data(self, **kwargs):
78 | context = super(DownloadFormView, self).get_context_data()
79 | context['ad_top'] = Ad.objects.filter(position=Ad.TOP).first()
80 | context['ad_bottom'] = Ad.objects.filter(position=Ad.BOTTOM).first()
81 |
82 | return context
83 |
84 |
85 | class ConvertAjaxView(JSONResponseMixin, AjaxResponseMixin, View):
86 | """
87 | Ajax view to start the video conversion.
88 | """
89 |
90 | def post_ajax(self, request, *args, **kwargs):
91 | url = self.parse_url(request.POST.get('url', '').strip())
92 |
93 | client_ip = get_client_ip(request)
94 | client_convert_count = ActivityLog.objects\
95 | .get_current_day_convert_count_by_ip(client_ip)
96 | daily_limit = settings.DAILY_CONVERT_LIMIT
97 | limit_reached = client_convert_count >= daily_limit
98 |
99 | if url and not limit_reached:
100 | task = tasks.convert.delay(url, client_ip)
101 | result = AsyncResult(task.id)
102 |
103 | # TODO: We're tying up resources here as we're waiting for the task
104 | # to finish. Remove this later and have the AJAX request retry
105 | # until result.ready().
106 | result.wait()
107 |
108 | data = {
109 | 'task_id': task.id,
110 | 'is_ready': False,
111 | }
112 | if result.successful():
113 | if result.result:
114 | youtube_id = result.result['youtube_id']
115 | filename = result.result['filename']
116 | download_link = reverse(
117 | 'download_view',
118 | kwargs={'youtube_id': youtube_id,
119 | 'filename': filename}
120 | )
121 |
122 | data['message'] = 'Conversion successful!'
123 | data['is_ready'] = True
124 | data['youtube_id'] = youtube_id
125 | data['title'] = result.result['title']
126 | data['filename'] = filename
127 | data['download_link'] = download_link
128 |
129 | return self.render_json_response(data, status=200)
130 |
131 | data['message'] = 'Could not convert the video. Please make ' \
132 | 'sure the URL you entered is correct and ' \
133 | 'the video is no more than {} minutes long.'\
134 | .format(settings.MAX_DURATION_SECONDS / 60)
135 | return self.render_json_response(data, status=200)
136 |
137 | data['message'] = 'Something went wrong :('
138 | return self.render_json_response(data, status=500)
139 |
140 | if limit_reached:
141 | logger.warn('Client reached convert limit: %s', client_ip)
142 | message = "Sorry, but you've reached your daily convert limit " \
143 | "of {}. Please try again tomorrow.".format(daily_limit)
144 | return self.render_json_response({'message': message}, status=200)
145 |
146 | return self.render_json_response({'message': 'Please provide a URL.'},
147 | status=200)
148 |
149 | def parse_url(self, url):
150 | """
151 | Remove the list parameter from the URL as we currently don't support
152 | conversion of an entire playlist.
153 | """
154 | qs = parse_qs(urlparse(url).query)
155 | if qs.get('list', None):
156 | del(qs['list'])
157 | parts = urlsplit(url)
158 | return urlunsplit([
159 | parts.scheme,
160 | parts.netloc,
161 | parts.path,
162 | urllib.urlencode(qs, True),
163 | parts.fragment
164 | ])
165 |
166 | return url
--------------------------------------------------------------------------------
/youtubeadl/celery.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 |
3 | import os
4 |
5 | from celery import Celery
6 |
7 | from django.conf import settings
8 |
9 | # set the default Django settings module for the 'celery' program.
10 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'youtubeadl.settings.local')
11 |
12 | app = Celery('youtubeadl')
13 |
14 | # Using a string here means the worker will not have to
15 | # pickle the object when using Windows.
16 | app.config_from_object('django.conf:settings')
17 | app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
18 |
19 |
20 | @app.task(bind=True)
21 | def debug_task(self):
22 | print('Request: {0!r}'.format(self.request))
--------------------------------------------------------------------------------
/youtubeadl/settings/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'jonathan'
2 |
--------------------------------------------------------------------------------
/youtubeadl/settings/base.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for youtubeadl project.
3 |
4 | For more information on this file, see
5 | https://docs.djangoproject.com/en/1.8/topics/settings/
6 |
7 | For the full list of settings and their values, see
8 | https://docs.djangoproject.com/en/1.8/ref/settings/
9 | """
10 |
11 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
12 | import os
13 |
14 |
15 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
16 |
17 |
18 | # Quick-start development settings - unsuitable for production
19 | # See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
20 |
21 | # SECURITY WARNING: keep the secret key used in production secret!
22 | SECRET_KEY = os.getenv('DJANGO_SECRET_KEY',
23 | '^b46d^zsxhrthkq2p7ty14^zov%4@eq@j5e%f(ki_#2rnbp%-l')
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = []
29 |
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = (
34 | # Grappelli needs to be defined before the admin.
35 | 'grappelli',
36 |
37 | 'django.contrib.admin',
38 | 'django.contrib.auth',
39 | 'django.contrib.contenttypes',
40 | 'django.contrib.sessions',
41 | 'django.contrib.messages',
42 | 'django.contrib.staticfiles',
43 |
44 | # 3rd-party apps.
45 | 'compressor',
46 | 'django_extensions',
47 |
48 | # Project apps.
49 | 'youtubeadl.apps.core',
50 | 'youtubeadl.apps.downloader',
51 | )
52 |
53 | MIDDLEWARE_CLASSES = (
54 | 'django.contrib.sessions.middleware.SessionMiddleware',
55 | 'django.middleware.common.CommonMiddleware',
56 | 'django.middleware.csrf.CsrfViewMiddleware',
57 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
58 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
59 | 'django.contrib.messages.middleware.MessageMiddleware',
60 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
61 | 'django.middleware.security.SecurityMiddleware',
62 | )
63 |
64 | ROOT_URLCONF = 'youtubeadl.urls'
65 |
66 | TEMPLATES = [
67 | {
68 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
69 | 'DIRS': [
70 | os.path.join(BASE_DIR, 'templates'),
71 | ],
72 | 'OPTIONS': {
73 | 'context_processors': [
74 | 'django.template.context_processors.debug',
75 | 'django.template.context_processors.request',
76 | 'django.contrib.auth.context_processors.auth',
77 | 'django.contrib.messages.context_processors.messages',
78 |
79 | # Local context processors.
80 | 'youtubeadl.apps.core.context_processors.third_party_tracking_ids',
81 | ],
82 | 'loaders': [
83 | 'django.template.loaders.filesystem.Loader',
84 | 'django.template.loaders.app_directories.Loader',
85 | ],
86 | },
87 | },
88 | ]
89 |
90 | WSGI_APPLICATION = 'youtubeadl.wsgi.application'
91 |
92 |
93 | # Database
94 | # https://docs.djangoproject.com/en/1.8/ref/settings/#databases
95 |
96 | DATABASES = {
97 | 'default': {
98 | 'ENGINE': 'django.db.backends.postgresql_psycopg2',
99 | 'NAME': os.getenv('DATABASE_NAME', 'youtubeadl'),
100 | 'USER': os.getenv('DATABASE_USER', 'youtubeadl'),
101 | 'PASSWORD': os.getenv('DATABASE_PASSWORD', 'password'),
102 | 'HOST': os.getenv('DATABASE_HOST', '127.0.0.1'),
103 | 'PORT': os.getenv('DATABASE_PORT', '5432'),
104 | }
105 | }
106 |
107 | # Internationalization
108 | # https://docs.djangoproject.com/en/1.8/topics/i18n/
109 |
110 | LANGUAGE_CODE = 'en-us'
111 |
112 | TIME_ZONE = 'UTC'
113 |
114 | USE_I18N = True
115 |
116 | USE_L10N = True
117 |
118 | USE_TZ = True
119 |
120 |
121 | # Static files (CSS, JavaScript, Images)
122 | # https://docs.djangoproject.com/en/1.8/howto/static-files/
123 |
124 | STATIC_ROOT = os.getenv('STATIC_ROOT',
125 | os.path.join(BASE_DIR, 'collected_static'))
126 |
127 | STATIC_URL = '/static/'
128 |
129 | # Additional locations of static files.
130 | STATICFILES_DIRS = (
131 | os.path.join(BASE_DIR, 'static'),
132 | )
133 |
134 | # List of finder classes that know how to find static files in
135 | # various locations.
136 | STATICFILES_FINDERS = (
137 | 'django.contrib.staticfiles.finders.FileSystemFinder',
138 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
139 | 'compressor.finders.CompressorFinder',
140 | )
141 |
142 |
143 | # Media files.
144 |
145 | MEDIA_ROOT = os.getenv('MEDIA_ROOT', os.path.join(BASE_DIR, 'media'))
146 |
147 | MEDIA_URL = '/media/'
148 |
149 |
150 | # Email settings.
151 |
152 | EMAIL_HOST = os.getenv('EMAIL_HOST')
153 | EMAIL_PORT = os.getenv('EMAIL_PORT', 587)
154 | EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER')
155 | EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD')
156 | EMAIL_USE_TLS = True
157 |
158 | DEFAULT_FROM_EMAIL = 'Info '
159 | SERVER_EMAIL = 'Alerts '
160 |
161 | ADMINS = (
162 | ('Admin', 'admin@youtubeadl.com'),
163 | )
164 |
165 |
166 | # Logging settings.
167 |
168 | LOGGING = {
169 | 'version': 1,
170 | 'disable_existing_loggers': False,
171 | 'formatters': {
172 | 'default': {
173 | 'format': '%(asctime)s [%(name)s:%(lineno)s] %(levelname)s - %(message)s',
174 | },
175 | 'simple': {
176 | 'format': '%(levelname)s %(message)s',
177 | },
178 | },
179 | 'filters': {
180 | 'require_debug_false': {
181 | '()': 'django.utils.log.RequireDebugFalse',
182 | }
183 | },
184 | 'handlers': {
185 | 'null': {
186 | 'level': 'DEBUG',
187 | 'class': 'logging.NullHandler',
188 | },
189 | 'console': {
190 | 'level': 'INFO',
191 | 'class': 'logging.StreamHandler',
192 | 'formatter': 'default',
193 | },
194 | 'mail_admins': {
195 | 'level': 'ERROR',
196 | 'filters': ['require_debug_false'],
197 | 'class': 'django.utils.log.AdminEmailHandler',
198 | }
199 | },
200 | 'loggers': {
201 | # Silence SuspiciousOperation.DisallowedHost exception ('Invalid
202 | # HTTP_HOST' header messages). Set the handler to 'null' so we don't
203 | # get those annoying emails.
204 | 'django.security.DisallowedHost': {
205 | 'handlers': ['null'],
206 | 'propagate': False,
207 | },
208 | 'django.request': {
209 | 'handlers': ['mail_admins'],
210 | 'level': 'ERROR',
211 | 'propagate': True,
212 | },
213 | '': {
214 | 'handlers': ['console', ],
215 | 'level': 'INFO',
216 | }
217 | }
218 | }
219 |
220 |
221 | # YouTube Audio Downloader settings.
222 | MAX_DURATION_SECONDS = 10800
223 | DAILY_CONVERT_LIMIT = 25
224 |
225 |
226 | # 3rd-party apps tracking IDs.
227 | GOOGLE_ANALYTICS_TRACKING_ID = os.getenv('GOOGLE_ANALYTICS_TRACKING_ID')
228 | ADDTHIS_PUBLISHER_ID = os.getenv('ADDTHIS_PUBLISHER_ID')
229 |
230 |
231 | # Celery settings.
232 | BROKER_URL = os.getenv('BROKER_URL', 'amqp://guest:guest@127.0.0.1//')
233 | CELERY_RESULT_BACKEND = os.getenv('CELERY_RESULT_BACKEND', 'amqp')
234 |
235 |
236 | # Grappelli settings.
237 | GRAPPELLI_ADMIN_TITLE = 'YouTube ADL Admin'
--------------------------------------------------------------------------------
/youtubeadl/settings/local.py:
--------------------------------------------------------------------------------
1 | from youtubeadl.settings.base import *
2 |
3 |
4 | INSTALLED_APPS += ('debug_toolbar',)
5 |
6 | MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware', )
7 |
8 | # The Django Debug Toolbar will only be shown to these client IPs.
9 | INTERNAL_IPS = (
10 | '127.0.0.1',
11 | )
12 |
13 | DEBUG_TOOLBAR_CONFIG = {
14 | 'INTERCEPT_REDIRECTS': False,
15 | 'SHOW_TEMPLATE_CONTEXT': True,
16 | 'HIDE_DJANGO_SQL': False,
17 | }
--------------------------------------------------------------------------------
/youtubeadl/settings/production.py:
--------------------------------------------------------------------------------
1 | from youtubeadl.settings.base import *
2 |
3 |
4 | DEBUG = False
5 |
6 | ALLOWED_HOSTS = ['.youtubeadl.com']
7 |
8 |
9 | # Use the cached template loader so template is compiled once and read from
10 | # memory instead of reading from disk on each load.
11 | TEMPLATES[0]['OPTIONS']['loaders'] = [
12 | ('django.template.loaders.cached.Loader', [
13 | 'django.template.loaders.filesystem.Loader',
14 | 'django.template.loaders.app_directories.Loader',
15 | ]),
16 | ]
17 |
--------------------------------------------------------------------------------
/youtubeadl/static/js/main.js:
--------------------------------------------------------------------------------
1 | /* Main JavaScript file used throughout the YouTubeADL app */
2 |
3 | function resetResultDiv() {
4 | $('#result').html("");
5 | $('#result').removeClass();
6 | }
7 |
8 | $(document).ajaxStart(function() {
9 | $('#result').removeClass();
10 | $('#result').addClass('alert');
11 | $('#result').html(" Converting video to MP3, please wait, this could take a few minutes... ");
12 | });
13 |
14 | $(document).ajaxStop(function() {
15 | $('#result').html();
16 | $('#convertButton').prop('disabled', false);
17 | });
18 |
19 | var downloadForm = $('#downloadForm');
20 | downloadForm.submit(function () {
21 | // Disable convert button to prevent multiple submissions.
22 | $('#convertButton').prop('disabled', true);
23 |
24 | $.ajax({
25 | type: downloadForm.attr('method'),
26 | url: downloadForm.attr('data-url'),
27 | data: downloadForm.serialize(),
28 | success: function (data, textStatus, xhr) {
29 | if (textStatus == 'success') {
30 | if (data['is_ready'] == true) {
31 | $('#result').addClass("alert-success");
32 | $('#result').html("""+ data['title'] + "" successfully converted!"
33 | + "
"
34 | + "Download MP3 File
");
35 | } else {
36 | $('#result').addClass("alert-danger");
37 | $('#result').html(data['message']);
38 | }
39 | } else {
40 | resetResultDiv();
41 | alert(data['message']);
42 | }
43 | },
44 | error: function(data) {
45 | resetResultDiv();
46 | alert("Sorry, something went wrong. Please try again.");
47 | }
48 | });
49 | return false;
50 | });
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/bootstrap/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "vars": {
3 | "@gray-base": "#000",
4 | "@gray-darker": "lighten(@gray-base, 13.5%)",
5 | "@gray-dark": "lighten(@gray-base, 20%)",
6 | "@gray": "lighten(@gray-base, 33.5%)",
7 | "@gray-light": "lighten(@gray-base, 46.7%)",
8 | "@gray-lighter": "lighten(@gray-base, 93.5%)",
9 | "@brand-primary": "darken(#428bca, 6.5%)",
10 | "@brand-success": "#5cb85c",
11 | "@brand-info": "#5bc0de",
12 | "@brand-warning": "#f0ad4e",
13 | "@brand-danger": "#d9534f",
14 | "@body-bg": "#fff",
15 | "@text-color": "@gray-dark",
16 | "@link-color": "@brand-primary",
17 | "@link-hover-color": "darken(@link-color, 15%)",
18 | "@link-hover-decoration": "underline",
19 | "@font-family-sans-serif": "\"Helvetica Neue\", Helvetica, Arial, sans-serif",
20 | "@font-family-serif": "Georgia, \"Times New Roman\", Times, serif",
21 | "@font-family-monospace": "Menlo, Monaco, Consolas, \"Courier New\", monospace",
22 | "@font-family-base": "@font-family-sans-serif",
23 | "@font-size-base": "14px",
24 | "@font-size-large": "ceil((@font-size-base * 1.25))",
25 | "@font-size-small": "ceil((@font-size-base * 0.85))",
26 | "@font-size-h1": "floor((@font-size-base * 2.6))",
27 | "@font-size-h2": "floor((@font-size-base * 2.15))",
28 | "@font-size-h3": "ceil((@font-size-base * 1.7))",
29 | "@font-size-h4": "ceil((@font-size-base * 1.25))",
30 | "@font-size-h5": "@font-size-base",
31 | "@font-size-h6": "ceil((@font-size-base * 0.85))",
32 | "@line-height-base": "1.428571429",
33 | "@line-height-computed": "floor((@font-size-base * @line-height-base))",
34 | "@headings-font-family": "inherit",
35 | "@headings-font-weight": "500",
36 | "@headings-line-height": "1.1",
37 | "@headings-color": "inherit",
38 | "@icon-font-path": "\"../fonts/\"",
39 | "@icon-font-name": "\"glyphicons-halflings-regular\"",
40 | "@icon-font-svg-id": "\"glyphicons_halflingsregular\"",
41 | "@padding-base-vertical": "6px",
42 | "@padding-base-horizontal": "12px",
43 | "@padding-large-vertical": "10px",
44 | "@padding-large-horizontal": "16px",
45 | "@padding-small-vertical": "5px",
46 | "@padding-small-horizontal": "10px",
47 | "@padding-xs-vertical": "1px",
48 | "@padding-xs-horizontal": "5px",
49 | "@line-height-large": "1.3333333",
50 | "@line-height-small": "1.5",
51 | "@border-radius-base": "4px",
52 | "@border-radius-large": "6px",
53 | "@border-radius-small": "3px",
54 | "@component-active-color": "#fff",
55 | "@component-active-bg": "@brand-primary",
56 | "@caret-width-base": "4px",
57 | "@caret-width-large": "5px",
58 | "@table-cell-padding": "8px",
59 | "@table-condensed-cell-padding": "5px",
60 | "@table-bg": "transparent",
61 | "@table-bg-accent": "#f9f9f9",
62 | "@table-bg-hover": "#f5f5f5",
63 | "@table-bg-active": "@table-bg-hover",
64 | "@table-border-color": "#ddd",
65 | "@btn-font-weight": "normal",
66 | "@btn-default-color": "#333",
67 | "@btn-default-bg": "#fff",
68 | "@btn-default-border": "#ccc",
69 | "@btn-primary-color": "#fff",
70 | "@btn-primary-bg": "@brand-primary",
71 | "@btn-primary-border": "darken(@btn-primary-bg, 5%)",
72 | "@btn-success-color": "#fff",
73 | "@btn-success-bg": "@brand-success",
74 | "@btn-success-border": "darken(@btn-success-bg, 5%)",
75 | "@btn-info-color": "#fff",
76 | "@btn-info-bg": "@brand-info",
77 | "@btn-info-border": "darken(@btn-info-bg, 5%)",
78 | "@btn-warning-color": "#fff",
79 | "@btn-warning-bg": "@brand-warning",
80 | "@btn-warning-border": "darken(@btn-warning-bg, 5%)",
81 | "@btn-danger-color": "#fff",
82 | "@btn-danger-bg": "@brand-danger",
83 | "@btn-danger-border": "darken(@btn-danger-bg, 5%)",
84 | "@btn-link-disabled-color": "@gray-light",
85 | "@input-bg": "#fff",
86 | "@input-bg-disabled": "@gray-lighter",
87 | "@input-color": "@gray",
88 | "@input-border": "#ccc",
89 | "@input-border-radius": "@border-radius-base",
90 | "@input-border-radius-large": "@border-radius-large",
91 | "@input-border-radius-small": "@border-radius-small",
92 | "@input-border-focus": "#66afe9",
93 | "@input-color-placeholder": "#999",
94 | "@input-height-base": "(@line-height-computed + (@padding-base-vertical * 2) + 2)",
95 | "@input-height-large": "(ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2)",
96 | "@input-height-small": "(floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2)",
97 | "@form-group-margin-bottom": "15px",
98 | "@legend-color": "@gray-dark",
99 | "@legend-border-color": "#e5e5e5",
100 | "@input-group-addon-bg": "@gray-lighter",
101 | "@input-group-addon-border-color": "@input-border",
102 | "@cursor-disabled": "not-allowed",
103 | "@dropdown-bg": "#fff",
104 | "@dropdown-border": "rgba(0,0,0,.15)",
105 | "@dropdown-fallback-border": "#ccc",
106 | "@dropdown-divider-bg": "#e5e5e5",
107 | "@dropdown-link-color": "@gray-dark",
108 | "@dropdown-link-hover-color": "darken(@gray-dark, 5%)",
109 | "@dropdown-link-hover-bg": "#f5f5f5",
110 | "@dropdown-link-active-color": "@component-active-color",
111 | "@dropdown-link-active-bg": "@component-active-bg",
112 | "@dropdown-link-disabled-color": "@gray-light",
113 | "@dropdown-header-color": "@gray-light",
114 | "@dropdown-caret-color": "#000",
115 | "@screen-xs": "480px",
116 | "@screen-xs-min": "@screen-xs",
117 | "@screen-phone": "@screen-xs-min",
118 | "@screen-sm": "768px",
119 | "@screen-sm-min": "@screen-sm",
120 | "@screen-tablet": "@screen-sm-min",
121 | "@screen-md": "992px",
122 | "@screen-md-min": "@screen-md",
123 | "@screen-desktop": "@screen-md-min",
124 | "@screen-lg": "1200px",
125 | "@screen-lg-min": "@screen-lg",
126 | "@screen-lg-desktop": "@screen-lg-min",
127 | "@screen-xs-max": "(@screen-sm-min - 1)",
128 | "@screen-sm-max": "(@screen-md-min - 1)",
129 | "@screen-md-max": "(@screen-lg-min - 1)",
130 | "@grid-columns": "12",
131 | "@grid-gutter-width": "30px",
132 | "@grid-float-breakpoint": "@screen-sm-min",
133 | "@grid-float-breakpoint-max": "(@grid-float-breakpoint - 1)",
134 | "@container-tablet": "(720px + @grid-gutter-width)",
135 | "@container-sm": "@container-tablet",
136 | "@container-desktop": "(940px + @grid-gutter-width)",
137 | "@container-md": "@container-desktop",
138 | "@container-large-desktop": "(1140px + @grid-gutter-width)",
139 | "@container-lg": "@container-large-desktop",
140 | "@navbar-height": "50px",
141 | "@navbar-margin-bottom": "@line-height-computed",
142 | "@navbar-border-radius": "@border-radius-base",
143 | "@navbar-padding-horizontal": "floor((@grid-gutter-width / 2))",
144 | "@navbar-padding-vertical": "((@navbar-height - @line-height-computed) / 2)",
145 | "@navbar-collapse-max-height": "340px",
146 | "@navbar-default-color": "#777",
147 | "@navbar-default-bg": "#f8f8f8",
148 | "@navbar-default-border": "darken(@navbar-default-bg, 6.5%)",
149 | "@navbar-default-link-color": "#777",
150 | "@navbar-default-link-hover-color": "#333",
151 | "@navbar-default-link-hover-bg": "transparent",
152 | "@navbar-default-link-active-color": "#555",
153 | "@navbar-default-link-active-bg": "darken(@navbar-default-bg, 6.5%)",
154 | "@navbar-default-link-disabled-color": "#ccc",
155 | "@navbar-default-link-disabled-bg": "transparent",
156 | "@navbar-default-brand-color": "@navbar-default-link-color",
157 | "@navbar-default-brand-hover-color": "darken(@navbar-default-brand-color, 10%)",
158 | "@navbar-default-brand-hover-bg": "transparent",
159 | "@navbar-default-toggle-hover-bg": "#ddd",
160 | "@navbar-default-toggle-icon-bar-bg": "#888",
161 | "@navbar-default-toggle-border-color": "#ddd",
162 | "@navbar-inverse-color": "lighten(@gray-light, 15%)",
163 | "@navbar-inverse-bg": "#222",
164 | "@navbar-inverse-border": "darken(@navbar-inverse-bg, 10%)",
165 | "@navbar-inverse-link-color": "lighten(@gray-light, 15%)",
166 | "@navbar-inverse-link-hover-color": "#fff",
167 | "@navbar-inverse-link-hover-bg": "transparent",
168 | "@navbar-inverse-link-active-color": "@navbar-inverse-link-hover-color",
169 | "@navbar-inverse-link-active-bg": "darken(@navbar-inverse-bg, 10%)",
170 | "@navbar-inverse-link-disabled-color": "#444",
171 | "@navbar-inverse-link-disabled-bg": "transparent",
172 | "@navbar-inverse-brand-color": "@navbar-inverse-link-color",
173 | "@navbar-inverse-brand-hover-color": "#fff",
174 | "@navbar-inverse-brand-hover-bg": "transparent",
175 | "@navbar-inverse-toggle-hover-bg": "#333",
176 | "@navbar-inverse-toggle-icon-bar-bg": "#fff",
177 | "@navbar-inverse-toggle-border-color": "#333",
178 | "@nav-link-padding": "10px 15px",
179 | "@nav-link-hover-bg": "@gray-lighter",
180 | "@nav-disabled-link-color": "@gray-light",
181 | "@nav-disabled-link-hover-color": "@gray-light",
182 | "@nav-tabs-border-color": "#ddd",
183 | "@nav-tabs-link-hover-border-color": "@gray-lighter",
184 | "@nav-tabs-active-link-hover-bg": "@body-bg",
185 | "@nav-tabs-active-link-hover-color": "@gray",
186 | "@nav-tabs-active-link-hover-border-color": "#ddd",
187 | "@nav-tabs-justified-link-border-color": "#ddd",
188 | "@nav-tabs-justified-active-link-border-color": "@body-bg",
189 | "@nav-pills-border-radius": "@border-radius-base",
190 | "@nav-pills-active-link-hover-bg": "@component-active-bg",
191 | "@nav-pills-active-link-hover-color": "@component-active-color",
192 | "@pagination-color": "@link-color",
193 | "@pagination-bg": "#fff",
194 | "@pagination-border": "#ddd",
195 | "@pagination-hover-color": "@link-hover-color",
196 | "@pagination-hover-bg": "@gray-lighter",
197 | "@pagination-hover-border": "#ddd",
198 | "@pagination-active-color": "#fff",
199 | "@pagination-active-bg": "@brand-primary",
200 | "@pagination-active-border": "@brand-primary",
201 | "@pagination-disabled-color": "@gray-light",
202 | "@pagination-disabled-bg": "#fff",
203 | "@pagination-disabled-border": "#ddd",
204 | "@pager-bg": "@pagination-bg",
205 | "@pager-border": "@pagination-border",
206 | "@pager-border-radius": "15px",
207 | "@pager-hover-bg": "@pagination-hover-bg",
208 | "@pager-active-bg": "@pagination-active-bg",
209 | "@pager-active-color": "@pagination-active-color",
210 | "@pager-disabled-color": "@pagination-disabled-color",
211 | "@jumbotron-padding": "30px",
212 | "@jumbotron-color": "inherit",
213 | "@jumbotron-bg": "@gray-lighter",
214 | "@jumbotron-heading-color": "inherit",
215 | "@jumbotron-font-size": "ceil((@font-size-base * 1.5))",
216 | "@state-success-text": "#3c763d",
217 | "@state-success-bg": "#dff0d8",
218 | "@state-success-border": "darken(spin(@state-success-bg, -10), 5%)",
219 | "@state-info-text": "#31708f",
220 | "@state-info-bg": "#d9edf7",
221 | "@state-info-border": "darken(spin(@state-info-bg, -10), 7%)",
222 | "@state-warning-text": "#8a6d3b",
223 | "@state-warning-bg": "#fcf8e3",
224 | "@state-warning-border": "darken(spin(@state-warning-bg, -10), 5%)",
225 | "@state-danger-text": "#a94442",
226 | "@state-danger-bg": "#f2dede",
227 | "@state-danger-border": "darken(spin(@state-danger-bg, -10), 5%)",
228 | "@tooltip-max-width": "200px",
229 | "@tooltip-color": "#fff",
230 | "@tooltip-bg": "#000",
231 | "@tooltip-opacity": ".9",
232 | "@tooltip-arrow-width": "5px",
233 | "@tooltip-arrow-color": "@tooltip-bg",
234 | "@popover-bg": "#fff",
235 | "@popover-max-width": "276px",
236 | "@popover-border-color": "rgba(0,0,0,.2)",
237 | "@popover-fallback-border-color": "#ccc",
238 | "@popover-title-bg": "darken(@popover-bg, 3%)",
239 | "@popover-arrow-width": "10px",
240 | "@popover-arrow-color": "@popover-bg",
241 | "@popover-arrow-outer-width": "(@popover-arrow-width + 1)",
242 | "@popover-arrow-outer-color": "fadein(@popover-border-color, 5%)",
243 | "@popover-arrow-outer-fallback-color": "darken(@popover-fallback-border-color, 20%)",
244 | "@label-default-bg": "@gray-light",
245 | "@label-primary-bg": "@brand-primary",
246 | "@label-success-bg": "@brand-success",
247 | "@label-info-bg": "@brand-info",
248 | "@label-warning-bg": "@brand-warning",
249 | "@label-danger-bg": "@brand-danger",
250 | "@label-color": "#fff",
251 | "@label-link-hover-color": "#fff",
252 | "@modal-inner-padding": "15px",
253 | "@modal-title-padding": "15px",
254 | "@modal-title-line-height": "@line-height-base",
255 | "@modal-content-bg": "#fff",
256 | "@modal-content-border-color": "rgba(0,0,0,.2)",
257 | "@modal-content-fallback-border-color": "#999",
258 | "@modal-backdrop-bg": "#000",
259 | "@modal-backdrop-opacity": ".5",
260 | "@modal-header-border-color": "#e5e5e5",
261 | "@modal-footer-border-color": "@modal-header-border-color",
262 | "@modal-lg": "900px",
263 | "@modal-md": "600px",
264 | "@modal-sm": "300px",
265 | "@alert-padding": "15px",
266 | "@alert-border-radius": "@border-radius-base",
267 | "@alert-link-font-weight": "bold",
268 | "@alert-success-bg": "@state-success-bg",
269 | "@alert-success-text": "@state-success-text",
270 | "@alert-success-border": "@state-success-border",
271 | "@alert-info-bg": "@state-info-bg",
272 | "@alert-info-text": "@state-info-text",
273 | "@alert-info-border": "@state-info-border",
274 | "@alert-warning-bg": "@state-warning-bg",
275 | "@alert-warning-text": "@state-warning-text",
276 | "@alert-warning-border": "@state-warning-border",
277 | "@alert-danger-bg": "@state-danger-bg",
278 | "@alert-danger-text": "@state-danger-text",
279 | "@alert-danger-border": "@state-danger-border",
280 | "@progress-bg": "#f5f5f5",
281 | "@progress-bar-color": "#fff",
282 | "@progress-border-radius": "@border-radius-base",
283 | "@progress-bar-bg": "@brand-primary",
284 | "@progress-bar-success-bg": "@brand-success",
285 | "@progress-bar-warning-bg": "@brand-warning",
286 | "@progress-bar-danger-bg": "@brand-danger",
287 | "@progress-bar-info-bg": "@brand-info",
288 | "@list-group-bg": "#fff",
289 | "@list-group-border": "#ddd",
290 | "@list-group-border-radius": "@border-radius-base",
291 | "@list-group-hover-bg": "#f5f5f5",
292 | "@list-group-active-color": "@component-active-color",
293 | "@list-group-active-bg": "@component-active-bg",
294 | "@list-group-active-border": "@list-group-active-bg",
295 | "@list-group-active-text-color": "lighten(@list-group-active-bg, 40%)",
296 | "@list-group-disabled-color": "@gray-light",
297 | "@list-group-disabled-bg": "@gray-lighter",
298 | "@list-group-disabled-text-color": "@list-group-disabled-color",
299 | "@list-group-link-color": "#555",
300 | "@list-group-link-hover-color": "@list-group-link-color",
301 | "@list-group-link-heading-color": "#333",
302 | "@panel-bg": "#fff",
303 | "@panel-body-padding": "15px",
304 | "@panel-heading-padding": "10px 15px",
305 | "@panel-footer-padding": "@panel-heading-padding",
306 | "@panel-border-radius": "@border-radius-base",
307 | "@panel-inner-border": "#ddd",
308 | "@panel-footer-bg": "#f5f5f5",
309 | "@panel-default-text": "@gray-dark",
310 | "@panel-default-border": "#ddd",
311 | "@panel-default-heading-bg": "#f5f5f5",
312 | "@panel-primary-text": "#fff",
313 | "@panel-primary-border": "@brand-primary",
314 | "@panel-primary-heading-bg": "@brand-primary",
315 | "@panel-success-text": "@state-success-text",
316 | "@panel-success-border": "@state-success-border",
317 | "@panel-success-heading-bg": "@state-success-bg",
318 | "@panel-info-text": "@state-info-text",
319 | "@panel-info-border": "@state-info-border",
320 | "@panel-info-heading-bg": "@state-info-bg",
321 | "@panel-warning-text": "@state-warning-text",
322 | "@panel-warning-border": "@state-warning-border",
323 | "@panel-warning-heading-bg": "@state-warning-bg",
324 | "@panel-danger-text": "@state-danger-text",
325 | "@panel-danger-border": "@state-danger-border",
326 | "@panel-danger-heading-bg": "@state-danger-bg",
327 | "@thumbnail-padding": "4px",
328 | "@thumbnail-bg": "@body-bg",
329 | "@thumbnail-border": "#ddd",
330 | "@thumbnail-border-radius": "@border-radius-base",
331 | "@thumbnail-caption-color": "@text-color",
332 | "@thumbnail-caption-padding": "9px",
333 | "@well-bg": "#f5f5f5",
334 | "@well-border": "darken(@well-bg, 7%)",
335 | "@badge-color": "#fff",
336 | "@badge-link-hover-color": "#fff",
337 | "@badge-bg": "@gray-light",
338 | "@badge-active-color": "@link-color",
339 | "@badge-active-bg": "#fff",
340 | "@badge-font-weight": "bold",
341 | "@badge-line-height": "1",
342 | "@badge-border-radius": "10px",
343 | "@breadcrumb-padding-vertical": "8px",
344 | "@breadcrumb-padding-horizontal": "15px",
345 | "@breadcrumb-bg": "#f5f5f5",
346 | "@breadcrumb-color": "#ccc",
347 | "@breadcrumb-active-color": "@gray-light",
348 | "@breadcrumb-separator": "\"/\"",
349 | "@carousel-text-shadow": "0 1px 2px rgba(0,0,0,.6)",
350 | "@carousel-control-color": "#fff",
351 | "@carousel-control-width": "15%",
352 | "@carousel-control-opacity": ".5",
353 | "@carousel-control-font-size": "20px",
354 | "@carousel-indicator-active-bg": "#fff",
355 | "@carousel-indicator-border-color": "#fff",
356 | "@carousel-caption-color": "#fff",
357 | "@close-font-weight": "bold",
358 | "@close-color": "#000",
359 | "@close-text-shadow": "0 1px 0 #fff",
360 | "@code-color": "#c7254e",
361 | "@code-bg": "#f9f2f4",
362 | "@kbd-color": "#fff",
363 | "@kbd-bg": "#333",
364 | "@pre-bg": "#f5f5f5",
365 | "@pre-color": "@gray-dark",
366 | "@pre-border-color": "#ccc",
367 | "@pre-scrollable-max-height": "340px",
368 | "@component-offset-horizontal": "180px",
369 | "@text-muted": "@gray-light",
370 | "@abbr-border-color": "@gray-light",
371 | "@headings-small-color": "@gray-light",
372 | "@blockquote-small-color": "@gray-light",
373 | "@blockquote-font-size": "(@font-size-base * 1.25)",
374 | "@blockquote-border-color": "@gray-lighter",
375 | "@page-header-border-color": "@gray-lighter",
376 | "@dl-horizontal-offset": "@component-offset-horizontal",
377 | "@hr-border": "@gray-lighter"
378 | },
379 | "css": [
380 | "print.less",
381 | "type.less",
382 | "code.less",
383 | "grid.less",
384 | "tables.less",
385 | "forms.less",
386 | "buttons.less",
387 | "responsive-utilities.less",
388 | "button-groups.less",
389 | "input-groups.less",
390 | "navs.less",
391 | "navbar.less",
392 | "breadcrumbs.less",
393 | "pagination.less",
394 | "pager.less",
395 | "labels.less",
396 | "badges.less",
397 | "jumbotron.less",
398 | "thumbnails.less",
399 | "alerts.less",
400 | "progress-bars.less",
401 | "media.less",
402 | "list-group.less",
403 | "panels.less",
404 | "responsive-embed.less",
405 | "wells.less",
406 | "close.less",
407 | "component-animations.less",
408 | "dropdowns.less",
409 | "tooltip.less",
410 | "popovers.less",
411 | "modals.less",
412 | "carousel.less"
413 | ],
414 | "js": [
415 | "alert.js",
416 | "button.js",
417 | "carousel.js",
418 | "dropdown.js",
419 | "modal.js",
420 | "tooltip.js",
421 | "popover.js",
422 | "tab.js",
423 | "affix.js",
424 | "collapse.js",
425 | "scrollspy.js",
426 | "transition.js"
427 | ],
428 | "customizerUrl": "http://getbootstrap.com/customize/?id=99a2c42cc1a0aed84751"
429 | }
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/bootstrap/css/bootstrap-theme.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v3.3.4 (http://getbootstrap.com)
3 | * Copyright 2011-2015 Twitter, Inc.
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 | */
6 |
7 | /*!
8 | * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=99a2c42cc1a0aed84751)
9 | * Config saved to config.json and https://gist.github.com/99a2c42cc1a0aed84751
10 | */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-default .badge,.btn-primary .badge,.btn-success .badge,.btn-info .badge,.btn-warning .badge,.btn-danger .badge{text-shadow:none}.btn:active,.btn.active{background-image:none}.btn-default{background-image:-webkit-linear-gradient(top, #fff 0, #e0e0e0 100%);background-image:-o-linear-gradient(top, #fff 0, #e0e0e0 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), to(#e0e0e0));background-image:linear-gradient(to bottom, #fff 0, #e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#dbdbdb;text-shadow:0 1px 0 #fff;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top, #337ab7 0, #265a88 100%);background-image:-o-linear-gradient(top, #337ab7 0, #265a88 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #337ab7), to(#265a88));background-image:linear-gradient(to bottom, #337ab7 0, #265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#245580}.btn-primary:hover,.btn-primary:focus{background-color:#265a88;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary:disabled,.btn-primary[disabled]{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top, #5cb85c 0, #419641 100%);background-image:-o-linear-gradient(top, #5cb85c 0, #419641 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #5cb85c), to(#419641));background-image:linear-gradient(to bottom, #5cb85c 0, #419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top, #5bc0de 0, #2aabd2 100%);background-image:-o-linear-gradient(top, #5bc0de 0, #2aabd2 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #5bc0de), to(#2aabd2));background-image:linear-gradient(to bottom, #5bc0de 0, #2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top, #f0ad4e 0, #eb9316 100%);background-image:-o-linear-gradient(top, #f0ad4e 0, #eb9316 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #f0ad4e), to(#eb9316));background-image:linear-gradient(to bottom, #f0ad4e 0, #eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top, #d9534f 0, #c12e2a 100%);background-image:-o-linear-gradient(top, #d9534f 0, #c12e2a 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #d9534f), to(#c12e2a));background-image:linear-gradient(to bottom, #d9534f 0, #c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-image:-webkit-linear-gradient(top, #f5f5f5 0, #e8e8e8 100%);background-image:-o-linear-gradient(top, #f5f5f5 0, #e8e8e8 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #f5f5f5), to(#e8e8e8));background-image:linear-gradient(to bottom, #f5f5f5 0, #e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-color:#e8e8e8}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-image:-webkit-linear-gradient(top, #337ab7 0, #2e6da4 100%);background-image:-o-linear-gradient(top, #337ab7 0, #2e6da4 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #337ab7), to(#2e6da4));background-image:linear-gradient(to bottom, #337ab7 0, #2e6da4 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-color:#2e6da4}.navbar-default{background-image:-webkit-linear-gradient(top, #fff 0, #f8f8f8 100%);background-image:-o-linear-gradient(top, #fff 0, #f8f8f8 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), to(#f8f8f8));background-image:linear-gradient(to bottom, #fff 0, #f8f8f8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top, #dbdbdb 0, #e2e2e2 100%);background-image:-o-linear-gradient(top, #dbdbdb 0, #e2e2e2 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #dbdbdb), to(#e2e2e2));background-image:linear-gradient(to bottom, #dbdbdb 0, #e2e2e2 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top, #3c3c3c 0, #222 100%);background-image:-o-linear-gradient(top, #3c3c3c 0, #222 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #3c3c3c), to(#222));background-image:linear-gradient(to bottom, #3c3c3c 0, #222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top, #080808 0, #0f0f0f 100%);background-image:-o-linear-gradient(top, #080808 0, #0f0f0f 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #080808), to(#0f0f0f));background-image:linear-gradient(to bottom, #080808 0, #0f0f0f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-image:-webkit-linear-gradient(top, #337ab7 0, #2e6da4 100%);background-image:-o-linear-gradient(top, #337ab7 0, #2e6da4 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #337ab7), to(#2e6da4));background-image:linear-gradient(to bottom, #337ab7 0, #2e6da4 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0)}}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-linear-gradient(top, #dff0d8 0, #c8e5bc 100%);background-image:-o-linear-gradient(top, #dff0d8 0, #c8e5bc 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #dff0d8), to(#c8e5bc));background-image:linear-gradient(to bottom, #dff0d8 0, #c8e5bc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top, #d9edf7 0, #b9def0 100%);background-image:-o-linear-gradient(top, #d9edf7 0, #b9def0 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #d9edf7), to(#b9def0));background-image:linear-gradient(to bottom, #d9edf7 0, #b9def0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top, #fcf8e3 0, #f8efc0 100%);background-image:-o-linear-gradient(top, #fcf8e3 0, #f8efc0 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #fcf8e3), to(#f8efc0));background-image:linear-gradient(to bottom, #fcf8e3 0, #f8efc0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top, #f2dede 0, #e7c3c3 100%);background-image:-o-linear-gradient(top, #f2dede 0, #e7c3c3 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #f2dede), to(#e7c3c3));background-image:linear-gradient(to bottom, #f2dede 0, #e7c3c3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top, #ebebeb 0, #f5f5f5 100%);background-image:-o-linear-gradient(top, #ebebeb 0, #f5f5f5 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #ebebeb), to(#f5f5f5));background-image:linear-gradient(to bottom, #ebebeb 0, #f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top, #337ab7 0, #286090 100%);background-image:-o-linear-gradient(top, #337ab7 0, #286090 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #337ab7), to(#286090));background-image:linear-gradient(to bottom, #337ab7 0, #286090 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top, #5cb85c 0, #449d44 100%);background-image:-o-linear-gradient(top, #5cb85c 0, #449d44 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #5cb85c), to(#449d44));background-image:linear-gradient(to bottom, #5cb85c 0, #449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top, #5bc0de 0, #31b0d5 100%);background-image:-o-linear-gradient(top, #5bc0de 0, #31b0d5 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #5bc0de), to(#31b0d5));background-image:linear-gradient(to bottom, #5bc0de 0, #31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top, #f0ad4e 0, #ec971f 100%);background-image:-o-linear-gradient(top, #f0ad4e 0, #ec971f 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #f0ad4e), to(#ec971f));background-image:linear-gradient(to bottom, #f0ad4e 0, #ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top, #d9534f 0, #c9302c 100%);background-image:-o-linear-gradient(top, #d9534f 0, #c9302c 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #d9534f), to(#c9302c));background-image:linear-gradient(to bottom, #d9534f 0, #c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0)}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top, #337ab7 0, #2b669a 100%);background-image:-o-linear-gradient(top, #337ab7 0, #2b669a 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #337ab7), to(#2b669a));background-image:linear-gradient(to bottom, #337ab7 0, #2b669a 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:hover .badge,.list-group-item.active:focus .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top, #f5f5f5 0, #e8e8e8 100%);background-image:-o-linear-gradient(top, #f5f5f5 0, #e8e8e8 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #f5f5f5), to(#e8e8e8));background-image:linear-gradient(to bottom, #f5f5f5 0, #e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top, #337ab7 0, #2e6da4 100%);background-image:-o-linear-gradient(top, #337ab7 0, #2e6da4 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #337ab7), to(#2e6da4));background-image:linear-gradient(to bottom, #337ab7 0, #2e6da4 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top, #dff0d8 0, #d0e9c6 100%);background-image:-o-linear-gradient(top, #dff0d8 0, #d0e9c6 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #dff0d8), to(#d0e9c6));background-image:linear-gradient(to bottom, #dff0d8 0, #d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top, #d9edf7 0, #c4e3f3 100%);background-image:-o-linear-gradient(top, #d9edf7 0, #c4e3f3 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #d9edf7), to(#c4e3f3));background-image:linear-gradient(to bottom, #d9edf7 0, #c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top, #fcf8e3 0, #faf2cc 100%);background-image:-o-linear-gradient(top, #fcf8e3 0, #faf2cc 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #fcf8e3), to(#faf2cc));background-image:linear-gradient(to bottom, #fcf8e3 0, #faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top, #f2dede 0, #ebcccc 100%);background-image:-o-linear-gradient(top, #f2dede 0, #ebcccc 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #f2dede), to(#ebcccc));background-image:linear-gradient(to bottom, #f2dede 0, #ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0)}.well{background-image:-webkit-linear-gradient(top, #e8e8e8 0, #f5f5f5 100%);background-image:-o-linear-gradient(top, #e8e8e8 0, #f5f5f5 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #e8e8e8), to(#f5f5f5));background-image:linear-gradient(to bottom, #e8e8e8 0, #f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)}
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwestergren/docker-compose-tor-demo/5f0795e74b534b33a14a86c98f29a34b7ca0227d/youtubeadl/static/vendor/font-awesome/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwestergren/docker-compose-tor-demo/5f0795e74b534b33a14a86c98f29a34b7ca0227d/youtubeadl/static/vendor/font-awesome/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwestergren/docker-compose-tor-demo/5f0795e74b534b33a14a86c98f29a34b7ca0227d/youtubeadl/static/vendor/font-awesome/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwestergren/docker-compose-tor-demo/5f0795e74b534b33a14a86c98f29a34b7ca0227d/youtubeadl/static/vendor/font-awesome/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwestergren/docker-compose-tor-demo/5f0795e74b534b33a14a86c98f29a34b7ca0227d/youtubeadl/static/vendor/font-awesome/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/less/animated.less:
--------------------------------------------------------------------------------
1 | // Animated Icons
2 | // --------------------------
3 |
4 | .@{fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .@{fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/less/bordered-pulled.less:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-border {
5 | padding: .2em .25em .15em;
6 | border: solid .08em @fa-border-color;
7 | border-radius: .1em;
8 | }
9 |
10 | .pull-right { float: right; }
11 | .pull-left { float: left; }
12 |
13 | .@{fa-css-prefix} {
14 | &.pull-left { margin-right: .3em; }
15 | &.pull-right { margin-left: .3em; }
16 | }
17 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/less/core.less:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .@{fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/1 FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | transform: translate(0, 0); // ensures no half-pixel rendering in firefox
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/less/fixed-width.less:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .@{fa-css-prefix}-fw {
4 | width: (18em / 14);
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/less/font-awesome.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "variables.less";
7 | @import "mixins.less";
8 | @import "path.less";
9 | @import "core.less";
10 | @import "larger.less";
11 | @import "fixed-width.less";
12 | @import "list.less";
13 | @import "bordered-pulled.less";
14 | @import "animated.less";
15 | @import "rotated-flipped.less";
16 | @import "stacked.less";
17 | @import "icons.less";
18 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/less/larger.less:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | .@{fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -15%;
9 | }
10 | .@{fa-css-prefix}-2x { font-size: 2em; }
11 | .@{fa-css-prefix}-3x { font-size: 3em; }
12 | .@{fa-css-prefix}-4x { font-size: 4em; }
13 | .@{fa-css-prefix}-5x { font-size: 5em; }
14 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/less/list.less:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-ul {
5 | padding-left: 0;
6 | margin-left: @fa-li-width;
7 | list-style-type: none;
8 | > li { position: relative; }
9 | }
10 | .@{fa-css-prefix}-li {
11 | position: absolute;
12 | left: -@fa-li-width;
13 | width: @fa-li-width;
14 | top: (2em / 14);
15 | text-align: center;
16 | &.@{fa-css-prefix}-lg {
17 | left: (-@fa-li-width + (4em / 14));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/less/mixins.less:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | .fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/1 FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | transform: translate(0, 0); // ensures no half-pixel rendering in firefox
12 |
13 | }
14 |
15 | .fa-icon-rotate(@degrees, @rotation) {
16 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation);
17 | -webkit-transform: rotate(@degrees);
18 | -ms-transform: rotate(@degrees);
19 | transform: rotate(@degrees);
20 | }
21 |
22 | .fa-icon-flip(@horiz, @vert, @rotation) {
23 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1);
24 | -webkit-transform: scale(@horiz, @vert);
25 | -ms-transform: scale(@horiz, @vert);
26 | transform: scale(@horiz, @vert);
27 | }
28 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/less/path.less:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: 'FontAwesome';
6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/less/rotated-flipped.less:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); }
5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
7 |
8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); }
10 |
11 | // Hook for IE8-9
12 | // -------------------------
13 |
14 | :root .@{fa-css-prefix}-rotate-90,
15 | :root .@{fa-css-prefix}-rotate-180,
16 | :root .@{fa-css-prefix}-rotate-270,
17 | :root .@{fa-css-prefix}-flip-horizontal,
18 | :root .@{fa-css-prefix}-flip-vertical {
19 | filter: none;
20 | }
21 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/less/stacked.less:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
13 | position: absolute;
14 | left: 0;
15 | width: 100%;
16 | text-align: center;
17 | }
18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; }
19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; }
20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; }
21 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/less/variables.less:
--------------------------------------------------------------------------------
1 | // Variables
2 | // --------------------------
3 |
4 | @fa-font-path: "../fonts";
5 | @fa-font-size-base: 14px;
6 | //@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.3.0/fonts"; // for referencing Bootstrap CDN font files directly
7 | @fa-css-prefix: fa;
8 | @fa-version: "4.3.0";
9 | @fa-border-color: #eee;
10 | @fa-inverse: #fff;
11 | @fa-li-width: (30em / 14);
12 |
13 | @fa-var-adjust: "\f042";
14 | @fa-var-adn: "\f170";
15 | @fa-var-align-center: "\f037";
16 | @fa-var-align-justify: "\f039";
17 | @fa-var-align-left: "\f036";
18 | @fa-var-align-right: "\f038";
19 | @fa-var-ambulance: "\f0f9";
20 | @fa-var-anchor: "\f13d";
21 | @fa-var-android: "\f17b";
22 | @fa-var-angellist: "\f209";
23 | @fa-var-angle-double-down: "\f103";
24 | @fa-var-angle-double-left: "\f100";
25 | @fa-var-angle-double-right: "\f101";
26 | @fa-var-angle-double-up: "\f102";
27 | @fa-var-angle-down: "\f107";
28 | @fa-var-angle-left: "\f104";
29 | @fa-var-angle-right: "\f105";
30 | @fa-var-angle-up: "\f106";
31 | @fa-var-apple: "\f179";
32 | @fa-var-archive: "\f187";
33 | @fa-var-area-chart: "\f1fe";
34 | @fa-var-arrow-circle-down: "\f0ab";
35 | @fa-var-arrow-circle-left: "\f0a8";
36 | @fa-var-arrow-circle-o-down: "\f01a";
37 | @fa-var-arrow-circle-o-left: "\f190";
38 | @fa-var-arrow-circle-o-right: "\f18e";
39 | @fa-var-arrow-circle-o-up: "\f01b";
40 | @fa-var-arrow-circle-right: "\f0a9";
41 | @fa-var-arrow-circle-up: "\f0aa";
42 | @fa-var-arrow-down: "\f063";
43 | @fa-var-arrow-left: "\f060";
44 | @fa-var-arrow-right: "\f061";
45 | @fa-var-arrow-up: "\f062";
46 | @fa-var-arrows: "\f047";
47 | @fa-var-arrows-alt: "\f0b2";
48 | @fa-var-arrows-h: "\f07e";
49 | @fa-var-arrows-v: "\f07d";
50 | @fa-var-asterisk: "\f069";
51 | @fa-var-at: "\f1fa";
52 | @fa-var-automobile: "\f1b9";
53 | @fa-var-backward: "\f04a";
54 | @fa-var-ban: "\f05e";
55 | @fa-var-bank: "\f19c";
56 | @fa-var-bar-chart: "\f080";
57 | @fa-var-bar-chart-o: "\f080";
58 | @fa-var-barcode: "\f02a";
59 | @fa-var-bars: "\f0c9";
60 | @fa-var-bed: "\f236";
61 | @fa-var-beer: "\f0fc";
62 | @fa-var-behance: "\f1b4";
63 | @fa-var-behance-square: "\f1b5";
64 | @fa-var-bell: "\f0f3";
65 | @fa-var-bell-o: "\f0a2";
66 | @fa-var-bell-slash: "\f1f6";
67 | @fa-var-bell-slash-o: "\f1f7";
68 | @fa-var-bicycle: "\f206";
69 | @fa-var-binoculars: "\f1e5";
70 | @fa-var-birthday-cake: "\f1fd";
71 | @fa-var-bitbucket: "\f171";
72 | @fa-var-bitbucket-square: "\f172";
73 | @fa-var-bitcoin: "\f15a";
74 | @fa-var-bold: "\f032";
75 | @fa-var-bolt: "\f0e7";
76 | @fa-var-bomb: "\f1e2";
77 | @fa-var-book: "\f02d";
78 | @fa-var-bookmark: "\f02e";
79 | @fa-var-bookmark-o: "\f097";
80 | @fa-var-briefcase: "\f0b1";
81 | @fa-var-btc: "\f15a";
82 | @fa-var-bug: "\f188";
83 | @fa-var-building: "\f1ad";
84 | @fa-var-building-o: "\f0f7";
85 | @fa-var-bullhorn: "\f0a1";
86 | @fa-var-bullseye: "\f140";
87 | @fa-var-bus: "\f207";
88 | @fa-var-buysellads: "\f20d";
89 | @fa-var-cab: "\f1ba";
90 | @fa-var-calculator: "\f1ec";
91 | @fa-var-calendar: "\f073";
92 | @fa-var-calendar-o: "\f133";
93 | @fa-var-camera: "\f030";
94 | @fa-var-camera-retro: "\f083";
95 | @fa-var-car: "\f1b9";
96 | @fa-var-caret-down: "\f0d7";
97 | @fa-var-caret-left: "\f0d9";
98 | @fa-var-caret-right: "\f0da";
99 | @fa-var-caret-square-o-down: "\f150";
100 | @fa-var-caret-square-o-left: "\f191";
101 | @fa-var-caret-square-o-right: "\f152";
102 | @fa-var-caret-square-o-up: "\f151";
103 | @fa-var-caret-up: "\f0d8";
104 | @fa-var-cart-arrow-down: "\f218";
105 | @fa-var-cart-plus: "\f217";
106 | @fa-var-cc: "\f20a";
107 | @fa-var-cc-amex: "\f1f3";
108 | @fa-var-cc-discover: "\f1f2";
109 | @fa-var-cc-mastercard: "\f1f1";
110 | @fa-var-cc-paypal: "\f1f4";
111 | @fa-var-cc-stripe: "\f1f5";
112 | @fa-var-cc-visa: "\f1f0";
113 | @fa-var-certificate: "\f0a3";
114 | @fa-var-chain: "\f0c1";
115 | @fa-var-chain-broken: "\f127";
116 | @fa-var-check: "\f00c";
117 | @fa-var-check-circle: "\f058";
118 | @fa-var-check-circle-o: "\f05d";
119 | @fa-var-check-square: "\f14a";
120 | @fa-var-check-square-o: "\f046";
121 | @fa-var-chevron-circle-down: "\f13a";
122 | @fa-var-chevron-circle-left: "\f137";
123 | @fa-var-chevron-circle-right: "\f138";
124 | @fa-var-chevron-circle-up: "\f139";
125 | @fa-var-chevron-down: "\f078";
126 | @fa-var-chevron-left: "\f053";
127 | @fa-var-chevron-right: "\f054";
128 | @fa-var-chevron-up: "\f077";
129 | @fa-var-child: "\f1ae";
130 | @fa-var-circle: "\f111";
131 | @fa-var-circle-o: "\f10c";
132 | @fa-var-circle-o-notch: "\f1ce";
133 | @fa-var-circle-thin: "\f1db";
134 | @fa-var-clipboard: "\f0ea";
135 | @fa-var-clock-o: "\f017";
136 | @fa-var-close: "\f00d";
137 | @fa-var-cloud: "\f0c2";
138 | @fa-var-cloud-download: "\f0ed";
139 | @fa-var-cloud-upload: "\f0ee";
140 | @fa-var-cny: "\f157";
141 | @fa-var-code: "\f121";
142 | @fa-var-code-fork: "\f126";
143 | @fa-var-codepen: "\f1cb";
144 | @fa-var-coffee: "\f0f4";
145 | @fa-var-cog: "\f013";
146 | @fa-var-cogs: "\f085";
147 | @fa-var-columns: "\f0db";
148 | @fa-var-comment: "\f075";
149 | @fa-var-comment-o: "\f0e5";
150 | @fa-var-comments: "\f086";
151 | @fa-var-comments-o: "\f0e6";
152 | @fa-var-compass: "\f14e";
153 | @fa-var-compress: "\f066";
154 | @fa-var-connectdevelop: "\f20e";
155 | @fa-var-copy: "\f0c5";
156 | @fa-var-copyright: "\f1f9";
157 | @fa-var-credit-card: "\f09d";
158 | @fa-var-crop: "\f125";
159 | @fa-var-crosshairs: "\f05b";
160 | @fa-var-css3: "\f13c";
161 | @fa-var-cube: "\f1b2";
162 | @fa-var-cubes: "\f1b3";
163 | @fa-var-cut: "\f0c4";
164 | @fa-var-cutlery: "\f0f5";
165 | @fa-var-dashboard: "\f0e4";
166 | @fa-var-dashcube: "\f210";
167 | @fa-var-database: "\f1c0";
168 | @fa-var-dedent: "\f03b";
169 | @fa-var-delicious: "\f1a5";
170 | @fa-var-desktop: "\f108";
171 | @fa-var-deviantart: "\f1bd";
172 | @fa-var-diamond: "\f219";
173 | @fa-var-digg: "\f1a6";
174 | @fa-var-dollar: "\f155";
175 | @fa-var-dot-circle-o: "\f192";
176 | @fa-var-download: "\f019";
177 | @fa-var-dribbble: "\f17d";
178 | @fa-var-dropbox: "\f16b";
179 | @fa-var-drupal: "\f1a9";
180 | @fa-var-edit: "\f044";
181 | @fa-var-eject: "\f052";
182 | @fa-var-ellipsis-h: "\f141";
183 | @fa-var-ellipsis-v: "\f142";
184 | @fa-var-empire: "\f1d1";
185 | @fa-var-envelope: "\f0e0";
186 | @fa-var-envelope-o: "\f003";
187 | @fa-var-envelope-square: "\f199";
188 | @fa-var-eraser: "\f12d";
189 | @fa-var-eur: "\f153";
190 | @fa-var-euro: "\f153";
191 | @fa-var-exchange: "\f0ec";
192 | @fa-var-exclamation: "\f12a";
193 | @fa-var-exclamation-circle: "\f06a";
194 | @fa-var-exclamation-triangle: "\f071";
195 | @fa-var-expand: "\f065";
196 | @fa-var-external-link: "\f08e";
197 | @fa-var-external-link-square: "\f14c";
198 | @fa-var-eye: "\f06e";
199 | @fa-var-eye-slash: "\f070";
200 | @fa-var-eyedropper: "\f1fb";
201 | @fa-var-facebook: "\f09a";
202 | @fa-var-facebook-f: "\f09a";
203 | @fa-var-facebook-official: "\f230";
204 | @fa-var-facebook-square: "\f082";
205 | @fa-var-fast-backward: "\f049";
206 | @fa-var-fast-forward: "\f050";
207 | @fa-var-fax: "\f1ac";
208 | @fa-var-female: "\f182";
209 | @fa-var-fighter-jet: "\f0fb";
210 | @fa-var-file: "\f15b";
211 | @fa-var-file-archive-o: "\f1c6";
212 | @fa-var-file-audio-o: "\f1c7";
213 | @fa-var-file-code-o: "\f1c9";
214 | @fa-var-file-excel-o: "\f1c3";
215 | @fa-var-file-image-o: "\f1c5";
216 | @fa-var-file-movie-o: "\f1c8";
217 | @fa-var-file-o: "\f016";
218 | @fa-var-file-pdf-o: "\f1c1";
219 | @fa-var-file-photo-o: "\f1c5";
220 | @fa-var-file-picture-o: "\f1c5";
221 | @fa-var-file-powerpoint-o: "\f1c4";
222 | @fa-var-file-sound-o: "\f1c7";
223 | @fa-var-file-text: "\f15c";
224 | @fa-var-file-text-o: "\f0f6";
225 | @fa-var-file-video-o: "\f1c8";
226 | @fa-var-file-word-o: "\f1c2";
227 | @fa-var-file-zip-o: "\f1c6";
228 | @fa-var-files-o: "\f0c5";
229 | @fa-var-film: "\f008";
230 | @fa-var-filter: "\f0b0";
231 | @fa-var-fire: "\f06d";
232 | @fa-var-fire-extinguisher: "\f134";
233 | @fa-var-flag: "\f024";
234 | @fa-var-flag-checkered: "\f11e";
235 | @fa-var-flag-o: "\f11d";
236 | @fa-var-flash: "\f0e7";
237 | @fa-var-flask: "\f0c3";
238 | @fa-var-flickr: "\f16e";
239 | @fa-var-floppy-o: "\f0c7";
240 | @fa-var-folder: "\f07b";
241 | @fa-var-folder-o: "\f114";
242 | @fa-var-folder-open: "\f07c";
243 | @fa-var-folder-open-o: "\f115";
244 | @fa-var-font: "\f031";
245 | @fa-var-forumbee: "\f211";
246 | @fa-var-forward: "\f04e";
247 | @fa-var-foursquare: "\f180";
248 | @fa-var-frown-o: "\f119";
249 | @fa-var-futbol-o: "\f1e3";
250 | @fa-var-gamepad: "\f11b";
251 | @fa-var-gavel: "\f0e3";
252 | @fa-var-gbp: "\f154";
253 | @fa-var-ge: "\f1d1";
254 | @fa-var-gear: "\f013";
255 | @fa-var-gears: "\f085";
256 | @fa-var-genderless: "\f1db";
257 | @fa-var-gift: "\f06b";
258 | @fa-var-git: "\f1d3";
259 | @fa-var-git-square: "\f1d2";
260 | @fa-var-github: "\f09b";
261 | @fa-var-github-alt: "\f113";
262 | @fa-var-github-square: "\f092";
263 | @fa-var-gittip: "\f184";
264 | @fa-var-glass: "\f000";
265 | @fa-var-globe: "\f0ac";
266 | @fa-var-google: "\f1a0";
267 | @fa-var-google-plus: "\f0d5";
268 | @fa-var-google-plus-square: "\f0d4";
269 | @fa-var-google-wallet: "\f1ee";
270 | @fa-var-graduation-cap: "\f19d";
271 | @fa-var-gratipay: "\f184";
272 | @fa-var-group: "\f0c0";
273 | @fa-var-h-square: "\f0fd";
274 | @fa-var-hacker-news: "\f1d4";
275 | @fa-var-hand-o-down: "\f0a7";
276 | @fa-var-hand-o-left: "\f0a5";
277 | @fa-var-hand-o-right: "\f0a4";
278 | @fa-var-hand-o-up: "\f0a6";
279 | @fa-var-hdd-o: "\f0a0";
280 | @fa-var-header: "\f1dc";
281 | @fa-var-headphones: "\f025";
282 | @fa-var-heart: "\f004";
283 | @fa-var-heart-o: "\f08a";
284 | @fa-var-heartbeat: "\f21e";
285 | @fa-var-history: "\f1da";
286 | @fa-var-home: "\f015";
287 | @fa-var-hospital-o: "\f0f8";
288 | @fa-var-hotel: "\f236";
289 | @fa-var-html5: "\f13b";
290 | @fa-var-ils: "\f20b";
291 | @fa-var-image: "\f03e";
292 | @fa-var-inbox: "\f01c";
293 | @fa-var-indent: "\f03c";
294 | @fa-var-info: "\f129";
295 | @fa-var-info-circle: "\f05a";
296 | @fa-var-inr: "\f156";
297 | @fa-var-instagram: "\f16d";
298 | @fa-var-institution: "\f19c";
299 | @fa-var-ioxhost: "\f208";
300 | @fa-var-italic: "\f033";
301 | @fa-var-joomla: "\f1aa";
302 | @fa-var-jpy: "\f157";
303 | @fa-var-jsfiddle: "\f1cc";
304 | @fa-var-key: "\f084";
305 | @fa-var-keyboard-o: "\f11c";
306 | @fa-var-krw: "\f159";
307 | @fa-var-language: "\f1ab";
308 | @fa-var-laptop: "\f109";
309 | @fa-var-lastfm: "\f202";
310 | @fa-var-lastfm-square: "\f203";
311 | @fa-var-leaf: "\f06c";
312 | @fa-var-leanpub: "\f212";
313 | @fa-var-legal: "\f0e3";
314 | @fa-var-lemon-o: "\f094";
315 | @fa-var-level-down: "\f149";
316 | @fa-var-level-up: "\f148";
317 | @fa-var-life-bouy: "\f1cd";
318 | @fa-var-life-buoy: "\f1cd";
319 | @fa-var-life-ring: "\f1cd";
320 | @fa-var-life-saver: "\f1cd";
321 | @fa-var-lightbulb-o: "\f0eb";
322 | @fa-var-line-chart: "\f201";
323 | @fa-var-link: "\f0c1";
324 | @fa-var-linkedin: "\f0e1";
325 | @fa-var-linkedin-square: "\f08c";
326 | @fa-var-linux: "\f17c";
327 | @fa-var-list: "\f03a";
328 | @fa-var-list-alt: "\f022";
329 | @fa-var-list-ol: "\f0cb";
330 | @fa-var-list-ul: "\f0ca";
331 | @fa-var-location-arrow: "\f124";
332 | @fa-var-lock: "\f023";
333 | @fa-var-long-arrow-down: "\f175";
334 | @fa-var-long-arrow-left: "\f177";
335 | @fa-var-long-arrow-right: "\f178";
336 | @fa-var-long-arrow-up: "\f176";
337 | @fa-var-magic: "\f0d0";
338 | @fa-var-magnet: "\f076";
339 | @fa-var-mail-forward: "\f064";
340 | @fa-var-mail-reply: "\f112";
341 | @fa-var-mail-reply-all: "\f122";
342 | @fa-var-male: "\f183";
343 | @fa-var-map-marker: "\f041";
344 | @fa-var-mars: "\f222";
345 | @fa-var-mars-double: "\f227";
346 | @fa-var-mars-stroke: "\f229";
347 | @fa-var-mars-stroke-h: "\f22b";
348 | @fa-var-mars-stroke-v: "\f22a";
349 | @fa-var-maxcdn: "\f136";
350 | @fa-var-meanpath: "\f20c";
351 | @fa-var-medium: "\f23a";
352 | @fa-var-medkit: "\f0fa";
353 | @fa-var-meh-o: "\f11a";
354 | @fa-var-mercury: "\f223";
355 | @fa-var-microphone: "\f130";
356 | @fa-var-microphone-slash: "\f131";
357 | @fa-var-minus: "\f068";
358 | @fa-var-minus-circle: "\f056";
359 | @fa-var-minus-square: "\f146";
360 | @fa-var-minus-square-o: "\f147";
361 | @fa-var-mobile: "\f10b";
362 | @fa-var-mobile-phone: "\f10b";
363 | @fa-var-money: "\f0d6";
364 | @fa-var-moon-o: "\f186";
365 | @fa-var-mortar-board: "\f19d";
366 | @fa-var-motorcycle: "\f21c";
367 | @fa-var-music: "\f001";
368 | @fa-var-navicon: "\f0c9";
369 | @fa-var-neuter: "\f22c";
370 | @fa-var-newspaper-o: "\f1ea";
371 | @fa-var-openid: "\f19b";
372 | @fa-var-outdent: "\f03b";
373 | @fa-var-pagelines: "\f18c";
374 | @fa-var-paint-brush: "\f1fc";
375 | @fa-var-paper-plane: "\f1d8";
376 | @fa-var-paper-plane-o: "\f1d9";
377 | @fa-var-paperclip: "\f0c6";
378 | @fa-var-paragraph: "\f1dd";
379 | @fa-var-paste: "\f0ea";
380 | @fa-var-pause: "\f04c";
381 | @fa-var-paw: "\f1b0";
382 | @fa-var-paypal: "\f1ed";
383 | @fa-var-pencil: "\f040";
384 | @fa-var-pencil-square: "\f14b";
385 | @fa-var-pencil-square-o: "\f044";
386 | @fa-var-phone: "\f095";
387 | @fa-var-phone-square: "\f098";
388 | @fa-var-photo: "\f03e";
389 | @fa-var-picture-o: "\f03e";
390 | @fa-var-pie-chart: "\f200";
391 | @fa-var-pied-piper: "\f1a7";
392 | @fa-var-pied-piper-alt: "\f1a8";
393 | @fa-var-pinterest: "\f0d2";
394 | @fa-var-pinterest-p: "\f231";
395 | @fa-var-pinterest-square: "\f0d3";
396 | @fa-var-plane: "\f072";
397 | @fa-var-play: "\f04b";
398 | @fa-var-play-circle: "\f144";
399 | @fa-var-play-circle-o: "\f01d";
400 | @fa-var-plug: "\f1e6";
401 | @fa-var-plus: "\f067";
402 | @fa-var-plus-circle: "\f055";
403 | @fa-var-plus-square: "\f0fe";
404 | @fa-var-plus-square-o: "\f196";
405 | @fa-var-power-off: "\f011";
406 | @fa-var-print: "\f02f";
407 | @fa-var-puzzle-piece: "\f12e";
408 | @fa-var-qq: "\f1d6";
409 | @fa-var-qrcode: "\f029";
410 | @fa-var-question: "\f128";
411 | @fa-var-question-circle: "\f059";
412 | @fa-var-quote-left: "\f10d";
413 | @fa-var-quote-right: "\f10e";
414 | @fa-var-ra: "\f1d0";
415 | @fa-var-random: "\f074";
416 | @fa-var-rebel: "\f1d0";
417 | @fa-var-recycle: "\f1b8";
418 | @fa-var-reddit: "\f1a1";
419 | @fa-var-reddit-square: "\f1a2";
420 | @fa-var-refresh: "\f021";
421 | @fa-var-remove: "\f00d";
422 | @fa-var-renren: "\f18b";
423 | @fa-var-reorder: "\f0c9";
424 | @fa-var-repeat: "\f01e";
425 | @fa-var-reply: "\f112";
426 | @fa-var-reply-all: "\f122";
427 | @fa-var-retweet: "\f079";
428 | @fa-var-rmb: "\f157";
429 | @fa-var-road: "\f018";
430 | @fa-var-rocket: "\f135";
431 | @fa-var-rotate-left: "\f0e2";
432 | @fa-var-rotate-right: "\f01e";
433 | @fa-var-rouble: "\f158";
434 | @fa-var-rss: "\f09e";
435 | @fa-var-rss-square: "\f143";
436 | @fa-var-rub: "\f158";
437 | @fa-var-ruble: "\f158";
438 | @fa-var-rupee: "\f156";
439 | @fa-var-save: "\f0c7";
440 | @fa-var-scissors: "\f0c4";
441 | @fa-var-search: "\f002";
442 | @fa-var-search-minus: "\f010";
443 | @fa-var-search-plus: "\f00e";
444 | @fa-var-sellsy: "\f213";
445 | @fa-var-send: "\f1d8";
446 | @fa-var-send-o: "\f1d9";
447 | @fa-var-server: "\f233";
448 | @fa-var-share: "\f064";
449 | @fa-var-share-alt: "\f1e0";
450 | @fa-var-share-alt-square: "\f1e1";
451 | @fa-var-share-square: "\f14d";
452 | @fa-var-share-square-o: "\f045";
453 | @fa-var-shekel: "\f20b";
454 | @fa-var-sheqel: "\f20b";
455 | @fa-var-shield: "\f132";
456 | @fa-var-ship: "\f21a";
457 | @fa-var-shirtsinbulk: "\f214";
458 | @fa-var-shopping-cart: "\f07a";
459 | @fa-var-sign-in: "\f090";
460 | @fa-var-sign-out: "\f08b";
461 | @fa-var-signal: "\f012";
462 | @fa-var-simplybuilt: "\f215";
463 | @fa-var-sitemap: "\f0e8";
464 | @fa-var-skyatlas: "\f216";
465 | @fa-var-skype: "\f17e";
466 | @fa-var-slack: "\f198";
467 | @fa-var-sliders: "\f1de";
468 | @fa-var-slideshare: "\f1e7";
469 | @fa-var-smile-o: "\f118";
470 | @fa-var-soccer-ball-o: "\f1e3";
471 | @fa-var-sort: "\f0dc";
472 | @fa-var-sort-alpha-asc: "\f15d";
473 | @fa-var-sort-alpha-desc: "\f15e";
474 | @fa-var-sort-amount-asc: "\f160";
475 | @fa-var-sort-amount-desc: "\f161";
476 | @fa-var-sort-asc: "\f0de";
477 | @fa-var-sort-desc: "\f0dd";
478 | @fa-var-sort-down: "\f0dd";
479 | @fa-var-sort-numeric-asc: "\f162";
480 | @fa-var-sort-numeric-desc: "\f163";
481 | @fa-var-sort-up: "\f0de";
482 | @fa-var-soundcloud: "\f1be";
483 | @fa-var-space-shuttle: "\f197";
484 | @fa-var-spinner: "\f110";
485 | @fa-var-spoon: "\f1b1";
486 | @fa-var-spotify: "\f1bc";
487 | @fa-var-square: "\f0c8";
488 | @fa-var-square-o: "\f096";
489 | @fa-var-stack-exchange: "\f18d";
490 | @fa-var-stack-overflow: "\f16c";
491 | @fa-var-star: "\f005";
492 | @fa-var-star-half: "\f089";
493 | @fa-var-star-half-empty: "\f123";
494 | @fa-var-star-half-full: "\f123";
495 | @fa-var-star-half-o: "\f123";
496 | @fa-var-star-o: "\f006";
497 | @fa-var-steam: "\f1b6";
498 | @fa-var-steam-square: "\f1b7";
499 | @fa-var-step-backward: "\f048";
500 | @fa-var-step-forward: "\f051";
501 | @fa-var-stethoscope: "\f0f1";
502 | @fa-var-stop: "\f04d";
503 | @fa-var-street-view: "\f21d";
504 | @fa-var-strikethrough: "\f0cc";
505 | @fa-var-stumbleupon: "\f1a4";
506 | @fa-var-stumbleupon-circle: "\f1a3";
507 | @fa-var-subscript: "\f12c";
508 | @fa-var-subway: "\f239";
509 | @fa-var-suitcase: "\f0f2";
510 | @fa-var-sun-o: "\f185";
511 | @fa-var-superscript: "\f12b";
512 | @fa-var-support: "\f1cd";
513 | @fa-var-table: "\f0ce";
514 | @fa-var-tablet: "\f10a";
515 | @fa-var-tachometer: "\f0e4";
516 | @fa-var-tag: "\f02b";
517 | @fa-var-tags: "\f02c";
518 | @fa-var-tasks: "\f0ae";
519 | @fa-var-taxi: "\f1ba";
520 | @fa-var-tencent-weibo: "\f1d5";
521 | @fa-var-terminal: "\f120";
522 | @fa-var-text-height: "\f034";
523 | @fa-var-text-width: "\f035";
524 | @fa-var-th: "\f00a";
525 | @fa-var-th-large: "\f009";
526 | @fa-var-th-list: "\f00b";
527 | @fa-var-thumb-tack: "\f08d";
528 | @fa-var-thumbs-down: "\f165";
529 | @fa-var-thumbs-o-down: "\f088";
530 | @fa-var-thumbs-o-up: "\f087";
531 | @fa-var-thumbs-up: "\f164";
532 | @fa-var-ticket: "\f145";
533 | @fa-var-times: "\f00d";
534 | @fa-var-times-circle: "\f057";
535 | @fa-var-times-circle-o: "\f05c";
536 | @fa-var-tint: "\f043";
537 | @fa-var-toggle-down: "\f150";
538 | @fa-var-toggle-left: "\f191";
539 | @fa-var-toggle-off: "\f204";
540 | @fa-var-toggle-on: "\f205";
541 | @fa-var-toggle-right: "\f152";
542 | @fa-var-toggle-up: "\f151";
543 | @fa-var-train: "\f238";
544 | @fa-var-transgender: "\f224";
545 | @fa-var-transgender-alt: "\f225";
546 | @fa-var-trash: "\f1f8";
547 | @fa-var-trash-o: "\f014";
548 | @fa-var-tree: "\f1bb";
549 | @fa-var-trello: "\f181";
550 | @fa-var-trophy: "\f091";
551 | @fa-var-truck: "\f0d1";
552 | @fa-var-try: "\f195";
553 | @fa-var-tty: "\f1e4";
554 | @fa-var-tumblr: "\f173";
555 | @fa-var-tumblr-square: "\f174";
556 | @fa-var-turkish-lira: "\f195";
557 | @fa-var-twitch: "\f1e8";
558 | @fa-var-twitter: "\f099";
559 | @fa-var-twitter-square: "\f081";
560 | @fa-var-umbrella: "\f0e9";
561 | @fa-var-underline: "\f0cd";
562 | @fa-var-undo: "\f0e2";
563 | @fa-var-university: "\f19c";
564 | @fa-var-unlink: "\f127";
565 | @fa-var-unlock: "\f09c";
566 | @fa-var-unlock-alt: "\f13e";
567 | @fa-var-unsorted: "\f0dc";
568 | @fa-var-upload: "\f093";
569 | @fa-var-usd: "\f155";
570 | @fa-var-user: "\f007";
571 | @fa-var-user-md: "\f0f0";
572 | @fa-var-user-plus: "\f234";
573 | @fa-var-user-secret: "\f21b";
574 | @fa-var-user-times: "\f235";
575 | @fa-var-users: "\f0c0";
576 | @fa-var-venus: "\f221";
577 | @fa-var-venus-double: "\f226";
578 | @fa-var-venus-mars: "\f228";
579 | @fa-var-viacoin: "\f237";
580 | @fa-var-video-camera: "\f03d";
581 | @fa-var-vimeo-square: "\f194";
582 | @fa-var-vine: "\f1ca";
583 | @fa-var-vk: "\f189";
584 | @fa-var-volume-down: "\f027";
585 | @fa-var-volume-off: "\f026";
586 | @fa-var-volume-up: "\f028";
587 | @fa-var-warning: "\f071";
588 | @fa-var-wechat: "\f1d7";
589 | @fa-var-weibo: "\f18a";
590 | @fa-var-weixin: "\f1d7";
591 | @fa-var-whatsapp: "\f232";
592 | @fa-var-wheelchair: "\f193";
593 | @fa-var-wifi: "\f1eb";
594 | @fa-var-windows: "\f17a";
595 | @fa-var-won: "\f159";
596 | @fa-var-wordpress: "\f19a";
597 | @fa-var-wrench: "\f0ad";
598 | @fa-var-xing: "\f168";
599 | @fa-var-xing-square: "\f169";
600 | @fa-var-yahoo: "\f19e";
601 | @fa-var-yelp: "\f1e9";
602 | @fa-var-yen: "\f157";
603 | @fa-var-youtube: "\f167";
604 | @fa-var-youtube-play: "\f16a";
605 | @fa-var-youtube-square: "\f166";
606 |
607 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/scss/_animated.scss:
--------------------------------------------------------------------------------
1 | // Spinning Icons
2 | // --------------------------
3 |
4 | .#{$fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .#{$fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/scss/_bordered-pulled.scss:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-border {
5 | padding: .2em .25em .15em;
6 | border: solid .08em $fa-border-color;
7 | border-radius: .1em;
8 | }
9 |
10 | .pull-right { float: right; }
11 | .pull-left { float: left; }
12 |
13 | .#{$fa-css-prefix} {
14 | &.pull-left { margin-right: .3em; }
15 | &.pull-right { margin-left: .3em; }
16 | }
17 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/scss/_core.scss:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/1 FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | transform: translate(0, 0); // ensures no half-pixel rendering in firefox
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/scss/_fixed-width.scss:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .#{$fa-css-prefix}-fw {
4 | width: (18em / 14);
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/scss/_larger.scss:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | .#{$fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -15%;
9 | }
10 | .#{$fa-css-prefix}-2x { font-size: 2em; }
11 | .#{$fa-css-prefix}-3x { font-size: 3em; }
12 | .#{$fa-css-prefix}-4x { font-size: 4em; }
13 | .#{$fa-css-prefix}-5x { font-size: 5em; }
14 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/scss/_list.scss:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-ul {
5 | padding-left: 0;
6 | margin-left: $fa-li-width;
7 | list-style-type: none;
8 | > li { position: relative; }
9 | }
10 | .#{$fa-css-prefix}-li {
11 | position: absolute;
12 | left: -$fa-li-width;
13 | width: $fa-li-width;
14 | top: (2em / 14);
15 | text-align: center;
16 | &.#{$fa-css-prefix}-lg {
17 | left: -$fa-li-width + (4em / 14);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/scss/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | @mixin fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/1 FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | transform: translate(0, 0); // ensures no half-pixel rendering in firefox
12 |
13 | }
14 |
15 | @mixin fa-icon-rotate($degrees, $rotation) {
16 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation});
17 | -webkit-transform: rotate($degrees);
18 | -ms-transform: rotate($degrees);
19 | transform: rotate($degrees);
20 | }
21 |
22 | @mixin fa-icon-flip($horiz, $vert, $rotation) {
23 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation});
24 | -webkit-transform: scale($horiz, $vert);
25 | -ms-transform: scale($horiz, $vert);
26 | transform: scale($horiz, $vert);
27 | }
28 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/scss/_path.scss:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: 'FontAwesome';
6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/scss/_rotated-flipped.scss:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); }
5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); }
6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); }
7 |
8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); }
9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); }
10 |
11 | // Hook for IE8-9
12 | // -------------------------
13 |
14 | :root .#{$fa-css-prefix}-rotate-90,
15 | :root .#{$fa-css-prefix}-rotate-180,
16 | :root .#{$fa-css-prefix}-rotate-270,
17 | :root .#{$fa-css-prefix}-flip-horizontal,
18 | :root .#{$fa-css-prefix}-flip-vertical {
19 | filter: none;
20 | }
21 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/scss/_stacked.scss:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x {
13 | position: absolute;
14 | left: 0;
15 | width: 100%;
16 | text-align: center;
17 | }
18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; }
19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; }
20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; }
21 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/scss/_variables.scss:
--------------------------------------------------------------------------------
1 | // Variables
2 | // --------------------------
3 |
4 | $fa-font-path: "../fonts" !default;
5 | $fa-font-size-base: 14px !default;
6 | //$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.3.0/fonts" !default; // for referencing Bootstrap CDN font files directly
7 | $fa-css-prefix: fa !default;
8 | $fa-version: "4.3.0" !default;
9 | $fa-border-color: #eee !default;
10 | $fa-inverse: #fff !default;
11 | $fa-li-width: (30em / 14) !default;
12 |
13 | $fa-var-adjust: "\f042";
14 | $fa-var-adn: "\f170";
15 | $fa-var-align-center: "\f037";
16 | $fa-var-align-justify: "\f039";
17 | $fa-var-align-left: "\f036";
18 | $fa-var-align-right: "\f038";
19 | $fa-var-ambulance: "\f0f9";
20 | $fa-var-anchor: "\f13d";
21 | $fa-var-android: "\f17b";
22 | $fa-var-angellist: "\f209";
23 | $fa-var-angle-double-down: "\f103";
24 | $fa-var-angle-double-left: "\f100";
25 | $fa-var-angle-double-right: "\f101";
26 | $fa-var-angle-double-up: "\f102";
27 | $fa-var-angle-down: "\f107";
28 | $fa-var-angle-left: "\f104";
29 | $fa-var-angle-right: "\f105";
30 | $fa-var-angle-up: "\f106";
31 | $fa-var-apple: "\f179";
32 | $fa-var-archive: "\f187";
33 | $fa-var-area-chart: "\f1fe";
34 | $fa-var-arrow-circle-down: "\f0ab";
35 | $fa-var-arrow-circle-left: "\f0a8";
36 | $fa-var-arrow-circle-o-down: "\f01a";
37 | $fa-var-arrow-circle-o-left: "\f190";
38 | $fa-var-arrow-circle-o-right: "\f18e";
39 | $fa-var-arrow-circle-o-up: "\f01b";
40 | $fa-var-arrow-circle-right: "\f0a9";
41 | $fa-var-arrow-circle-up: "\f0aa";
42 | $fa-var-arrow-down: "\f063";
43 | $fa-var-arrow-left: "\f060";
44 | $fa-var-arrow-right: "\f061";
45 | $fa-var-arrow-up: "\f062";
46 | $fa-var-arrows: "\f047";
47 | $fa-var-arrows-alt: "\f0b2";
48 | $fa-var-arrows-h: "\f07e";
49 | $fa-var-arrows-v: "\f07d";
50 | $fa-var-asterisk: "\f069";
51 | $fa-var-at: "\f1fa";
52 | $fa-var-automobile: "\f1b9";
53 | $fa-var-backward: "\f04a";
54 | $fa-var-ban: "\f05e";
55 | $fa-var-bank: "\f19c";
56 | $fa-var-bar-chart: "\f080";
57 | $fa-var-bar-chart-o: "\f080";
58 | $fa-var-barcode: "\f02a";
59 | $fa-var-bars: "\f0c9";
60 | $fa-var-bed: "\f236";
61 | $fa-var-beer: "\f0fc";
62 | $fa-var-behance: "\f1b4";
63 | $fa-var-behance-square: "\f1b5";
64 | $fa-var-bell: "\f0f3";
65 | $fa-var-bell-o: "\f0a2";
66 | $fa-var-bell-slash: "\f1f6";
67 | $fa-var-bell-slash-o: "\f1f7";
68 | $fa-var-bicycle: "\f206";
69 | $fa-var-binoculars: "\f1e5";
70 | $fa-var-birthday-cake: "\f1fd";
71 | $fa-var-bitbucket: "\f171";
72 | $fa-var-bitbucket-square: "\f172";
73 | $fa-var-bitcoin: "\f15a";
74 | $fa-var-bold: "\f032";
75 | $fa-var-bolt: "\f0e7";
76 | $fa-var-bomb: "\f1e2";
77 | $fa-var-book: "\f02d";
78 | $fa-var-bookmark: "\f02e";
79 | $fa-var-bookmark-o: "\f097";
80 | $fa-var-briefcase: "\f0b1";
81 | $fa-var-btc: "\f15a";
82 | $fa-var-bug: "\f188";
83 | $fa-var-building: "\f1ad";
84 | $fa-var-building-o: "\f0f7";
85 | $fa-var-bullhorn: "\f0a1";
86 | $fa-var-bullseye: "\f140";
87 | $fa-var-bus: "\f207";
88 | $fa-var-buysellads: "\f20d";
89 | $fa-var-cab: "\f1ba";
90 | $fa-var-calculator: "\f1ec";
91 | $fa-var-calendar: "\f073";
92 | $fa-var-calendar-o: "\f133";
93 | $fa-var-camera: "\f030";
94 | $fa-var-camera-retro: "\f083";
95 | $fa-var-car: "\f1b9";
96 | $fa-var-caret-down: "\f0d7";
97 | $fa-var-caret-left: "\f0d9";
98 | $fa-var-caret-right: "\f0da";
99 | $fa-var-caret-square-o-down: "\f150";
100 | $fa-var-caret-square-o-left: "\f191";
101 | $fa-var-caret-square-o-right: "\f152";
102 | $fa-var-caret-square-o-up: "\f151";
103 | $fa-var-caret-up: "\f0d8";
104 | $fa-var-cart-arrow-down: "\f218";
105 | $fa-var-cart-plus: "\f217";
106 | $fa-var-cc: "\f20a";
107 | $fa-var-cc-amex: "\f1f3";
108 | $fa-var-cc-discover: "\f1f2";
109 | $fa-var-cc-mastercard: "\f1f1";
110 | $fa-var-cc-paypal: "\f1f4";
111 | $fa-var-cc-stripe: "\f1f5";
112 | $fa-var-cc-visa: "\f1f0";
113 | $fa-var-certificate: "\f0a3";
114 | $fa-var-chain: "\f0c1";
115 | $fa-var-chain-broken: "\f127";
116 | $fa-var-check: "\f00c";
117 | $fa-var-check-circle: "\f058";
118 | $fa-var-check-circle-o: "\f05d";
119 | $fa-var-check-square: "\f14a";
120 | $fa-var-check-square-o: "\f046";
121 | $fa-var-chevron-circle-down: "\f13a";
122 | $fa-var-chevron-circle-left: "\f137";
123 | $fa-var-chevron-circle-right: "\f138";
124 | $fa-var-chevron-circle-up: "\f139";
125 | $fa-var-chevron-down: "\f078";
126 | $fa-var-chevron-left: "\f053";
127 | $fa-var-chevron-right: "\f054";
128 | $fa-var-chevron-up: "\f077";
129 | $fa-var-child: "\f1ae";
130 | $fa-var-circle: "\f111";
131 | $fa-var-circle-o: "\f10c";
132 | $fa-var-circle-o-notch: "\f1ce";
133 | $fa-var-circle-thin: "\f1db";
134 | $fa-var-clipboard: "\f0ea";
135 | $fa-var-clock-o: "\f017";
136 | $fa-var-close: "\f00d";
137 | $fa-var-cloud: "\f0c2";
138 | $fa-var-cloud-download: "\f0ed";
139 | $fa-var-cloud-upload: "\f0ee";
140 | $fa-var-cny: "\f157";
141 | $fa-var-code: "\f121";
142 | $fa-var-code-fork: "\f126";
143 | $fa-var-codepen: "\f1cb";
144 | $fa-var-coffee: "\f0f4";
145 | $fa-var-cog: "\f013";
146 | $fa-var-cogs: "\f085";
147 | $fa-var-columns: "\f0db";
148 | $fa-var-comment: "\f075";
149 | $fa-var-comment-o: "\f0e5";
150 | $fa-var-comments: "\f086";
151 | $fa-var-comments-o: "\f0e6";
152 | $fa-var-compass: "\f14e";
153 | $fa-var-compress: "\f066";
154 | $fa-var-connectdevelop: "\f20e";
155 | $fa-var-copy: "\f0c5";
156 | $fa-var-copyright: "\f1f9";
157 | $fa-var-credit-card: "\f09d";
158 | $fa-var-crop: "\f125";
159 | $fa-var-crosshairs: "\f05b";
160 | $fa-var-css3: "\f13c";
161 | $fa-var-cube: "\f1b2";
162 | $fa-var-cubes: "\f1b3";
163 | $fa-var-cut: "\f0c4";
164 | $fa-var-cutlery: "\f0f5";
165 | $fa-var-dashboard: "\f0e4";
166 | $fa-var-dashcube: "\f210";
167 | $fa-var-database: "\f1c0";
168 | $fa-var-dedent: "\f03b";
169 | $fa-var-delicious: "\f1a5";
170 | $fa-var-desktop: "\f108";
171 | $fa-var-deviantart: "\f1bd";
172 | $fa-var-diamond: "\f219";
173 | $fa-var-digg: "\f1a6";
174 | $fa-var-dollar: "\f155";
175 | $fa-var-dot-circle-o: "\f192";
176 | $fa-var-download: "\f019";
177 | $fa-var-dribbble: "\f17d";
178 | $fa-var-dropbox: "\f16b";
179 | $fa-var-drupal: "\f1a9";
180 | $fa-var-edit: "\f044";
181 | $fa-var-eject: "\f052";
182 | $fa-var-ellipsis-h: "\f141";
183 | $fa-var-ellipsis-v: "\f142";
184 | $fa-var-empire: "\f1d1";
185 | $fa-var-envelope: "\f0e0";
186 | $fa-var-envelope-o: "\f003";
187 | $fa-var-envelope-square: "\f199";
188 | $fa-var-eraser: "\f12d";
189 | $fa-var-eur: "\f153";
190 | $fa-var-euro: "\f153";
191 | $fa-var-exchange: "\f0ec";
192 | $fa-var-exclamation: "\f12a";
193 | $fa-var-exclamation-circle: "\f06a";
194 | $fa-var-exclamation-triangle: "\f071";
195 | $fa-var-expand: "\f065";
196 | $fa-var-external-link: "\f08e";
197 | $fa-var-external-link-square: "\f14c";
198 | $fa-var-eye: "\f06e";
199 | $fa-var-eye-slash: "\f070";
200 | $fa-var-eyedropper: "\f1fb";
201 | $fa-var-facebook: "\f09a";
202 | $fa-var-facebook-f: "\f09a";
203 | $fa-var-facebook-official: "\f230";
204 | $fa-var-facebook-square: "\f082";
205 | $fa-var-fast-backward: "\f049";
206 | $fa-var-fast-forward: "\f050";
207 | $fa-var-fax: "\f1ac";
208 | $fa-var-female: "\f182";
209 | $fa-var-fighter-jet: "\f0fb";
210 | $fa-var-file: "\f15b";
211 | $fa-var-file-archive-o: "\f1c6";
212 | $fa-var-file-audio-o: "\f1c7";
213 | $fa-var-file-code-o: "\f1c9";
214 | $fa-var-file-excel-o: "\f1c3";
215 | $fa-var-file-image-o: "\f1c5";
216 | $fa-var-file-movie-o: "\f1c8";
217 | $fa-var-file-o: "\f016";
218 | $fa-var-file-pdf-o: "\f1c1";
219 | $fa-var-file-photo-o: "\f1c5";
220 | $fa-var-file-picture-o: "\f1c5";
221 | $fa-var-file-powerpoint-o: "\f1c4";
222 | $fa-var-file-sound-o: "\f1c7";
223 | $fa-var-file-text: "\f15c";
224 | $fa-var-file-text-o: "\f0f6";
225 | $fa-var-file-video-o: "\f1c8";
226 | $fa-var-file-word-o: "\f1c2";
227 | $fa-var-file-zip-o: "\f1c6";
228 | $fa-var-files-o: "\f0c5";
229 | $fa-var-film: "\f008";
230 | $fa-var-filter: "\f0b0";
231 | $fa-var-fire: "\f06d";
232 | $fa-var-fire-extinguisher: "\f134";
233 | $fa-var-flag: "\f024";
234 | $fa-var-flag-checkered: "\f11e";
235 | $fa-var-flag-o: "\f11d";
236 | $fa-var-flash: "\f0e7";
237 | $fa-var-flask: "\f0c3";
238 | $fa-var-flickr: "\f16e";
239 | $fa-var-floppy-o: "\f0c7";
240 | $fa-var-folder: "\f07b";
241 | $fa-var-folder-o: "\f114";
242 | $fa-var-folder-open: "\f07c";
243 | $fa-var-folder-open-o: "\f115";
244 | $fa-var-font: "\f031";
245 | $fa-var-forumbee: "\f211";
246 | $fa-var-forward: "\f04e";
247 | $fa-var-foursquare: "\f180";
248 | $fa-var-frown-o: "\f119";
249 | $fa-var-futbol-o: "\f1e3";
250 | $fa-var-gamepad: "\f11b";
251 | $fa-var-gavel: "\f0e3";
252 | $fa-var-gbp: "\f154";
253 | $fa-var-ge: "\f1d1";
254 | $fa-var-gear: "\f013";
255 | $fa-var-gears: "\f085";
256 | $fa-var-genderless: "\f1db";
257 | $fa-var-gift: "\f06b";
258 | $fa-var-git: "\f1d3";
259 | $fa-var-git-square: "\f1d2";
260 | $fa-var-github: "\f09b";
261 | $fa-var-github-alt: "\f113";
262 | $fa-var-github-square: "\f092";
263 | $fa-var-gittip: "\f184";
264 | $fa-var-glass: "\f000";
265 | $fa-var-globe: "\f0ac";
266 | $fa-var-google: "\f1a0";
267 | $fa-var-google-plus: "\f0d5";
268 | $fa-var-google-plus-square: "\f0d4";
269 | $fa-var-google-wallet: "\f1ee";
270 | $fa-var-graduation-cap: "\f19d";
271 | $fa-var-gratipay: "\f184";
272 | $fa-var-group: "\f0c0";
273 | $fa-var-h-square: "\f0fd";
274 | $fa-var-hacker-news: "\f1d4";
275 | $fa-var-hand-o-down: "\f0a7";
276 | $fa-var-hand-o-left: "\f0a5";
277 | $fa-var-hand-o-right: "\f0a4";
278 | $fa-var-hand-o-up: "\f0a6";
279 | $fa-var-hdd-o: "\f0a0";
280 | $fa-var-header: "\f1dc";
281 | $fa-var-headphones: "\f025";
282 | $fa-var-heart: "\f004";
283 | $fa-var-heart-o: "\f08a";
284 | $fa-var-heartbeat: "\f21e";
285 | $fa-var-history: "\f1da";
286 | $fa-var-home: "\f015";
287 | $fa-var-hospital-o: "\f0f8";
288 | $fa-var-hotel: "\f236";
289 | $fa-var-html5: "\f13b";
290 | $fa-var-ils: "\f20b";
291 | $fa-var-image: "\f03e";
292 | $fa-var-inbox: "\f01c";
293 | $fa-var-indent: "\f03c";
294 | $fa-var-info: "\f129";
295 | $fa-var-info-circle: "\f05a";
296 | $fa-var-inr: "\f156";
297 | $fa-var-instagram: "\f16d";
298 | $fa-var-institution: "\f19c";
299 | $fa-var-ioxhost: "\f208";
300 | $fa-var-italic: "\f033";
301 | $fa-var-joomla: "\f1aa";
302 | $fa-var-jpy: "\f157";
303 | $fa-var-jsfiddle: "\f1cc";
304 | $fa-var-key: "\f084";
305 | $fa-var-keyboard-o: "\f11c";
306 | $fa-var-krw: "\f159";
307 | $fa-var-language: "\f1ab";
308 | $fa-var-laptop: "\f109";
309 | $fa-var-lastfm: "\f202";
310 | $fa-var-lastfm-square: "\f203";
311 | $fa-var-leaf: "\f06c";
312 | $fa-var-leanpub: "\f212";
313 | $fa-var-legal: "\f0e3";
314 | $fa-var-lemon-o: "\f094";
315 | $fa-var-level-down: "\f149";
316 | $fa-var-level-up: "\f148";
317 | $fa-var-life-bouy: "\f1cd";
318 | $fa-var-life-buoy: "\f1cd";
319 | $fa-var-life-ring: "\f1cd";
320 | $fa-var-life-saver: "\f1cd";
321 | $fa-var-lightbulb-o: "\f0eb";
322 | $fa-var-line-chart: "\f201";
323 | $fa-var-link: "\f0c1";
324 | $fa-var-linkedin: "\f0e1";
325 | $fa-var-linkedin-square: "\f08c";
326 | $fa-var-linux: "\f17c";
327 | $fa-var-list: "\f03a";
328 | $fa-var-list-alt: "\f022";
329 | $fa-var-list-ol: "\f0cb";
330 | $fa-var-list-ul: "\f0ca";
331 | $fa-var-location-arrow: "\f124";
332 | $fa-var-lock: "\f023";
333 | $fa-var-long-arrow-down: "\f175";
334 | $fa-var-long-arrow-left: "\f177";
335 | $fa-var-long-arrow-right: "\f178";
336 | $fa-var-long-arrow-up: "\f176";
337 | $fa-var-magic: "\f0d0";
338 | $fa-var-magnet: "\f076";
339 | $fa-var-mail-forward: "\f064";
340 | $fa-var-mail-reply: "\f112";
341 | $fa-var-mail-reply-all: "\f122";
342 | $fa-var-male: "\f183";
343 | $fa-var-map-marker: "\f041";
344 | $fa-var-mars: "\f222";
345 | $fa-var-mars-double: "\f227";
346 | $fa-var-mars-stroke: "\f229";
347 | $fa-var-mars-stroke-h: "\f22b";
348 | $fa-var-mars-stroke-v: "\f22a";
349 | $fa-var-maxcdn: "\f136";
350 | $fa-var-meanpath: "\f20c";
351 | $fa-var-medium: "\f23a";
352 | $fa-var-medkit: "\f0fa";
353 | $fa-var-meh-o: "\f11a";
354 | $fa-var-mercury: "\f223";
355 | $fa-var-microphone: "\f130";
356 | $fa-var-microphone-slash: "\f131";
357 | $fa-var-minus: "\f068";
358 | $fa-var-minus-circle: "\f056";
359 | $fa-var-minus-square: "\f146";
360 | $fa-var-minus-square-o: "\f147";
361 | $fa-var-mobile: "\f10b";
362 | $fa-var-mobile-phone: "\f10b";
363 | $fa-var-money: "\f0d6";
364 | $fa-var-moon-o: "\f186";
365 | $fa-var-mortar-board: "\f19d";
366 | $fa-var-motorcycle: "\f21c";
367 | $fa-var-music: "\f001";
368 | $fa-var-navicon: "\f0c9";
369 | $fa-var-neuter: "\f22c";
370 | $fa-var-newspaper-o: "\f1ea";
371 | $fa-var-openid: "\f19b";
372 | $fa-var-outdent: "\f03b";
373 | $fa-var-pagelines: "\f18c";
374 | $fa-var-paint-brush: "\f1fc";
375 | $fa-var-paper-plane: "\f1d8";
376 | $fa-var-paper-plane-o: "\f1d9";
377 | $fa-var-paperclip: "\f0c6";
378 | $fa-var-paragraph: "\f1dd";
379 | $fa-var-paste: "\f0ea";
380 | $fa-var-pause: "\f04c";
381 | $fa-var-paw: "\f1b0";
382 | $fa-var-paypal: "\f1ed";
383 | $fa-var-pencil: "\f040";
384 | $fa-var-pencil-square: "\f14b";
385 | $fa-var-pencil-square-o: "\f044";
386 | $fa-var-phone: "\f095";
387 | $fa-var-phone-square: "\f098";
388 | $fa-var-photo: "\f03e";
389 | $fa-var-picture-o: "\f03e";
390 | $fa-var-pie-chart: "\f200";
391 | $fa-var-pied-piper: "\f1a7";
392 | $fa-var-pied-piper-alt: "\f1a8";
393 | $fa-var-pinterest: "\f0d2";
394 | $fa-var-pinterest-p: "\f231";
395 | $fa-var-pinterest-square: "\f0d3";
396 | $fa-var-plane: "\f072";
397 | $fa-var-play: "\f04b";
398 | $fa-var-play-circle: "\f144";
399 | $fa-var-play-circle-o: "\f01d";
400 | $fa-var-plug: "\f1e6";
401 | $fa-var-plus: "\f067";
402 | $fa-var-plus-circle: "\f055";
403 | $fa-var-plus-square: "\f0fe";
404 | $fa-var-plus-square-o: "\f196";
405 | $fa-var-power-off: "\f011";
406 | $fa-var-print: "\f02f";
407 | $fa-var-puzzle-piece: "\f12e";
408 | $fa-var-qq: "\f1d6";
409 | $fa-var-qrcode: "\f029";
410 | $fa-var-question: "\f128";
411 | $fa-var-question-circle: "\f059";
412 | $fa-var-quote-left: "\f10d";
413 | $fa-var-quote-right: "\f10e";
414 | $fa-var-ra: "\f1d0";
415 | $fa-var-random: "\f074";
416 | $fa-var-rebel: "\f1d0";
417 | $fa-var-recycle: "\f1b8";
418 | $fa-var-reddit: "\f1a1";
419 | $fa-var-reddit-square: "\f1a2";
420 | $fa-var-refresh: "\f021";
421 | $fa-var-remove: "\f00d";
422 | $fa-var-renren: "\f18b";
423 | $fa-var-reorder: "\f0c9";
424 | $fa-var-repeat: "\f01e";
425 | $fa-var-reply: "\f112";
426 | $fa-var-reply-all: "\f122";
427 | $fa-var-retweet: "\f079";
428 | $fa-var-rmb: "\f157";
429 | $fa-var-road: "\f018";
430 | $fa-var-rocket: "\f135";
431 | $fa-var-rotate-left: "\f0e2";
432 | $fa-var-rotate-right: "\f01e";
433 | $fa-var-rouble: "\f158";
434 | $fa-var-rss: "\f09e";
435 | $fa-var-rss-square: "\f143";
436 | $fa-var-rub: "\f158";
437 | $fa-var-ruble: "\f158";
438 | $fa-var-rupee: "\f156";
439 | $fa-var-save: "\f0c7";
440 | $fa-var-scissors: "\f0c4";
441 | $fa-var-search: "\f002";
442 | $fa-var-search-minus: "\f010";
443 | $fa-var-search-plus: "\f00e";
444 | $fa-var-sellsy: "\f213";
445 | $fa-var-send: "\f1d8";
446 | $fa-var-send-o: "\f1d9";
447 | $fa-var-server: "\f233";
448 | $fa-var-share: "\f064";
449 | $fa-var-share-alt: "\f1e0";
450 | $fa-var-share-alt-square: "\f1e1";
451 | $fa-var-share-square: "\f14d";
452 | $fa-var-share-square-o: "\f045";
453 | $fa-var-shekel: "\f20b";
454 | $fa-var-sheqel: "\f20b";
455 | $fa-var-shield: "\f132";
456 | $fa-var-ship: "\f21a";
457 | $fa-var-shirtsinbulk: "\f214";
458 | $fa-var-shopping-cart: "\f07a";
459 | $fa-var-sign-in: "\f090";
460 | $fa-var-sign-out: "\f08b";
461 | $fa-var-signal: "\f012";
462 | $fa-var-simplybuilt: "\f215";
463 | $fa-var-sitemap: "\f0e8";
464 | $fa-var-skyatlas: "\f216";
465 | $fa-var-skype: "\f17e";
466 | $fa-var-slack: "\f198";
467 | $fa-var-sliders: "\f1de";
468 | $fa-var-slideshare: "\f1e7";
469 | $fa-var-smile-o: "\f118";
470 | $fa-var-soccer-ball-o: "\f1e3";
471 | $fa-var-sort: "\f0dc";
472 | $fa-var-sort-alpha-asc: "\f15d";
473 | $fa-var-sort-alpha-desc: "\f15e";
474 | $fa-var-sort-amount-asc: "\f160";
475 | $fa-var-sort-amount-desc: "\f161";
476 | $fa-var-sort-asc: "\f0de";
477 | $fa-var-sort-desc: "\f0dd";
478 | $fa-var-sort-down: "\f0dd";
479 | $fa-var-sort-numeric-asc: "\f162";
480 | $fa-var-sort-numeric-desc: "\f163";
481 | $fa-var-sort-up: "\f0de";
482 | $fa-var-soundcloud: "\f1be";
483 | $fa-var-space-shuttle: "\f197";
484 | $fa-var-spinner: "\f110";
485 | $fa-var-spoon: "\f1b1";
486 | $fa-var-spotify: "\f1bc";
487 | $fa-var-square: "\f0c8";
488 | $fa-var-square-o: "\f096";
489 | $fa-var-stack-exchange: "\f18d";
490 | $fa-var-stack-overflow: "\f16c";
491 | $fa-var-star: "\f005";
492 | $fa-var-star-half: "\f089";
493 | $fa-var-star-half-empty: "\f123";
494 | $fa-var-star-half-full: "\f123";
495 | $fa-var-star-half-o: "\f123";
496 | $fa-var-star-o: "\f006";
497 | $fa-var-steam: "\f1b6";
498 | $fa-var-steam-square: "\f1b7";
499 | $fa-var-step-backward: "\f048";
500 | $fa-var-step-forward: "\f051";
501 | $fa-var-stethoscope: "\f0f1";
502 | $fa-var-stop: "\f04d";
503 | $fa-var-street-view: "\f21d";
504 | $fa-var-strikethrough: "\f0cc";
505 | $fa-var-stumbleupon: "\f1a4";
506 | $fa-var-stumbleupon-circle: "\f1a3";
507 | $fa-var-subscript: "\f12c";
508 | $fa-var-subway: "\f239";
509 | $fa-var-suitcase: "\f0f2";
510 | $fa-var-sun-o: "\f185";
511 | $fa-var-superscript: "\f12b";
512 | $fa-var-support: "\f1cd";
513 | $fa-var-table: "\f0ce";
514 | $fa-var-tablet: "\f10a";
515 | $fa-var-tachometer: "\f0e4";
516 | $fa-var-tag: "\f02b";
517 | $fa-var-tags: "\f02c";
518 | $fa-var-tasks: "\f0ae";
519 | $fa-var-taxi: "\f1ba";
520 | $fa-var-tencent-weibo: "\f1d5";
521 | $fa-var-terminal: "\f120";
522 | $fa-var-text-height: "\f034";
523 | $fa-var-text-width: "\f035";
524 | $fa-var-th: "\f00a";
525 | $fa-var-th-large: "\f009";
526 | $fa-var-th-list: "\f00b";
527 | $fa-var-thumb-tack: "\f08d";
528 | $fa-var-thumbs-down: "\f165";
529 | $fa-var-thumbs-o-down: "\f088";
530 | $fa-var-thumbs-o-up: "\f087";
531 | $fa-var-thumbs-up: "\f164";
532 | $fa-var-ticket: "\f145";
533 | $fa-var-times: "\f00d";
534 | $fa-var-times-circle: "\f057";
535 | $fa-var-times-circle-o: "\f05c";
536 | $fa-var-tint: "\f043";
537 | $fa-var-toggle-down: "\f150";
538 | $fa-var-toggle-left: "\f191";
539 | $fa-var-toggle-off: "\f204";
540 | $fa-var-toggle-on: "\f205";
541 | $fa-var-toggle-right: "\f152";
542 | $fa-var-toggle-up: "\f151";
543 | $fa-var-train: "\f238";
544 | $fa-var-transgender: "\f224";
545 | $fa-var-transgender-alt: "\f225";
546 | $fa-var-trash: "\f1f8";
547 | $fa-var-trash-o: "\f014";
548 | $fa-var-tree: "\f1bb";
549 | $fa-var-trello: "\f181";
550 | $fa-var-trophy: "\f091";
551 | $fa-var-truck: "\f0d1";
552 | $fa-var-try: "\f195";
553 | $fa-var-tty: "\f1e4";
554 | $fa-var-tumblr: "\f173";
555 | $fa-var-tumblr-square: "\f174";
556 | $fa-var-turkish-lira: "\f195";
557 | $fa-var-twitch: "\f1e8";
558 | $fa-var-twitter: "\f099";
559 | $fa-var-twitter-square: "\f081";
560 | $fa-var-umbrella: "\f0e9";
561 | $fa-var-underline: "\f0cd";
562 | $fa-var-undo: "\f0e2";
563 | $fa-var-university: "\f19c";
564 | $fa-var-unlink: "\f127";
565 | $fa-var-unlock: "\f09c";
566 | $fa-var-unlock-alt: "\f13e";
567 | $fa-var-unsorted: "\f0dc";
568 | $fa-var-upload: "\f093";
569 | $fa-var-usd: "\f155";
570 | $fa-var-user: "\f007";
571 | $fa-var-user-md: "\f0f0";
572 | $fa-var-user-plus: "\f234";
573 | $fa-var-user-secret: "\f21b";
574 | $fa-var-user-times: "\f235";
575 | $fa-var-users: "\f0c0";
576 | $fa-var-venus: "\f221";
577 | $fa-var-venus-double: "\f226";
578 | $fa-var-venus-mars: "\f228";
579 | $fa-var-viacoin: "\f237";
580 | $fa-var-video-camera: "\f03d";
581 | $fa-var-vimeo-square: "\f194";
582 | $fa-var-vine: "\f1ca";
583 | $fa-var-vk: "\f189";
584 | $fa-var-volume-down: "\f027";
585 | $fa-var-volume-off: "\f026";
586 | $fa-var-volume-up: "\f028";
587 | $fa-var-warning: "\f071";
588 | $fa-var-wechat: "\f1d7";
589 | $fa-var-weibo: "\f18a";
590 | $fa-var-weixin: "\f1d7";
591 | $fa-var-whatsapp: "\f232";
592 | $fa-var-wheelchair: "\f193";
593 | $fa-var-wifi: "\f1eb";
594 | $fa-var-windows: "\f17a";
595 | $fa-var-won: "\f159";
596 | $fa-var-wordpress: "\f19a";
597 | $fa-var-wrench: "\f0ad";
598 | $fa-var-xing: "\f168";
599 | $fa-var-xing-square: "\f169";
600 | $fa-var-yahoo: "\f19e";
601 | $fa-var-yelp: "\f1e9";
602 | $fa-var-yen: "\f157";
603 | $fa-var-youtube: "\f167";
604 | $fa-var-youtube-play: "\f16a";
605 | $fa-var-youtube-square: "\f166";
606 |
607 |
--------------------------------------------------------------------------------
/youtubeadl/static/vendor/font-awesome/scss/font-awesome.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "variables";
7 | @import "mixins";
8 | @import "path";
9 | @import "core";
10 | @import "larger";
11 | @import "fixed-width";
12 | @import "list";
13 | @import "bordered-pulled";
14 | @import "animated";
15 | @import "rotated-flipped";
16 | @import "stacked";
17 | @import "icons";
18 |
--------------------------------------------------------------------------------
/youtubeadl/templates/403.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block main %}
4 | Sorry, you're not allowed to view that page.
5 | {% endblock %}
--------------------------------------------------------------------------------
/youtubeadl/templates/404.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block main %}
4 | Sorry, that page does not exist.
5 | {% endblock %}
--------------------------------------------------------------------------------
/youtubeadl/templates/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Server Error
6 |
28 |
29 |
30 |
31 |
Server Error :(
32 |
Sorry, but the server encountered an error while processing your request.
33 |
34 |
35 |
--------------------------------------------------------------------------------
/youtubeadl/templates/base.html:
--------------------------------------------------------------------------------
1 | {% load staticfiles %}
2 |
3 |
4 | {% load compress %}
5 |
6 |
7 |
8 |
9 | {% block title %}Convert YouTube videos to MP3 audio{% endblock %} | YouTube Audio Downloader
10 |
11 |
12 |
13 | {% compress css %}
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 | {% block extracss %}{% endblock %}
24 | {% endcompress %}
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
36 |
37 |
38 |
39 | {% block main %}{% endblock %}
40 |
41 |
42 | {% compress js %}
43 |
44 |
45 |
46 |
47 | {% block extrajs %}{% endblock %}
48 | {% endcompress %}
49 |
50 |
51 |
52 |
55 |
56 |
57 |
66 |
67 |
--------------------------------------------------------------------------------
/youtubeadl/templates/home.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% load static %}
4 |
5 | {% block main %}
6 |
7 |
8 | {% if ad_top %}
9 |
10 | {{ ad_top.code|safe }}
11 |
12 | {% endif %}
13 |
14 |
35 |
36 |
39 |
40 |
41 | {% if ad_bottom %}
42 |
43 | {{ ad_bottom.code|safe }}
44 |
45 | {% endif %}
46 |
47 | {% endblock %}
48 |
49 | {% block extrajs %}
50 |
51 | {% endblock %}
--------------------------------------------------------------------------------
/youtubeadl/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import include, url
2 | from django.contrib import admin
3 |
4 | from youtubeadl.apps.downloader.views import DownloadFormView
5 |
6 |
7 | admin.site.site_header = 'YouTube ADL Admin'
8 | admin.site.site_title = 'YouTube ADL Admin'
9 |
10 | urlpatterns = [
11 | url(r'^$', DownloadFormView.as_view(), name='home'),
12 | url(r'^downloader/', include('youtubeadl.apps.downloader.urls')),
13 |
14 | # Grappelli needs to be defined before the admin.
15 | url(r'^grappelli/', include('grappelli.urls')),
16 |
17 | url(r'^admin/', include(admin.site.urls)),
18 | ]
19 |
--------------------------------------------------------------------------------
/youtubeadl/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for youtubeadl project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE',
15 | 'youtubeadl.settings.local')
16 |
17 | application = get_wsgi_application()
18 |
--------------------------------------------------------------------------------