mirror of
https://github.com/ytdl-org/youtube-dl
synced 2025-10-21 15:48:36 +09:00
Compare commits
97 Commits
2013.06.34
...
2013.07.05
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fa343954d4 | ||
![]() |
2491f5898e | ||
![]() |
b27c856fbc | ||
![]() |
9941ceb331 | ||
![]() |
c536d38059 | ||
![]() |
8de64cac98 | ||
![]() |
6d6d286539 | ||
![]() |
5d2eac9eba | ||
![]() |
9826925a20 | ||
![]() |
24a267b562 | ||
![]() |
d4da3d6116 | ||
![]() |
d5a62e4f5f | ||
![]() |
9a82b2389f | ||
![]() |
8dba13f7e8 | ||
![]() |
deacef651f | ||
![]() |
2e1b3afeca | ||
![]() |
652e776893 | ||
![]() |
d055fe4cb0 | ||
![]() |
131842bb0b | ||
![]() |
59fc531f78 | ||
![]() |
5c44c15438 | ||
![]() |
62067cb9b8 | ||
![]() |
0f81866329 | ||
![]() |
2db67bc0f4 | ||
![]() |
7dba9cd039 | ||
![]() |
75dff0eef7 | ||
![]() |
d828f3a550 | ||
![]() |
bcd6e4bd07 | ||
![]() |
53936f3d57 | ||
![]() |
0beb3add18 | ||
![]() |
f9bd64c098 | ||
![]() |
d7f44b5bdb | ||
![]() |
48bfb5f238 | ||
![]() |
97ebe8dcaf | ||
![]() |
d4409747ba | ||
![]() |
37b6a6617f | ||
![]() |
ca1c9cfe11 | ||
![]() |
adeb4d7469 | ||
![]() |
50587ee8ec | ||
![]() |
8244288dfe | ||
![]() |
6ffe72835a | ||
![]() |
8ba5e990a5 | ||
![]() |
9afb1afcc6 | ||
![]() |
0e21093a8f | ||
![]() |
9c5cd0948f | ||
![]() |
1083705fe8 | ||
![]() |
f3d294617f | ||
![]() |
de33a30858 | ||
![]() |
887a227953 | ||
![]() |
705f6f35bc | ||
![]() |
e648b22dbd | ||
![]() |
257a2501fa | ||
![]() |
99afb3ddd4 | ||
![]() |
a3c776203f | ||
![]() |
53f350c165 | ||
![]() |
f46d31f948 | ||
![]() |
bf64ff72db | ||
![]() |
bc2884afc1 | ||
![]() |
023fa8c440 | ||
![]() |
427023a1e6 | ||
![]() |
a924876fed | ||
![]() |
3f223f7b2e | ||
![]() |
fc2c063e1e | ||
![]() |
20db33e299 | ||
![]() |
c0109aa497 | ||
![]() |
ba7a1de04d | ||
![]() |
4269e78a80 | ||
![]() |
6f5ac90cf3 | ||
![]() |
de282fc217 | ||
![]() |
ddbd903576 | ||
![]() |
0c56a3f773 | ||
![]() |
9d069c4778 | ||
![]() |
0d843f796b | ||
![]() |
67f51b3d8c | ||
![]() |
5c5de1c79a | ||
![]() |
0821771466 | ||
![]() |
83f6f68e79 | ||
![]() |
27473d18da | ||
![]() |
0c6c096c20 | ||
![]() |
52c8ade4ad | ||
![]() |
0e853ca4c4 | ||
![]() |
41beccbab0 | ||
![]() |
2eb88d953f | ||
![]() |
1f0483b4b1 | ||
![]() |
6b47c7f24e | ||
![]() |
d798e1c7a9 | ||
![]() |
3a8736bd74 | ||
![]() |
c8c5163618 | ||
![]() |
500f3d2432 | ||
![]() |
ed4a915e08 | ||
![]() |
b8f7b1579a | ||
![]() |
ed54491c60 | ||
![]() |
e4decf2750 | ||
![]() |
c90f13d106 | ||
![]() |
62008f69c1 | ||
![]() |
8b50fed04b | ||
![]() |
5b66de8859 |
23
README.md
23
README.md
@@ -18,19 +18,13 @@ which means you can modify it, redistribute it or use it however you like.
|
|||||||
--version print program version and exit
|
--version print program version and exit
|
||||||
-U, --update update this program to latest version
|
-U, --update update this program to latest version
|
||||||
-i, --ignore-errors continue on download errors
|
-i, --ignore-errors continue on download errors
|
||||||
-r, --rate-limit LIMIT maximum download rate (e.g. 50k or 44.6m)
|
|
||||||
-R, --retries RETRIES number of retries (default is 10)
|
|
||||||
--buffer-size SIZE size of download buffer (e.g. 1024 or 16k)
|
|
||||||
(default is 1024)
|
|
||||||
--no-resize-buffer do not automatically adjust the buffer size. By
|
|
||||||
default, the buffer size is automatically resized
|
|
||||||
from an initial value of SIZE.
|
|
||||||
--dump-user-agent display the current browser identification
|
--dump-user-agent display the current browser identification
|
||||||
--user-agent UA specify a custom user agent
|
--user-agent UA specify a custom user agent
|
||||||
--referer REF specify a custom referer, use if the video access
|
--referer REF specify a custom referer, use if the video access
|
||||||
is restricted to one domain
|
is restricted to one domain
|
||||||
--list-extractors List all supported extractors and the URLs they
|
--list-extractors List all supported extractors and the URLs they
|
||||||
would handle
|
would handle
|
||||||
|
--extractor-descriptions Output descriptions of all supported extractors
|
||||||
--proxy URL Use the specified HTTP/HTTPS proxy
|
--proxy URL Use the specified HTTP/HTTPS proxy
|
||||||
--no-check-certificate Suppress HTTPS certificate validation.
|
--no-check-certificate Suppress HTTPS certificate validation.
|
||||||
|
|
||||||
@@ -50,6 +44,15 @@ which means you can modify it, redistribute it or use it however you like.
|
|||||||
--datebefore DATE download only videos uploaded before this date
|
--datebefore DATE download only videos uploaded before this date
|
||||||
--dateafter DATE download only videos uploaded after this date
|
--dateafter DATE download only videos uploaded after this date
|
||||||
|
|
||||||
|
## Download Options:
|
||||||
|
-r, --rate-limit LIMIT maximum download rate (e.g. 50k or 44.6m)
|
||||||
|
-R, --retries RETRIES number of retries (default is 10)
|
||||||
|
--buffer-size SIZE size of download buffer (e.g. 1024 or 16k)
|
||||||
|
(default is 1024)
|
||||||
|
--no-resize-buffer do not automatically adjust the buffer size. By
|
||||||
|
default, the buffer size is automatically resized
|
||||||
|
from an initial value of SIZE.
|
||||||
|
|
||||||
## Filesystem Options:
|
## Filesystem Options:
|
||||||
-t, --title use title in file name (default)
|
-t, --title use title in file name (default)
|
||||||
--id use only video ID in file name
|
--id use only video ID in file name
|
||||||
@@ -168,7 +171,7 @@ The `-o` option allows users to indicate a template for the output file names. T
|
|||||||
- `playlist`: The name or the id of the playlist that contains the video.
|
- `playlist`: The name or the id of the playlist that contains the video.
|
||||||
- `playlist_index`: The index of the video in the playlist, a five-digit number.
|
- `playlist_index`: The index of the video in the playlist, a five-digit number.
|
||||||
|
|
||||||
The current default template is `%(id)s.%(ext)s`, but that will be switchted to `%(title)s-%(id)s.%(ext)s` (which can be requested with `-t` at the moment).
|
The current default template is `%(title)s-%(id)s.%(ext)s`.
|
||||||
|
|
||||||
In some cases, you don't want special characters such as 中, spaces, or &, such as when transferring the downloaded filename to a Windows system or the filename through an 8bit-unsafe channel. In these cases, add the `--restrict-filenames` flag to get a shorter title:
|
In some cases, you don't want special characters such as 中, spaces, or &, such as when transferring the downloaded filename to a Windows system or the filename through an 8bit-unsafe channel. In these cases, add the `--restrict-filenames` flag to get a shorter title:
|
||||||
|
|
||||||
@@ -194,11 +197,11 @@ Examples:
|
|||||||
|
|
||||||
### Can you please put the -b option back?
|
### Can you please put the -b option back?
|
||||||
|
|
||||||
Most people asking this question are not aware that youtube-dl now defaults to downloading the highest available quality as reported by YouTube, which will be 1080p or 720p in some cases, so you no longer need the -b option. For some specific videos, maybe YouTube does not report them to be available in a specific high quality format you''re interested in. In that case, simply request it with the -f option and youtube-dl will try to download it.
|
Most people asking this question are not aware that youtube-dl now defaults to downloading the highest available quality as reported by YouTube, which will be 1080p or 720p in some cases, so you no longer need the `-b` option. For some specific videos, maybe YouTube does not report them to be available in a specific high quality format you're interested in. In that case, simply request it with the `-f` option and youtube-dl will try to download it.
|
||||||
|
|
||||||
### I get HTTP error 402 when trying to download a video. What's this?
|
### I get HTTP error 402 when trying to download a video. What's this?
|
||||||
|
|
||||||
Apparently YouTube requires you to pass a CAPTCHA test if you download too much. We''re [considering to provide a way to let you solve the CAPTCHA](https://github.com/rg3/youtube-dl/issues/154), but at the moment, your best course of action is pointing a webbrowser to the youtube URL, solving the CAPTCHA, and restart youtube-dl.
|
Apparently YouTube requires you to pass a CAPTCHA test if you download too much. We're [considering to provide a way to let you solve the CAPTCHA](https://github.com/rg3/youtube-dl/issues/154), but at the moment, your best course of action is pointing a webbrowser to the youtube URL, solving the CAPTCHA, and restart youtube-dl.
|
||||||
|
|
||||||
### I have downloaded a video but how can I play it?
|
### I have downloaded a video but how can I play it?
|
||||||
|
|
||||||
|
@@ -5,18 +5,25 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
tests = [
|
tests = [
|
||||||
|
# 88
|
||||||
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[]}|:;?/>.<",
|
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[]}|:;?/>.<",
|
||||||
"J:|}][{=+-_)(*&;%$#@>MNBVCXZASDFGH^KLPOIUYTREWQ0987654321mnbvcxzasdfghrklpoiuytej"),
|
"J:|}][{=+-_)(*&;%$#@>MNBVCXZASDFGH^KLPOIUYTREWQ0987654321mnbvcxzasdfghrklpoiuytej"),
|
||||||
|
# 87
|
||||||
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$^&*()_-+={[]}|:;?/>.<",
|
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$^&*()_-+={[]}|:;?/>.<",
|
||||||
"!?;:|}][{=+-_)(*&^$#@/MNBVCXZASqFGHJKLPOIUYTREWQ0987654321mnbvcxzasdfghjklpoiuytr"),
|
"!?;:|}][{=+-_)(*&^$#@/MNBVCXZASqFGHJKLPOIUYTREWQ0987654321mnbvcxzasdfghjklpoiuytr"),
|
||||||
|
# 86 - vfl_ymO4Z 2013/06/27
|
||||||
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[|};?/>.<",
|
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[|};?/>.<",
|
||||||
"ertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!/#$%^&*()_-+={[|};?@"),
|
"ertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!/#$%^&*()_-+={[|};?@"),
|
||||||
|
# 85
|
||||||
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[};?/>.<",
|
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[};?/>.<",
|
||||||
"{>/?;}[.=+-_)(*&^%$#@!MqBVCXZASDFwHJKLPOIUYTREWQ0987654321mnbvcxzasdfghjklpoiuytr"),
|
"{>/?;}[.=+-_)(*&^%$#@!MqBVCXZASDFwHJKLPOIUYTREWQ0987654321mnbvcxzasdfghjklpoiuytr"),
|
||||||
|
# 84
|
||||||
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[};?>.<",
|
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[};?>.<",
|
||||||
"<.>?;}[{=+-_)(*&^%$#@!MNBVCXZASDFGHJKLPOIUYTREWe098765432rmnbvcxzasdfghjklpoiuyt1"),
|
"<.>?;}[{=+-_)(*&^%$#@!MNBVCXZASDFGHJKLPOIUYTREWe098765432rmnbvcxzasdfghjklpoiuyt1"),
|
||||||
|
# 83
|
||||||
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!#$%^&*()_+={[};?/>.<",
|
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!#$%^&*()_+={[};?/>.<",
|
||||||
"D.>/?;}[{=+_)(*&^%$#!MNBVCXeAS<FGHJKLPOIUYTREWZ0987654321mnbvcxzasdfghjklpoiuytrQ"),
|
"D.>/?;}[{=+_)(*&^%$#!MNBVCXeAS<FGHJKLPOIUYTREWZ0987654321mnbvcxzasdfghjklpoiuytrQ"),
|
||||||
|
# 82
|
||||||
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKHGFDSAZXCVBNM!@#$%^&*(-+={[};?/>.<",
|
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKHGFDSAZXCVBNM!@#$%^&*(-+={[};?/>.<",
|
||||||
"Q>/?;}[{=+-(*<^%$#@!MNBVCXZASDFGHKLPOIUY8REWT0q&7654321mnbvcxzasdfghjklpoiuytrew9"),
|
"Q>/?;}[{=+-(*<^%$#@!MNBVCXZASDFGHKLPOIUY8REWT0q&7654321mnbvcxzasdfghjklpoiuytrew9"),
|
||||||
]
|
]
|
||||||
|
17
setup.py
17
setup.py
@@ -12,8 +12,9 @@ except ImportError:
|
|||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# This will create an exe that needs Microsoft Visual C++ 2008
|
||||||
|
# Redistributable Package
|
||||||
import py2exe
|
import py2exe
|
||||||
"""This will create an exe that needs Microsoft Visual C++ 2008 Redistributable Package"""
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
if len(sys.argv) >= 2 and sys.argv[1] == 'py2exe':
|
if len(sys.argv) >= 2 and sys.argv[1] == 'py2exe':
|
||||||
print("Cannot import py2exe", file=sys.stderr)
|
print("Cannot import py2exe", file=sys.stderr)
|
||||||
@@ -26,10 +27,12 @@ py2exe_options = {
|
|||||||
"dist_dir": '.',
|
"dist_dir": '.',
|
||||||
"dll_excludes": ['w9xpopen.exe'],
|
"dll_excludes": ['w9xpopen.exe'],
|
||||||
}
|
}
|
||||||
|
|
||||||
py2exe_console = [{
|
py2exe_console = [{
|
||||||
"script": "./youtube_dl/__main__.py",
|
"script": "./youtube_dl/__main__.py",
|
||||||
"dest_base": "youtube-dl",
|
"dest_base": "youtube-dl",
|
||||||
}]
|
}]
|
||||||
|
|
||||||
py2exe_params = {
|
py2exe_params = {
|
||||||
'console': py2exe_console,
|
'console': py2exe_console,
|
||||||
'options': {"py2exe": py2exe_options},
|
'options': {"py2exe": py2exe_options},
|
||||||
@@ -41,19 +44,23 @@ if len(sys.argv) >= 2 and sys.argv[1] == 'py2exe':
|
|||||||
else:
|
else:
|
||||||
params = {
|
params = {
|
||||||
'scripts': ['bin/youtube-dl'],
|
'scripts': ['bin/youtube-dl'],
|
||||||
'data_files': [('etc/bash_completion.d', ['youtube-dl.bash-completion']), # Installing system-wide would require sudo...
|
'data_files': [ # Installing system-wide would require sudo...
|
||||||
|
('etc/bash_completion.d', ['youtube-dl.bash-completion']),
|
||||||
('share/doc/youtube_dl', ['README.txt']),
|
('share/doc/youtube_dl', ['README.txt']),
|
||||||
('share/man/man1/', ['youtube-dl.1'])]
|
('share/man/man1/', ['youtube-dl.1'])
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get the version from youtube_dl/version.py without importing the package
|
# Get the version from youtube_dl/version.py without importing the package
|
||||||
exec(compile(open('youtube_dl/version.py').read(), 'youtube_dl/version.py', 'exec'))
|
exec(compile(open('youtube_dl/version.py').read(),
|
||||||
|
'youtube_dl/version.py', 'exec'))
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='youtube_dl',
|
name='youtube_dl',
|
||||||
version=__version__,
|
version=__version__,
|
||||||
description='YouTube video downloader',
|
description='YouTube video downloader',
|
||||||
long_description = 'Small command-line program to download videos from YouTube.com and other video sites.',
|
long_description='Small command-line program to download videos from'
|
||||||
|
' YouTube.com and other video sites.',
|
||||||
url='https://github.com/rg3/youtube-dl',
|
url='https://github.com/rg3/youtube-dl',
|
||||||
author='Ricardo Garcia',
|
author='Ricardo Garcia',
|
||||||
maintainer='Philipp Hagemeister',
|
maintainer='Philipp Hagemeister',
|
||||||
|
@@ -2,6 +2,7 @@ import io
|
|||||||
import json
|
import json
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
|
import youtube_dl.extractor
|
||||||
from youtube_dl import YoutubeDL, YoutubeDLHandler
|
from youtube_dl import YoutubeDL, YoutubeDLHandler
|
||||||
from youtube_dl.utils import (
|
from youtube_dl.utils import (
|
||||||
compat_cookiejar,
|
compat_cookiejar,
|
||||||
@@ -31,3 +32,13 @@ class FakeYDL(YoutubeDL):
|
|||||||
raise Exception(s)
|
raise Exception(s)
|
||||||
def download(self, x):
|
def download(self, x):
|
||||||
self.result.append(x)
|
self.result.append(x)
|
||||||
|
|
||||||
|
def get_testcases():
|
||||||
|
for ie in youtube_dl.extractor.gen_extractors():
|
||||||
|
t = getattr(ie, '_TEST', None)
|
||||||
|
if t:
|
||||||
|
t['name'] = type(ie).__name__[:-len('IE')]
|
||||||
|
yield t
|
||||||
|
for t in getattr(ie, '_TESTS', []):
|
||||||
|
t['name'] = type(ie).__name__[:-len('IE')]
|
||||||
|
yield t
|
||||||
|
@@ -7,7 +7,8 @@ import unittest
|
|||||||
import os
|
import os
|
||||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
from youtube_dl.extractor import YoutubeIE, YoutubePlaylistIE, YoutubeChannelIE, JustinTVIE
|
from youtube_dl.extractor import YoutubeIE, YoutubePlaylistIE, YoutubeChannelIE, JustinTVIE, gen_extractors
|
||||||
|
from helper import get_testcases
|
||||||
|
|
||||||
class TestAllURLsMatching(unittest.TestCase):
|
class TestAllURLsMatching(unittest.TestCase):
|
||||||
def test_youtube_playlist_matching(self):
|
def test_youtube_playlist_matching(self):
|
||||||
@@ -50,5 +51,16 @@ class TestAllURLsMatching(unittest.TestCase):
|
|||||||
self.assertEqual(YoutubeIE()._extract_id('https://www.youtube.com/watch?&v=BaW_jenozKc'), 'BaW_jenozKc')
|
self.assertEqual(YoutubeIE()._extract_id('https://www.youtube.com/watch?&v=BaW_jenozKc'), 'BaW_jenozKc')
|
||||||
self.assertEqual(YoutubeIE()._extract_id('https://www.youtube.com/watch?feature=player_embedded&v=BaW_jenozKc'), 'BaW_jenozKc')
|
self.assertEqual(YoutubeIE()._extract_id('https://www.youtube.com/watch?feature=player_embedded&v=BaW_jenozKc'), 'BaW_jenozKc')
|
||||||
|
|
||||||
|
def test_no_duplicates(self):
|
||||||
|
ies = gen_extractors()
|
||||||
|
for tc in get_testcases():
|
||||||
|
url = tc['url']
|
||||||
|
for ie in ies:
|
||||||
|
if type(ie).__name__ in ['GenericIE', tc['name'] + 'IE']:
|
||||||
|
self.assertTrue(ie.suitable(url), '%s should match URL %r' % (type(ie).__name__, url))
|
||||||
|
else:
|
||||||
|
self.assertFalse(ie.suitable(url), '%s should not match URL %r' % (type(ie).__name__, url))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@@ -14,10 +14,8 @@ import binascii
|
|||||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
import youtube_dl.YoutubeDL
|
import youtube_dl.YoutubeDL
|
||||||
import youtube_dl.extractor
|
|
||||||
from youtube_dl.utils import *
|
from youtube_dl.utils import *
|
||||||
|
|
||||||
DEF_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tests.json')
|
|
||||||
PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "parameters.json")
|
PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "parameters.json")
|
||||||
|
|
||||||
RETRIES = 3
|
RETRIES = 3
|
||||||
@@ -56,8 +54,9 @@ def _file_md5(fn):
|
|||||||
with open(fn, 'rb') as f:
|
with open(fn, 'rb') as f:
|
||||||
return hashlib.md5(f.read()).hexdigest()
|
return hashlib.md5(f.read()).hexdigest()
|
||||||
|
|
||||||
with io.open(DEF_FILE, encoding='utf-8') as deff:
|
from helper import get_testcases
|
||||||
defs = json.load(deff)
|
defs = get_testcases()
|
||||||
|
|
||||||
with io.open(PARAMETERS_FILE, encoding='utf-8') as pf:
|
with io.open(PARAMETERS_FILE, encoding='utf-8') as pf:
|
||||||
parameters = json.load(pf)
|
parameters = json.load(pf)
|
||||||
|
|
||||||
@@ -73,22 +72,23 @@ def generator(test_case):
|
|||||||
|
|
||||||
def test_template(self):
|
def test_template(self):
|
||||||
ie = youtube_dl.extractor.get_info_extractor(test_case['name'])
|
ie = youtube_dl.extractor.get_info_extractor(test_case['name'])
|
||||||
|
def print_skipping(reason):
|
||||||
|
print('Skipping %s: %s' % (test_case['name'], reason))
|
||||||
if not ie._WORKING:
|
if not ie._WORKING:
|
||||||
print('Skipping: IE marked as not _WORKING')
|
print_skipping('IE marked as not _WORKING')
|
||||||
return
|
return
|
||||||
if 'playlist' not in test_case and not test_case['file']:
|
if 'playlist' not in test_case and not test_case['file']:
|
||||||
print('Skipping: No output file specified')
|
print_skipping('No output file specified')
|
||||||
return
|
return
|
||||||
if 'skip' in test_case:
|
if 'skip' in test_case:
|
||||||
print('Skipping: {0}'.format(test_case['skip']))
|
print_skipping(test_case['skip'])
|
||||||
return
|
return
|
||||||
|
|
||||||
params = self.parameters.copy()
|
params = self.parameters.copy()
|
||||||
params.update(test_case.get('params', {}))
|
params.update(test_case.get('params', {}))
|
||||||
|
|
||||||
ydl = YoutubeDL(params)
|
ydl = YoutubeDL(params)
|
||||||
for ie in youtube_dl.extractor.gen_extractors():
|
ydl.add_default_info_extractors()
|
||||||
ydl.add_info_extractor(ie)
|
|
||||||
finished_hook_called = set()
|
finished_hook_called = set()
|
||||||
def _hook(status):
|
def _hook(status):
|
||||||
if status['status'] == 'finished':
|
if status['status'] == 'finished':
|
||||||
@@ -155,9 +155,12 @@ def generator(test_case):
|
|||||||
### And add them to TestDownload
|
### And add them to TestDownload
|
||||||
for n, test_case in enumerate(defs):
|
for n, test_case in enumerate(defs):
|
||||||
test_method = generator(test_case)
|
test_method = generator(test_case)
|
||||||
test_method.__name__ = "test_{0}".format(test_case["name"])
|
tname = 'test_' + str(test_case['name'])
|
||||||
if getattr(TestDownload, test_method.__name__, False):
|
i = 1
|
||||||
test_method.__name__ = "test_{0}_{1}".format(test_case["name"], n)
|
while hasattr(TestDownload, tname):
|
||||||
|
tname = 'test_' + str(test_case['name']) + '_' + str(i)
|
||||||
|
i += 1
|
||||||
|
test_method.__name__ = tname
|
||||||
setattr(TestDownload, test_method.__name__, test_method)
|
setattr(TestDownload, test_method.__name__, test_method)
|
||||||
del test_method
|
del test_method
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
from youtube_dl.extractor import YoutubeUserIE, YoutubePlaylistIE, YoutubeIE, YoutubeChannelIE
|
from youtube_dl.extractor import YoutubeUserIE, YoutubePlaylistIE, YoutubeIE, YoutubeChannelIE, YoutubeShowIE
|
||||||
from youtube_dl.utils import *
|
from youtube_dl.utils import *
|
||||||
|
|
||||||
from helper import FakeYDL
|
from helper import FakeYDL
|
||||||
@@ -88,5 +88,11 @@ class TestYoutubeLists(unittest.TestCase):
|
|||||||
result = ie.extract('PLtPgu7CB4gbY9oDN3drwC3cMbJggS7dKl')[0]
|
result = ie.extract('PLtPgu7CB4gbY9oDN3drwC3cMbJggS7dKl')[0]
|
||||||
self.assertEqual(len(result['entries']), 2)
|
self.assertEqual(len(result['entries']), 2)
|
||||||
|
|
||||||
|
def test_youtube_show(self):
|
||||||
|
dl = FakeYDL()
|
||||||
|
ie = YoutubeShowIE(dl)
|
||||||
|
result = ie.extract('http://www.youtube.com/show/airdisasters')
|
||||||
|
self.assertTrue(len(result) >= 4)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
718
test/tests.json
718
test/tests.json
@@ -1,718 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"name": "Youtube",
|
|
||||||
"url": "http://www.youtube.com/watch?v=BaW_jenozKc",
|
|
||||||
"file": "BaW_jenozKc.mp4",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "youtube-dl test video \"'/\\ä↭𝕐",
|
|
||||||
"uploader": "Philipp Hagemeister",
|
|
||||||
"uploader_id": "phihag",
|
|
||||||
"upload_date": "20121002",
|
|
||||||
"description": "test chars: \"'/\\ä↭𝕐\n\nThis is a test video for youtube-dl.\n\nFor more information, contact phihag@phihag.de ."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Youtube",
|
|
||||||
"url": "http://www.youtube.com/watch?v=1ltcDfZMA3U",
|
|
||||||
"file": "1ltcDfZMA3U.flv",
|
|
||||||
"note": "Test VEVO video (#897)",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20070518",
|
|
||||||
"title": "Maps - It Will Find You",
|
|
||||||
"description": "Music video by Maps performing It Will Find You.",
|
|
||||||
"uploader": "MuteUSA",
|
|
||||||
"uploader_id": "MuteUSA"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Youtube",
|
|
||||||
"url": "http://www.youtube.com/watch?v=UxxajLWwzqY",
|
|
||||||
"file": "UxxajLWwzqY.mp4",
|
|
||||||
"note": "Test generic use_cipher_signature video (#897)",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20120506",
|
|
||||||
"title": "Icona Pop - I Love It (feat. Charli XCX) [OFFICIAL VIDEO]",
|
|
||||||
"description": "md5:b085c9804f5ab69f4adea963a2dceb3c",
|
|
||||||
"uploader": "IconaPop",
|
|
||||||
"uploader_id": "IconaPop"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Dailymotion",
|
|
||||||
"md5": "392c4b85a60a90dc4792da41ce3144eb",
|
|
||||||
"url": "http://www.dailymotion.com/video/x33vw9_tutoriel-de-youtubeur-dl-des-video_tech",
|
|
||||||
"file": "x33vw9.mp4",
|
|
||||||
"info_dict": {
|
|
||||||
"uploader": "Alex and Van .",
|
|
||||||
"title": "Tutoriel de Youtubeur\"DL DES VIDEO DE YOUTUBE\""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Metacafe",
|
|
||||||
"add_ie": ["Youtube"],
|
|
||||||
"url": "http://metacafe.com/watch/yt-_aUehQsCQtM/the_electric_company_short_i_pbs_kids_go/",
|
|
||||||
"file": "_aUehQsCQtM.flv",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20090102",
|
|
||||||
"title": "The Electric Company | \"Short I\" | PBS KIDS GO!",
|
|
||||||
"description": "md5:2439a8ef6d5a70e380c22f5ad323e5a8",
|
|
||||||
"uploader": "PBS",
|
|
||||||
"uploader_id": "PBS"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "BlipTV",
|
|
||||||
"md5": "b2d849efcf7ee18917e4b4d9ff37cafe",
|
|
||||||
"url": "http://blip.tv/cbr/cbr-exclusive-gotham-city-imposters-bats-vs-jokerz-short-3-5796352",
|
|
||||||
"file": "5779306.m4v",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20111205",
|
|
||||||
"description": "md5:9bc31f227219cde65e47eeec8d2dc596",
|
|
||||||
"uploader": "Comic Book Resources - CBR TV",
|
|
||||||
"title": "CBR EXCLUSIVE: \"Gotham City Imposters\" Bats VS Jokerz Short 3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "XVideos",
|
|
||||||
"md5": "1d0c835822f0a71a7bf011855db929d0",
|
|
||||||
"url": "http://www.xvideos.com/video939581/funny_porns_by_s_-1",
|
|
||||||
"file": "939581.flv",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Funny Porns By >>>>S<<<<<< -1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "YouPorn",
|
|
||||||
"md5": "c37ddbaaa39058c76a7e86c6813423c1",
|
|
||||||
"url": "http://www.youporn.com/watch/505835/sex-ed-is-it-safe-to-masturbate-daily/",
|
|
||||||
"file": "505835.mp4",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20101221",
|
|
||||||
"description": "Love & Sex Answers: http://bit.ly/DanAndJenn -- Is It Unhealthy To Masturbate Daily?",
|
|
||||||
"uploader": "Ask Dan And Jennifer",
|
|
||||||
"title": "Sex Ed: Is It Safe To Masturbate Daily?"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Pornotube",
|
|
||||||
"md5": "374dd6dcedd24234453b295209aa69b6",
|
|
||||||
"url": "http://pornotube.com/c/173/m/1689755/Marilyn-Monroe-Bathing",
|
|
||||||
"file": "1689755.flv",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20090708",
|
|
||||||
"title": "Marilyn-Monroe-Bathing"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "YouJizz",
|
|
||||||
"md5": "07e15fa469ba384c7693fd246905547c",
|
|
||||||
"url": "http://www.youjizz.com/videos/zeichentrick-1-2189178.html",
|
|
||||||
"file": "2189178.flv",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Zeichentrick 1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Vimeo",
|
|
||||||
"md5": "8879b6cc097e987f02484baf890129e5",
|
|
||||||
"url": "http://vimeo.com/56015672",
|
|
||||||
"file": "56015672.mp4",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "youtube-dl test video - ★ \" ' 幸 / \\ ä ↭ 𝕐",
|
|
||||||
"uploader": "Filippo Valsorda",
|
|
||||||
"uploader_id": "user7108434",
|
|
||||||
"upload_date": "20121220",
|
|
||||||
"description": "This is a test case for youtube-dl.\nFor more information, see github.com/rg3/youtube-dl\nTest chars: ★ \" ' 幸 / \\ ä ↭ 𝕐"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Soundcloud",
|
|
||||||
"md5": "ebef0a451b909710ed1d7787dddbf0d7",
|
|
||||||
"url": "http://soundcloud.com/ethmusic/lostin-powers-she-so-heavy",
|
|
||||||
"file": "62986583.mp3",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20121011",
|
|
||||||
"description": "No Downloads untill we record the finished version this weekend, i was too pumped n i had to post it , earl is prolly gonna b hella p.o'd",
|
|
||||||
"uploader": "E.T. ExTerrestrial Music",
|
|
||||||
"title": "Lostin Powers - She so Heavy (SneakPreview) Adrian Ackers Blueprint 1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "StanfordOpenClassroom",
|
|
||||||
"md5": "544a9468546059d4e80d76265b0443b8",
|
|
||||||
"url": "http://openclassroom.stanford.edu/MainFolder/VideoPage.php?course=PracticalUnix&video=intro-environment&speed=100",
|
|
||||||
"file": "PracticalUnix_intro-environment.mp4",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Intro Environment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "XNXX",
|
|
||||||
"md5": "0831677e2b4761795f68d417e0b7b445",
|
|
||||||
"url": "http://video.xnxx.com/video1135332/lida_naked_funny_actress_5_",
|
|
||||||
"file": "1135332.flv",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "lida » Naked Funny Actress (5)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Youku",
|
|
||||||
"url": "http://v.youku.com/v_show/id_XNDgyMDQ2NTQw.html",
|
|
||||||
"file": "XNDgyMDQ2NTQw_part00.flv",
|
|
||||||
"md5": "ffe3f2e435663dc2d1eea34faeff5b5b",
|
|
||||||
"params": { "test": false },
|
|
||||||
"info_dict": {
|
|
||||||
"title": "youtube-dl test video \"'/\\ä↭𝕐"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "NBA",
|
|
||||||
"url": "http://www.nba.com/video/games/nets/2012/12/04/0021200253-okc-bkn-recap.nba/index.html",
|
|
||||||
"file": "0021200253-okc-bkn-recap.nba.mp4",
|
|
||||||
"md5": "c0edcfc37607344e2ff8f13c378c88a4",
|
|
||||||
"info_dict": {
|
|
||||||
"description": "Kevin Durant scores 32 points and dishes out six assists as the Thunder beat the Nets in Brooklyn.",
|
|
||||||
"title": "Thunder vs. Nets"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "JustinTV",
|
|
||||||
"url": "http://www.twitch.tv/thegamedevhub/b/296128360",
|
|
||||||
"file": "296128360.flv",
|
|
||||||
"md5": "ecaa8a790c22a40770901460af191c9a",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20110927",
|
|
||||||
"uploader_id": 25114803,
|
|
||||||
"uploader": "thegamedevhub",
|
|
||||||
"title": "Beginner Series - Scripting With Python Pt.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "MyVideo",
|
|
||||||
"url": "http://www.myvideo.de/watch/8229274/bowling_fail_or_win",
|
|
||||||
"file": "8229274.flv",
|
|
||||||
"md5": "2d2753e8130479ba2cb7e0a37002053e",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "bowling-fail-or-win"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Escapist",
|
|
||||||
"url": "http://www.escapistmagazine.com/videos/view/the-escapist-presents/6618-Breaking-Down-Baldurs-Gate",
|
|
||||||
"file": "6618-Breaking-Down-Baldurs-Gate.mp4",
|
|
||||||
"md5": "c6793dbda81388f4264c1ba18684a74d",
|
|
||||||
"info_dict": {
|
|
||||||
"description": "Baldur's Gate: Original, Modded or Enhanced Edition? I'll break down what you can expect from the new Baldur's Gate: Enhanced Edition.",
|
|
||||||
"uploader": "the-escapist-presents",
|
|
||||||
"title": "Breaking Down Baldur's Gate"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "GooglePlus",
|
|
||||||
"url": "https://plus.google.com/u/0/108897254135232129896/posts/ZButuJc6CtH",
|
|
||||||
"file": "ZButuJc6CtH.flv",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20120613",
|
|
||||||
"uploader": "井上ヨシマサ",
|
|
||||||
"title": "嘆きの天使 降臨"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "FunnyOrDie",
|
|
||||||
"url": "http://www.funnyordie.com/videos/0732f586d7/heart-shaped-box-literal-video-version",
|
|
||||||
"file": "0732f586d7.mp4",
|
|
||||||
"md5": "f647e9e90064b53b6e046e75d0241fbd",
|
|
||||||
"info_dict": {
|
|
||||||
"description": "Lyrics changed to match the video. Spoken cameo by Obscurus Lupa (from ThatGuyWithTheGlasses.com). Based on a concept by Dustin McLean (DustFilms.com). Performed, edited, and written by David A. Scott.",
|
|
||||||
"title": "Heart-Shaped Box: Literal Video Version"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Steam",
|
|
||||||
"url": "http://store.steampowered.com/video/105600/",
|
|
||||||
"playlist": [
|
|
||||||
{
|
|
||||||
"file": "81300.flv",
|
|
||||||
"md5": "f870007cee7065d7c76b88f0a45ecc07",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Terraria 1.1 Trailer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "80859.flv",
|
|
||||||
"md5": "61aaf31a5c5c3041afb58fb83cbb5751",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Terraria Trailer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ustream",
|
|
||||||
"url": "http://www.ustream.tv/recorded/20274954",
|
|
||||||
"file": "20274954.flv",
|
|
||||||
"md5": "088f151799e8f572f84eb62f17d73e5c",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Young Americans for Liberty February 7, 2012 2:28 AM",
|
|
||||||
"uploader": "Young Americans for Liberty"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "InfoQ",
|
|
||||||
"url": "http://www.infoq.com/presentations/A-Few-of-My-Favorite-Python-Things",
|
|
||||||
"file": "12-jan-pythonthings.mp4",
|
|
||||||
"info_dict": {
|
|
||||||
"description": "Mike Pirnat presents some tips and tricks, standard libraries and third party packages that make programming in Python a richer experience.",
|
|
||||||
"title": "A Few of My Favorite [Python] Things"
|
|
||||||
},
|
|
||||||
"params": {
|
|
||||||
"skip_download": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ComedyCentral",
|
|
||||||
"url": "http://www.thedailyshow.com/watch/thu-december-13-2012/kristen-stewart",
|
|
||||||
"file": "422212.mp4",
|
|
||||||
"md5": "4e2f5cb088a83cd8cdb7756132f9739d",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20121214",
|
|
||||||
"description": "Kristen Stewart",
|
|
||||||
"uploader": "thedailyshow",
|
|
||||||
"title": "thedailyshow-kristen-stewart part 1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "RBMARadio",
|
|
||||||
"url": "http://www.rbmaradio.com/shows/ford-lopatin-live-at-primavera-sound-2011",
|
|
||||||
"file": "ford-lopatin-live-at-primavera-sound-2011.mp3",
|
|
||||||
"md5": "6bc6f9bcb18994b4c983bc3bf4384d95",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Live at Primavera Sound 2011",
|
|
||||||
"description": "Joel Ford and Daniel \u2019Oneohtrix Point Never\u2019 Lopatin fly their midified pop extravaganza to Spain. Live at Primavera Sound 2011.",
|
|
||||||
"uploader": "Ford & Lopatin",
|
|
||||||
"uploader_id": "ford-lopatin",
|
|
||||||
"location": "Spain"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Facebook",
|
|
||||||
"url": "https://www.facebook.com/photo.php?v=120708114770723",
|
|
||||||
"file": "120708114770723.mp4",
|
|
||||||
"md5": "48975a41ccc4b7a581abd68651c1a5a8",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "PEOPLE ARE AWESOME 2013",
|
|
||||||
"duration": 279
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "EightTracks",
|
|
||||||
"url": "http://8tracks.com/ytdl/youtube-dl-test-tracks-a",
|
|
||||||
"playlist": [
|
|
||||||
{
|
|
||||||
"file": "11885610.m4a",
|
|
||||||
"md5": "96ce57f24389fc8734ce47f4c1abcc55",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "youtue-dl project<>\"' - youtube-dl test track 1 \"'/\\\u00e4\u21ad",
|
|
||||||
"uploader_id": "ytdl"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "11885608.m4a",
|
|
||||||
"md5": "4ab26f05c1f7291ea460a3920be8021f",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "youtube-dl project - youtube-dl test track 2 \"'/\\\u00e4\u21ad",
|
|
||||||
"uploader_id": "ytdl"
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "11885679.m4a",
|
|
||||||
"md5": "d30b5b5f74217410f4689605c35d1fd7",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "youtube-dl project as well - youtube-dl test track 3 \"'/\\\u00e4\u21ad",
|
|
||||||
"uploader_id": "ytdl"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "11885680.m4a",
|
|
||||||
"md5": "4eb0a669317cd725f6bbd336a29f923a",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "youtube-dl project as well - youtube-dl test track 4 \"'/\\\u00e4\u21ad",
|
|
||||||
"uploader_id": "ytdl"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "11885682.m4a",
|
|
||||||
"md5": "1893e872e263a2705558d1d319ad19e8",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "PH - youtube-dl test track 5 \"'/\\\u00e4\u21ad",
|
|
||||||
"uploader_id": "ytdl"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "11885683.m4a",
|
|
||||||
"md5": "b673c46f47a216ab1741ae8836af5899",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "PH - youtube-dl test track 6 \"'/\\\u00e4\u21ad",
|
|
||||||
"uploader_id": "ytdl"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "11885684.m4a",
|
|
||||||
"md5": "1d74534e95df54986da7f5abf7d842b7",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "phihag - youtube-dl test track 7 \"'/\\\u00e4\u21ad",
|
|
||||||
"uploader_id": "ytdl"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "11885685.m4a",
|
|
||||||
"md5": "f081f47af8f6ae782ed131d38b9cd1c0",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "phihag - youtube-dl test track 8 \"'/\\\u00e4\u21ad",
|
|
||||||
"uploader_id": "ytdl"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Keek",
|
|
||||||
"url": "http://www.keek.com/ytdl/keeks/NODfbab",
|
|
||||||
"file": "NODfbab.mp4",
|
|
||||||
"md5": "9b0636f8c0f7614afa4ea5e4c6e57e83",
|
|
||||||
"info_dict": {
|
|
||||||
"uploader": "ytdl",
|
|
||||||
"title": "test chars: \"'/\\ä<>This is a test video for youtube-dl.For more information, contact phihag@phihag.de ."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "TED",
|
|
||||||
"url": "http://www.ted.com/talks/dan_dennett_on_our_consciousness.html",
|
|
||||||
"file": "102.mp4",
|
|
||||||
"md5": "8cd9dfa41ee000ce658fd48fb5d89a61",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Dan Dennett: The illusion of consciousness",
|
|
||||||
"description": "md5:c6fa72e6eedbd938c9caf6b2702f5922"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "MySpass",
|
|
||||||
"url": "http://www.myspass.de/myspass/shows/tvshows/absolute-mehrheit/Absolute-Mehrheit-vom-17022013-Die-Highlights-Teil-2--/11741/",
|
|
||||||
"file": "11741.mp4",
|
|
||||||
"md5": "0b49f4844a068f8b33f4b7c88405862b",
|
|
||||||
"info_dict": {
|
|
||||||
"description": "Wer kann in die Fußstapfen von Wolfgang Kubicki treten und die Mehrheit der Zuschauer hinter sich versammeln? Wird vielleicht sogar die Absolute Mehrheit geknackt und der Jackpot von 200.000 Euro mit nach Hause genommen?",
|
|
||||||
"title": "Absolute Mehrheit vom 17.02.2013 - Die Highlights, Teil 2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic",
|
|
||||||
"url": "http://www.hodiho.fr/2013/02/regis-plante-sa-jeep.html",
|
|
||||||
"file": "13601338388002.mp4",
|
|
||||||
"md5": "85b90ccc9d73b4acd9138d3af4c27f89",
|
|
||||||
"info_dict": {
|
|
||||||
"uploader": "www.hodiho.fr",
|
|
||||||
"title": "Régis plante sa Jeep"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Spiegel",
|
|
||||||
"url": "http://www.spiegel.de/video/vulkan-tungurahua-in-ecuador-ist-wieder-aktiv-video-1259285.html",
|
|
||||||
"file": "1259285.mp4",
|
|
||||||
"md5": "2c2754212136f35fb4b19767d242f66e",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Vulkanausbruch in Ecuador: Der \"Feuerschlund\" ist wieder aktiv"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "LiveLeak",
|
|
||||||
"md5": "0813c2430bea7a46bf13acf3406992f4",
|
|
||||||
"url": "http://www.liveleak.com/view?i=757_1364311680",
|
|
||||||
"file": "757_1364311680.mp4",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Most unlucky car accident",
|
|
||||||
"description": "extremely bad day for this guy..!",
|
|
||||||
"uploader": "ljfriel2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "WorldStarHipHop",
|
|
||||||
"url": "http://www.worldstarhiphop.com/videos/video.php?v=wshh6a7q1ny0G34ZwuIO",
|
|
||||||
"file": "wshh6a7q1ny0G34ZwuIO.mp4",
|
|
||||||
"md5": "9d04de741161603bf7071bbf4e883186",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Video: KO Of The Week: MMA Fighter Gets Knocked Out By Swift Head Kick!"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ARD",
|
|
||||||
"url": "http://www.ardmediathek.de/das-erste/tagesschau-in-100-sek?documentId=14077640",
|
|
||||||
"file": "14077640.mp4",
|
|
||||||
"md5": "6ca8824255460c787376353f9e20bbd8",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "11.04.2013 09:23 Uhr - Tagesschau in 100 Sekunden"
|
|
||||||
},
|
|
||||||
"skip": "Requires rtmpdump"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Tumblr",
|
|
||||||
"url": "http://resigno.tumblr.com/post/53364321212/e-de-extrema-importancia-que-esse-video-seja",
|
|
||||||
"file": "53364321212.mp4",
|
|
||||||
"md5": "0716d3dd51baf68a28b40fdf1251494e",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Rafael Lemos | Tumblr"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "SoundcloudSet",
|
|
||||||
"url":"https://soundcloud.com/the-concept-band/sets/the-royal-concept-ep",
|
|
||||||
"playlist":[
|
|
||||||
{
|
|
||||||
"file":"30510138.mp3",
|
|
||||||
"md5":"f9136bf103901728f29e419d2c70f55d",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20111213",
|
|
||||||
"description": "The Royal Concept from Stockholm\r\nFilip / Povel / David / Magnus\r\nwww.royalconceptband.com",
|
|
||||||
"uploader": "The Royal Concept",
|
|
||||||
"title": "D-D-Dance"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file":"47127625.mp3",
|
|
||||||
"md5":"09b6758a018470570f8fd423c9453dd8",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20120521",
|
|
||||||
"description": "The Royal Concept from Stockholm\r\nFilip / Povel / David / Magnus\r\nwww.royalconceptband.com",
|
|
||||||
"uploader": "The Royal Concept",
|
|
||||||
"title": "The Royal Concept - Gimme Twice"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file":"47127627.mp3",
|
|
||||||
"md5":"154abd4e418cea19c3b901f1e1306d9c",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20120521",
|
|
||||||
"uploader": "The Royal Concept",
|
|
||||||
"title": "Goldrushed"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file":"47127629.mp3",
|
|
||||||
"md5":"2f5471edc79ad3f33a683153e96a79c1",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20120521",
|
|
||||||
"description": "The Royal Concept from Stockholm\r\nFilip / Povel / David / Magnus\r\nwww.royalconceptband.com",
|
|
||||||
"uploader": "The Royal Concept",
|
|
||||||
"title": "In the End"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file":"47127631.mp3",
|
|
||||||
"md5":"f9ba87aa940af7213f98949254f1c6e2",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20120521",
|
|
||||||
"description": "The Royal Concept from Stockholm\r\nFilip / David / Povel / Magnus\r\nwww.theroyalconceptband.com",
|
|
||||||
"uploader": "The Royal Concept",
|
|
||||||
"title": "Knocked Up"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file":"75206121.mp3",
|
|
||||||
"md5":"f9d1fe9406717e302980c30de4af9353",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20130116",
|
|
||||||
"description": "The unreleased track World on Fire premiered on the CW's hit show Arrow (8pm/7pm central). \r\nAs a gift to our fans we would like to offer you a free download of the track! ",
|
|
||||||
"uploader": "The Royal Concept",
|
|
||||||
"title": "World On Fire"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name":"Bandcamp",
|
|
||||||
"url":"http://youtube-dl.bandcamp.com/track/youtube-dl-test-song",
|
|
||||||
"file":"1812978515.mp3",
|
|
||||||
"md5":"cdeb30cdae1921719a3cbcab696ef53c",
|
|
||||||
"info_dict": {
|
|
||||||
"title":"youtube-dl test song \"'/\\ä↭"
|
|
||||||
},
|
|
||||||
"skip": "There is a limit of 200 free downloads / month for the test song"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "RedTube",
|
|
||||||
"url": "http://www.redtube.com/66418",
|
|
||||||
"file": "66418.mp4",
|
|
||||||
"md5": "7b8c22b5e7098a3e1c09709df1126d2d",
|
|
||||||
"info_dict":{
|
|
||||||
"title":"Sucked on a toilet"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Photobucket",
|
|
||||||
"url": "http://media.photobucket.com/user/rachaneronas/media/TiredofLinkBuildingTryBacklinkMyDomaincom_zpsc0c3b9fa.mp4.html?filters[term]=search&filters[primary]=videos&filters[secondary]=images&sort=1&o=0",
|
|
||||||
"file": "zpsc0c3b9fa.mp4",
|
|
||||||
"md5": "7dabfb92b0a31f6c16cebc0f8e60ff99",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20130504",
|
|
||||||
"uploader": "rachaneronas",
|
|
||||||
"title": "Tired of Link Building? Try BacklinkMyDomain.com!"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ina",
|
|
||||||
"url": "www.ina.fr/video/I12055569/francois-hollande-je-crois-que-c-est-clair-video.html",
|
|
||||||
"file": "I12055569.mp4",
|
|
||||||
"md5": "a667021bf2b41f8dc6049479d9bb38a3",
|
|
||||||
"info_dict":{
|
|
||||||
"title":"François Hollande \"Je crois que c'est clair\""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Yahoo",
|
|
||||||
"url": "http://screen.yahoo.com/julian-smith-travis-legg-watch-214727115.html",
|
|
||||||
"file": "214727115.flv",
|
|
||||||
"md5": "2e717f169c1be93d84d3794a00d4a325",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Julian Smith & Travis Legg Watch Julian Smith"
|
|
||||||
},
|
|
||||||
"skip": "Requires rtmpdump"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Howcast",
|
|
||||||
"url": "http://www.howcast.com/videos/390161-How-to-Tie-a-Square-Knot-Properly",
|
|
||||||
"file": "390161.mp4",
|
|
||||||
"md5": "1d7ba54e2c9d7dc6935ef39e00529138",
|
|
||||||
"info_dict":{
|
|
||||||
"title":"How to Tie a Square Knot Properly",
|
|
||||||
"description":"The square knot, also known as the reef knot, is one of the oldest, most basic knots to tie, and can be used in many different ways. Here's the proper way to tie a square knot."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Vine",
|
|
||||||
"url": "https://vine.co/v/b9KOOWX7HUx",
|
|
||||||
"file": "b9KOOWX7HUx.mp4",
|
|
||||||
"md5": "2f36fed6235b16da96ce9b4dc890940d",
|
|
||||||
"info_dict":{
|
|
||||||
"title": "Chicken.",
|
|
||||||
"uploader": "Jack Dorsey"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Flickr",
|
|
||||||
"url": "http://www.flickr.com/photos/forestwander-nature-pictures/5645318632/in/photostream/",
|
|
||||||
"file": "5645318632.mp4",
|
|
||||||
"md5": "6fdc01adbc89d72fc9c4f15b4a4ba87b",
|
|
||||||
"info_dict":{
|
|
||||||
"title": "Dark Hollow Waterfalls",
|
|
||||||
"uploader_id": "forestwander-nature-pictures",
|
|
||||||
"description": "Waterfalls in the Springtime at Dark Hollow Waterfalls. These are located just off of Skyline Drive in Virginia. They are only about 6/10 of a mile hike but it is a pretty steep hill and a good climb back up."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Teamcoco",
|
|
||||||
"url": "http://teamcoco.com/video/louis-ck-interview-george-w-bush",
|
|
||||||
"file": "19705.mp4",
|
|
||||||
"md5": "27b6f7527da5acf534b15f21b032656e",
|
|
||||||
"info_dict":{
|
|
||||||
"title": "Louis C.K. Interview Pt. 1 11/3/11",
|
|
||||||
"description": "Louis C.K. got starstruck by George W. Bush, so what? Part one."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "XHamster",
|
|
||||||
"url": "http://xhamster.com/movies/1509445/femaleagent_shy_beauty_takes_the_bait.html",
|
|
||||||
"file": "1509445.flv",
|
|
||||||
"md5": "9f48e0e8d58e3076bb236ff412ab62fa",
|
|
||||||
"info_dict": {
|
|
||||||
"upload_date": "20121014",
|
|
||||||
"uploader_id": "Ruseful2011",
|
|
||||||
"title": "FemaleAgent Shy beauty takes the bait"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Hypem",
|
|
||||||
"url": "http://hypem.com/track/1v6ga/BODYWORK+-+TAME",
|
|
||||||
"file": "1v6ga.mp3",
|
|
||||||
"md5": "b9cc91b5af8995e9f0c1cee04c575828",
|
|
||||||
"info_dict":{
|
|
||||||
"title":"Tame"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Vbox7",
|
|
||||||
"url": "http://vbox7.com/play:249bb972c2",
|
|
||||||
"file": "249bb972c2.flv",
|
|
||||||
"md5": "9c70d6d956f888bdc08c124acc120cfe",
|
|
||||||
"info_dict":{
|
|
||||||
"title":"Смях! Чудо - чист за секунди - Скрита камера"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Gametrailers",
|
|
||||||
"url": "http://www.gametrailers.com/videos/zbvr8i/mirror-s-edge-2-e3-2013--debut-trailer",
|
|
||||||
"file": "zbvr8i.flv",
|
|
||||||
"md5": "c3edbc995ab4081976e16779bd96a878",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "E3 2013: Debut Trailer"
|
|
||||||
},
|
|
||||||
"skip": "Requires rtmpdump"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Statigram",
|
|
||||||
"url": "http://statigr.am/p/484091715184808010_284179915",
|
|
||||||
"file": "484091715184808010_284179915.mp4",
|
|
||||||
"md5": "deda4ff333abe2e118740321e992605b",
|
|
||||||
"info_dict": {
|
|
||||||
"uploader_id": "videoseconds",
|
|
||||||
"title": "Instagram photo by @videoseconds (Videos)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Break",
|
|
||||||
"url": "http://www.break.com/video/when-girls-act-like-guys-2468056",
|
|
||||||
"file": "2468056.mp4",
|
|
||||||
"md5": "a3513fb1547fba4fb6cfac1bffc6c46b",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "When Girls Act Like D-Bags"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Vevo",
|
|
||||||
"url": "http://www.vevo.com/watch/hurts/somebody-to-die-for/GB1101300280",
|
|
||||||
"file": "GB1101300280.mp4",
|
|
||||||
"md5": "06bea460acb744eab74a9d7dcb4bfd61",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Somebody To Die For",
|
|
||||||
"upload_date": "20130624",
|
|
||||||
"uploader": "Hurts"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Tudou",
|
|
||||||
"url": "http://www.tudou.com/listplay/zzdE77v6Mmo/2xN2duXMxmw.html",
|
|
||||||
"file": "159447792.f4v",
|
|
||||||
"md5": "ad7c358a01541e926a1e413612c6b10a",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "卡马乔国足开大脚长传冲吊集锦"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "CSpan",
|
|
||||||
"url": "http://www.c-spanvideo.org/program/HolderonV",
|
|
||||||
"file": "315139.flv",
|
|
||||||
"md5": "74a623266956f69e4df0068ab6c80fe4",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Attorney General Eric Holder on Voting Rights Act Decision"
|
|
||||||
},
|
|
||||||
"skip": "Requires rtmpdump"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Wimp",
|
|
||||||
"url": "http://www.wimp.com/deerfence/",
|
|
||||||
"file": "deerfence.flv",
|
|
||||||
"md5": "8b215e2e0168c6081a1cf84b2846a2b5",
|
|
||||||
"info_dict": {
|
|
||||||
"title": "Watch Till End: Herd of deer jump over a fence."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
@@ -13,7 +13,7 @@ import time
|
|||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from .utils import *
|
from .utils import *
|
||||||
from .extractor import get_info_extractor
|
from .extractor import get_info_extractor, gen_extractors
|
||||||
from .FileDownloader import FileDownloader
|
from .FileDownloader import FileDownloader
|
||||||
|
|
||||||
|
|
||||||
@@ -113,6 +113,13 @@ class YoutubeDL(object):
|
|||||||
self._ies.append(ie)
|
self._ies.append(ie)
|
||||||
ie.set_downloader(self)
|
ie.set_downloader(self)
|
||||||
|
|
||||||
|
def add_default_info_extractors(self):
|
||||||
|
"""
|
||||||
|
Add the InfoExtractors returned by gen_extractors to the end of the list
|
||||||
|
"""
|
||||||
|
for ie in gen_extractors():
|
||||||
|
self.add_info_extractor(ie)
|
||||||
|
|
||||||
def add_post_processor(self, pp):
|
def add_post_processor(self, pp):
|
||||||
"""Add a PostProcessor object to the end of the chain."""
|
"""Add a PostProcessor object to the end of the chain."""
|
||||||
self._pps.append(pp)
|
self._pps.append(pp)
|
||||||
|
@@ -26,6 +26,7 @@ __authors__ = (
|
|||||||
'Julien Fraichard',
|
'Julien Fraichard',
|
||||||
'Johny Mo Swag',
|
'Johny Mo Swag',
|
||||||
'Axel Noack',
|
'Axel Noack',
|
||||||
|
'Albert Kim',
|
||||||
)
|
)
|
||||||
|
|
||||||
__license__ = 'Public Domain'
|
__license__ = 'Public Domain'
|
||||||
@@ -34,6 +35,7 @@ import codecs
|
|||||||
import getpass
|
import getpass
|
||||||
import optparse
|
import optparse
|
||||||
import os
|
import os
|
||||||
|
import random
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
import socket
|
import socket
|
||||||
@@ -117,6 +119,7 @@ def parseOpts(overrideArguments=None):
|
|||||||
selection = optparse.OptionGroup(parser, 'Video Selection')
|
selection = optparse.OptionGroup(parser, 'Video Selection')
|
||||||
authentication = optparse.OptionGroup(parser, 'Authentication Options')
|
authentication = optparse.OptionGroup(parser, 'Authentication Options')
|
||||||
video_format = optparse.OptionGroup(parser, 'Video Format Options')
|
video_format = optparse.OptionGroup(parser, 'Video Format Options')
|
||||||
|
downloader = optparse.OptionGroup(parser, 'Download Options')
|
||||||
postproc = optparse.OptionGroup(parser, 'Post-processing Options')
|
postproc = optparse.OptionGroup(parser, 'Post-processing Options')
|
||||||
filesystem = optparse.OptionGroup(parser, 'Filesystem Options')
|
filesystem = optparse.OptionGroup(parser, 'Filesystem Options')
|
||||||
verbosity = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
|
verbosity = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
|
||||||
@@ -129,15 +132,6 @@ def parseOpts(overrideArguments=None):
|
|||||||
action='store_true', dest='update_self', help='update this program to latest version')
|
action='store_true', dest='update_self', help='update this program to latest version')
|
||||||
general.add_option('-i', '--ignore-errors',
|
general.add_option('-i', '--ignore-errors',
|
||||||
action='store_true', dest='ignoreerrors', help='continue on download errors', default=False)
|
action='store_true', dest='ignoreerrors', help='continue on download errors', default=False)
|
||||||
general.add_option('-r', '--rate-limit',
|
|
||||||
dest='ratelimit', metavar='LIMIT', help='maximum download rate (e.g. 50k or 44.6m)')
|
|
||||||
general.add_option('-R', '--retries',
|
|
||||||
dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
|
|
||||||
general.add_option('--buffer-size',
|
|
||||||
dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16k) (default is %default)', default="1024")
|
|
||||||
general.add_option('--no-resize-buffer',
|
|
||||||
action='store_true', dest='noresizebuffer',
|
|
||||||
help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
|
|
||||||
general.add_option('--dump-user-agent',
|
general.add_option('--dump-user-agent',
|
||||||
action='store_true', dest='dump_user_agent',
|
action='store_true', dest='dump_user_agent',
|
||||||
help='display the current browser identification', default=False)
|
help='display the current browser identification', default=False)
|
||||||
@@ -149,9 +143,12 @@ def parseOpts(overrideArguments=None):
|
|||||||
general.add_option('--list-extractors',
|
general.add_option('--list-extractors',
|
||||||
action='store_true', dest='list_extractors',
|
action='store_true', dest='list_extractors',
|
||||||
help='List all supported extractors and the URLs they would handle', default=False)
|
help='List all supported extractors and the URLs they would handle', default=False)
|
||||||
|
general.add_option('--extractor-descriptions',
|
||||||
|
action='store_true', dest='list_extractor_descriptions',
|
||||||
|
help='Output descriptions of all supported extractors', default=False)
|
||||||
general.add_option('--proxy', dest='proxy', default=None, help='Use the specified HTTP/HTTPS proxy', metavar='URL')
|
general.add_option('--proxy', dest='proxy', default=None, help='Use the specified HTTP/HTTPS proxy', metavar='URL')
|
||||||
general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
|
general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
|
||||||
general.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
|
|
||||||
|
|
||||||
selection.add_option('--playlist-start',
|
selection.add_option('--playlist-start',
|
||||||
dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
|
dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
|
||||||
@@ -210,6 +207,17 @@ def parseOpts(overrideArguments=None):
|
|||||||
action='store', dest='subtitleslang', metavar='LANG',
|
action='store', dest='subtitleslang', metavar='LANG',
|
||||||
help='language of the subtitles to download (optional) use IETF language tags like \'en\'')
|
help='language of the subtitles to download (optional) use IETF language tags like \'en\'')
|
||||||
|
|
||||||
|
downloader.add_option('-r', '--rate-limit',
|
||||||
|
dest='ratelimit', metavar='LIMIT', help='maximum download rate (e.g. 50k or 44.6m)')
|
||||||
|
downloader.add_option('-R', '--retries',
|
||||||
|
dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
|
||||||
|
downloader.add_option('--buffer-size',
|
||||||
|
dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16k) (default is %default)', default="1024")
|
||||||
|
downloader.add_option('--no-resize-buffer',
|
||||||
|
action='store_true', dest='noresizebuffer',
|
||||||
|
help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
|
||||||
|
downloader.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
|
||||||
|
|
||||||
verbosity.add_option('-q', '--quiet',
|
verbosity.add_option('-q', '--quiet',
|
||||||
action='store_true', dest='quiet', help='activates quiet mode', default=False)
|
action='store_true', dest='quiet', help='activates quiet mode', default=False)
|
||||||
verbosity.add_option('-s', '--simulate',
|
verbosity.add_option('-s', '--simulate',
|
||||||
@@ -316,6 +324,7 @@ def parseOpts(overrideArguments=None):
|
|||||||
|
|
||||||
parser.add_option_group(general)
|
parser.add_option_group(general)
|
||||||
parser.add_option_group(selection)
|
parser.add_option_group(selection)
|
||||||
|
parser.add_option_group(downloader)
|
||||||
parser.add_option_group(filesystem)
|
parser.add_option_group(filesystem)
|
||||||
parser.add_option_group(verbosity)
|
parser.add_option_group(verbosity)
|
||||||
parser.add_option_group(video_format)
|
parser.add_option_group(video_format)
|
||||||
@@ -415,13 +424,25 @@ def _real_main(argv=None):
|
|||||||
extractors = gen_extractors()
|
extractors = gen_extractors()
|
||||||
|
|
||||||
if opts.list_extractors:
|
if opts.list_extractors:
|
||||||
for ie in extractors:
|
for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
|
||||||
compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
|
compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
|
||||||
matchedUrls = [url for url in all_urls if ie.suitable(url)]
|
matchedUrls = [url for url in all_urls if ie.suitable(url)]
|
||||||
all_urls = [url for url in all_urls if url not in matchedUrls]
|
all_urls = [url for url in all_urls if url not in matchedUrls]
|
||||||
for mu in matchedUrls:
|
for mu in matchedUrls:
|
||||||
compat_print(u' ' + mu)
|
compat_print(u' ' + mu)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
if opts.list_extractor_descriptions:
|
||||||
|
for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
|
||||||
|
if not ie._WORKING:
|
||||||
|
continue
|
||||||
|
desc = getattr(ie, 'IE_DESC', ie.IE_NAME)
|
||||||
|
if hasattr(ie, 'SEARCH_KEY'):
|
||||||
|
_SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise')
|
||||||
|
_COUNTS = (u'', u'5', u'10', u'all')
|
||||||
|
desc += u' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES))
|
||||||
|
compat_print(desc)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
# Conflicting, missing and erroneous options
|
# Conflicting, missing and erroneous options
|
||||||
if opts.usenetrc and (opts.username is not None or opts.password is not None):
|
if opts.usenetrc and (opts.username is not None or opts.password is not None):
|
||||||
@@ -561,19 +582,20 @@ def _real_main(argv=None):
|
|||||||
if opts.verbose:
|
if opts.verbose:
|
||||||
ydl.to_screen(u'[debug] youtube-dl version ' + __version__)
|
ydl.to_screen(u'[debug] youtube-dl version ' + __version__)
|
||||||
try:
|
try:
|
||||||
sp = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
sp = subprocess.Popen(
|
||||||
|
['git', 'rev-parse', '--short', 'HEAD'],
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||||
cwd=os.path.dirname(os.path.abspath(__file__)))
|
cwd=os.path.dirname(os.path.abspath(__file__)))
|
||||||
out, err = sp.communicate()
|
out, err = sp.communicate()
|
||||||
out = out.decode().strip()
|
out = out.decode().strip()
|
||||||
if re.match('[0-9a-f]+', out):
|
if re.match('[0-9a-f]+', out):
|
||||||
ydl.to_screen(u'[debug] Git HEAD: ' + out)
|
ydl.to_screen(u'[debug] Git HEAD: ' + out)
|
||||||
except:
|
except:
|
||||||
pass
|
sys.exc_clear()
|
||||||
ydl.to_screen(u'[debug] Python version %s - %s' %(platform.python_version(), platform.platform()))
|
ydl.to_screen(u'[debug] Python version %s - %s' %(platform.python_version(), platform.platform()))
|
||||||
ydl.to_screen(u'[debug] Proxy map: ' + str(proxy_handler.proxies))
|
ydl.to_screen(u'[debug] Proxy map: ' + str(proxy_handler.proxies))
|
||||||
|
|
||||||
for extractor in extractors:
|
ydl.add_default_info_extractors()
|
||||||
ydl.add_info_extractor(extractor)
|
|
||||||
|
|
||||||
# PostProcessors
|
# PostProcessors
|
||||||
if opts.extractaudio:
|
if opts.extractaudio:
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
from .ard import ARDIE
|
from .ard import ARDIE
|
||||||
from .arte import ArteTvIE
|
from .arte import ArteTvIE
|
||||||
|
from .auengine import AUEngineIE
|
||||||
from .bandcamp import BandcampIE
|
from .bandcamp import BandcampIE
|
||||||
from .bliptv import BlipTVIE, BlipTVUserIE
|
from .bliptv import BlipTVIE, BlipTVUserIE
|
||||||
from .breakcom import BreakIE
|
from .breakcom import BreakIE
|
||||||
@@ -14,14 +15,17 @@ from .escapist import EscapistIE
|
|||||||
from .facebook import FacebookIE
|
from .facebook import FacebookIE
|
||||||
from .flickr import FlickrIE
|
from .flickr import FlickrIE
|
||||||
from .funnyordie import FunnyOrDieIE
|
from .funnyordie import FunnyOrDieIE
|
||||||
|
from .gamespot import GameSpotIE
|
||||||
from .gametrailers import GametrailersIE
|
from .gametrailers import GametrailersIE
|
||||||
from .generic import GenericIE
|
from .generic import GenericIE
|
||||||
from .googleplus import GooglePlusIE
|
from .googleplus import GooglePlusIE
|
||||||
from .googlesearch import GoogleSearchIE
|
from .googlesearch import GoogleSearchIE
|
||||||
|
from .hotnewhiphop import HotNewHipHopIE
|
||||||
from .howcast import HowcastIE
|
from .howcast import HowcastIE
|
||||||
from .hypem import HypemIE
|
from .hypem import HypemIE
|
||||||
from .ina import InaIE
|
from .ina import InaIE
|
||||||
from .infoq import InfoQIE
|
from .infoq import InfoQIE
|
||||||
|
from .instagram import InstagramIE
|
||||||
from .jukebox import JukeboxIE
|
from .jukebox import JukeboxIE
|
||||||
from .justintv import JustinTVIE
|
from .justintv import JustinTVIE
|
||||||
from .keek import KeekIE
|
from .keek import KeekIE
|
||||||
@@ -36,6 +40,7 @@ from .photobucket import PhotobucketIE
|
|||||||
from .pornotube import PornotubeIE
|
from .pornotube import PornotubeIE
|
||||||
from .rbmaradio import RBMARadioIE
|
from .rbmaradio import RBMARadioIE
|
||||||
from .redtube import RedTubeIE
|
from .redtube import RedTubeIE
|
||||||
|
from .ringtv import RingTVIE
|
||||||
from .soundcloud import SoundcloudIE, SoundcloudSetIE
|
from .soundcloud import SoundcloudIE, SoundcloudSetIE
|
||||||
from .spiegel import SpiegelIE
|
from .spiegel import SpiegelIE
|
||||||
from .stanfordoc import StanfordOpenClassroomIE
|
from .stanfordoc import StanfordOpenClassroomIE
|
||||||
@@ -43,13 +48,17 @@ from .statigram import StatigramIE
|
|||||||
from .steam import SteamIE
|
from .steam import SteamIE
|
||||||
from .teamcoco import TeamcocoIE
|
from .teamcoco import TeamcocoIE
|
||||||
from .ted import TEDIE
|
from .ted import TEDIE
|
||||||
|
from .tf1 import TF1IE
|
||||||
|
from .traileraddict import TrailerAddictIE
|
||||||
from .tudou import TudouIE
|
from .tudou import TudouIE
|
||||||
from .tumblr import TumblrIE
|
from .tumblr import TumblrIE
|
||||||
|
from .tutv import TutvIE
|
||||||
from .ustream import UstreamIE
|
from .ustream import UstreamIE
|
||||||
from .vbox7 import Vbox7IE
|
from .vbox7 import Vbox7IE
|
||||||
from .vevo import VevoIE
|
from .vevo import VevoIE
|
||||||
from .vimeo import VimeoIE
|
from .vimeo import VimeoIE
|
||||||
from .vine import VineIE
|
from .vine import VineIE
|
||||||
|
from .wat import WatIE
|
||||||
from .wimp import WimpIE
|
from .wimp import WimpIE
|
||||||
from .worldstarhiphop import WorldStarHipHopIE
|
from .worldstarhiphop import WorldStarHipHopIE
|
||||||
from .xhamster import XHamsterIE
|
from .xhamster import XHamsterIE
|
||||||
@@ -59,85 +68,22 @@ from .yahoo import YahooIE, YahooSearchIE
|
|||||||
from .youjizz import YouJizzIE
|
from .youjizz import YouJizzIE
|
||||||
from .youku import YoukuIE
|
from .youku import YoukuIE
|
||||||
from .youporn import YouPornIE
|
from .youporn import YouPornIE
|
||||||
from .youtube import YoutubeIE, YoutubePlaylistIE, YoutubeSearchIE, YoutubeUserIE, YoutubeChannelIE
|
from .youtube import YoutubeIE, YoutubePlaylistIE, YoutubeSearchIE, YoutubeUserIE, YoutubeChannelIE, YoutubeShowIE
|
||||||
from .zdf import ZDFIE
|
from .zdf import ZDFIE
|
||||||
|
|
||||||
|
|
||||||
|
_ALL_CLASSES = [
|
||||||
|
klass
|
||||||
|
for name, klass in globals().items()
|
||||||
|
if name.endswith('IE') and name != 'GenericIE'
|
||||||
|
]
|
||||||
|
_ALL_CLASSES.append(GenericIE)
|
||||||
|
|
||||||
def gen_extractors():
|
def gen_extractors():
|
||||||
""" Return a list of an instance of every supported extractor.
|
""" Return a list of an instance of every supported extractor.
|
||||||
The order does matter; the first extractor matched is the one handling the URL.
|
The order does matter; the first extractor matched is the one handling the URL.
|
||||||
"""
|
"""
|
||||||
return [
|
return [klass() for klass in _ALL_CLASSES]
|
||||||
YoutubePlaylistIE(),
|
|
||||||
YoutubeChannelIE(),
|
|
||||||
YoutubeUserIE(),
|
|
||||||
YoutubeSearchIE(),
|
|
||||||
YoutubeIE(),
|
|
||||||
MetacafeIE(),
|
|
||||||
DailymotionIE(),
|
|
||||||
GoogleSearchIE(),
|
|
||||||
PhotobucketIE(),
|
|
||||||
YahooIE(),
|
|
||||||
YahooSearchIE(),
|
|
||||||
DepositFilesIE(),
|
|
||||||
FacebookIE(),
|
|
||||||
BlipTVIE(),
|
|
||||||
BlipTVUserIE(),
|
|
||||||
VimeoIE(),
|
|
||||||
MyVideoIE(),
|
|
||||||
ComedyCentralIE(),
|
|
||||||
EscapistIE(),
|
|
||||||
CollegeHumorIE(),
|
|
||||||
XVideosIE(),
|
|
||||||
SoundcloudSetIE(),
|
|
||||||
SoundcloudIE(),
|
|
||||||
InfoQIE(),
|
|
||||||
MixcloudIE(),
|
|
||||||
StanfordOpenClassroomIE(),
|
|
||||||
MTVIE(),
|
|
||||||
YoukuIE(),
|
|
||||||
XNXXIE(),
|
|
||||||
YouJizzIE(),
|
|
||||||
PornotubeIE(),
|
|
||||||
YouPornIE(),
|
|
||||||
GooglePlusIE(),
|
|
||||||
ArteTvIE(),
|
|
||||||
NBAIE(),
|
|
||||||
WorldStarHipHopIE(),
|
|
||||||
JustinTVIE(),
|
|
||||||
FunnyOrDieIE(),
|
|
||||||
SteamIE(),
|
|
||||||
UstreamIE(),
|
|
||||||
RBMARadioIE(),
|
|
||||||
EightTracksIE(),
|
|
||||||
KeekIE(),
|
|
||||||
TEDIE(),
|
|
||||||
MySpassIE(),
|
|
||||||
SpiegelIE(),
|
|
||||||
LiveLeakIE(),
|
|
||||||
ARDIE(),
|
|
||||||
ZDFIE(),
|
|
||||||
TumblrIE(),
|
|
||||||
BandcampIE(),
|
|
||||||
RedTubeIE(),
|
|
||||||
InaIE(),
|
|
||||||
HowcastIE(),
|
|
||||||
VineIE(),
|
|
||||||
FlickrIE(),
|
|
||||||
TeamcocoIE(),
|
|
||||||
XHamsterIE(),
|
|
||||||
HypemIE(),
|
|
||||||
Vbox7IE(),
|
|
||||||
GametrailersIE(),
|
|
||||||
StatigramIE(),
|
|
||||||
BreakIE(),
|
|
||||||
VevoIE(),
|
|
||||||
JukeboxIE(),
|
|
||||||
TudouIE(),
|
|
||||||
CSpanIE(),
|
|
||||||
WimpIE(),
|
|
||||||
GenericIE()
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_info_extractor(ie_name):
|
def get_info_extractor(ie_name):
|
||||||
"""Returns the info extractor class with the given ie_name"""
|
"""Returns the info extractor class with the given ie_name"""
|
||||||
|
@@ -9,6 +9,15 @@ class ARDIE(InfoExtractor):
|
|||||||
_VALID_URL = r'^(?:https?://)?(?:(?:www\.)?ardmediathek\.de|mediathek\.daserste\.de)/(?:.*/)(?P<video_id>[^/\?]+)(?:\?.*)?'
|
_VALID_URL = r'^(?:https?://)?(?:(?:www\.)?ardmediathek\.de|mediathek\.daserste\.de)/(?:.*/)(?P<video_id>[^/\?]+)(?:\?.*)?'
|
||||||
_TITLE = r'<h1(?: class="boxTopHeadline")?>(?P<title>.*)</h1>'
|
_TITLE = r'<h1(?: class="boxTopHeadline")?>(?P<title>.*)</h1>'
|
||||||
_MEDIA_STREAM = r'mediaCollection\.addMediaStream\((?P<media_type>\d+), (?P<quality>\d+), "(?P<rtmp_url>[^"]*)", "(?P<video_url>[^"]*)", "[^"]*"\)'
|
_MEDIA_STREAM = r'mediaCollection\.addMediaStream\((?P<media_type>\d+), (?P<quality>\d+), "(?P<rtmp_url>[^"]*)", "(?P<video_url>[^"]*)", "[^"]*"\)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.ardmediathek.de/das-erste/tagesschau-in-100-sek?documentId=14077640',
|
||||||
|
u'file': u'14077640.mp4',
|
||||||
|
u'md5': u'6ca8824255460c787376353f9e20bbd8',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"11.04.2013 09:23 Uhr - Tagesschau in 100 Sekunden"
|
||||||
|
},
|
||||||
|
u'skip': u'Requires rtmpdump'
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
# determine video id from url
|
# determine video id from url
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
|
import xml.etree.ElementTree
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
@@ -11,11 +12,21 @@ from ..utils import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
class ArteTvIE(InfoExtractor):
|
class ArteTvIE(InfoExtractor):
|
||||||
_VALID_URL = r'(?:http://)?www\.arte.tv/guide/(?:fr|de)/(?:(?:sendungen|emissions)/)?(?P<id>.*?)/(?P<name>.*?)(\?.*)?'
|
"""
|
||||||
|
There are two sources of video in arte.tv: videos.arte.tv and
|
||||||
|
www.arte.tv/guide, the extraction process is different for each one.
|
||||||
|
The videos expire in 7 days, so we can't add tests.
|
||||||
|
"""
|
||||||
|
_EMISSION_URL = r'(?:http://)?www\.arte.tv/guide/(?P<lang>fr|de)/(?:(?:sendungen|emissions)/)?(?P<id>.*?)/(?P<name>.*?)(\?.*)?'
|
||||||
|
_VIDEOS_URL = r'(?:http://)?videos.arte.tv/(?P<lang>fr|de)/.*-(?P<id>.*?).html'
|
||||||
_LIVE_URL = r'index-[0-9]+\.html$'
|
_LIVE_URL = r'index-[0-9]+\.html$'
|
||||||
|
|
||||||
IE_NAME = u'arte.tv'
|
IE_NAME = u'arte.tv'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def suitable(cls, url):
|
||||||
|
return any(re.match(regex, url) for regex in (cls._EMISSION_URL, cls._VIDEOS_URL))
|
||||||
|
|
||||||
# TODO implement Live Stream
|
# TODO implement Live Stream
|
||||||
# def extractLiveStream(self, url):
|
# def extractLiveStream(self, url):
|
||||||
# video_lang = url.split('/')[-4]
|
# video_lang = url.split('/')[-4]
|
||||||
@@ -44,17 +55,32 @@ class ArteTvIE(InfoExtractor):
|
|||||||
# video_url = u'%s/%s' % (info.get('url'), info.get('path'))
|
# video_url = u'%s/%s' % (info.get('url'), info.get('path'))
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._EMISSION_URL, url)
|
||||||
|
if mobj is not None:
|
||||||
name = mobj.group('name')
|
name = mobj.group('name')
|
||||||
|
lang = mobj.group('lang')
|
||||||
# This is not a real id, it can be for example AJT for the news
|
# This is not a real id, it can be for example AJT for the news
|
||||||
# http://www.arte.tv/guide/fr/emissions/AJT/arte-journal
|
# http://www.arte.tv/guide/fr/emissions/AJT/arte-journal
|
||||||
video_id = mobj.group('id')
|
video_id = mobj.group('id')
|
||||||
|
return self._extract_emission(url, video_id, lang)
|
||||||
|
|
||||||
|
mobj = re.match(self._VIDEOS_URL, url)
|
||||||
|
if mobj is not None:
|
||||||
|
id = mobj.group('id')
|
||||||
|
lang = mobj.group('lang')
|
||||||
|
return self._extract_video(url, id, lang)
|
||||||
|
|
||||||
if re.search(self._LIVE_URL, video_id) is not None:
|
if re.search(self._LIVE_URL, video_id) is not None:
|
||||||
raise ExtractorError(u'Arte live streams are not yet supported, sorry')
|
raise ExtractorError(u'Arte live streams are not yet supported, sorry')
|
||||||
# self.extractLiveStream(url)
|
# self.extractLiveStream(url)
|
||||||
# return
|
# return
|
||||||
|
|
||||||
|
def _extract_emission(self, url, video_id, lang):
|
||||||
|
"""Extract from www.arte.tv/guide"""
|
||||||
|
if video_id.replace('-','').isdigit():
|
||||||
|
json_url = 'http://org-www.arte.tv/papi/tvguide/videos/stream/player/F/%s_PLUS7-F/ALL/ALL.json' % video_id
|
||||||
|
else:
|
||||||
|
# We don't know the real id of the video, we have to search in the webpage
|
||||||
webpage = self._download_webpage(url, video_id)
|
webpage = self._download_webpage(url, video_id)
|
||||||
json_url = self._html_search_regex(r'arte_vp_url="(.*?)"', webpage, 'json url')
|
json_url = self._html_search_regex(r'arte_vp_url="(.*?)"', webpage, 'json url')
|
||||||
|
|
||||||
@@ -68,9 +94,20 @@ class ArteTvIE(InfoExtractor):
|
|||||||
'description': player_info['VDE'],
|
'description': player_info['VDE'],
|
||||||
'upload_date': unified_strdate(player_info['VDA'].split(' ')[0]),
|
'upload_date': unified_strdate(player_info['VDA'].split(' ')[0]),
|
||||||
'thumbnail': player_info['programImage'],
|
'thumbnail': player_info['programImage'],
|
||||||
|
'ext': 'flv',
|
||||||
}
|
}
|
||||||
|
|
||||||
formats = player_info['VSR'].values()
|
formats = player_info['VSR'].values()
|
||||||
|
def _match_lang(f):
|
||||||
|
# Return true if that format is in the language of the url
|
||||||
|
if lang == 'fr':
|
||||||
|
l = 'F'
|
||||||
|
elif lang == 'de':
|
||||||
|
l = 'A'
|
||||||
|
regexes = [r'VO?%s' % l, r'V%s-ST.' % l]
|
||||||
|
return any(re.match(r, f['versionCode']) for r in regexes)
|
||||||
|
# Some formats may not be in the same language as the url
|
||||||
|
formats = filter(_match_lang, formats)
|
||||||
# We order the formats by quality
|
# We order the formats by quality
|
||||||
formats = sorted(formats, key=lambda f: int(f['height']))
|
formats = sorted(formats, key=lambda f: int(f['height']))
|
||||||
# Pick the best quality
|
# Pick the best quality
|
||||||
@@ -78,9 +115,38 @@ class ArteTvIE(InfoExtractor):
|
|||||||
if format_info['mediaType'] == u'rtmp':
|
if format_info['mediaType'] == u'rtmp':
|
||||||
info_dict['url'] = format_info['streamer']
|
info_dict['url'] = format_info['streamer']
|
||||||
info_dict['play_path'] = 'mp4:' + format_info['url']
|
info_dict['play_path'] = 'mp4:' + format_info['url']
|
||||||
info_dict['ext'] = 'mp4'
|
|
||||||
else:
|
else:
|
||||||
info_dict['url'] = format_info['url']
|
info_dict['url'] = format_info['url']
|
||||||
info_dict['ext'] = 'mp4'
|
|
||||||
|
|
||||||
return info_dict
|
return info_dict
|
||||||
|
|
||||||
|
def _extract_video(self, url, video_id, lang):
|
||||||
|
"""Extract from videos.arte.tv"""
|
||||||
|
ref_xml_url = url.replace('/videos/', '/do_delegate/videos/')
|
||||||
|
ref_xml_url = ref_xml_url.replace('.html', ',view,asPlayerXml.xml')
|
||||||
|
ref_xml = self._download_webpage(ref_xml_url, video_id, note=u'Downloading metadata')
|
||||||
|
ref_xml_doc = xml.etree.ElementTree.fromstring(ref_xml)
|
||||||
|
config_node = ref_xml_doc.find('.//video[@lang="%s"]' % lang)
|
||||||
|
config_xml_url = config_node.attrib['ref']
|
||||||
|
config_xml = self._download_webpage(config_xml_url, video_id, note=u'Downloading configuration')
|
||||||
|
|
||||||
|
video_urls = list(re.finditer(r'<url quality="(?P<quality>.*?)">(?P<url>.*?)</url>', config_xml))
|
||||||
|
def _key(m):
|
||||||
|
quality = m.group('quality')
|
||||||
|
if quality == 'hd':
|
||||||
|
return 2
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
# We pick the best quality
|
||||||
|
video_urls = sorted(video_urls, key=_key)
|
||||||
|
video_url = list(video_urls)[-1].group('url')
|
||||||
|
|
||||||
|
title = self._html_search_regex(r'<name>(.*?)</name>', config_xml, 'title')
|
||||||
|
thumbnail = self._html_search_regex(r'<firstThumbnailUrl>(.*?)</firstThumbnailUrl>',
|
||||||
|
config_xml, 'thumbnail')
|
||||||
|
return {'id': video_id,
|
||||||
|
'title': title,
|
||||||
|
'thumbnail': thumbnail,
|
||||||
|
'url': video_url,
|
||||||
|
'ext': 'flv',
|
||||||
|
}
|
||||||
|
46
youtube_dl/extractor/auengine.py
Normal file
46
youtube_dl/extractor/auengine.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import os.path
|
||||||
|
import re
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import (
|
||||||
|
compat_urllib_parse,
|
||||||
|
compat_urllib_parse_urlparse,
|
||||||
|
)
|
||||||
|
|
||||||
|
class AUEngineIE(InfoExtractor):
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://auengine.com/embed.php?file=lfvlytY6&w=650&h=370',
|
||||||
|
u'file': u'lfvlytY6.mp4',
|
||||||
|
u'md5': u'48972bdbcf1a3a2f5533e62425b41d4f',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"[Commie]The Legend of the Legendary Heroes - 03 - Replication Eye (Alpha Stigma)[F9410F5A]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_VALID_URL = r'(?:http://)?(?:www\.)?auengine\.com/embed.php\?.*?file=([^&]+).*?'
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
video_id = mobj.group(1)
|
||||||
|
webpage = self._download_webpage(url, video_id)
|
||||||
|
title = self._html_search_regex(r'<title>(?P<title>.+?)</title>',
|
||||||
|
webpage, u'title')
|
||||||
|
title = title.strip()
|
||||||
|
links = re.findall(r'[^A-Za-z0-9]?(?:file|url):\s*["\'](http[^\'"&]*)', webpage)
|
||||||
|
links = [compat_urllib_parse.unquote(l) for l in links]
|
||||||
|
for link in links:
|
||||||
|
root, pathext = os.path.splitext(compat_urllib_parse_urlparse(link).path)
|
||||||
|
if pathext == '.png':
|
||||||
|
thumbnail = link
|
||||||
|
elif pathext == '.mp4':
|
||||||
|
url = link
|
||||||
|
ext = pathext
|
||||||
|
if ext == title[-len(ext):]:
|
||||||
|
title = title[:-len(ext)]
|
||||||
|
ext = ext[1:]
|
||||||
|
return [{
|
||||||
|
'id': video_id,
|
||||||
|
'url': url,
|
||||||
|
'ext': ext,
|
||||||
|
'title': title,
|
||||||
|
'thumbnail': thumbnail,
|
||||||
|
}]
|
@@ -9,6 +9,15 @@ from ..utils import (
|
|||||||
|
|
||||||
class BandcampIE(InfoExtractor):
|
class BandcampIE(InfoExtractor):
|
||||||
_VALID_URL = r'http://.*?\.bandcamp\.com/track/(?P<title>.*)'
|
_VALID_URL = r'http://.*?\.bandcamp\.com/track/(?P<title>.*)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://youtube-dl.bandcamp.com/track/youtube-dl-test-song',
|
||||||
|
u'file': u'1812978515.mp3',
|
||||||
|
u'md5': u'cdeb30cdae1921719a3cbcab696ef53c',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"youtube-dl test song \"'/\\\u00e4\u21ad"
|
||||||
|
},
|
||||||
|
u'skip': u'There is a limit of 200 free downloads / month for the test song'
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -24,6 +24,17 @@ class BlipTVIE(InfoExtractor):
|
|||||||
_VALID_URL = r'^(?:https?://)?(?:\w+\.)?blip\.tv/((.+/)|(play/)|(api\.swf#))(.+)$'
|
_VALID_URL = r'^(?:https?://)?(?:\w+\.)?blip\.tv/((.+/)|(play/)|(api\.swf#))(.+)$'
|
||||||
_URL_EXT = r'^.*\.([a-z0-9]+)$'
|
_URL_EXT = r'^.*\.([a-z0-9]+)$'
|
||||||
IE_NAME = u'blip.tv'
|
IE_NAME = u'blip.tv'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://blip.tv/cbr/cbr-exclusive-gotham-city-imposters-bats-vs-jokerz-short-3-5796352',
|
||||||
|
u'file': u'5779306.m4v',
|
||||||
|
u'md5': u'80baf1ec5c3d2019037c1c707d676b9f',
|
||||||
|
u'info_dict': {
|
||||||
|
u"upload_date": u"20111205",
|
||||||
|
u"description": u"md5:9bc31f227219cde65e47eeec8d2dc596",
|
||||||
|
u"uploader": u"Comic Book Resources - CBR TV",
|
||||||
|
u"title": u"CBR EXCLUSIVE: \"Gotham City Imposters\" Bats VS Jokerz Short 3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def report_direct_download(self, title):
|
def report_direct_download(self, title):
|
||||||
"""Report information extraction."""
|
"""Report information extraction."""
|
||||||
@@ -92,6 +103,11 @@ class BlipTVIE(InfoExtractor):
|
|||||||
data = json_data
|
data = json_data
|
||||||
|
|
||||||
upload_date = datetime.datetime.strptime(data['datestamp'], '%m-%d-%y %H:%M%p').strftime('%Y%m%d')
|
upload_date = datetime.datetime.strptime(data['datestamp'], '%m-%d-%y %H:%M%p').strftime('%Y%m%d')
|
||||||
|
if 'additionalMedia' in data:
|
||||||
|
formats = sorted(data['additionalMedia'], key=lambda f: int(f['media_height']))
|
||||||
|
best_format = formats[-1]
|
||||||
|
video_url = best_format['url']
|
||||||
|
else:
|
||||||
video_url = data['media']['url']
|
video_url = data['media']['url']
|
||||||
umobj = re.match(self._URL_EXT, video_url)
|
umobj = re.match(self._URL_EXT, video_url)
|
||||||
if umobj is None:
|
if umobj is None:
|
||||||
|
@@ -5,6 +5,14 @@ from .common import InfoExtractor
|
|||||||
|
|
||||||
class BreakIE(InfoExtractor):
|
class BreakIE(InfoExtractor):
|
||||||
_VALID_URL = r'(?:http://)?(?:www\.)?break\.com/video/([^/]+)'
|
_VALID_URL = r'(?:http://)?(?:www\.)?break\.com/video/([^/]+)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.break.com/video/when-girls-act-like-guys-2468056',
|
||||||
|
u'file': u'2468056.mp4',
|
||||||
|
u'md5': u'a3513fb1547fba4fb6cfac1bffc6c46b',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"When Girls Act Like D-Bags"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -12,8 +12,7 @@ from ..utils import (
|
|||||||
|
|
||||||
|
|
||||||
class ComedyCentralIE(InfoExtractor):
|
class ComedyCentralIE(InfoExtractor):
|
||||||
"""Information extractor for The Daily Show and Colbert Report """
|
IE_DESC = u'The Daily Show / Colbert Report'
|
||||||
|
|
||||||
# urls can be abbreviations like :thedailyshow or :colbert
|
# urls can be abbreviations like :thedailyshow or :colbert
|
||||||
# urls for episodes like:
|
# urls for episodes like:
|
||||||
# or urls for clips like: http://www.thedailyshow.com/watch/mon-december-10-2012/any-given-gun-day
|
# or urls for clips like: http://www.thedailyshow.com/watch/mon-december-10-2012/any-given-gun-day
|
||||||
@@ -27,6 +26,17 @@ class ComedyCentralIE(InfoExtractor):
|
|||||||
(the-colbert-report-(videos|collections)/(?P<clipID>[0-9]+)/[^/]*/(?P<cntitle>.*?))
|
(the-colbert-report-(videos|collections)/(?P<clipID>[0-9]+)/[^/]*/(?P<cntitle>.*?))
|
||||||
|(watch/(?P<date>[^/]*)/(?P<tdstitle>.*)))))
|
|(watch/(?P<date>[^/]*)/(?P<tdstitle>.*)))))
|
||||||
$"""
|
$"""
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.thedailyshow.com/watch/thu-december-13-2012/kristen-stewart',
|
||||||
|
u'file': u'422212.mp4',
|
||||||
|
u'md5': u'4e2f5cb088a83cd8cdb7756132f9739d',
|
||||||
|
u'info_dict': {
|
||||||
|
u"upload_date": u"20121214",
|
||||||
|
u"description": u"Kristen Stewart",
|
||||||
|
u"uploader": u"thedailyshow",
|
||||||
|
u"title": u"thedailyshow-kristen-stewart part 1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_available_formats = ['3500', '2200', '1700', '1200', '750', '400']
|
_available_formats = ['3500', '2200', '1700', '1200', '750', '400']
|
||||||
|
|
||||||
|
@@ -44,6 +44,7 @@ class InfoExtractor(object):
|
|||||||
location: Physical location of the video.
|
location: Physical location of the video.
|
||||||
player_url: SWF Player URL (used for rtmpdump).
|
player_url: SWF Player URL (used for rtmpdump).
|
||||||
subtitles: The subtitle file contents.
|
subtitles: The subtitle file contents.
|
||||||
|
view_count: How many users have watched the video on the platform.
|
||||||
urlhandle: [internal] The urlHandle to be used to download the file,
|
urlhandle: [internal] The urlHandle to be used to download the file,
|
||||||
like returned by urllib.request.urlopen
|
like returned by urllib.request.urlopen
|
||||||
|
|
||||||
@@ -262,3 +263,7 @@ class SearchInfoExtractor(InfoExtractor):
|
|||||||
def _get_n_results(self, query, n):
|
def _get_n_results(self, query, n):
|
||||||
"""Get a specified number of results for a query"""
|
"""Get a specified number of results for a query"""
|
||||||
raise NotImplementedError("This method must be implemented by sublclasses")
|
raise NotImplementedError("This method must be implemented by sublclasses")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def SEARCH_KEY(self):
|
||||||
|
return self._SEARCH_KEY
|
||||||
|
@@ -7,6 +7,15 @@ from ..utils import (
|
|||||||
|
|
||||||
class CSpanIE(InfoExtractor):
|
class CSpanIE(InfoExtractor):
|
||||||
_VALID_URL = r'http://www.c-spanvideo.org/program/(.*)'
|
_VALID_URL = r'http://www.c-spanvideo.org/program/(.*)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.c-spanvideo.org/program/HolderonV',
|
||||||
|
u'file': u'315139.flv',
|
||||||
|
u'md5': u'74a623266956f69e4df0068ab6c80fe4',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Attorney General Eric Holder on Voting Rights Act Decision"
|
||||||
|
},
|
||||||
|
u'skip': u'Requires rtmpdump'
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -1,12 +1,11 @@
|
|||||||
import re
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
compat_urllib_request,
|
compat_urllib_request,
|
||||||
compat_urllib_parse,
|
|
||||||
|
|
||||||
ExtractorError,
|
ExtractorError,
|
||||||
unescapeHTML,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
class DailymotionIE(InfoExtractor):
|
class DailymotionIE(InfoExtractor):
|
||||||
@@ -14,6 +13,15 @@ class DailymotionIE(InfoExtractor):
|
|||||||
|
|
||||||
_VALID_URL = r'(?i)(?:https?://)?(?:www\.)?dailymotion\.[a-z]{2,3}/video/([^/]+)'
|
_VALID_URL = r'(?i)(?:https?://)?(?:www\.)?dailymotion\.[a-z]{2,3}/video/([^/]+)'
|
||||||
IE_NAME = u'dailymotion'
|
IE_NAME = u'dailymotion'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.dailymotion.com/video/x33vw9_tutoriel-de-youtubeur-dl-des-video_tech',
|
||||||
|
u'file': u'x33vw9.mp4',
|
||||||
|
u'md5': u'392c4b85a60a90dc4792da41ce3144eb',
|
||||||
|
u'info_dict': {
|
||||||
|
u"uploader": u"Alex and Van .",
|
||||||
|
u"title": u"Tutoriel de Youtubeur\"DL DES VIDEO DE YOUTUBE\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
# Extract id and simplified title from URL
|
# Extract id and simplified title from URL
|
||||||
@@ -30,33 +38,10 @@ class DailymotionIE(InfoExtractor):
|
|||||||
|
|
||||||
# Extract URL, uploader and title from webpage
|
# Extract URL, uploader and title from webpage
|
||||||
self.report_extraction(video_id)
|
self.report_extraction(video_id)
|
||||||
mobj = re.search(r'\s*var flashvars = (.*)', webpage)
|
|
||||||
if mobj is None:
|
|
||||||
raise ExtractorError(u'Unable to extract media URL')
|
|
||||||
flashvars = compat_urllib_parse.unquote(mobj.group(1))
|
|
||||||
|
|
||||||
for key in ['hd1080URL', 'hd720URL', 'hqURL', 'sdURL', 'ldURL', 'video_url']:
|
video_title = self._html_search_regex(r'<meta property="og:title" content="(.*?)" />',
|
||||||
if key in flashvars:
|
webpage, 'title')
|
||||||
max_quality = key
|
|
||||||
self.to_screen(u'Using %s' % key)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise ExtractorError(u'Unable to extract video URL')
|
|
||||||
|
|
||||||
mobj = re.search(r'"' + max_quality + r'":"(.+?)"', flashvars)
|
|
||||||
if mobj is None:
|
|
||||||
raise ExtractorError(u'Unable to extract video URL')
|
|
||||||
|
|
||||||
video_url = compat_urllib_parse.unquote(mobj.group(1)).replace('\\/', '/')
|
|
||||||
|
|
||||||
# TODO: support choosing qualities
|
|
||||||
|
|
||||||
mobj = re.search(r'<meta property="og:title" content="(?P<title>[^"]*)" />', webpage)
|
|
||||||
if mobj is None:
|
|
||||||
raise ExtractorError(u'Unable to extract title')
|
|
||||||
video_title = unescapeHTML(mobj.group('title'))
|
|
||||||
|
|
||||||
video_uploader = None
|
|
||||||
video_uploader = self._search_regex([r'(?im)<span class="owner[^\"]+?">[^<]+?<a [^>]+?>([^<]+?)</a>',
|
video_uploader = self._search_regex([r'(?im)<span class="owner[^\"]+?">[^<]+?<a [^>]+?>([^<]+?)</a>',
|
||||||
# Looking for official user
|
# Looking for official user
|
||||||
r'<(?:span|a) .*?rel="author".*?>([^<]+?)</'],
|
r'<(?:span|a) .*?rel="author".*?>([^<]+?)</'],
|
||||||
@@ -67,6 +52,25 @@ class DailymotionIE(InfoExtractor):
|
|||||||
if mobj is not None:
|
if mobj is not None:
|
||||||
video_upload_date = mobj.group(3) + mobj.group(2) + mobj.group(1)
|
video_upload_date = mobj.group(3) + mobj.group(2) + mobj.group(1)
|
||||||
|
|
||||||
|
embed_url = 'http://www.dailymotion.com/embed/video/%s' % video_id
|
||||||
|
embed_page = self._download_webpage(embed_url, video_id,
|
||||||
|
u'Downloading embed page')
|
||||||
|
info = self._search_regex(r'var info = ({.*?}),', embed_page, 'video info')
|
||||||
|
info = json.loads(info)
|
||||||
|
|
||||||
|
# TODO: support choosing qualities
|
||||||
|
|
||||||
|
for key in ['stream_h264_hd1080_url','stream_h264_hd_url',
|
||||||
|
'stream_h264_hq_url','stream_h264_url',
|
||||||
|
'stream_h264_ld_url']:
|
||||||
|
if info.get(key):#key in info and info[key]:
|
||||||
|
max_quality = key
|
||||||
|
self.to_screen(u'Using %s' % key)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ExtractorError(u'Unable to extract video URL')
|
||||||
|
video_url = info[max_quality]
|
||||||
|
|
||||||
return [{
|
return [{
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
'url': video_url,
|
'url': video_url,
|
||||||
|
@@ -12,6 +12,77 @@ from ..utils import (
|
|||||||
class EightTracksIE(InfoExtractor):
|
class EightTracksIE(InfoExtractor):
|
||||||
IE_NAME = '8tracks'
|
IE_NAME = '8tracks'
|
||||||
_VALID_URL = r'https?://8tracks.com/(?P<user>[^/]+)/(?P<id>[^/#]+)(?:#.*)?$'
|
_VALID_URL = r'https?://8tracks.com/(?P<user>[^/]+)/(?P<id>[^/#]+)(?:#.*)?$'
|
||||||
|
_TEST = {
|
||||||
|
u"name": u"EightTracks",
|
||||||
|
u"url": u"http://8tracks.com/ytdl/youtube-dl-test-tracks-a",
|
||||||
|
u"playlist": [
|
||||||
|
{
|
||||||
|
u"file": u"11885610.m4a",
|
||||||
|
u"md5": u"96ce57f24389fc8734ce47f4c1abcc55",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"youtue-dl project<>\"' - youtube-dl test track 1 \"'/\\\u00e4\u21ad",
|
||||||
|
u"uploader_id": u"ytdl"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file": u"11885608.m4a",
|
||||||
|
u"md5": u"4ab26f05c1f7291ea460a3920be8021f",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"youtube-dl project - youtube-dl test track 2 \"'/\\\u00e4\u21ad",
|
||||||
|
u"uploader_id": u"ytdl"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file": u"11885679.m4a",
|
||||||
|
u"md5": u"d30b5b5f74217410f4689605c35d1fd7",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"youtube-dl project as well - youtube-dl test track 3 \"'/\\\u00e4\u21ad",
|
||||||
|
u"uploader_id": u"ytdl"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file": u"11885680.m4a",
|
||||||
|
u"md5": u"4eb0a669317cd725f6bbd336a29f923a",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"youtube-dl project as well - youtube-dl test track 4 \"'/\\\u00e4\u21ad",
|
||||||
|
u"uploader_id": u"ytdl"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file": u"11885682.m4a",
|
||||||
|
u"md5": u"1893e872e263a2705558d1d319ad19e8",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"PH - youtube-dl test track 5 \"'/\\\u00e4\u21ad",
|
||||||
|
u"uploader_id": u"ytdl"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file": u"11885683.m4a",
|
||||||
|
u"md5": u"b673c46f47a216ab1741ae8836af5899",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"PH - youtube-dl test track 6 \"'/\\\u00e4\u21ad",
|
||||||
|
u"uploader_id": u"ytdl"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file": u"11885684.m4a",
|
||||||
|
u"md5": u"1d74534e95df54986da7f5abf7d842b7",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"phihag - youtube-dl test track 7 \"'/\\\u00e4\u21ad",
|
||||||
|
u"uploader_id": u"ytdl"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file": u"11885685.m4a",
|
||||||
|
u"md5": u"f081f47af8f6ae782ed131d38b9cd1c0",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"phihag - youtube-dl test track 8 \"'/\\\u00e4\u21ad",
|
||||||
|
u"uploader_id": u"ytdl"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -12,6 +12,16 @@ from ..utils import (
|
|||||||
|
|
||||||
class EscapistIE(InfoExtractor):
|
class EscapistIE(InfoExtractor):
|
||||||
_VALID_URL = r'^(https?://)?(www\.)?escapistmagazine\.com/videos/view/(?P<showname>[^/]+)/(?P<episode>[^/?]+)[/?]?.*$'
|
_VALID_URL = r'^(https?://)?(www\.)?escapistmagazine\.com/videos/view/(?P<showname>[^/]+)/(?P<episode>[^/?]+)[/?]?.*$'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.escapistmagazine.com/videos/view/the-escapist-presents/6618-Breaking-Down-Baldurs-Gate',
|
||||||
|
u'file': u'6618-Breaking-Down-Baldurs-Gate.mp4',
|
||||||
|
u'md5': u'c6793dbda81388f4264c1ba18684a74d',
|
||||||
|
u'info_dict': {
|
||||||
|
u"description": u"Baldur's Gate: Original, Modded or Enhanced Edition? I'll break down what you can expect from the new Baldur's Gate: Enhanced Edition.",
|
||||||
|
u"uploader": u"the-escapist-presents",
|
||||||
|
u"title": u"Breaking Down Baldur's Gate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -22,6 +22,15 @@ class FacebookIE(InfoExtractor):
|
|||||||
_LOGIN_URL = 'https://login.facebook.com/login.php?m&next=http%3A%2F%2Fm.facebook.com%2Fhome.php&'
|
_LOGIN_URL = 'https://login.facebook.com/login.php?m&next=http%3A%2F%2Fm.facebook.com%2Fhome.php&'
|
||||||
_NETRC_MACHINE = 'facebook'
|
_NETRC_MACHINE = 'facebook'
|
||||||
IE_NAME = u'facebook'
|
IE_NAME = u'facebook'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'https://www.facebook.com/photo.php?v=120708114770723',
|
||||||
|
u'file': u'120708114770723.mp4',
|
||||||
|
u'md5': u'48975a41ccc4b7a581abd68651c1a5a8',
|
||||||
|
u'info_dict': {
|
||||||
|
u"duration": 279,
|
||||||
|
u"title": u"PEOPLE ARE AWESOME 2013"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def report_login(self):
|
def report_login(self):
|
||||||
"""Report attempt to log in."""
|
"""Report attempt to log in."""
|
||||||
|
@@ -10,6 +10,16 @@ from ..utils import (
|
|||||||
class FlickrIE(InfoExtractor):
|
class FlickrIE(InfoExtractor):
|
||||||
"""Information Extractor for Flickr videos"""
|
"""Information Extractor for Flickr videos"""
|
||||||
_VALID_URL = r'(?:https?://)?(?:www\.)?flickr\.com/photos/(?P<uploader_id>[\w\-_@]+)/(?P<id>\d+).*'
|
_VALID_URL = r'(?:https?://)?(?:www\.)?flickr\.com/photos/(?P<uploader_id>[\w\-_@]+)/(?P<id>\d+).*'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.flickr.com/photos/forestwander-nature-pictures/5645318632/in/photostream/',
|
||||||
|
u'file': u'5645318632.mp4',
|
||||||
|
u'md5': u'6fdc01adbc89d72fc9c4f15b4a4ba87b',
|
||||||
|
u'info_dict': {
|
||||||
|
u"description": u"Waterfalls in the Springtime at Dark Hollow Waterfalls. These are located just off of Skyline Drive in Virginia. They are only about 6/10 of a mile hike but it is a pretty steep hill and a good climb back up.",
|
||||||
|
u"uploader_id": u"forestwander-nature-pictures",
|
||||||
|
u"title": u"Dark Hollow Waterfalls"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -5,6 +5,15 @@ from .common import InfoExtractor
|
|||||||
|
|
||||||
class FunnyOrDieIE(InfoExtractor):
|
class FunnyOrDieIE(InfoExtractor):
|
||||||
_VALID_URL = r'^(?:https?://)?(?:www\.)?funnyordie\.com/videos/(?P<id>[0-9a-f]+)/.*$'
|
_VALID_URL = r'^(?:https?://)?(?:www\.)?funnyordie\.com/videos/(?P<id>[0-9a-f]+)/.*$'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.funnyordie.com/videos/0732f586d7/heart-shaped-box-literal-video-version',
|
||||||
|
u'file': u'0732f586d7.mp4',
|
||||||
|
u'md5': u'f647e9e90064b53b6e046e75d0241fbd',
|
||||||
|
u'info_dict': {
|
||||||
|
u"description": u"Lyrics changed to match the video. Spoken cameo by Obscurus Lupa (from ThatGuyWithTheGlasses.com). Based on a concept by Dustin McLean (DustFilms.com). Performed, edited, and written by David A. Scott.",
|
||||||
|
u"title": u"Heart-Shaped Box: Literal Video Version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
45
youtube_dl/extractor/gamespot.py
Normal file
45
youtube_dl/extractor/gamespot.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import re
|
||||||
|
import xml.etree.ElementTree
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import (
|
||||||
|
unified_strdate,
|
||||||
|
)
|
||||||
|
|
||||||
|
class GameSpotIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'(?:http://)?(?:www\.)?gamespot\.com/([^/]+)/videos/([^/]+)-([^/d]+)/'
|
||||||
|
_TEST = {
|
||||||
|
u"url": u"http://www.gamespot.com/arma-iii/videos/arma-iii-community-guide-sitrep-i-6410818/",
|
||||||
|
u"file": u"6410818.mp4",
|
||||||
|
u"md5": u"5569d64ca98db01f0177c934fe8c1e9b",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"Arma III - Community Guide: SITREP I",
|
||||||
|
u"upload_date": u"20130627",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
video_id = mobj.group(3).split("-")[-1]
|
||||||
|
info_url = "http://www.gamespot.com/pages/video_player/xml.php?id="+str(video_id)
|
||||||
|
info_xml = self._download_webpage(info_url, video_id)
|
||||||
|
doc = xml.etree.ElementTree.fromstring(info_xml)
|
||||||
|
clip_el = doc.find('./playList/clip')
|
||||||
|
|
||||||
|
video_url = clip_el.find('./URI').text
|
||||||
|
title = clip_el.find('./title').text
|
||||||
|
ext = video_url.rpartition('.')[2]
|
||||||
|
thumbnail_url = clip_el.find('./screenGrabURI').text
|
||||||
|
view_count = int(clip_el.find('./views').text)
|
||||||
|
upload_date = unified_strdate(clip_el.find('./postDate').text)
|
||||||
|
|
||||||
|
return [{
|
||||||
|
'id' : video_id,
|
||||||
|
'url' : video_url,
|
||||||
|
'ext' : ext,
|
||||||
|
'title' : title,
|
||||||
|
'thumbnail' : thumbnail_url,
|
||||||
|
'upload_date' : upload_date,
|
||||||
|
'view_count' : view_count,
|
||||||
|
}]
|
@@ -9,6 +9,15 @@ from ..utils import (
|
|||||||
|
|
||||||
class GametrailersIE(InfoExtractor):
|
class GametrailersIE(InfoExtractor):
|
||||||
_VALID_URL = r'http://www.gametrailers.com/(?P<type>videos|reviews|full-episodes)/(?P<id>.*?)/(?P<title>.*)'
|
_VALID_URL = r'http://www.gametrailers.com/(?P<type>videos|reviews|full-episodes)/(?P<id>.*?)/(?P<title>.*)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.gametrailers.com/videos/zbvr8i/mirror-s-edge-2-e3-2013--debut-trailer',
|
||||||
|
u'file': u'zbvr8i.flv',
|
||||||
|
u'md5': u'c3edbc995ab4081976e16779bd96a878',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"E3 2013: Debut Trailer"
|
||||||
|
},
|
||||||
|
u'skip': u'Requires rtmpdump'
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -11,10 +11,18 @@ from ..utils import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
class GenericIE(InfoExtractor):
|
class GenericIE(InfoExtractor):
|
||||||
"""Generic last-resort information extractor."""
|
IE_DESC = u'Generic downloader that works on some sites'
|
||||||
|
|
||||||
_VALID_URL = r'.*'
|
_VALID_URL = r'.*'
|
||||||
IE_NAME = u'generic'
|
IE_NAME = u'generic'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.hodiho.fr/2013/02/regis-plante-sa-jeep.html',
|
||||||
|
u'file': u'13601338388002.mp4',
|
||||||
|
u'md5': u'85b90ccc9d73b4acd9138d3af4c27f89',
|
||||||
|
u'info_dict': {
|
||||||
|
u"uploader": u"www.hodiho.fr",
|
||||||
|
u"title": u"R\u00e9gis plante sa Jeep"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def report_download_webpage(self, video_id):
|
def report_download_webpage(self, video_id):
|
||||||
"""Report webpage download."""
|
"""Report webpage download."""
|
||||||
@@ -102,7 +110,7 @@ class GenericIE(InfoExtractor):
|
|||||||
mobj = re.search(r'[^A-Za-z0-9]?(?:file|source)=(http[^\'"&]*)', webpage)
|
mobj = re.search(r'[^A-Za-z0-9]?(?:file|source)=(http[^\'"&]*)', webpage)
|
||||||
if mobj is None:
|
if mobj is None:
|
||||||
# Broaden the search a little bit: JWPlayer JS loader
|
# Broaden the search a little bit: JWPlayer JS loader
|
||||||
mobj = re.search(r'[^A-Za-z0-9]?file:\s*["\'](http[^\'"&]*)', webpage)
|
mobj = re.search(r'[^A-Za-z0-9]?file["\']?:\s*["\'](http[^\'"&]*)', webpage)
|
||||||
if mobj is None:
|
if mobj is None:
|
||||||
# Try to find twitter cards info
|
# Try to find twitter cards info
|
||||||
mobj = re.search(r'<meta (?:property|name)="twitter:player:stream" (?:content|value)="(.+?)"', webpage)
|
mobj = re.search(r'<meta (?:property|name)="twitter:player:stream" (?:content|value)="(.+?)"', webpage)
|
||||||
@@ -135,7 +143,7 @@ class GenericIE(InfoExtractor):
|
|||||||
# Video Title - Tagline | Site Name
|
# Video Title - Tagline | Site Name
|
||||||
# and so on and so forth; it's just not practical
|
# and so on and so forth; it's just not practical
|
||||||
video_title = self._html_search_regex(r'<title>(.*)</title>',
|
video_title = self._html_search_regex(r'<title>(.*)</title>',
|
||||||
webpage, u'video title')
|
webpage, u'video title', default=u'video', flags=re.DOTALL)
|
||||||
|
|
||||||
# video uploader is domain name
|
# video uploader is domain name
|
||||||
video_uploader = self._search_regex(r'(?:https?://)?([^/]*)/.*',
|
video_uploader = self._search_regex(r'(?:https?://)?([^/]*)/.*',
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@@ -8,10 +10,18 @@ from ..utils import (
|
|||||||
|
|
||||||
|
|
||||||
class GooglePlusIE(InfoExtractor):
|
class GooglePlusIE(InfoExtractor):
|
||||||
"""Information extractor for plus.google.com."""
|
IE_DESC = u'Google Plus'
|
||||||
|
|
||||||
_VALID_URL = r'(?:https://)?plus\.google\.com/(?:[^/]+/)*?posts/(\w+)'
|
_VALID_URL = r'(?:https://)?plus\.google\.com/(?:[^/]+/)*?posts/(\w+)'
|
||||||
IE_NAME = u'plus.google'
|
IE_NAME = u'plus.google'
|
||||||
|
_TEST = {
|
||||||
|
u"url": u"https://plus.google.com/u/0/108897254135232129896/posts/ZButuJc6CtH",
|
||||||
|
u"file": u"ZButuJc6CtH.flv",
|
||||||
|
u"info_dict": {
|
||||||
|
u"upload_date": u"20120613",
|
||||||
|
u"uploader": u"井上ヨシマサ",
|
||||||
|
u"title": u"嘆きの天使 降臨"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
# Extract id from URL
|
# Extract id from URL
|
||||||
|
@@ -8,7 +8,7 @@ from ..utils import (
|
|||||||
|
|
||||||
|
|
||||||
class GoogleSearchIE(SearchInfoExtractor):
|
class GoogleSearchIE(SearchInfoExtractor):
|
||||||
"""Information Extractor for Google Video search queries."""
|
IE_DESC = u'Google Video search'
|
||||||
_MORE_PAGES_INDICATOR = r'id="pnnext" class="pn"'
|
_MORE_PAGES_INDICATOR = r'id="pnnext" class="pn"'
|
||||||
_MAX_RESULTS = 1000
|
_MAX_RESULTS = 1000
|
||||||
IE_NAME = u'video.google:search'
|
IE_NAME = u'video.google:search'
|
||||||
|
48
youtube_dl/extractor/hotnewhiphop.py
Normal file
48
youtube_dl/extractor/hotnewhiphop.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import re
|
||||||
|
import base64
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
|
||||||
|
|
||||||
|
class HotNewHipHopIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'http://www\.hotnewhiphop.com/.*\.(?P<id>.*)\.html'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u"http://www.hotnewhiphop.com/freddie-gibbs-lay-it-down-song.1435540.html'",
|
||||||
|
u'file': u'1435540.mp3',
|
||||||
|
u'md5': u'2c2cd2f76ef11a9b3b581e8b232f3d96',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Freddie Gibbs Songs - Lay It Down"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
m = re.match(self._VALID_URL, url)
|
||||||
|
video_id = m.group('id')
|
||||||
|
|
||||||
|
webpage_src = self._download_webpage(url, video_id)
|
||||||
|
|
||||||
|
video_url_base64 = self._search_regex(r'data-path="(.*?)"',
|
||||||
|
webpage_src, u'video URL', fatal=False)
|
||||||
|
|
||||||
|
if video_url_base64 == None:
|
||||||
|
video_url = self._search_regex(r'"contentUrl" content="(.*?)"', webpage_src,
|
||||||
|
u'video URL')
|
||||||
|
return self.url_result(video_url, ie='Youtube')
|
||||||
|
|
||||||
|
video_url = base64.b64decode(video_url_base64).decode('utf-8')
|
||||||
|
|
||||||
|
video_title = self._html_search_regex(r"<title>(.*)</title>",
|
||||||
|
webpage_src, u'title')
|
||||||
|
|
||||||
|
# Getting thumbnail and if not thumbnail sets correct title for WSHH candy video.
|
||||||
|
thumbnail = self._html_search_regex(r'"og:image" content="(.*)"',
|
||||||
|
webpage_src, u'thumbnail', fatal=False)
|
||||||
|
|
||||||
|
results = [{
|
||||||
|
'id': video_id,
|
||||||
|
'url' : video_url,
|
||||||
|
'title' : video_title,
|
||||||
|
'thumbnail' : thumbnail,
|
||||||
|
'ext' : 'mp3',
|
||||||
|
}]
|
||||||
|
return results
|
@@ -5,6 +5,15 @@ from .common import InfoExtractor
|
|||||||
|
|
||||||
class HowcastIE(InfoExtractor):
|
class HowcastIE(InfoExtractor):
|
||||||
_VALID_URL = r'(?:https?://)?(?:www\.)?howcast\.com/videos/(?P<id>\d+)'
|
_VALID_URL = r'(?:https?://)?(?:www\.)?howcast\.com/videos/(?P<id>\d+)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.howcast.com/videos/390161-How-to-Tie-a-Square-Knot-Properly',
|
||||||
|
u'file': u'390161.mp4',
|
||||||
|
u'md5': u'1d7ba54e2c9d7dc6935ef39e00529138',
|
||||||
|
u'info_dict': {
|
||||||
|
u"description": u"The square knot, also known as the reef knot, is one of the oldest, most basic knots to tie, and can be used in many different ways. Here's the proper way to tie a square knot.",
|
||||||
|
u"title": u"How to Tie a Square Knot Properly"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -15,6 +15,14 @@ from ..utils import (
|
|||||||
class HypemIE(InfoExtractor):
|
class HypemIE(InfoExtractor):
|
||||||
"""Information Extractor for hypem"""
|
"""Information Extractor for hypem"""
|
||||||
_VALID_URL = r'(?:http://)?(?:www\.)?hypem\.com/track/([^/]+)/([^/]+)'
|
_VALID_URL = r'(?:http://)?(?:www\.)?hypem\.com/track/([^/]+)/([^/]+)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://hypem.com/track/1v6ga/BODYWORK+-+TAME',
|
||||||
|
u'file': u'1v6ga.mp3',
|
||||||
|
u'md5': u'b9cc91b5af8995e9f0c1cee04c575828',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Tame"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -6,6 +6,14 @@ from .common import InfoExtractor
|
|||||||
class InaIE(InfoExtractor):
|
class InaIE(InfoExtractor):
|
||||||
"""Information Extractor for Ina.fr"""
|
"""Information Extractor for Ina.fr"""
|
||||||
_VALID_URL = r'(?:http://)?(?:www\.)?ina\.fr/video/(?P<id>I[0-9]+)/.*'
|
_VALID_URL = r'(?:http://)?(?:www\.)?ina\.fr/video/(?P<id>I[0-9]+)/.*'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'www.ina.fr/video/I12055569/francois-hollande-je-crois-que-c-est-clair-video.html',
|
||||||
|
u'file': u'I12055569.mp4',
|
||||||
|
u'md5': u'a667021bf2b41f8dc6049479d9bb38a3',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Fran\u00e7ois Hollande \"Je crois que c'est clair\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self,url):
|
def _real_extract(self,url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -11,6 +11,18 @@ from ..utils import (
|
|||||||
|
|
||||||
class InfoQIE(InfoExtractor):
|
class InfoQIE(InfoExtractor):
|
||||||
_VALID_URL = r'^(?:https?://)?(?:www\.)?infoq\.com/[^/]+/[^/]+$'
|
_VALID_URL = r'^(?:https?://)?(?:www\.)?infoq\.com/[^/]+/[^/]+$'
|
||||||
|
_TEST = {
|
||||||
|
u"name": u"InfoQ",
|
||||||
|
u"url": u"http://www.infoq.com/presentations/A-Few-of-My-Favorite-Python-Things",
|
||||||
|
u"file": u"12-jan-pythonthings.mp4",
|
||||||
|
u"info_dict": {
|
||||||
|
u"description": u"Mike Pirnat presents some tips and tricks, standard libraries and third party packages that make programming in Python a richer experience.",
|
||||||
|
u"title": u"A Few of My Favorite [Python] Things"
|
||||||
|
},
|
||||||
|
u"params": {
|
||||||
|
u"skip_download": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
42
youtube_dl/extractor/instagram.py
Normal file
42
youtube_dl/extractor/instagram.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
|
||||||
|
class InstagramIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'(?:http://)?instagram.com/p/(.*?)/'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://instagram.com/p/aye83DjauH/#',
|
||||||
|
u'file': u'aye83DjauH.mp4',
|
||||||
|
u'md5': u'0d2da106a9d2631273e192b372806516',
|
||||||
|
u'info_dict': {
|
||||||
|
u"uploader_id": u"naomipq",
|
||||||
|
u"title": u"Video by naomipq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
video_id = mobj.group(1)
|
||||||
|
webpage = self._download_webpage(url, video_id)
|
||||||
|
video_url = self._html_search_regex(
|
||||||
|
r'<meta property="og:video" content="(.+?)"',
|
||||||
|
webpage, u'video URL')
|
||||||
|
thumbnail_url = self._html_search_regex(
|
||||||
|
r'<meta property="og:image" content="(.+?)" />',
|
||||||
|
webpage, u'thumbnail URL', fatal=False)
|
||||||
|
html_title = self._html_search_regex(
|
||||||
|
r'<title>(.+?)</title>',
|
||||||
|
webpage, u'title', flags=re.DOTALL)
|
||||||
|
title = re.sub(u'(?: *\(Videos?\))? \u2022 Instagram$', '', html_title).strip()
|
||||||
|
uploader_id = self._html_search_regex(r'content="(.*?)\'s video on Instagram',
|
||||||
|
webpage, u'uploader name', fatal=False)
|
||||||
|
ext = 'mp4'
|
||||||
|
|
||||||
|
return [{
|
||||||
|
'id': video_id,
|
||||||
|
'url': video_url,
|
||||||
|
'ext': ext,
|
||||||
|
'title': title,
|
||||||
|
'thumbnail': thumbnail_url,
|
||||||
|
'uploader_id' : uploader_id
|
||||||
|
}]
|
@@ -26,6 +26,17 @@ class JustinTVIE(InfoExtractor):
|
|||||||
"""
|
"""
|
||||||
_JUSTIN_PAGE_LIMIT = 100
|
_JUSTIN_PAGE_LIMIT = 100
|
||||||
IE_NAME = u'justin.tv'
|
IE_NAME = u'justin.tv'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.twitch.tv/thegamedevhub/b/296128360',
|
||||||
|
u'file': u'296128360.flv',
|
||||||
|
u'md5': u'ecaa8a790c22a40770901460af191c9a',
|
||||||
|
u'info_dict': {
|
||||||
|
u"upload_date": u"20110927",
|
||||||
|
u"uploader_id": 25114803,
|
||||||
|
u"uploader": u"thegamedevhub",
|
||||||
|
u"title": u"Beginner Series - Scripting With Python Pt.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def report_download_page(self, channel, offset):
|
def report_download_page(self, channel, offset):
|
||||||
"""Report attempt to download a single page of videos."""
|
"""Report attempt to download a single page of videos."""
|
||||||
|
@@ -6,6 +6,15 @@ from .common import InfoExtractor
|
|||||||
class KeekIE(InfoExtractor):
|
class KeekIE(InfoExtractor):
|
||||||
_VALID_URL = r'http://(?:www\.)?keek\.com/(?:!|\w+/keeks/)(?P<videoID>\w+)'
|
_VALID_URL = r'http://(?:www\.)?keek\.com/(?:!|\w+/keeks/)(?P<videoID>\w+)'
|
||||||
IE_NAME = u'keek'
|
IE_NAME = u'keek'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.keek.com/ytdl/keeks/NODfbab',
|
||||||
|
u'file': u'NODfbab.mp4',
|
||||||
|
u'md5': u'9b0636f8c0f7614afa4ea5e4c6e57e83',
|
||||||
|
u'info_dict': {
|
||||||
|
u"uploader": u"ytdl",
|
||||||
|
u"title": u"test chars: \"'/\\\u00e4<>This is a test video for youtube-dl.For more information, contact phihag@phihag.de ."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
m = re.match(self._VALID_URL, url)
|
m = re.match(self._VALID_URL, url)
|
||||||
|
@@ -10,6 +10,16 @@ class LiveLeakIE(InfoExtractor):
|
|||||||
|
|
||||||
_VALID_URL = r'^(?:http?://)?(?:\w+\.)?liveleak\.com/view\?(?:.*?)i=(?P<video_id>[\w_]+)(?:.*)'
|
_VALID_URL = r'^(?:http?://)?(?:\w+\.)?liveleak\.com/view\?(?:.*?)i=(?P<video_id>[\w_]+)(?:.*)'
|
||||||
IE_NAME = u'liveleak'
|
IE_NAME = u'liveleak'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.liveleak.com/view?i=757_1364311680',
|
||||||
|
u'file': u'757_1364311680.mp4',
|
||||||
|
u'md5': u'0813c2430bea7a46bf13acf3406992f4',
|
||||||
|
u'info_dict': {
|
||||||
|
u"description": u"extremely bad day for this guy..!",
|
||||||
|
u"uploader": u"ljfriel2",
|
||||||
|
u"title": u"Most unlucky car accident"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -20,6 +20,19 @@ class MetacafeIE(InfoExtractor):
|
|||||||
_DISCLAIMER = 'http://www.metacafe.com/family_filter/'
|
_DISCLAIMER = 'http://www.metacafe.com/family_filter/'
|
||||||
_FILTER_POST = 'http://www.metacafe.com/f/index.php?inputType=filter&controllerGroup=user'
|
_FILTER_POST = 'http://www.metacafe.com/f/index.php?inputType=filter&controllerGroup=user'
|
||||||
IE_NAME = u'metacafe'
|
IE_NAME = u'metacafe'
|
||||||
|
_TEST = {
|
||||||
|
u"add_ie": ["Youtube"],
|
||||||
|
u"url": u"http://metacafe.com/watch/yt-_aUehQsCQtM/the_electric_company_short_i_pbs_kids_go/",
|
||||||
|
u"file": u"_aUehQsCQtM.flv",
|
||||||
|
u"info_dict": {
|
||||||
|
u"upload_date": u"20090102",
|
||||||
|
u"title": u"The Electric Company | \"Short I\" | PBS KIDS GO!",
|
||||||
|
u"description": u"md5:2439a8ef6d5a70e380c22f5ad323e5a8",
|
||||||
|
u"uploader": u"PBS",
|
||||||
|
u"uploader_id": u"PBS"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def report_disclaimer(self):
|
def report_disclaimer(self):
|
||||||
"""Report disclaimer retrieval."""
|
"""Report disclaimer retrieval."""
|
||||||
|
@@ -11,6 +11,15 @@ from ..utils import (
|
|||||||
|
|
||||||
class MySpassIE(InfoExtractor):
|
class MySpassIE(InfoExtractor):
|
||||||
_VALID_URL = r'http://www.myspass.de/.*'
|
_VALID_URL = r'http://www.myspass.de/.*'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.myspass.de/myspass/shows/tvshows/absolute-mehrheit/Absolute-Mehrheit-vom-17022013-Die-Highlights-Teil-2--/11741/',
|
||||||
|
u'file': u'11741.mp4',
|
||||||
|
u'md5': u'0b49f4844a068f8b33f4b7c88405862b',
|
||||||
|
u'info_dict': {
|
||||||
|
u"description": u"Wer kann in die Fu\u00dfstapfen von Wolfgang Kubicki treten und die Mehrheit der Zuschauer hinter sich versammeln? Wird vielleicht sogar die Absolute Mehrheit geknackt und der Jackpot von 200.000 Euro mit nach Hause genommen?",
|
||||||
|
u"title": u"Absolute Mehrheit vom 17.02.2013 - Die Highlights, Teil 2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
META_DATA_URL_TEMPLATE = 'http://www.myspass.de/myspass/includes/apps/video/getvideometadataxml.php?id=%s'
|
META_DATA_URL_TEMPLATE = 'http://www.myspass.de/myspass/includes/apps/video/getvideometadataxml.php?id=%s'
|
||||||
|
@@ -18,6 +18,14 @@ class MyVideoIE(InfoExtractor):
|
|||||||
|
|
||||||
_VALID_URL = r'(?:http://)?(?:www\.)?myvideo\.de/watch/([0-9]+)/([^?/]+).*'
|
_VALID_URL = r'(?:http://)?(?:www\.)?myvideo\.de/watch/([0-9]+)/([^?/]+).*'
|
||||||
IE_NAME = u'myvideo'
|
IE_NAME = u'myvideo'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.myvideo.de/watch/8229274/bowling_fail_or_win',
|
||||||
|
u'file': u'8229274.flv',
|
||||||
|
u'md5': u'2d2753e8130479ba2cb7e0a37002053e',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"bowling-fail-or-win"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Original Code from: https://github.com/dersphere/plugin.video.myvideo_de.git
|
# Original Code from: https://github.com/dersphere/plugin.video.myvideo_de.git
|
||||||
# Released into the Public Domain by Tristan Fischer on 2013-05-19
|
# Released into the Public Domain by Tristan Fischer on 2013-05-19
|
||||||
|
@@ -8,6 +8,15 @@ from ..utils import (
|
|||||||
|
|
||||||
class NBAIE(InfoExtractor):
|
class NBAIE(InfoExtractor):
|
||||||
_VALID_URL = r'^(?:https?://)?(?:watch\.|www\.)?nba\.com/(?:nba/)?video(/[^?]*?)(?:/index\.html)?(?:\?.*)?$'
|
_VALID_URL = r'^(?:https?://)?(?:watch\.|www\.)?nba\.com/(?:nba/)?video(/[^?]*?)(?:/index\.html)?(?:\?.*)?$'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.nba.com/video/games/nets/2012/12/04/0021200253-okc-bkn-recap.nba/index.html',
|
||||||
|
u'file': u'0021200253-okc-bkn-recap.nba.mp4',
|
||||||
|
u'md5': u'c0edcfc37607344e2ff8f13c378c88a4',
|
||||||
|
u'info_dict': {
|
||||||
|
u"description": u"Kevin Durant scores 32 points and dishes out six assists as the Thunder beat the Nets in Brooklyn.",
|
||||||
|
u"title": u"Thunder vs. Nets"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -16,6 +16,16 @@ class PhotobucketIE(InfoExtractor):
|
|||||||
# Check if it's necessary to keep the old extracion process
|
# Check if it's necessary to keep the old extracion process
|
||||||
_VALID_URL = r'(?:http://)?(?:[a-z0-9]+\.)?photobucket\.com/.*(([\?\&]current=)|_)(?P<id>.*)\.(?P<ext>(flv)|(mp4))'
|
_VALID_URL = r'(?:http://)?(?:[a-z0-9]+\.)?photobucket\.com/.*(([\?\&]current=)|_)(?P<id>.*)\.(?P<ext>(flv)|(mp4))'
|
||||||
IE_NAME = u'photobucket'
|
IE_NAME = u'photobucket'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://media.photobucket.com/user/rachaneronas/media/TiredofLinkBuildingTryBacklinkMyDomaincom_zpsc0c3b9fa.mp4.html?filters[term]=search&filters[primary]=videos&filters[secondary]=images&sort=1&o=0',
|
||||||
|
u'file': u'zpsc0c3b9fa.mp4',
|
||||||
|
u'md5': u'7dabfb92b0a31f6c16cebc0f8e60ff99',
|
||||||
|
u'info_dict': {
|
||||||
|
u"upload_date": u"20130504",
|
||||||
|
u"uploader": u"rachaneronas",
|
||||||
|
u"title": u"Tired of Link Building? Try BacklinkMyDomain.com!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
# Extract id from URL
|
# Extract id from URL
|
||||||
|
@@ -10,6 +10,15 @@ from ..utils import (
|
|||||||
|
|
||||||
class PornotubeIE(InfoExtractor):
|
class PornotubeIE(InfoExtractor):
|
||||||
_VALID_URL = r'^(?:https?://)?(?:\w+\.)?pornotube\.com(/c/(?P<channel>[0-9]+))?(/m/(?P<videoid>[0-9]+))(/(?P<title>.+))$'
|
_VALID_URL = r'^(?:https?://)?(?:\w+\.)?pornotube\.com(/c/(?P<channel>[0-9]+))?(/m/(?P<videoid>[0-9]+))(/(?P<title>.+))$'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://pornotube.com/c/173/m/1689755/Marilyn-Monroe-Bathing',
|
||||||
|
u'file': u'1689755.flv',
|
||||||
|
u'md5': u'374dd6dcedd24234453b295209aa69b6',
|
||||||
|
u'info_dict': {
|
||||||
|
u"upload_date": u"20090708",
|
||||||
|
u"title": u"Marilyn-Monroe-Bathing"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -11,6 +11,18 @@ from ..utils import (
|
|||||||
|
|
||||||
class RBMARadioIE(InfoExtractor):
|
class RBMARadioIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://(?:www\.)?rbmaradio\.com/shows/(?P<videoID>[^/]+)$'
|
_VALID_URL = r'https?://(?:www\.)?rbmaradio\.com/shows/(?P<videoID>[^/]+)$'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.rbmaradio.com/shows/ford-lopatin-live-at-primavera-sound-2011',
|
||||||
|
u'file': u'ford-lopatin-live-at-primavera-sound-2011.mp3',
|
||||||
|
u'md5': u'6bc6f9bcb18994b4c983bc3bf4384d95',
|
||||||
|
u'info_dict': {
|
||||||
|
u"uploader_id": u"ford-lopatin",
|
||||||
|
u"location": u"Spain",
|
||||||
|
u"description": u"Joel Ford and Daniel \u2019Oneohtrix Point Never\u2019 Lopatin fly their midified pop extravaganza to Spain. Live at Primavera Sound 2011.",
|
||||||
|
u"uploader": u"Ford & Lopatin",
|
||||||
|
u"title": u"Live at Primavera Sound 2011"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
m = re.match(self._VALID_URL, url)
|
m = re.match(self._VALID_URL, url)
|
||||||
|
@@ -5,6 +5,14 @@ from .common import InfoExtractor
|
|||||||
|
|
||||||
class RedTubeIE(InfoExtractor):
|
class RedTubeIE(InfoExtractor):
|
||||||
_VALID_URL = r'(?:http://)?(?:www\.)?redtube\.com/(?P<id>[0-9]+)'
|
_VALID_URL = r'(?:http://)?(?:www\.)?redtube\.com/(?P<id>[0-9]+)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.redtube.com/66418',
|
||||||
|
u'file': u'66418.mp4',
|
||||||
|
u'md5': u'7b8c22b5e7098a3e1c09709df1126d2d',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Sucked on a toilet"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self,url):
|
def _real_extract(self,url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
37
youtube_dl/extractor/ringtv.py
Normal file
37
youtube_dl/extractor/ringtv.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
|
||||||
|
|
||||||
|
class RingTVIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'(?:http://)?(?:www\.)?ringtv\.craveonline\.com/videos/video/([^/]+)'
|
||||||
|
_TEST = {
|
||||||
|
u"url": u"http://ringtv.craveonline.com/videos/video/746619-canelo-alvarez-talks-about-mayweather-showdown",
|
||||||
|
u"file": u"746619.mp4",
|
||||||
|
u"md5": u"7c46b4057d22de32e0a539f017e64ad3",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"Canelo Alvarez talks about Mayweather showdown",
|
||||||
|
u"description": u"Saul \\\"Canelo\\\" Alvarez spoke to the media about his Sept. 14 showdown with Floyd Mayweather after their kick-off presser in NYC. Canelo is motivated and confident that he will have the speed and gameplan to beat the pound-for-pound king."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
video_id = mobj.group(1).split('-')[0]
|
||||||
|
webpage = self._download_webpage(url, video_id)
|
||||||
|
title = self._search_regex(r'<title>(.+?)</title>',
|
||||||
|
webpage, 'video title').replace(' | RingTV','')
|
||||||
|
description = self._search_regex(r'<div class="blurb">(.+?)</div>',
|
||||||
|
webpage, 'Description')
|
||||||
|
final_url = "http://ringtv.craveonline.springboardplatform.com/storage/ringtv.craveonline.com/conversion/%s.mp4" %(str(video_id))
|
||||||
|
thumbnail_url = "http://ringtv.craveonline.springboardplatform.com/storage/ringtv.craveonline.com/snapshots/%s.jpg" %(str(video_id))
|
||||||
|
ext = final_url.split('.')[-1]
|
||||||
|
return [{
|
||||||
|
'id' : video_id,
|
||||||
|
'url' : final_url,
|
||||||
|
'ext' : ext,
|
||||||
|
'title' : title,
|
||||||
|
'thumbnail' : thumbnail_url,
|
||||||
|
'description' : description,
|
||||||
|
}]
|
||||||
|
|
@@ -19,8 +19,19 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
of the stream token and uid
|
of the stream token and uid
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_VALID_URL = r'^(?:https?://)?(?:www\.)?soundcloud\.com/([\w\d-]+)/([\w\d-]+)'
|
_VALID_URL = r'^(?:https?://)?(?:www\.)?soundcloud\.com/([\w\d-]+)/([\w\d-]+)(?:[?].*)?$'
|
||||||
IE_NAME = u'soundcloud'
|
IE_NAME = u'soundcloud'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://soundcloud.com/ethmusic/lostin-powers-she-so-heavy',
|
||||||
|
u'file': u'62986583.mp3',
|
||||||
|
u'md5': u'ebef0a451b909710ed1d7787dddbf0d7',
|
||||||
|
u'info_dict': {
|
||||||
|
u"upload_date": u"20121011",
|
||||||
|
u"description": u"No Downloads untill we record the finished version this weekend, i was too pumped n i had to post it , earl is prolly gonna b hella p.o'd",
|
||||||
|
u"uploader": u"E.T. ExTerrestrial Music",
|
||||||
|
u"title": u"Lostin Powers - She so Heavy (SneakPreview) Adrian Ackers Blueprint 1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def report_resolve(self, video_id):
|
def report_resolve(self, video_id):
|
||||||
"""Report information extraction."""
|
"""Report information extraction."""
|
||||||
@@ -75,8 +86,72 @@ class SoundcloudSetIE(InfoExtractor):
|
|||||||
of the stream token and uid
|
of the stream token and uid
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_VALID_URL = r'^(?:https?://)?(?:www\.)?soundcloud\.com/([\w\d-]+)/sets/([\w\d-]+)'
|
_VALID_URL = r'^(?:https?://)?(?:www\.)?soundcloud\.com/([\w\d-]+)/sets/([\w\d-]+)(?:[?].*)?$'
|
||||||
IE_NAME = u'soundcloud:set'
|
IE_NAME = u'soundcloud:set'
|
||||||
|
_TEST = {
|
||||||
|
u"url":"https://soundcloud.com/the-concept-band/sets/the-royal-concept-ep",
|
||||||
|
u"playlist": [
|
||||||
|
{
|
||||||
|
u"file":"30510138.mp3",
|
||||||
|
u"md5":"f9136bf103901728f29e419d2c70f55d",
|
||||||
|
u"info_dict": {
|
||||||
|
u"upload_date": u"20111213",
|
||||||
|
u"description": u"The Royal Concept from Stockholm\r\nFilip / Povel / David / Magnus\r\nwww.royalconceptband.com",
|
||||||
|
u"uploader": u"The Royal Concept",
|
||||||
|
u"title": u"D-D-Dance"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file":"47127625.mp3",
|
||||||
|
u"md5":"09b6758a018470570f8fd423c9453dd8",
|
||||||
|
u"info_dict": {
|
||||||
|
u"upload_date": u"20120521",
|
||||||
|
u"description": u"The Royal Concept from Stockholm\r\nFilip / Povel / David / Magnus\r\nwww.royalconceptband.com",
|
||||||
|
u"uploader": u"The Royal Concept",
|
||||||
|
u"title": u"The Royal Concept - Gimme Twice"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file":"47127627.mp3",
|
||||||
|
u"md5":"154abd4e418cea19c3b901f1e1306d9c",
|
||||||
|
u"info_dict": {
|
||||||
|
u"upload_date": u"20120521",
|
||||||
|
u"uploader": u"The Royal Concept",
|
||||||
|
u"title": u"Goldrushed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file":"47127629.mp3",
|
||||||
|
u"md5":"2f5471edc79ad3f33a683153e96a79c1",
|
||||||
|
u"info_dict": {
|
||||||
|
u"upload_date": u"20120521",
|
||||||
|
u"description": u"The Royal Concept from Stockholm\r\nFilip / Povel / David / Magnus\r\nwww.royalconceptband.com",
|
||||||
|
u"uploader": u"The Royal Concept",
|
||||||
|
u"title": u"In the End"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file":"47127631.mp3",
|
||||||
|
u"md5":"f9ba87aa940af7213f98949254f1c6e2",
|
||||||
|
u"info_dict": {
|
||||||
|
u"upload_date": u"20120521",
|
||||||
|
u"description": u"The Royal Concept from Stockholm\r\nFilip / David / Povel / Magnus\r\nwww.theroyalconceptband.com",
|
||||||
|
u"uploader": u"The Royal Concept",
|
||||||
|
u"title": u"Knocked Up"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file":"75206121.mp3",
|
||||||
|
u"md5":"f9d1fe9406717e302980c30de4af9353",
|
||||||
|
u"info_dict": {
|
||||||
|
u"upload_date": u"20130116",
|
||||||
|
u"description": u"The unreleased track World on Fire premiered on the CW's hit show Arrow (8pm/7pm central). \r\nAs a gift to our fans we would like to offer you a free download of the track! ",
|
||||||
|
u"uploader": u"The Royal Concept",
|
||||||
|
u"title": u"World On Fire"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
def report_resolve(self, video_id):
|
def report_resolve(self, video_id):
|
||||||
"""Report information extraction."""
|
"""Report information extraction."""
|
||||||
|
@@ -6,6 +6,14 @@ from .common import InfoExtractor
|
|||||||
|
|
||||||
class SpiegelIE(InfoExtractor):
|
class SpiegelIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://(?:www\.)?spiegel\.de/video/[^/]*-(?P<videoID>[0-9]+)(?:\.html)?(?:#.*)?$'
|
_VALID_URL = r'https?://(?:www\.)?spiegel\.de/video/[^/]*-(?P<videoID>[0-9]+)(?:\.html)?(?:#.*)?$'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.spiegel.de/video/vulkan-tungurahua-in-ecuador-ist-wieder-aktiv-video-1259285.html',
|
||||||
|
u'file': u'1259285.mp4',
|
||||||
|
u'md5': u'2c2754212136f35fb4b19767d242f66e',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Vulkanausbruch in Ecuador: Der \"Feuerschlund\" ist wieder aktiv"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
m = re.match(self._VALID_URL, url)
|
m = re.match(self._VALID_URL, url)
|
||||||
|
@@ -16,10 +16,17 @@ from ..utils import (
|
|||||||
|
|
||||||
|
|
||||||
class StanfordOpenClassroomIE(InfoExtractor):
|
class StanfordOpenClassroomIE(InfoExtractor):
|
||||||
"""Information extractor for Stanford's Open ClassRoom"""
|
|
||||||
|
|
||||||
_VALID_URL = r'^(?:https?://)?openclassroom.stanford.edu(?P<path>/?|(/MainFolder/(?:HomePage|CoursePage|VideoPage)\.php([?]course=(?P<course>[^&]+)(&video=(?P<video>[^&]+))?(&.*)?)?))$'
|
|
||||||
IE_NAME = u'stanfordoc'
|
IE_NAME = u'stanfordoc'
|
||||||
|
IE_DESC = u'Stanford Open ClassRoom'
|
||||||
|
_VALID_URL = r'^(?:https?://)?openclassroom.stanford.edu(?P<path>/?|(/MainFolder/(?:HomePage|CoursePage|VideoPage)\.php([?]course=(?P<course>[^&]+)(&video=(?P<video>[^&]+))?(&.*)?)?))$'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://openclassroom.stanford.edu/MainFolder/VideoPage.php?course=PracticalUnix&video=intro-environment&speed=100',
|
||||||
|
u'file': u'PracticalUnix_intro-environment.mp4',
|
||||||
|
u'md5': u'544a9468546059d4e80d76265b0443b8',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Intro Environment"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -4,6 +4,15 @@ from .common import InfoExtractor
|
|||||||
|
|
||||||
class StatigramIE(InfoExtractor):
|
class StatigramIE(InfoExtractor):
|
||||||
_VALID_URL = r'(?:http://)?(?:www\.)?statigr\.am/p/([^/]+)'
|
_VALID_URL = r'(?:http://)?(?:www\.)?statigr\.am/p/([^/]+)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://statigr.am/p/484091715184808010_284179915',
|
||||||
|
u'file': u'484091715184808010_284179915.mp4',
|
||||||
|
u'md5': u'deda4ff333abe2e118740321e992605b',
|
||||||
|
u'info_dict': {
|
||||||
|
u"uploader_id": u"videoseconds",
|
||||||
|
u"title": u"Instagram photo by @videoseconds"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
@@ -18,7 +27,7 @@ class StatigramIE(InfoExtractor):
|
|||||||
html_title = self._html_search_regex(
|
html_title = self._html_search_regex(
|
||||||
r'<title>(.+?)</title>',
|
r'<title>(.+?)</title>',
|
||||||
webpage, u'title')
|
webpage, u'title')
|
||||||
title = html_title.rpartition(u' | Statigram')[0]
|
title = re.sub(r'(?: *\(Videos?\))? \| Statigram$', '', html_title)
|
||||||
uploader_id = self._html_search_regex(
|
uploader_id = self._html_search_regex(
|
||||||
r'@([^ ]+)', title, u'uploader name', fatal=False)
|
r'@([^ ]+)', title, u'uploader name', fatal=False)
|
||||||
ext = 'mp4'
|
ext = 'mp4'
|
||||||
|
@@ -16,6 +16,26 @@ class SteamIE(InfoExtractor):
|
|||||||
"""
|
"""
|
||||||
_VIDEO_PAGE_TEMPLATE = 'http://store.steampowered.com/video/%s/'
|
_VIDEO_PAGE_TEMPLATE = 'http://store.steampowered.com/video/%s/'
|
||||||
_AGECHECK_TEMPLATE = 'http://store.steampowered.com/agecheck/video/%s/?snr=1_agecheck_agecheck__age-gate&ageDay=1&ageMonth=January&ageYear=1970'
|
_AGECHECK_TEMPLATE = 'http://store.steampowered.com/agecheck/video/%s/?snr=1_agecheck_agecheck__age-gate&ageDay=1&ageMonth=January&ageYear=1970'
|
||||||
|
_TEST = {
|
||||||
|
u"url": u"http://store.steampowered.com/video/105600/",
|
||||||
|
u"playlist": [
|
||||||
|
{
|
||||||
|
u"file": u"81300.flv",
|
||||||
|
u"md5": u"f870007cee7065d7c76b88f0a45ecc07",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"Terraria 1.1 Trailer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"file": u"80859.flv",
|
||||||
|
u"md5": u"61aaf31a5c5c3041afb58fb83cbb5751",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"Terraria Trailer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def suitable(cls, url):
|
def suitable(cls, url):
|
||||||
|
@@ -8,6 +8,15 @@ from ..utils import (
|
|||||||
|
|
||||||
class TeamcocoIE(InfoExtractor):
|
class TeamcocoIE(InfoExtractor):
|
||||||
_VALID_URL = r'http://teamcoco\.com/video/(?P<url_title>.*)'
|
_VALID_URL = r'http://teamcoco\.com/video/(?P<url_title>.*)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://teamcoco.com/video/louis-ck-interview-george-w-bush',
|
||||||
|
u'file': u'19705.mp4',
|
||||||
|
u'md5': u'27b6f7527da5acf534b15f21b032656e',
|
||||||
|
u'info_dict': {
|
||||||
|
u"description": u"Louis C.K. got starstruck by George W. Bush, so what? Part one.",
|
||||||
|
u"title": u"Louis C.K. Interview Pt. 1 11/3/11"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -14,6 +14,15 @@ class TEDIE(InfoExtractor):
|
|||||||
(/lang/(.*?))? # The url may contain the language
|
(/lang/(.*?))? # The url may contain the language
|
||||||
/(?P<name>\w+) # Here goes the name and then ".html"
|
/(?P<name>\w+) # Here goes the name and then ".html"
|
||||||
'''
|
'''
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.ted.com/talks/dan_dennett_on_our_consciousness.html',
|
||||||
|
u'file': u'102.mp4',
|
||||||
|
u'md5': u'2d76ee1576672e0bd8f187513267adf6',
|
||||||
|
u'info_dict': {
|
||||||
|
u"description": u"md5:c6fa72e6eedbd938c9caf6b2702f5922",
|
||||||
|
u"title": u"Dan Dennett: The illusion of consciousness"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def suitable(cls, url):
|
def suitable(cls, url):
|
||||||
|
35
youtube_dl/extractor/tf1.py
Normal file
35
youtube_dl/extractor/tf1.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
|
||||||
|
class TF1IE(InfoExtractor):
|
||||||
|
"""
|
||||||
|
TF1 uses the wat.tv player, currently it can only download videos with the
|
||||||
|
html5 player enabled, it cannot download HD videos.
|
||||||
|
"""
|
||||||
|
_VALID_URL = r'http://videos.tf1.fr/.*-(.*?).html'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://videos.tf1.fr/auto-moto/citroen-grand-c4-picasso-2013-presentation-officielle-8062060.html',
|
||||||
|
u'file': u'10635995.mp4',
|
||||||
|
u'md5': u'66789d3e91278d332f75e1feb7aea327',
|
||||||
|
u'info_dict': {
|
||||||
|
u'title': u'Citroën Grand C4 Picasso 2013 : présentation officielle',
|
||||||
|
u'description': u'Vidéo officielle du nouveau Citroën Grand C4 Picasso, lancé à l\'automne 2013.',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
id = mobj.group(1)
|
||||||
|
webpage = self._download_webpage(url, id)
|
||||||
|
embed_url = self._html_search_regex(r'"(https://www.wat.tv/embedframe/.*?)"',
|
||||||
|
webpage, 'embed url')
|
||||||
|
embed_page = self._download_webpage(embed_url, id, u'Downloading embed player page')
|
||||||
|
wat_id = self._search_regex(r'UVID=(.*?)&', embed_page, 'wat id')
|
||||||
|
wat_info = self._download_webpage('http://www.wat.tv/interface/contentv3/%s' % wat_id, id, u'Downloading Wat info')
|
||||||
|
wat_info = json.loads(wat_info)['media']
|
||||||
|
wat_url = wat_info['url']
|
||||||
|
return self.url_result(wat_url, 'Wat')
|
49
youtube_dl/extractor/traileraddict.py
Normal file
49
youtube_dl/extractor/traileraddict.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
|
||||||
|
|
||||||
|
class TrailerAddictIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'(?:http://)?(?:www\.)?traileraddict\.com/trailer/([^/]+)/(?:trailer|feature-trailer)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.traileraddict.com/trailer/prince-avalanche/trailer',
|
||||||
|
u'file': u'76184.mp4',
|
||||||
|
u'md5': u'41365557f3c8c397d091da510e73ceb4',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Prince Avalanche Trailer",
|
||||||
|
u"description": u"Trailer for Prince Avalanche.Two highway road workers spend the summer of 1988 away from their city lives. The isolated landscape becomes a place of misadventure as the men find themselves at odds with each other and the women they left behind."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
video_id = mobj.group(1)
|
||||||
|
webpage = self._download_webpage(url, video_id)
|
||||||
|
|
||||||
|
title = self._search_regex(r'<title>(.+?)</title>',
|
||||||
|
webpage, 'video title').replace(' - Trailer Addict','')
|
||||||
|
view_count = self._search_regex(r'Views: (.+?)<br />',
|
||||||
|
webpage, 'Views Count')
|
||||||
|
description = self._search_regex(r'<meta property="og:description" content="(.+?)" />',
|
||||||
|
webpage, 'video description')
|
||||||
|
video_id = self._search_regex(r'<meta property="og:video" content="(.+?)" />',
|
||||||
|
webpage, 'Video id').split('=')[1]
|
||||||
|
|
||||||
|
info_url = "http://www.traileraddict.com/fvar.php?tid=%s" %(str(video_id))
|
||||||
|
info_webpage = self._download_webpage(info_url, video_id , "Downloading the info webpage")
|
||||||
|
|
||||||
|
final_url = self._search_regex(r'&fileurl=(.+)',
|
||||||
|
info_webpage, 'Download url').replace('%3F','?')
|
||||||
|
thumbnail_url = self._search_regex(r'&image=(.+?)&',
|
||||||
|
info_webpage, 'thumbnail url')
|
||||||
|
ext = final_url.split('.')[-1].split('?')[0]
|
||||||
|
|
||||||
|
return [{
|
||||||
|
'id' : video_id,
|
||||||
|
'url' : final_url,
|
||||||
|
'ext' : ext,
|
||||||
|
'title' : title,
|
||||||
|
'thumbnail' : thumbnail_url,
|
||||||
|
'description' : description,
|
||||||
|
'view_count' : view_count,
|
||||||
|
}]
|
@@ -1,16 +1,34 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
|
|
||||||
|
|
||||||
class TudouIE(InfoExtractor):
|
class TudouIE(InfoExtractor):
|
||||||
_VALID_URL = r'(?:http://)?(?:www\.)?tudou\.com/(?:listplay|programs)/(?:view|(.+?))/(?:([^/]+)|([^/]+)\.html)'
|
_VALID_URL = r'(?:http://)?(?:www\.)?tudou\.com/(?:listplay|programs)/(?:view|(.+?))/(?:([^/]+)|([^/]+))(?:\.html)?'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.tudou.com/listplay/zzdE77v6Mmo/2xN2duXMxmw.html',
|
||||||
|
u'file': u'159448201.f4v',
|
||||||
|
u'md5': u'140a49ed444bd22f93330985d8475fcb',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"卡马乔国足开大脚长传冲吊集锦"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _url_for_id(self, id, quality = None):
|
||||||
|
info_url = "http://v2.tudou.com/f?id="+str(id)
|
||||||
|
if quality:
|
||||||
|
info_url += '&hd' + quality
|
||||||
|
webpage = self._download_webpage(info_url, id, "Opening the info webpage")
|
||||||
|
final_url = self._html_search_regex('>(.+?)</f>',webpage, 'video url')
|
||||||
|
return final_url
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
video_id = mobj.group(2).replace('.html','')
|
video_id = mobj.group(2)
|
||||||
webpage = self._download_webpage(url, video_id)
|
webpage = self._download_webpage(url, video_id)
|
||||||
video_id = re.search('"k":(.+?),',webpage).group(1)
|
|
||||||
title = re.search(",kw:\"(.+)\"",webpage)
|
title = re.search(",kw:\"(.+)\"",webpage)
|
||||||
if title is None:
|
if title is None:
|
||||||
title = re.search(",kw: \'(.+)\'",webpage)
|
title = re.search(",kw: \'(.+)\'",webpage)
|
||||||
@@ -19,14 +37,27 @@ class TudouIE(InfoExtractor):
|
|||||||
if thumbnail_url is None:
|
if thumbnail_url is None:
|
||||||
thumbnail_url = re.search(",pic:\"(.+?)\"",webpage)
|
thumbnail_url = re.search(",pic:\"(.+?)\"",webpage)
|
||||||
thumbnail_url = thumbnail_url.group(1)
|
thumbnail_url = thumbnail_url.group(1)
|
||||||
info_url = "http://v2.tudou.com/f?id="+str(video_id)
|
|
||||||
webpage = self._download_webpage(info_url, video_id, "Opening the info webpage")
|
segs_json = self._search_regex(r'segs: \'(.*)\'', webpage, 'segments')
|
||||||
final_url = re.search('\>(.+?)\<\/f\>',webpage).group(1)
|
segments = json.loads(segs_json)
|
||||||
|
# It looks like the keys are the arguments that have to be passed as
|
||||||
|
# the hd field in the request url, we pick the higher
|
||||||
|
quality = sorted(segments.keys())[-1]
|
||||||
|
parts = segments[quality]
|
||||||
|
result = []
|
||||||
|
len_parts = len(parts)
|
||||||
|
if len_parts > 1:
|
||||||
|
self.to_screen(u'%s: found %s parts' % (video_id, len_parts))
|
||||||
|
for part in parts:
|
||||||
|
part_id = part['k']
|
||||||
|
final_url = self._url_for_id(part_id, quality)
|
||||||
ext = (final_url.split('?')[0]).split('.')[-1]
|
ext = (final_url.split('?')[0]).split('.')[-1]
|
||||||
return [{
|
part_info = {'id': part_id,
|
||||||
'id': video_id,
|
|
||||||
'url': final_url,
|
'url': final_url,
|
||||||
'ext': ext,
|
'ext': ext,
|
||||||
'title': title,
|
'title': title,
|
||||||
'thumbnail': thumbnail_url,
|
'thumbnail': thumbnail_url,
|
||||||
}]
|
}
|
||||||
|
result.append(part_info)
|
||||||
|
|
||||||
|
return result
|
||||||
|
@@ -8,6 +8,14 @@ from ..utils import (
|
|||||||
|
|
||||||
class TumblrIE(InfoExtractor):
|
class TumblrIE(InfoExtractor):
|
||||||
_VALID_URL = r'http://(?P<blog_name>.*?)\.tumblr\.com/((post)|(video))/(?P<id>\d*)/(.*?)'
|
_VALID_URL = r'http://(?P<blog_name>.*?)\.tumblr\.com/((post)|(video))/(?P<id>\d*)/(.*?)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://tatianamaslanydaily.tumblr.com/post/54196191430/orphan-black-dvd-extra-behind-the-scenes',
|
||||||
|
u'file': u'54196191430.mp4',
|
||||||
|
u'md5': u'479bb068e5b16462f5176a6828829767',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"tatiana maslany news"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
m_url = re.match(self._VALID_URL, url)
|
m_url = re.match(self._VALID_URL, url)
|
||||||
@@ -30,7 +38,7 @@ class TumblrIE(InfoExtractor):
|
|||||||
|
|
||||||
# The only place where you can get a title, it's not complete,
|
# The only place where you can get a title, it's not complete,
|
||||||
# but searching in other places doesn't work for all videos
|
# but searching in other places doesn't work for all videos
|
||||||
video_title = self._html_search_regex(r'<title>(?P<title>.*?)</title>',
|
video_title = self._html_search_regex(r'<title>(?P<title>.*?)(?: \| Tumblr)?</title>',
|
||||||
webpage, u'title', flags=re.DOTALL)
|
webpage, u'title', flags=re.DOTALL)
|
||||||
|
|
||||||
return [{'id': video_id,
|
return [{'id': video_id,
|
||||||
|
41
youtube_dl/extractor/tutv.py
Normal file
41
youtube_dl/extractor/tutv.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import base64
|
||||||
|
import re
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import (
|
||||||
|
compat_parse_qs,
|
||||||
|
)
|
||||||
|
|
||||||
|
class TutvIE(InfoExtractor):
|
||||||
|
_VALID_URL=r'https?://(?:www\.)?tu\.tv/videos/(?P<id>[^/?]+)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://tu.tv/videos/noah-en-pabellon-cuahutemoc',
|
||||||
|
u'file': u'2742556.flv',
|
||||||
|
u'md5': u'5eb766671f69b82e528dc1e7769c5cb2',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Noah en pabellon cuahutemoc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
video_id = mobj.group('id')
|
||||||
|
|
||||||
|
webpage = self._download_webpage(url, video_id)
|
||||||
|
title = self._html_search_regex(
|
||||||
|
r'<meta property="og:title" content="(.*?)">', webpage, u'title')
|
||||||
|
internal_id = self._search_regex(r'codVideo=([0-9]+)', webpage, u'internal video ID')
|
||||||
|
|
||||||
|
data_url = u'http://tu.tv/flvurl.php?codVideo=' + str(internal_id)
|
||||||
|
data_content = self._download_webpage(data_url, video_id, note=u'Downloading video info')
|
||||||
|
data = compat_parse_qs(data_content)
|
||||||
|
video_url = base64.b64decode(data['kpt'][0]).decode('utf-8')
|
||||||
|
ext = video_url.partition(u'?')[0].rpartition(u'.')[2]
|
||||||
|
|
||||||
|
info = {
|
||||||
|
'id': internal_id,
|
||||||
|
'url': video_url,
|
||||||
|
'ext': ext,
|
||||||
|
'title': title,
|
||||||
|
}
|
||||||
|
return [info]
|
@@ -6,6 +6,15 @@ from .common import InfoExtractor
|
|||||||
class UstreamIE(InfoExtractor):
|
class UstreamIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://www\.ustream\.tv/recorded/(?P<videoID>\d+)'
|
_VALID_URL = r'https?://www\.ustream\.tv/recorded/(?P<videoID>\d+)'
|
||||||
IE_NAME = u'ustream'
|
IE_NAME = u'ustream'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.ustream.tv/recorded/20274954',
|
||||||
|
u'file': u'20274954.flv',
|
||||||
|
u'md5': u'088f151799e8f572f84eb62f17d73e5c',
|
||||||
|
u'info_dict': {
|
||||||
|
u"uploader": u"Young Americans for Liberty",
|
||||||
|
u"title": u"Young Americans for Liberty February 7, 2012 2:28 AM"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
m = re.match(self._VALID_URL, url)
|
m = re.match(self._VALID_URL, url)
|
||||||
|
@@ -12,6 +12,14 @@ from ..utils import (
|
|||||||
class Vbox7IE(InfoExtractor):
|
class Vbox7IE(InfoExtractor):
|
||||||
"""Information Extractor for Vbox7"""
|
"""Information Extractor for Vbox7"""
|
||||||
_VALID_URL = r'(?:http://)?(?:www\.)?vbox7\.com/play:([^/]+)'
|
_VALID_URL = r'(?:http://)?(?:www\.)?vbox7\.com/play:([^/]+)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://vbox7.com/play:249bb972c2',
|
||||||
|
u'file': u'249bb972c2.flv',
|
||||||
|
u'md5': u'9c70d6d956f888bdc08c124acc120cfe',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"\u0421\u043c\u044f\u0445! \u0427\u0443\u0434\u043e - \u0447\u0438\u0441\u0442 \u0437\u0430 \u0441\u0435\u043a\u0443\u043d\u0434\u0438 - \u0421\u043a\u0440\u0438\u0442\u0430 \u043a\u0430\u043c\u0435\u0440\u0430"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self,url):
|
def _real_extract(self,url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -12,6 +12,16 @@ class VevoIE(InfoExtractor):
|
|||||||
(currently used by MTVIE)
|
(currently used by MTVIE)
|
||||||
"""
|
"""
|
||||||
_VALID_URL = r'((http://www.vevo.com/watch/.*?/.*?/)|(vevo:))(?P<id>.*)$'
|
_VALID_URL = r'((http://www.vevo.com/watch/.*?/.*?/)|(vevo:))(?P<id>.*)$'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.vevo.com/watch/hurts/somebody-to-die-for/GB1101300280',
|
||||||
|
u'file': u'GB1101300280.mp4',
|
||||||
|
u'md5': u'06bea460acb744eab74a9d7dcb4bfd61',
|
||||||
|
u'info_dict': {
|
||||||
|
u"upload_date": u"20130624",
|
||||||
|
u"uploader": u"Hurts",
|
||||||
|
u"title": u"Somebody To Die For"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -16,8 +16,20 @@ class VimeoIE(InfoExtractor):
|
|||||||
"""Information extractor for vimeo.com."""
|
"""Information extractor for vimeo.com."""
|
||||||
|
|
||||||
# _VALID_URL matches Vimeo URLs
|
# _VALID_URL matches Vimeo URLs
|
||||||
_VALID_URL = r'(?P<proto>https?://)?(?:(?:www|player)\.)?vimeo(?P<pro>pro)?\.com/(?:(?:(?:groups|album)/[^/]+)|(?:.*?)/)?(?P<direct_link>play_redirect_hls\?clip_id=)?(?:videos?/)?(?P<id>[0-9]+)'
|
_VALID_URL = r'(?P<proto>https?://)?(?:(?:www|player)\.)?vimeo(?P<pro>pro)?\.com/(?:(?:(?:groups|album)/[^/]+)|(?:.*?)/)?(?P<direct_link>play_redirect_hls\?clip_id=)?(?:videos?/)?(?P<id>[0-9]+)(?:[?].*)?$'
|
||||||
IE_NAME = u'vimeo'
|
IE_NAME = u'vimeo'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://vimeo.com/56015672',
|
||||||
|
u'file': u'56015672.mp4',
|
||||||
|
u'md5': u'8879b6cc097e987f02484baf890129e5',
|
||||||
|
u'info_dict': {
|
||||||
|
u"upload_date": u"20121220",
|
||||||
|
u"description": u"This is a test case for youtube-dl.\nFor more information, see github.com/rg3/youtube-dl\nTest chars: \u2605 \" ' \u5e78 / \\ \u00e4 \u21ad \U0001d550",
|
||||||
|
u"uploader_id": u"user7108434",
|
||||||
|
u"uploader": u"Filippo Valsorda",
|
||||||
|
u"title": u"youtube-dl test video - \u2605 \" ' \u5e78 / \\ \u00e4 \u21ad \U0001d550"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _verify_video_password(self, url, video_id, webpage):
|
def _verify_video_password(self, url, video_id, webpage):
|
||||||
password = self._downloader.params.get('videopassword', None)
|
password = self._downloader.params.get('videopassword', None)
|
||||||
|
@@ -5,6 +5,15 @@ from .common import InfoExtractor
|
|||||||
|
|
||||||
class VineIE(InfoExtractor):
|
class VineIE(InfoExtractor):
|
||||||
_VALID_URL = r'(?:https?://)?(?:www\.)?vine\.co/v/(?P<id>\w+)'
|
_VALID_URL = r'(?:https?://)?(?:www\.)?vine\.co/v/(?P<id>\w+)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'https://vine.co/v/b9KOOWX7HUx',
|
||||||
|
u'file': u'b9KOOWX7HUx.mp4',
|
||||||
|
u'md5': u'2f36fed6235b16da96ce9b4dc890940d',
|
||||||
|
u'info_dict': {
|
||||||
|
u"uploader": u"Jack Dorsey",
|
||||||
|
u"title": u"Chicken."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
84
youtube_dl/extractor/wat.py
Normal file
84
youtube_dl/extractor/wat.py
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
|
||||||
|
from ..utils import (
|
||||||
|
compat_urllib_parse,
|
||||||
|
unified_strdate,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class WatIE(InfoExtractor):
|
||||||
|
_VALID_URL=r'http://www.wat.tv/.*-(?P<shortID>.*?)_.*?.html'
|
||||||
|
IE_NAME = 'wat.tv'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.wat.tv/video/world-war-philadelphia-vost-6bv55_2fjr7_.html',
|
||||||
|
u'file': u'10631273.mp4',
|
||||||
|
u'md5': u'0a4fe7870f31eaeabb5e25fd8da8414a',
|
||||||
|
u'info_dict': {
|
||||||
|
u'title': u'World War Z - Philadelphia VOST',
|
||||||
|
u'description': u'La menace est partout. Que se passe-t-il à Philadelphia ?\r\nWORLD WAR Z, avec Brad Pitt, au cinéma le 3 juillet.\r\nhttp://www.worldwarz.fr',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def download_video_info(self, real_id):
|
||||||
|
# 'contentv4' is used in the website, but it also returns the related
|
||||||
|
# videos, we don't need them
|
||||||
|
info = self._download_webpage('http://www.wat.tv/interface/contentv3/' + real_id, real_id, 'Downloading video info')
|
||||||
|
info = json.loads(info)
|
||||||
|
return info['media']
|
||||||
|
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
def real_id_for_chapter(chapter):
|
||||||
|
return chapter['tc_start'].split('-')[0]
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
short_id = mobj.group('shortID')
|
||||||
|
webpage = self._download_webpage(url, short_id)
|
||||||
|
real_id = self._search_regex(r'xtpage = ".*-(.*?)";', webpage, 'real id')
|
||||||
|
|
||||||
|
video_info = self.download_video_info(real_id)
|
||||||
|
chapters = video_info['chapters']
|
||||||
|
first_chapter = chapters[0]
|
||||||
|
|
||||||
|
if real_id_for_chapter(first_chapter) != real_id:
|
||||||
|
self.to_screen('Multipart video detected')
|
||||||
|
chapter_urls = []
|
||||||
|
for chapter in chapters:
|
||||||
|
chapter_id = real_id_for_chapter(chapter)
|
||||||
|
# Yes, when we this chapter is processed by WatIE,
|
||||||
|
# it will download the info again
|
||||||
|
chapter_info = self.download_video_info(chapter_id)
|
||||||
|
chapter_urls.append(chapter_info['url'])
|
||||||
|
entries = [self.url_result(chapter_url) for chapter_url in chapter_urls]
|
||||||
|
return self.playlist_result(entries, real_id, video_info['title'])
|
||||||
|
|
||||||
|
# Otherwise we can continue and extract just one part, we have to use
|
||||||
|
# the short id for getting the video url
|
||||||
|
player_data = compat_urllib_parse.urlencode({'shortVideoId': short_id,
|
||||||
|
'html5': '1'})
|
||||||
|
player_info = self._download_webpage('http://www.wat.tv/player?' + player_data,
|
||||||
|
real_id, u'Downloading player info')
|
||||||
|
player = json.loads(player_info)['player']
|
||||||
|
html5_player = self._html_search_regex(r'iframe src="(.*?)"', player,
|
||||||
|
'html5 player')
|
||||||
|
player_webpage = self._download_webpage(html5_player, real_id,
|
||||||
|
u'Downloading player webpage')
|
||||||
|
|
||||||
|
video_url = self._search_regex(r'urlhtml5 : "(.*?)"', player_webpage,
|
||||||
|
'video url')
|
||||||
|
info = {'id': real_id,
|
||||||
|
'url': video_url,
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': first_chapter['title'],
|
||||||
|
'thumbnail': first_chapter['preview'],
|
||||||
|
'description': first_chapter['description'],
|
||||||
|
'view_count': video_info['views'],
|
||||||
|
}
|
||||||
|
if 'date_diffusion' in first_chapter:
|
||||||
|
info['upload_date'] = unified_strdate(first_chapter['date_diffusion'])
|
||||||
|
|
||||||
|
return info
|
@@ -6,6 +6,14 @@ from .common import InfoExtractor
|
|||||||
|
|
||||||
class WimpIE(InfoExtractor):
|
class WimpIE(InfoExtractor):
|
||||||
_VALID_URL = r'(?:http://)?(?:www\.)?wimp\.com/([^/]+)/'
|
_VALID_URL = r'(?:http://)?(?:www\.)?wimp\.com/([^/]+)/'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.wimp.com/deerfence/',
|
||||||
|
u'file': u'deerfence.flv',
|
||||||
|
u'md5': u'8b215e2e0168c6081a1cf84b2846a2b5',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Watch Till End: Herd of deer jump over a fence."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -5,7 +5,15 @@ from .common import InfoExtractor
|
|||||||
|
|
||||||
class WorldStarHipHopIE(InfoExtractor):
|
class WorldStarHipHopIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://(?:www|m)\.worldstar(?:candy|hiphop)\.com/videos/video\.php\?v=(?P<id>.*)'
|
_VALID_URL = r'https?://(?:www|m)\.worldstar(?:candy|hiphop)\.com/videos/video\.php\?v=(?P<id>.*)'
|
||||||
IE_NAME = u'WorldStarHipHop'
|
_TEST = {
|
||||||
|
"url": "http://www.worldstarhiphop.com/videos/video.php?v=wshh6a7q1ny0G34ZwuIO",
|
||||||
|
"file": "wshh6a7q1ny0G34ZwuIO.mp4",
|
||||||
|
"md5": "9d04de741161603bf7071bbf4e883186",
|
||||||
|
"info_dict": {
|
||||||
|
"title": "Video: KO Of The Week: MMA Fighter Gets Knocked Out By Swift Head Kick!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
m = re.match(self._VALID_URL, url)
|
m = re.match(self._VALID_URL, url)
|
||||||
|
@@ -11,6 +11,16 @@ from ..utils import (
|
|||||||
class XHamsterIE(InfoExtractor):
|
class XHamsterIE(InfoExtractor):
|
||||||
"""Information Extractor for xHamster"""
|
"""Information Extractor for xHamster"""
|
||||||
_VALID_URL = r'(?:http://)?(?:www.)?xhamster\.com/movies/(?P<id>[0-9]+)/.*\.html'
|
_VALID_URL = r'(?:http://)?(?:www.)?xhamster\.com/movies/(?P<id>[0-9]+)/.*\.html'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://xhamster.com/movies/1509445/femaleagent_shy_beauty_takes_the_bait.html',
|
||||||
|
u'file': u'1509445.flv',
|
||||||
|
u'md5': u'9f48e0e8d58e3076bb236ff412ab62fa',
|
||||||
|
u'info_dict': {
|
||||||
|
u"upload_date": u"20121014",
|
||||||
|
u"uploader_id": u"Ruseful2011",
|
||||||
|
u"title": u"FemaleAgent Shy beauty takes the bait"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self,url):
|
def _real_extract(self,url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -13,6 +13,14 @@ class XNXXIE(InfoExtractor):
|
|||||||
VIDEO_URL_RE = r'flv_url=(.*?)&'
|
VIDEO_URL_RE = r'flv_url=(.*?)&'
|
||||||
VIDEO_TITLE_RE = r'<title>(.*?)\s+-\s+XNXX.COM'
|
VIDEO_TITLE_RE = r'<title>(.*?)\s+-\s+XNXX.COM'
|
||||||
VIDEO_THUMB_RE = r'url_bigthumb=(.*?)&'
|
VIDEO_THUMB_RE = r'url_bigthumb=(.*?)&'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://video.xnxx.com/video1135332/lida_naked_funny_actress_5_',
|
||||||
|
u'file': u'1135332.flv',
|
||||||
|
u'md5': u'0831677e2b4761795f68d417e0b7b445',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"lida \u00bb Naked Funny Actress (5)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -8,6 +8,14 @@ from ..utils import (
|
|||||||
|
|
||||||
class XVideosIE(InfoExtractor):
|
class XVideosIE(InfoExtractor):
|
||||||
_VALID_URL = r'^(?:https?://)?(?:www\.)?xvideos\.com/video([0-9]+)(?:.*)'
|
_VALID_URL = r'^(?:https?://)?(?:www\.)?xvideos\.com/video([0-9]+)(?:.*)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.xvideos.com/video939581/funny_porns_by_s_-1',
|
||||||
|
u'file': u'939581.flv',
|
||||||
|
u'md5': u'1d0c835822f0a71a7bf011855db929d0',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Funny Porns By >>>>S<<<<<< -1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -11,8 +11,17 @@ from ..utils import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
class YahooIE(InfoExtractor):
|
class YahooIE(InfoExtractor):
|
||||||
"""Information extractor for screen.yahoo.com."""
|
IE_DESC = u'Yahoo screen'
|
||||||
_VALID_URL = r'http://screen\.yahoo\.com/.*?-(?P<id>\d*?)\.html'
|
_VALID_URL = r'http://screen\.yahoo\.com/.*?-(?P<id>\d*?)\.html'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://screen.yahoo.com/julian-smith-travis-legg-watch-214727115.html',
|
||||||
|
u'file': u'214727115.flv',
|
||||||
|
u'md5': u'2e717f169c1be93d84d3794a00d4a325',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Julian Smith & Travis Legg Watch Julian Smith"
|
||||||
|
},
|
||||||
|
u'skip': u'Requires rtmpdump'
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
@@ -79,8 +88,7 @@ class YahooIE(InfoExtractor):
|
|||||||
return info_dict
|
return info_dict
|
||||||
|
|
||||||
class YahooSearchIE(SearchInfoExtractor):
|
class YahooSearchIE(SearchInfoExtractor):
|
||||||
"""Information Extractor for Yahoo! Video search queries."""
|
IE_DESC = u'Yahoo screen search'
|
||||||
|
|
||||||
_MAX_RESULTS = 1000
|
_MAX_RESULTS = 1000
|
||||||
IE_NAME = u'screen.yahoo:search'
|
IE_NAME = u'screen.yahoo:search'
|
||||||
_SEARCH_KEY = 'yvsearch'
|
_SEARCH_KEY = 'yvsearch'
|
||||||
|
@@ -8,6 +8,14 @@ from ..utils import (
|
|||||||
|
|
||||||
class YouJizzIE(InfoExtractor):
|
class YouJizzIE(InfoExtractor):
|
||||||
_VALID_URL = r'^(?:https?://)?(?:\w+\.)?youjizz\.com/videos/(?P<videoid>[^.]+).html$'
|
_VALID_URL = r'^(?:https?://)?(?:\w+\.)?youjizz\.com/videos/(?P<videoid>[^.]+).html$'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.youjizz.com/videos/zeichentrick-1-2189178.html',
|
||||||
|
u'file': u'2189178.flv',
|
||||||
|
u'md5': u'07e15fa469ba384c7693fd246905547c',
|
||||||
|
u'info_dict': {
|
||||||
|
u"title": u"Zeichentrick 1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
import random
|
import random
|
||||||
@@ -12,6 +14,16 @@ from ..utils import (
|
|||||||
|
|
||||||
class YoukuIE(InfoExtractor):
|
class YoukuIE(InfoExtractor):
|
||||||
_VALID_URL = r'(?:http://)?v\.youku\.com/v_show/id_(?P<ID>[A-Za-z0-9]+)\.html'
|
_VALID_URL = r'(?:http://)?v\.youku\.com/v_show/id_(?P<ID>[A-Za-z0-9]+)\.html'
|
||||||
|
_TEST = {
|
||||||
|
u"url": u"http://v.youku.com/v_show/id_XNDgyMDQ2NTQw.html",
|
||||||
|
u"file": u"XNDgyMDQ2NTQw_part00.flv",
|
||||||
|
u"md5": u"ffe3f2e435663dc2d1eea34faeff5b5b",
|
||||||
|
u"params": { u"test": False },
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"youtube-dl test video \"'/\\ä↭𝕐"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _gen_sid(self):
|
def _gen_sid(self):
|
||||||
nowTime = int(time.time() * 1000)
|
nowTime = int(time.time() * 1000)
|
||||||
|
@@ -16,6 +16,17 @@ from ..utils import (
|
|||||||
|
|
||||||
class YouPornIE(InfoExtractor):
|
class YouPornIE(InfoExtractor):
|
||||||
_VALID_URL = r'^(?:https?://)?(?:\w+\.)?youporn\.com/watch/(?P<videoid>[0-9]+)/(?P<title>[^/]+)'
|
_VALID_URL = r'^(?:https?://)?(?:\w+\.)?youporn\.com/watch/(?P<videoid>[0-9]+)/(?P<title>[^/]+)'
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.youporn.com/watch/505835/sex-ed-is-it-safe-to-masturbate-daily/',
|
||||||
|
u'file': u'505835.mp4',
|
||||||
|
u'md5': u'c37ddbaaa39058c76a7e86c6813423c1',
|
||||||
|
u'info_dict': {
|
||||||
|
u"upload_date": u"20101221",
|
||||||
|
u"description": u"Love & Sex Answers: http://bit.ly/DanAndJenn -- Is It Unhealthy To Masturbate Daily?",
|
||||||
|
u"uploader": u"Ask Dan And Jennifer",
|
||||||
|
u"title": u"Sex Ed: Is It Safe To Masturbate Daily?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def _print_formats(self, formats):
|
def _print_formats(self, formats):
|
||||||
"""Print all available formats"""
|
"""Print all available formats"""
|
||||||
|
@@ -23,8 +23,7 @@ from ..utils import (
|
|||||||
|
|
||||||
|
|
||||||
class YoutubeIE(InfoExtractor):
|
class YoutubeIE(InfoExtractor):
|
||||||
"""Information extractor for youtube.com."""
|
IE_DESC = u'YouTube.com'
|
||||||
|
|
||||||
_VALID_URL = r"""^
|
_VALID_URL = r"""^
|
||||||
(
|
(
|
||||||
(?:https?://)? # http(s):// (optional)
|
(?:https?://)? # http(s):// (optional)
|
||||||
@@ -34,7 +33,7 @@ class YoutubeIE(InfoExtractor):
|
|||||||
(?: # the various things that can precede the ID:
|
(?: # the various things that can precede the ID:
|
||||||
(?:(?:v|embed|e)/) # v/ or embed/ or e/
|
(?:(?:v|embed|e)/) # v/ or embed/ or e/
|
||||||
|(?: # or the v= param in all its forms
|
|(?: # or the v= param in all its forms
|
||||||
(?:watch(?:_popup)?(?:\.php)?)? # preceding watch(_popup|.php) or nothing (like /?v=xxxx)
|
(?:watch|movie(?:_popup)?(?:\.php)?)? # preceding watch(_popup|.php) or nothing (like /?v=xxxx)
|
||||||
(?:\?|\#!?) # the params delimiter ? or # or #!
|
(?:\?|\#!?) # the params delimiter ? or # or #!
|
||||||
(?:.*?&)? # any other preceding param (like /?s=tuff&v=xxxx)
|
(?:.*?&)? # any other preceding param (like /?s=tuff&v=xxxx)
|
||||||
v=
|
v=
|
||||||
@@ -81,6 +80,44 @@ class YoutubeIE(InfoExtractor):
|
|||||||
'46': '1080x1920',
|
'46': '1080x1920',
|
||||||
}
|
}
|
||||||
IE_NAME = u'youtube'
|
IE_NAME = u'youtube'
|
||||||
|
_TESTS = [
|
||||||
|
{
|
||||||
|
u"url": u"http://www.youtube.com/watch?v=BaW_jenozKc",
|
||||||
|
u"file": u"BaW_jenozKc.mp4",
|
||||||
|
u"info_dict": {
|
||||||
|
u"title": u"youtube-dl test video \"'/\\ä↭𝕐",
|
||||||
|
u"uploader": u"Philipp Hagemeister",
|
||||||
|
u"uploader_id": u"phihag",
|
||||||
|
u"upload_date": u"20121002",
|
||||||
|
u"description": u"test chars: \"'/\\ä↭𝕐\n\nThis is a test video for youtube-dl.\n\nFor more information, contact phihag@phihag.de ."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"url": u"http://www.youtube.com/watch?v=1ltcDfZMA3U",
|
||||||
|
u"file": u"1ltcDfZMA3U.flv",
|
||||||
|
u"note": u"Test VEVO video (#897)",
|
||||||
|
u"info_dict": {
|
||||||
|
u"upload_date": u"20070518",
|
||||||
|
u"title": u"Maps - It Will Find You",
|
||||||
|
u"description": u"Music video by Maps performing It Will Find You.",
|
||||||
|
u"uploader": u"MuteUSA",
|
||||||
|
u"uploader_id": u"MuteUSA"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"url": u"http://www.youtube.com/watch?v=UxxajLWwzqY",
|
||||||
|
u"file": u"UxxajLWwzqY.mp4",
|
||||||
|
u"note": u"Test generic use_cipher_signature video (#897)",
|
||||||
|
u"info_dict": {
|
||||||
|
u"upload_date": u"20120506",
|
||||||
|
u"title": u"Icona Pop - I Love It (feat. Charli XCX) [OFFICIAL VIDEO]",
|
||||||
|
u"description": u"md5:b085c9804f5ab69f4adea963a2dceb3c",
|
||||||
|
u"uploader": u"IconaPop",
|
||||||
|
u"uploader_id": u"IconaPop"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def suitable(cls, url):
|
def suitable(cls, url):
|
||||||
@@ -130,7 +167,7 @@ class YoutubeIE(InfoExtractor):
|
|||||||
self.to_screen(u'RTMP download detected')
|
self.to_screen(u'RTMP download detected')
|
||||||
|
|
||||||
def _decrypt_signature(self, s):
|
def _decrypt_signature(self, s):
|
||||||
"""Decrypt the key the two subkeys must have a length of 43"""
|
"""Turn the encrypted s field into a working signature"""
|
||||||
|
|
||||||
if len(s) == 88:
|
if len(s) == 88:
|
||||||
return s[48] + s[81:67:-1] + s[82] + s[66:62:-1] + s[85] + s[61:48:-1] + s[67] + s[47:12:-1] + s[3] + s[11:3:-1] + s[2] + s[12]
|
return s[48] + s[81:67:-1] + s[82] + s[66:62:-1] + s[85] + s[61:48:-1] + s[67] + s[47:12:-1] + s[3] + s[11:3:-1] + s[2] + s[12]
|
||||||
@@ -148,7 +185,7 @@ class YoutubeIE(InfoExtractor):
|
|||||||
return s[36] + s[79:67:-1] + s[81] + s[66:40:-1] + s[33] + s[39:36:-1] + s[40] + s[35] + s[0] + s[67] + s[32:0:-1] + s[34]
|
return s[36] + s[79:67:-1] + s[81] + s[66:40:-1] + s[33] + s[39:36:-1] + s[40] + s[35] + s[0] + s[67] + s[32:0:-1] + s[34]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ExtractorError(u'Unable to decrypt signature, subkeys length %d not supported; retrying might work' % (len(s)))
|
raise ExtractorError(u'Unable to decrypt signature, key length %d not supported; retrying might work' % (len(s)))
|
||||||
|
|
||||||
def _get_available_subtitles(self, video_id):
|
def _get_available_subtitles(self, video_id):
|
||||||
self.report_video_subtitles_download(video_id)
|
self.report_video_subtitles_download(video_id)
|
||||||
@@ -364,6 +401,9 @@ class YoutubeIE(InfoExtractor):
|
|||||||
return video_id
|
return video_id
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
|
if re.match(r'(?:https?://)?[^/]+/watch\?feature=[a-z_]+$', url):
|
||||||
|
self._downloader.report_warning(u'Did you forget to quote the URL? Remember that & is a meta-character in most shells, so you want to put the URL in quotes, like youtube-dl \'http://www.youtube.com/watch?feature=foo&v=BaW_jenozKc\' (or simply youtube-dl BaW_jenozKc ).')
|
||||||
|
|
||||||
# Extract original video URL from URL with redirection, like age verification, using next_url parameter
|
# Extract original video URL from URL with redirection, like age verification, using next_url parameter
|
||||||
mobj = re.search(self._NEXT_URL_RE, url)
|
mobj = re.search(self._NEXT_URL_RE, url)
|
||||||
if mobj:
|
if mobj:
|
||||||
@@ -401,7 +441,7 @@ class YoutubeIE(InfoExtractor):
|
|||||||
break
|
break
|
||||||
if 'token' not in video_info:
|
if 'token' not in video_info:
|
||||||
if 'reason' in video_info:
|
if 'reason' in video_info:
|
||||||
raise ExtractorError(u'YouTube said: %s' % video_info['reason'][0])
|
raise ExtractorError(u'YouTube said: %s' % video_info['reason'][0], expected=True)
|
||||||
else:
|
else:
|
||||||
raise ExtractorError(u'"token" parameter not in video info for unknown reason')
|
raise ExtractorError(u'"token" parameter not in video info for unknown reason')
|
||||||
|
|
||||||
@@ -545,7 +585,7 @@ class YoutubeIE(InfoExtractor):
|
|||||||
if req_format is None or req_format == 'best':
|
if req_format is None or req_format == 'best':
|
||||||
video_url_list = [(existing_formats[0], url_map[existing_formats[0]])] # Best quality
|
video_url_list = [(existing_formats[0], url_map[existing_formats[0]])] # Best quality
|
||||||
elif req_format == 'worst':
|
elif req_format == 'worst':
|
||||||
video_url_list = [(existing_formats[len(existing_formats)-1], url_map[existing_formats[len(existing_formats)-1]])] # worst quality
|
video_url_list = [(existing_formats[-1], url_map[existing_formats[-1]])] # worst quality
|
||||||
elif req_format in ('-1', 'all'):
|
elif req_format in ('-1', 'all'):
|
||||||
video_url_list = [(f, url_map[f]) for f in existing_formats] # All formats
|
video_url_list = [(f, url_map[f]) for f in existing_formats] # All formats
|
||||||
else:
|
else:
|
||||||
@@ -588,8 +628,7 @@ class YoutubeIE(InfoExtractor):
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
class YoutubePlaylistIE(InfoExtractor):
|
class YoutubePlaylistIE(InfoExtractor):
|
||||||
"""Information Extractor for YouTube playlists."""
|
IE_DESC = u'YouTube.com playlists'
|
||||||
|
|
||||||
_VALID_URL = r"""(?:
|
_VALID_URL = r"""(?:
|
||||||
(?:https?://)?
|
(?:https?://)?
|
||||||
(?:\w+\.)?
|
(?:\w+\.)?
|
||||||
@@ -656,8 +695,7 @@ class YoutubePlaylistIE(InfoExtractor):
|
|||||||
|
|
||||||
|
|
||||||
class YoutubeChannelIE(InfoExtractor):
|
class YoutubeChannelIE(InfoExtractor):
|
||||||
"""Information Extractor for YouTube channels."""
|
IE_DESC = u'YouTube.com channels'
|
||||||
|
|
||||||
_VALID_URL = r"^(?:https?://)?(?:youtu\.be|(?:\w+\.)?youtube(?:-nocookie)?\.com)/channel/([0-9A-Za-z_-]+)"
|
_VALID_URL = r"^(?:https?://)?(?:youtu\.be|(?:\w+\.)?youtube(?:-nocookie)?\.com)/channel/([0-9A-Za-z_-]+)"
|
||||||
_TEMPLATE_URL = 'http://www.youtube.com/channel/%s/videos?sort=da&flow=list&view=0&page=%s&gl=US&hl=en'
|
_TEMPLATE_URL = 'http://www.youtube.com/channel/%s/videos?sort=da&flow=list&view=0&page=%s&gl=US&hl=en'
|
||||||
_MORE_PAGES_INDICATOR = 'yt-uix-load-more'
|
_MORE_PAGES_INDICATOR = 'yt-uix-load-more'
|
||||||
@@ -715,8 +753,7 @@ class YoutubeChannelIE(InfoExtractor):
|
|||||||
|
|
||||||
|
|
||||||
class YoutubeUserIE(InfoExtractor):
|
class YoutubeUserIE(InfoExtractor):
|
||||||
"""Information Extractor for YouTube users."""
|
IE_DESC = u'YouTube.com user videos (URL or "ytuser" keyword)'
|
||||||
|
|
||||||
_VALID_URL = r'(?:(?:(?:https?://)?(?:\w+\.)?youtube\.com/user/)|ytuser:)([A-Za-z0-9_-]+)'
|
_VALID_URL = r'(?:(?:(?:https?://)?(?:\w+\.)?youtube\.com/user/)|ytuser:)([A-Za-z0-9_-]+)'
|
||||||
_TEMPLATE_URL = 'http://gdata.youtube.com/feeds/api/users/%s'
|
_TEMPLATE_URL = 'http://gdata.youtube.com/feeds/api/users/%s'
|
||||||
_GDATA_PAGE_SIZE = 50
|
_GDATA_PAGE_SIZE = 50
|
||||||
@@ -772,7 +809,7 @@ class YoutubeUserIE(InfoExtractor):
|
|||||||
return [self.playlist_result(url_results, playlist_title = username)]
|
return [self.playlist_result(url_results, playlist_title = username)]
|
||||||
|
|
||||||
class YoutubeSearchIE(SearchInfoExtractor):
|
class YoutubeSearchIE(SearchInfoExtractor):
|
||||||
"""Information Extractor for YouTube search queries."""
|
IE_DESC = u'YouTube.com searches'
|
||||||
_API_URL = 'https://gdata.youtube.com/feeds/api/videos?q=%s&start-index=%i&max-results=50&v=2&alt=jsonc'
|
_API_URL = 'https://gdata.youtube.com/feeds/api/videos?q=%s&start-index=%i&max-results=50&v=2&alt=jsonc'
|
||||||
_MAX_RESULTS = 1000
|
_MAX_RESULTS = 1000
|
||||||
IE_NAME = u'youtube:search'
|
IE_NAME = u'youtube:search'
|
||||||
@@ -812,3 +849,18 @@ class YoutubeSearchIE(SearchInfoExtractor):
|
|||||||
video_ids = video_ids[:n]
|
video_ids = video_ids[:n]
|
||||||
videos = [self.url_result('http://www.youtube.com/watch?v=%s' % id, 'Youtube') for id in video_ids]
|
videos = [self.url_result('http://www.youtube.com/watch?v=%s' % id, 'Youtube') for id in video_ids]
|
||||||
return self.playlist_result(videos, query)
|
return self.playlist_result(videos, query)
|
||||||
|
|
||||||
|
|
||||||
|
class YoutubeShowIE(InfoExtractor):
|
||||||
|
IE_DESC = u'YouTube.com (multi-season) shows'
|
||||||
|
_VALID_URL = r'https?://www\.youtube\.com/show/(.*)'
|
||||||
|
IE_NAME = u'youtube:show'
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
show_name = mobj.group(1)
|
||||||
|
webpage = self._download_webpage(url, show_name, u'Downloading show webpage')
|
||||||
|
# There's one playlist for each season of the show
|
||||||
|
m_seasons = list(re.finditer(r'href="(/playlist\?list=.*?)"', webpage))
|
||||||
|
self.to_screen(u'%s: Found %s seasons' % (show_name, len(m_seasons)))
|
||||||
|
return [self.url_result('https://www.youtube.com' + season.group(1), 'YoutubePlaylist') for season in m_seasons]
|
||||||
|
@@ -44,7 +44,7 @@ def update_self(to_screen, verbose, filename):
|
|||||||
|
|
||||||
|
|
||||||
if not isinstance(globals().get('__loader__'), zipimporter) and not hasattr(sys, "frozen"):
|
if not isinstance(globals().get('__loader__'), zipimporter) and not hasattr(sys, "frozen"):
|
||||||
to_screen(u'It looks like you installed youtube-dl with pip, setup.py or a tarball. Please use that to update.')
|
to_screen(u'It looks like you installed youtube-dl with a package manager, pip, setup.py or a tarball. Please use that to update.')
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check if there is a new version
|
# Check if there is a new version
|
||||||
|
@@ -470,11 +470,15 @@ def make_HTTPS_handler(opts):
|
|||||||
|
|
||||||
class ExtractorError(Exception):
|
class ExtractorError(Exception):
|
||||||
"""Error during info extraction."""
|
"""Error during info extraction."""
|
||||||
def __init__(self, msg, tb=None):
|
def __init__(self, msg, tb=None, expected=False):
|
||||||
""" tb, if given, is the original traceback (so that it can be printed out). """
|
""" tb, if given, is the original traceback (so that it can be printed out).
|
||||||
|
If expected is set, this is a normal error message and most likely not a bug in youtube-dl.
|
||||||
|
"""
|
||||||
|
|
||||||
if not sys.exc_info()[0] in (compat_urllib_error.URLError, socket.timeout, UnavailableVideoError):
|
if sys.exc_info()[0] in (compat_urllib_error.URLError, socket.timeout, UnavailableVideoError):
|
||||||
msg = msg + u'; please report this issue on http://yt-dl.org/bug'
|
expected = True
|
||||||
|
if not expected:
|
||||||
|
msg = msg + u'; please report this issue on https://yt-dl.org/bug . Be sure to call youtube-dl with the --verbose flag and include its complete output.'
|
||||||
super(ExtractorError, self).__init__(msg)
|
super(ExtractorError, self).__init__(msg)
|
||||||
|
|
||||||
self.traceback = tb
|
self.traceback = tb
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
|
|
||||||
__version__ = '2013.06.34'
|
__version__ = '2013.07.05'
|
||||||
|
Reference in New Issue
Block a user