mirror of
https://source.netsyms.com/Mirrors/youtube-dl
synced 2026-04-23 15:24:06 +00:00
Compare commits
83 Commits
2015.12.06
...
2015.12.13
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3711edcf1 | ||
|
|
22d07ba4e4 | ||
|
|
f6abca506e | ||
|
|
b5424acdb9 | ||
|
|
47c7f3d995 | ||
|
|
0014ffa829 | ||
|
|
c03943f394 | ||
|
|
deb1e8d20e | ||
|
|
174964a7bc | ||
|
|
9c568178fb | ||
|
|
dbb7d7e26c | ||
|
|
ade2340971 | ||
|
|
4d77550cf0 | ||
|
|
c683454e7e | ||
|
|
f133fd326b | ||
|
|
1faa66f005 | ||
|
|
8773f3158f | ||
|
|
7e37c39485 | ||
|
|
14c17cafa1 | ||
|
|
8696a7fd13 | ||
|
|
d63cfc3f0f | ||
|
|
f377f44dae | ||
|
|
0b1bb1ac3a | ||
|
|
f208e52a76 | ||
|
|
b091529a3c | ||
|
|
b323a3cbff | ||
|
|
b59623ef43 | ||
|
|
9c163950da | ||
|
|
d357bbd375 | ||
|
|
f542a3d26b | ||
|
|
59a4ff482a | ||
|
|
40ca5b04f4 | ||
|
|
411e5b88c9 | ||
|
|
b4c299bad0 | ||
|
|
ab4bdc913f | ||
|
|
1fe248a51b | ||
|
|
2559b9d017 | ||
|
|
4db43567e8 | ||
|
|
5333842a1d | ||
|
|
98c3806b15 | ||
|
|
b6afc225c8 | ||
|
|
ad30dc1e20 | ||
|
|
ff51983e15 | ||
|
|
fdf01663d1 | ||
|
|
4b94288301 | ||
|
|
4bf99ade15 | ||
|
|
75ed53320e | ||
|
|
17b786ae73 | ||
|
|
dfd42a43c3 | ||
|
|
f7b8dd63f0 | ||
|
|
a8abf124c8 | ||
|
|
176ccefcd8 | ||
|
|
cbd2ffd031 | ||
|
|
0b534d2adc | ||
|
|
526a20bd16 | ||
|
|
51094b1b08 | ||
|
|
f1ac2033ab | ||
|
|
a1b8d815f5 | ||
|
|
8b756bd98e | ||
|
|
46047c58d0 | ||
|
|
374c761e77 | ||
|
|
6c7b26e13f | ||
|
|
b51b108045 | ||
|
|
86e8c89488 | ||
|
|
47f48f5d85 | ||
|
|
e15e2ef7a0 | ||
|
|
d0c8b279da | ||
|
|
612d83b51d | ||
|
|
9c30efeb7e | ||
|
|
39fa4cc107 | ||
|
|
b09c122373 | ||
|
|
3348243b7b | ||
|
|
b46b65ed37 | ||
|
|
18e4088fad | ||
|
|
5fd6cd64f9 | ||
|
|
3d24bbfbe4 | ||
|
|
1775612512 | ||
|
|
0d2d967cc7 | ||
|
|
a5e52a1fd4 | ||
|
|
291a93bafa | ||
|
|
c4737bea17 | ||
|
|
45dad7ba1b | ||
|
|
db7c9da871 |
2
AUTHORS
2
AUTHORS
@@ -147,3 +147,5 @@ Qijiang Fan
|
|||||||
Rémy Léone
|
Rémy Léone
|
||||||
Marco Ferragina
|
Marco Ferragina
|
||||||
reiv
|
reiv
|
||||||
|
Muratcan Simsek
|
||||||
|
Evan Lu
|
||||||
|
|||||||
@@ -1,4 +1,18 @@
|
|||||||
**Please include the full output of youtube-dl when run with `-v`**.
|
**Please include the full output of youtube-dl when run with `-v`**, i.e. add `-v` flag to your command line, copy the **whole** output and post it in the issue body wrapped in \`\`\` for better formatting. It should look similar to this:
|
||||||
|
```
|
||||||
|
$ youtube-dl -v http://www.youtube.com/watch?v=BaW_jenozKcj
|
||||||
|
[debug] System config: []
|
||||||
|
[debug] User config: []
|
||||||
|
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
||||||
|
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
||||||
|
[debug] youtube-dl version 2015.12.06
|
||||||
|
[debug] Git HEAD: 135392e
|
||||||
|
[debug] Python version 2.6.6 - Windows-2003Server-5.2.3790-SP2
|
||||||
|
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
...
|
||||||
|
```
|
||||||
|
**Do not post screenshots of verbose log only plain text is acceptable.**
|
||||||
|
|
||||||
The output (including the first lines) contains important debugging information. Issues without the full output are often not reproducible and therefore do not get solved in short order, if ever.
|
The output (including the first lines) contains important debugging information. Issues without the full output are often not reproducible and therefore do not get solved in short order, if ever.
|
||||||
|
|
||||||
@@ -20,7 +34,7 @@ For bug reports, this means that your report should contain the *complete* outpu
|
|||||||
|
|
||||||
If your server has multiple IPs or you suspect censorship, adding `--call-home` may be a good idea to get more diagnostics. If the error is `ERROR: Unable to extract ...` and you cannot reproduce it from multiple countries, add `--dump-pages` (warning: this will yield a rather large output, redirect it to the file `log.txt` by adding `>log.txt 2>&1` to your command-line) or upload the `.dump` files you get when you add `--write-pages` [somewhere](https://gist.github.com/).
|
If your server has multiple IPs or you suspect censorship, adding `--call-home` may be a good idea to get more diagnostics. If the error is `ERROR: Unable to extract ...` and you cannot reproduce it from multiple countries, add `--dump-pages` (warning: this will yield a rather large output, redirect it to the file `log.txt` by adding `>log.txt 2>&1` to your command-line) or upload the `.dump` files you get when you add `--write-pages` [somewhere](https://gist.github.com/).
|
||||||
|
|
||||||
**Site support requests must contain an example URL**. An example URL is a URL you might want to download, like http://www.youtube.com/watch?v=BaW_jenozKc . There should be an obvious video present. Except under very special circumstances, the main page of a video service (e.g. http://www.youtube.com/ ) is *not* an example URL.
|
**Site support requests must contain an example URL**. An example URL is a URL you might want to download, like `http://www.youtube.com/watch?v=BaW_jenozKc`. There should be an obvious video present. Except under very special circumstances, the main page of a video service (e.g. `http://www.youtube.com/`) is *not* an example URL.
|
||||||
|
|
||||||
### Are you using the latest version?
|
### Are you using the latest version?
|
||||||
|
|
||||||
@@ -28,7 +42,7 @@ Before reporting any issue, type `youtube-dl -U`. This should report that you're
|
|||||||
|
|
||||||
### Is the issue already documented?
|
### Is the issue already documented?
|
||||||
|
|
||||||
Make sure that someone has not already opened the issue you're trying to open. Search at the top of the window or at https://github.com/rg3/youtube-dl/search?type=Issues . If there is an issue, feel free to write something along the lines of "This affects me as well, with version 2015.01.01. Here is some more information on the issue: ...". While some issues may be old, a new post into them often spurs rapid activity.
|
Make sure that someone has not already opened the issue you're trying to open. Search at the top of the window or browse the [GitHub Issues](https://github.com/rg3/youtube-dl/search?type=Issues) of this repository. If there is an issue, feel free to write something along the lines of "This affects me as well, with version 2015.01.01. Here is some more information on the issue: ...". While some issues may be old, a new post into them often spurs rapid activity.
|
||||||
|
|
||||||
### Why are existing options not enough?
|
### Why are existing options not enough?
|
||||||
|
|
||||||
|
|||||||
36
README.md
36
README.md
@@ -35,7 +35,7 @@ You can also use pip:
|
|||||||
|
|
||||||
sudo pip install youtube-dl
|
sudo pip install youtube-dl
|
||||||
|
|
||||||
Alternatively, refer to the [developer instructions](#developer-instructions) for how to check out and work with the git repository. For further options, including PGP signatures, see https://rg3.github.io/youtube-dl/download.html .
|
Alternatively, refer to the [developer instructions](#developer-instructions) for how to check out and work with the git repository. For further options, including PGP signatures, see the [youtube-dl Download Page](https://rg3.github.io/youtube-dl/download.html).
|
||||||
|
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
**youtube-dl** is a small command-line program to download videos from
|
**youtube-dl** is a small command-line program to download videos from
|
||||||
@@ -414,7 +414,7 @@ You can configure youtube-dl by placing any supported command line option to a c
|
|||||||
|
|
||||||
You can use `--ignore-config` if you want to disable the configuration file for a particular youtube-dl run.
|
You can use `--ignore-config` if you want to disable the configuration file for a particular youtube-dl run.
|
||||||
|
|
||||||
### Authentication with `.netrc` file ###
|
### Authentication with `.netrc` file
|
||||||
|
|
||||||
You may also want to configure automatic credentials storage for extractors that support authentication (by providing login and password with `--username` and `--password`) in order not to pass credentials as command line arguments on every youtube-dl execution and prevent tracking plain text passwords in the shell command history. You can achieve this using a [`.netrc` file](http://stackoverflow.com/tags/.netrc/info) on per extractor basis. For that you will need to create a`.netrc` file in your `$HOME` and restrict permissions to read/write by you only:
|
You may also want to configure automatic credentials storage for extractors that support authentication (by providing login and password with `--username` and `--password`) in order not to pass credentials as command line arguments on every youtube-dl execution and prevent tracking plain text passwords in the shell command history. You can achieve this using a [`.netrc` file](http://stackoverflow.com/tags/.netrc/info) on per extractor basis. For that you will need to create a`.netrc` file in your `$HOME` and restrict permissions to read/write by you only:
|
||||||
```
|
```
|
||||||
@@ -559,11 +559,11 @@ If you want to play the video on a machine that is not running youtube-dl, you c
|
|||||||
|
|
||||||
YouTube has switched to a new video info format in July 2011 which is not supported by old versions of youtube-dl. See [above](#how-do-i-update-youtube-dl) for how to update youtube-dl.
|
YouTube has switched to a new video info format in July 2011 which is not supported by old versions of youtube-dl. See [above](#how-do-i-update-youtube-dl) for how to update youtube-dl.
|
||||||
|
|
||||||
### ERROR: unable to download video ###
|
### ERROR: unable to download video
|
||||||
|
|
||||||
YouTube requires an additional signature since September 2012 which is not supported by old versions of youtube-dl. See [above](#how-do-i-update-youtube-dl) for how to update youtube-dl.
|
YouTube requires an additional signature since September 2012 which is not supported by old versions of youtube-dl. See [above](#how-do-i-update-youtube-dl) for how to update youtube-dl.
|
||||||
|
|
||||||
### Video URL contains an ampersand and I'm getting some strange output `[1] 2839` or `'v' is not recognized as an internal or external command` ###
|
### Video URL contains an ampersand and I'm getting some strange output `[1] 2839` or `'v' is not recognized as an internal or external command`
|
||||||
|
|
||||||
That's actually the output from your shell. Since ampersand is one of the special shell characters it's interpreted by the shell preventing you from passing the whole URL to youtube-dl. To disable your shell from interpreting the ampersands (or any other special characters) you have to either put the whole URL in quotes or escape them with a backslash (which approach will work depends on your shell).
|
That's actually the output from your shell. Since ampersand is one of the special shell characters it's interpreted by the shell preventing you from passing the whole URL to youtube-dl. To disable your shell from interpreting the ampersands (or any other special characters) you have to either put the whole URL in quotes or escape them with a backslash (which approach will work depends on your shell).
|
||||||
|
|
||||||
@@ -587,7 +587,7 @@ In February 2015, the new YouTube player contained a character sequence in a str
|
|||||||
|
|
||||||
These two error codes indicate that the service is blocking your IP address because of overuse. Contact the service and ask them to unblock your IP address, or - if you have acquired a whitelisted IP address already - use the [`--proxy` or `--source-address` options](#network-options) to select another IP address.
|
These two error codes indicate that the service is blocking your IP address because of overuse. Contact the service and ask them to unblock your IP address, or - if you have acquired a whitelisted IP address already - use the [`--proxy` or `--source-address` options](#network-options) to select another IP address.
|
||||||
|
|
||||||
### SyntaxError: Non-ASCII character ###
|
### SyntaxError: Non-ASCII character
|
||||||
|
|
||||||
The error
|
The error
|
||||||
|
|
||||||
@@ -616,7 +616,7 @@ From then on, after restarting your shell, you will be able to access both youtu
|
|||||||
|
|
||||||
Use the `-o` to specify an [output template](#output-template), for example `-o "/home/user/videos/%(title)s-%(id)s.%(ext)s"`. If you want this for all of your downloads, put the option into your [configuration file](#configuration).
|
Use the `-o` to specify an [output template](#output-template), for example `-o "/home/user/videos/%(title)s-%(id)s.%(ext)s"`. If you want this for all of your downloads, put the option into your [configuration file](#configuration).
|
||||||
|
|
||||||
### How do I download a video starting with a `-` ?
|
### How do I download a video starting with a `-`?
|
||||||
|
|
||||||
Either prepend `http://www.youtube.com/watch?v=` or separate the ID from the options with `--`:
|
Either prepend `http://www.youtube.com/watch?v=` or separate the ID from the options with `--`:
|
||||||
|
|
||||||
@@ -798,9 +798,23 @@ with youtube_dl.YoutubeDL(ydl_opts) as ydl:
|
|||||||
|
|
||||||
# BUGS
|
# BUGS
|
||||||
|
|
||||||
Bugs and suggestions should be reported at: <https://github.com/rg3/youtube-dl/issues> . Unless you were prompted so or there is another pertinent reason (e.g. GitHub fails to accept the bug report), please do not send bug reports via personal email. For discussions, join us in the irc channel #youtube-dl on freenode.
|
Bugs and suggestions should be reported at: <https://github.com/rg3/youtube-dl/issues>. Unless you were prompted so or there is another pertinent reason (e.g. GitHub fails to accept the bug report), please do not send bug reports via personal email. For discussions, join us in the IRC channel [#youtube-dl](irc://chat.freenode.net/#youtube-dl) on freenode ([webchat](http://webchat.freenode.net/?randomnick=1&channels=youtube-dl)).
|
||||||
|
|
||||||
**Please include the full output of youtube-dl when run with `-v`**.
|
**Please include the full output of youtube-dl when run with `-v`**, i.e. add `-v` flag to your command line, copy the **whole** output and post it in the issue body wrapped in \`\`\` for better formatting. It should look similar to this:
|
||||||
|
```
|
||||||
|
$ youtube-dl -v http://www.youtube.com/watch?v=BaW_jenozKcj
|
||||||
|
[debug] System config: []
|
||||||
|
[debug] User config: []
|
||||||
|
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
||||||
|
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
||||||
|
[debug] youtube-dl version 2015.12.06
|
||||||
|
[debug] Git HEAD: 135392e
|
||||||
|
[debug] Python version 2.6.6 - Windows-2003Server-5.2.3790-SP2
|
||||||
|
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
...
|
||||||
|
```
|
||||||
|
**Do not post screenshots of verbose log only plain text is acceptable.**
|
||||||
|
|
||||||
The output (including the first lines) contains important debugging information. Issues without the full output are often not reproducible and therefore do not get solved in short order, if ever.
|
The output (including the first lines) contains important debugging information. Issues without the full output are often not reproducible and therefore do not get solved in short order, if ever.
|
||||||
|
|
||||||
@@ -822,7 +836,7 @@ For bug reports, this means that your report should contain the *complete* outpu
|
|||||||
|
|
||||||
If your server has multiple IPs or you suspect censorship, adding `--call-home` may be a good idea to get more diagnostics. If the error is `ERROR: Unable to extract ...` and you cannot reproduce it from multiple countries, add `--dump-pages` (warning: this will yield a rather large output, redirect it to the file `log.txt` by adding `>log.txt 2>&1` to your command-line) or upload the `.dump` files you get when you add `--write-pages` [somewhere](https://gist.github.com/).
|
If your server has multiple IPs or you suspect censorship, adding `--call-home` may be a good idea to get more diagnostics. If the error is `ERROR: Unable to extract ...` and you cannot reproduce it from multiple countries, add `--dump-pages` (warning: this will yield a rather large output, redirect it to the file `log.txt` by adding `>log.txt 2>&1` to your command-line) or upload the `.dump` files you get when you add `--write-pages` [somewhere](https://gist.github.com/).
|
||||||
|
|
||||||
**Site support requests must contain an example URL**. An example URL is a URL you might want to download, like http://www.youtube.com/watch?v=BaW_jenozKc . There should be an obvious video present. Except under very special circumstances, the main page of a video service (e.g. http://www.youtube.com/ ) is *not* an example URL.
|
**Site support requests must contain an example URL**. An example URL is a URL you might want to download, like `http://www.youtube.com/watch?v=BaW_jenozKc`. There should be an obvious video present. Except under very special circumstances, the main page of a video service (e.g. `http://www.youtube.com/`) is *not* an example URL.
|
||||||
|
|
||||||
### Are you using the latest version?
|
### Are you using the latest version?
|
||||||
|
|
||||||
@@ -830,7 +844,7 @@ Before reporting any issue, type `youtube-dl -U`. This should report that you're
|
|||||||
|
|
||||||
### Is the issue already documented?
|
### Is the issue already documented?
|
||||||
|
|
||||||
Make sure that someone has not already opened the issue you're trying to open. Search at the top of the window or at https://github.com/rg3/youtube-dl/search?type=Issues . If there is an issue, feel free to write something along the lines of "This affects me as well, with version 2015.01.01. Here is some more information on the issue: ...". While some issues may be old, a new post into them often spurs rapid activity.
|
Make sure that someone has not already opened the issue you're trying to open. Search at the top of the window or browse the [GitHub Issues](https://github.com/rg3/youtube-dl/search?type=Issues) of this repository. If there is an issue, feel free to write something along the lines of "This affects me as well, with version 2015.01.01. Here is some more information on the issue: ...". While some issues may be old, a new post into them often spurs rapid activity.
|
||||||
|
|
||||||
### Why are existing options not enough?
|
### Why are existing options not enough?
|
||||||
|
|
||||||
@@ -860,4 +874,4 @@ It may sound strange, but some bug reports we receive are completely unrelated t
|
|||||||
|
|
||||||
youtube-dl is released into the public domain by the copyright holders.
|
youtube-dl is released into the public domain by the copyright holders.
|
||||||
|
|
||||||
This README file was originally written by Daniel Bolton (<https://github.com/dbbolton>) and is likewise released into the public domain.
|
This README file was originally written by [Daniel Bolton](https://github.com/dbbolton) and is likewise released into the public domain.
|
||||||
|
|||||||
@@ -188,6 +188,7 @@
|
|||||||
- **Freesound**
|
- **Freesound**
|
||||||
- **freespeech.org**
|
- **freespeech.org**
|
||||||
- **FreeVideo**
|
- **FreeVideo**
|
||||||
|
- **Funimation**
|
||||||
- **FunnyOrDie**
|
- **FunnyOrDie**
|
||||||
- **GameInformer**
|
- **GameInformer**
|
||||||
- **Gamekings**
|
- **Gamekings**
|
||||||
@@ -400,7 +401,7 @@
|
|||||||
- **orf:tvthek**: ORF TVthek
|
- **orf:tvthek**: ORF TVthek
|
||||||
- **parliamentlive.tv**: UK parliament videos
|
- **parliamentlive.tv**: UK parliament videos
|
||||||
- **Patreon**
|
- **Patreon**
|
||||||
- **PBS**
|
- **pbs**: Public Broadcasting Service (PBS) and member stations: PBS: Public Broadcasting Service, APT - Alabama Public Television (WBIQ), GPB/Georgia Public Broadcasting (WGTV), Mississippi Public Broadcasting (WMPN), Nashville Public Television (WNPT), WFSU-TV (WFSU), WSRE (WSRE), WTCI (WTCI), WPBA/Channel 30 (WPBA), Alaska Public Media (KAKM), Arizona PBS (KAET), KNME-TV/Channel 5 (KNME), Vegas PBS (KLVX), AETN/ARKANSAS ETV NETWORK (KETS), KET (WKLE), WKNO/Channel 10 (WKNO), LPB/LOUISIANA PUBLIC BROADCASTING (WLPB), OETA (KETA), Ozarks Public Television (KOZK), WSIU Public Broadcasting (WSIU), KEET TV (KEET), KIXE/Channel 9 (KIXE), KPBS San Diego (KPBS), KQED (KQED), KVIE Public Television (KVIE), PBS SoCal/KOCE (KOCE), ValleyPBS (KVPT), CONNECTICUT PUBLIC TELEVISION (WEDH), KNPB Channel 5 (KNPB), SOPTV (KSYS), Rocky Mountain PBS (KRMA), KENW-TV3 (KENW), KUED Channel 7 (KUED), Wyoming PBS (KCWC), Colorado Public Television / KBDI 12 (KBDI), KBYU-TV (KBYU), Thirteen/WNET New York (WNET), WGBH/Channel 2 (WGBH), WGBY (WGBY), NJTV Public Media NJ (WNJT), WLIW21 (WLIW), mpt/Maryland Public Television (WMPB), WETA Television and Radio (WETA), WHYY (WHYY), PBS 39 (WLVT), WVPT - Your Source for PBS and More! (WVPT), Howard University Television (WHUT), WEDU PBS (WEDU), WGCU Public Media (WGCU), WPBT2 (WPBT), WUCF TV (WUCF), WUFT/Channel 5 (WUFT), WXEL/Channel 42 (WXEL), WLRN/Channel 17 (WLRN), WUSF Public Broadcasting (WUSF), ETV (WRLK), UNC-TV (WUNC), PBS Hawaii - Oceanic Cable Channel 10 (KHET), Idaho Public Television (KAID), KSPS (KSPS), OPB (KOPB), KWSU/Channel 10 & KTNW/Channel 31 (KWSU), WILL-TV (WILL), Network Knowledge - WSEC/Springfield (WSEC), WTTW11 (WTTW), Iowa Public Television/IPTV (KDIN), Nine Network (KETC), PBS39 Fort Wayne (WFWA), WFYI Indianapolis (WFYI), Milwaukee Public Television (WMVS), WNIN (WNIN), WNIT Public Television (WNIT), WPT (WPNE), WVUT/Channel 22 (WVUT), WEIU/Channel 51 (WEIU), WQPT-TV (WQPT), WYCC PBS Chicago (WYCC), WIPB-TV (WIPB), WTIU (WTIU), CET (WCET), ThinkTVNetwork (WPTD), WBGU-TV (WBGU), WGVU TV (WGVU), NET1 (KUON), Pioneer Public Television (KWCM), SDPB Television (KUSD), TPT (KTCA), KSMQ (KSMQ), KPTS/Channel 8 (KPTS), KTWU/Channel 11 (KTWU), East Tennessee PBS (WSJK), WCTE-TV (WCTE), WLJT, Channel 11 (WLJT), WOSU TV (WOSU), WOUB/WOUC (WOUB), WVPB (WVPB), WKYU-PBS (WKYU), KERA 13 (KERA), MPBN (WCBB), Mountain Lake PBS (WCFE), NHPTV (WENH), Vermont PBS (WETK), witf (WITF), WQED Multimedia (WQED), WMHT Educational Telecommunications (WMHT), Q-TV (WDCQ), WTVS Detroit Public TV (WTVS), CMU Public Television (WCMU), WKAR-TV (WKAR), WNMU-TV Public TV 13 (WNMU), WDSE - WRPT (WDSE), WGTE TV (WGTE), Lakeland Public Television (KAWE), KMOS-TV - Channels 6.1, 6.2 and 6.3 (KMOS), MontanaPBS (KUSM), KRWG/Channel 22 (KRWG), KACV (KACV), KCOS/Channel 13 (KCOS), WCNY/Channel 24 (WCNY), WNED (WNED), WPBS (WPBS), WSKG Public TV (WSKG), WXXI (WXXI), WPSU (WPSU), WVIA Public Media Studios (WVIA), WTVI (WTVI), Western Reserve PBS (WNEO), WVIZ/PBS ideastream (WVIZ), KCTS 9 (KCTS), Basin PBS (KPBT), KUHT / Channel 8 (KUHT), KLRN (KLRN), KLRU (KLRU), WTJX Channel 12 (WTJX), WCVE PBS (WCVE), KBTC Public Television (KBTC)
|
||||||
- **Periscope**: Periscope
|
- **Periscope**: Periscope
|
||||||
- **PhilharmonieDeParis**: Philharmonie de Paris
|
- **PhilharmonieDeParis**: Philharmonie de Paris
|
||||||
- **Phoenix**
|
- **Phoenix**
|
||||||
|
|||||||
@@ -121,8 +121,8 @@ class TestAllURLsMatching(unittest.TestCase):
|
|||||||
|
|
||||||
def test_pbs(self):
|
def test_pbs(self):
|
||||||
# https://github.com/rg3/youtube-dl/issues/2350
|
# https://github.com/rg3/youtube-dl/issues/2350
|
||||||
self.assertMatch('http://video.pbs.org/viralplayer/2365173446/', ['PBS'])
|
self.assertMatch('http://video.pbs.org/viralplayer/2365173446/', ['pbs'])
|
||||||
self.assertMatch('http://video.pbs.org/widget/partnerplayer/980042464/', ['PBS'])
|
self.assertMatch('http://video.pbs.org/widget/partnerplayer/980042464/', ['pbs'])
|
||||||
|
|
||||||
def test_yahoo_https(self):
|
def test_yahoo_https(self):
|
||||||
# https://github.com/rg3/youtube-dl/issues/2701
|
# https://github.com/rg3/youtube-dl/issues/2701
|
||||||
|
|||||||
@@ -1110,6 +1110,12 @@ class YoutubeDL(object):
|
|||||||
'contain the video, try using '
|
'contain the video, try using '
|
||||||
'"-f %s+%s"' % (format_2, format_1))
|
'"-f %s+%s"' % (format_2, format_1))
|
||||||
return
|
return
|
||||||
|
# Formats must be opposite (video+audio)
|
||||||
|
if formats_info[0].get('acodec') == 'none' and formats_info[1].get('acodec') == 'none':
|
||||||
|
self.report_error(
|
||||||
|
'Both formats %s and %s are video-only, you must specify "-f video+audio"'
|
||||||
|
% (format_1, format_2))
|
||||||
|
return
|
||||||
output_ext = (
|
output_ext = (
|
||||||
formats_info[0]['ext']
|
formats_info[0]['ext']
|
||||||
if self.params.get('merge_output_format') is None
|
if self.params.get('merge_output_format') is None
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from ..compat import (
|
|||||||
)
|
)
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
encodeFilename,
|
encodeFilename,
|
||||||
|
fix_xml_ampersands,
|
||||||
sanitize_open,
|
sanitize_open,
|
||||||
struct_pack,
|
struct_pack,
|
||||||
struct_unpack,
|
struct_unpack,
|
||||||
@@ -288,7 +289,10 @@ class F4mFD(FragmentFD):
|
|||||||
self.to_screen('[%s] Downloading f4m manifest' % self.FD_NAME)
|
self.to_screen('[%s] Downloading f4m manifest' % self.FD_NAME)
|
||||||
urlh = self.ydl.urlopen(man_url)
|
urlh = self.ydl.urlopen(man_url)
|
||||||
man_url = urlh.geturl()
|
man_url = urlh.geturl()
|
||||||
manifest = urlh.read()
|
# Some manifests may be malformed, e.g. prosiebensat1 generated manifests
|
||||||
|
# (see https://github.com/rg3/youtube-dl/issues/6215#issuecomment-121704244
|
||||||
|
# and https://github.com/rg3/youtube-dl/issues/7823)
|
||||||
|
manifest = fix_xml_ampersands(urlh.read().decode('utf-8', 'ignore')).strip()
|
||||||
|
|
||||||
doc = compat_etree_fromstring(manifest)
|
doc = compat_etree_fromstring(manifest)
|
||||||
formats = [(int(f.attrib.get('bitrate', -1)), f)
|
formats = [(int(f.attrib.get('bitrate', -1)), f)
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ from .francetv import (
|
|||||||
from .freesound import FreesoundIE
|
from .freesound import FreesoundIE
|
||||||
from .freespeech import FreespeechIE
|
from .freespeech import FreespeechIE
|
||||||
from .freevideo import FreeVideoIE
|
from .freevideo import FreeVideoIE
|
||||||
|
from .funimation import FunimationIE
|
||||||
from .funnyordie import FunnyOrDieIE
|
from .funnyordie import FunnyOrDieIE
|
||||||
from .gameinformer import GameInformerIE
|
from .gameinformer import GameInformerIE
|
||||||
from .gamekings import GamekingsIE
|
from .gamekings import GamekingsIE
|
||||||
|
|||||||
@@ -34,15 +34,29 @@ class BeegIE(InfoExtractor):
|
|||||||
video_id = self._match_id(url)
|
video_id = self._match_id(url)
|
||||||
|
|
||||||
video = self._download_json(
|
video = self._download_json(
|
||||||
'http://beeg.com/api/v4/video/%s' % video_id, video_id)
|
'http://beeg.com/api/v5/video/%s' % video_id, video_id)
|
||||||
|
|
||||||
|
def split(o, e):
|
||||||
|
def cut(s, x):
|
||||||
|
n.append(s[:x])
|
||||||
|
return s[x:]
|
||||||
|
n = []
|
||||||
|
r = len(o) % e
|
||||||
|
if r > 0:
|
||||||
|
o = cut(o, r)
|
||||||
|
while len(o) > e:
|
||||||
|
o = cut(o, e)
|
||||||
|
n.append(o)
|
||||||
|
return n
|
||||||
|
|
||||||
def decrypt_key(key):
|
def decrypt_key(key):
|
||||||
# Reverse engineered from http://static.beeg.com/cpl/1067.js
|
# Reverse engineered from http://static.beeg.com/cpl/1105.js
|
||||||
a = '8RPUUCS35ZWp3ADnKcSmpH71ZusrROo'
|
a = '5ShMcIQlssOd7zChAIOlmeTZDaUxULbJRnywYaiB'
|
||||||
e = compat_urllib_parse_unquote(key)
|
e = compat_urllib_parse_unquote(key)
|
||||||
return ''.join([
|
o = ''.join([
|
||||||
compat_chr(compat_ord(e[n]) - compat_ord(a[n % len(a)]) % 25)
|
compat_chr(compat_ord(e[n]) - compat_ord(a[n % len(a)]) % 21)
|
||||||
for n in range(len(e))])
|
for n in range(len(e))])
|
||||||
|
return ''.join(split(o, 3)[::-1])
|
||||||
|
|
||||||
def decrypt_url(encrypted_url):
|
def decrypt_url(encrypted_url):
|
||||||
encrypted_url = self._proto_relative_url(
|
encrypted_url = self._proto_relative_url(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from ..utils import determine_ext
|
from ..utils import int_or_none
|
||||||
|
|
||||||
|
|
||||||
_translation_table = {
|
_translation_table = {
|
||||||
@@ -42,31 +42,26 @@ class CliphunterIE(InfoExtractor):
|
|||||||
video_title = self._search_regex(
|
video_title = self._search_regex(
|
||||||
r'mediaTitle = "([^"]+)"', webpage, 'title')
|
r'mediaTitle = "([^"]+)"', webpage, 'title')
|
||||||
|
|
||||||
fmts = {}
|
gexo_files = self._parse_json(
|
||||||
for fmt in ('mp4', 'flv'):
|
self._search_regex(
|
||||||
fmt_list = self._parse_json(self._search_regex(
|
r'var\s+gexoFiles\s*=\s*({.+?});', webpage, 'gexo files'),
|
||||||
r'var %sjson\s*=\s*(\[.*?\]);' % fmt, webpage, '%s formats' % fmt), video_id)
|
video_id)
|
||||||
for f in fmt_list:
|
|
||||||
fmts[f['fname']] = _decode(f['sUrl'])
|
|
||||||
|
|
||||||
qualities = self._parse_json(self._search_regex(
|
|
||||||
r'var player_btns\s*=\s*(.*?);\n', webpage, 'quality info'), video_id)
|
|
||||||
|
|
||||||
formats = []
|
formats = []
|
||||||
for fname, url in fmts.items():
|
for format_id, f in gexo_files.items():
|
||||||
f = {
|
video_url = f.get('url')
|
||||||
'url': url,
|
if not video_url:
|
||||||
}
|
continue
|
||||||
if fname in qualities:
|
fmt = f.get('fmt')
|
||||||
qual = qualities[fname]
|
height = f.get('h')
|
||||||
f.update({
|
format_id = '%s_%sp' % (fmt, height) if fmt and height else format_id
|
||||||
'format_id': '%s_%sp' % (determine_ext(url), qual['h']),
|
formats.append({
|
||||||
'width': qual['w'],
|
'url': _decode(video_url),
|
||||||
'height': qual['h'],
|
'format_id': format_id,
|
||||||
'tbr': qual['br'],
|
'width': int_or_none(f.get('w')),
|
||||||
})
|
'height': int_or_none(height),
|
||||||
formats.append(f)
|
'tbr': int_or_none(f.get('br')),
|
||||||
|
})
|
||||||
self._sort_formats(formats)
|
self._sort_formats(formats)
|
||||||
|
|
||||||
thumbnail = self._search_regex(
|
thumbnail = self._search_regex(
|
||||||
|
|||||||
@@ -99,6 +99,11 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
|
|||||||
{
|
{
|
||||||
'url': 'http://www.dailymotion.com/video/xhza0o',
|
'url': 'http://www.dailymotion.com/video/xhza0o',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
|
},
|
||||||
|
# with subtitles
|
||||||
|
{
|
||||||
|
'url': 'http://www.dailymotion.com/video/x20su5f_the-power-of-nightmares-1-the-rise-of-the-politics-of-fear-bbc-2004_news',
|
||||||
|
'only_matching': True,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -122,7 +127,9 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
|
|||||||
webpage, 'comment count', fatal=False))
|
webpage, 'comment count', fatal=False))
|
||||||
|
|
||||||
player_v5 = self._search_regex(
|
player_v5 = self._search_regex(
|
||||||
[r'buildPlayer\(({.+?})\);', r'playerV5\s*=\s*dmp\.create\([^,]+?,\s*({.+?})\);'],
|
[r'buildPlayer\(({.+?})\);\n', # See https://github.com/rg3/youtube-dl/issues/7826
|
||||||
|
r'playerV5\s*=\s*dmp\.create\([^,]+?,\s*({.+?})\);',
|
||||||
|
r'buildPlayer\(({.+?})\);'],
|
||||||
webpage, 'player v5', default=None)
|
webpage, 'player v5', default=None)
|
||||||
if player_v5:
|
if player_v5:
|
||||||
player = self._parse_json(player_v5, video_id)
|
player = self._parse_json(player_v5, video_id)
|
||||||
@@ -172,11 +179,13 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
|
|||||||
uploader_id = metadata.get('owner', {}).get('id')
|
uploader_id = metadata.get('owner', {}).get('id')
|
||||||
|
|
||||||
subtitles = {}
|
subtitles = {}
|
||||||
for subtitle_lang, subtitle in metadata.get('subtitles', {}).get('data', {}).items():
|
subtitles_data = metadata.get('subtitles', {}).get('data', {})
|
||||||
subtitles[subtitle_lang] = [{
|
if subtitles_data and isinstance(subtitles_data, dict):
|
||||||
'ext': determine_ext(subtitle_url),
|
for subtitle_lang, subtitle in subtitles_data.items():
|
||||||
'url': subtitle_url,
|
subtitles[subtitle_lang] = [{
|
||||||
} for subtitle_url in subtitle.get('urls', [])]
|
'ext': determine_ext(subtitle_url),
|
||||||
|
'url': subtitle_url,
|
||||||
|
} for subtitle_url in subtitle.get('urls', [])]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
|
|||||||
193
youtube_dl/extractor/funimation.py
Normal file
193
youtube_dl/extractor/funimation.py
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import (
|
||||||
|
clean_html,
|
||||||
|
determine_ext,
|
||||||
|
encode_dict,
|
||||||
|
int_or_none,
|
||||||
|
sanitized_Request,
|
||||||
|
ExtractorError,
|
||||||
|
urlencode_postdata
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FunimationIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?funimation\.com/shows/[^/]+/videos/(?:official|promotional)/(?P<id>[^/?#&]+)'
|
||||||
|
|
||||||
|
_NETRC_MACHINE = 'funimation'
|
||||||
|
|
||||||
|
_TESTS = [{
|
||||||
|
'url': 'http://www.funimation.com/shows/air/videos/official/breeze',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '658',
|
||||||
|
'display_id': 'breeze',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Air - 1 - Breeze',
|
||||||
|
'description': 'md5:1769f43cd5fc130ace8fd87232207892',
|
||||||
|
'thumbnail': 're:https?://.*\.jpg',
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
'url': 'http://www.funimation.com/shows/hacksign/videos/official/role-play',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '31128',
|
||||||
|
'display_id': 'role-play',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': '.hack//SIGN - 1 - Role Play',
|
||||||
|
'description': 'md5:b602bdc15eef4c9bbb201bb6e6a4a2dd',
|
||||||
|
'thumbnail': 're:https?://.*\.jpg',
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
'url': 'http://www.funimation.com/shows/attack-on-titan-junior-high/videos/promotional/broadcast-dub-preview',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '9635',
|
||||||
|
'display_id': 'broadcast-dub-preview',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Attack on Titan: Junior High - Broadcast Dub Preview',
|
||||||
|
'description': 'md5:f8ec49c0aff702a7832cd81b8a44f803',
|
||||||
|
'thumbnail': 're:https?://.*\.(?:jpg|png)',
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
|
||||||
|
def _login(self):
|
||||||
|
(username, password) = self._get_login_info()
|
||||||
|
if username is None:
|
||||||
|
return
|
||||||
|
data = urlencode_postdata(encode_dict({
|
||||||
|
'email_field': username,
|
||||||
|
'password_field': password,
|
||||||
|
}))
|
||||||
|
login_request = sanitized_Request('http://www.funimation.com/login', data, headers={
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 5.2; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0',
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
})
|
||||||
|
login_page = self._download_webpage(
|
||||||
|
login_request, None, 'Logging in as %s' % username)
|
||||||
|
if any(p in login_page for p in ('funimation.com/logout', '>Log Out<')):
|
||||||
|
return
|
||||||
|
error = self._html_search_regex(
|
||||||
|
r'(?s)<div[^>]+id=["\']errorMessages["\'][^>]*>(.+?)</div>',
|
||||||
|
login_page, 'error messages', default=None)
|
||||||
|
if error:
|
||||||
|
raise ExtractorError('Unable to login: %s' % error, expected=True)
|
||||||
|
raise ExtractorError('Unable to log in')
|
||||||
|
|
||||||
|
def _real_initialize(self):
|
||||||
|
self._login()
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
display_id = self._match_id(url)
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
formats = []
|
||||||
|
|
||||||
|
ERRORS_MAP = {
|
||||||
|
'ERROR_MATURE_CONTENT_LOGGED_IN': 'matureContentLoggedIn',
|
||||||
|
'ERROR_MATURE_CONTENT_LOGGED_OUT': 'matureContentLoggedOut',
|
||||||
|
'ERROR_SUBSCRIPTION_LOGGED_OUT': 'subscriptionLoggedOut',
|
||||||
|
'ERROR_VIDEO_EXPIRED': 'videoExpired',
|
||||||
|
'ERROR_TERRITORY_UNAVAILABLE': 'territoryUnavailable',
|
||||||
|
'SVODBASIC_SUBSCRIPTION_IN_PLAYER': 'basicSubscription',
|
||||||
|
'SVODNON_SUBSCRIPTION_IN_PLAYER': 'nonSubscription',
|
||||||
|
'ERROR_PLAYER_NOT_RESPONDING': 'playerNotResponding',
|
||||||
|
'ERROR_UNABLE_TO_CONNECT_TO_CDN': 'unableToConnectToCDN',
|
||||||
|
'ERROR_STREAM_NOT_FOUND': 'streamNotFound',
|
||||||
|
}
|
||||||
|
|
||||||
|
USER_AGENTS = (
|
||||||
|
# PC UA is served with m3u8 that provides some bonus lower quality formats
|
||||||
|
('pc', 'Mozilla/5.0 (Windows NT 5.2; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0'),
|
||||||
|
# Mobile UA allows to extract direct links and also does not fail when
|
||||||
|
# PC UA fails with hulu error (e.g.
|
||||||
|
# http://www.funimation.com/shows/hacksign/videos/official/role-play)
|
||||||
|
('mobile', 'Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36'),
|
||||||
|
)
|
||||||
|
|
||||||
|
for kind, user_agent in USER_AGENTS:
|
||||||
|
request = sanitized_Request(url)
|
||||||
|
request.add_header('User-Agent', user_agent)
|
||||||
|
webpage = self._download_webpage(
|
||||||
|
request, display_id, 'Downloading %s webpage' % kind)
|
||||||
|
|
||||||
|
playlist = self._parse_json(
|
||||||
|
self._search_regex(
|
||||||
|
r'var\s+playersData\s*=\s*(\[.+?\]);\n',
|
||||||
|
webpage, 'players data'),
|
||||||
|
display_id)[0]['playlist']
|
||||||
|
|
||||||
|
items = next(item['items'] for item in playlist if item.get('items'))
|
||||||
|
item = next(item for item in items if item.get('itemAK') == display_id)
|
||||||
|
|
||||||
|
error_messages = {}
|
||||||
|
video_error_messages = self._search_regex(
|
||||||
|
r'var\s+videoErrorMessages\s*=\s*({.+?});\n',
|
||||||
|
webpage, 'error messages', default=None)
|
||||||
|
if video_error_messages:
|
||||||
|
error_messages_json = self._parse_json(video_error_messages, display_id, fatal=False)
|
||||||
|
if error_messages_json:
|
||||||
|
for _, error in error_messages_json.items():
|
||||||
|
type_ = error.get('type')
|
||||||
|
description = error.get('description')
|
||||||
|
content = error.get('content')
|
||||||
|
if type_ == 'text' and description and content:
|
||||||
|
error_message = ERRORS_MAP.get(description)
|
||||||
|
if error_message:
|
||||||
|
error_messages[error_message] = content
|
||||||
|
|
||||||
|
for video in item.get('videoSet', []):
|
||||||
|
auth_token = video.get('authToken')
|
||||||
|
if not auth_token:
|
||||||
|
continue
|
||||||
|
funimation_id = video.get('FUNImationID') or video.get('videoId')
|
||||||
|
preference = 1 if video.get('languageMode') == 'dub' else 0
|
||||||
|
if not auth_token.startswith('?'):
|
||||||
|
auth_token = '?%s' % auth_token
|
||||||
|
for quality, height in (('sd', 480), ('hd', 720), ('hd1080', 1080)):
|
||||||
|
format_url = video.get('%sUrl' % quality)
|
||||||
|
if not format_url:
|
||||||
|
continue
|
||||||
|
if not format_url.startswith(('http', '//')):
|
||||||
|
errors.append(format_url)
|
||||||
|
continue
|
||||||
|
if determine_ext(format_url) == 'm3u8':
|
||||||
|
m3u8_formats = self._extract_m3u8_formats(
|
||||||
|
format_url + auth_token, display_id, 'mp4', entry_protocol='m3u8_native',
|
||||||
|
preference=preference, m3u8_id='%s-hls' % funimation_id, fatal=False)
|
||||||
|
if m3u8_formats:
|
||||||
|
formats.extend(m3u8_formats)
|
||||||
|
else:
|
||||||
|
tbr = int_or_none(self._search_regex(
|
||||||
|
r'-(\d+)[Kk]', format_url, 'tbr', default=None))
|
||||||
|
formats.append({
|
||||||
|
'url': format_url + auth_token,
|
||||||
|
'format_id': '%s-http-%dp' % (funimation_id, height),
|
||||||
|
'height': height,
|
||||||
|
'tbr': tbr,
|
||||||
|
'preference': preference,
|
||||||
|
})
|
||||||
|
|
||||||
|
if not formats and errors:
|
||||||
|
raise ExtractorError(
|
||||||
|
'%s returned error: %s'
|
||||||
|
% (self.IE_NAME, clean_html(error_messages.get(errors[0], errors[0]))),
|
||||||
|
expected=True)
|
||||||
|
|
||||||
|
self._sort_formats(formats)
|
||||||
|
|
||||||
|
title = item['title']
|
||||||
|
artist = item.get('artist')
|
||||||
|
if artist:
|
||||||
|
title = '%s - %s' % (artist, title)
|
||||||
|
description = self._og_search_description(webpage) or item.get('description')
|
||||||
|
thumbnail = self._og_search_thumbnail(webpage) or item.get('posterUrl')
|
||||||
|
video_id = item.get('itemId') or display_id
|
||||||
|
|
||||||
|
return {
|
||||||
|
'id': video_id,
|
||||||
|
'display_id': display_id,
|
||||||
|
'title': title,
|
||||||
|
'description': description,
|
||||||
|
'thumbnail': thumbnail,
|
||||||
|
'formats': formats,
|
||||||
|
}
|
||||||
@@ -54,6 +54,7 @@ from .onionstudios import OnionStudiosIE
|
|||||||
from .snagfilms import SnagFilmsEmbedIE
|
from .snagfilms import SnagFilmsEmbedIE
|
||||||
from .screenwavemedia import ScreenwaveMediaIE
|
from .screenwavemedia import ScreenwaveMediaIE
|
||||||
from .mtv import MTVServicesEmbeddedIE
|
from .mtv import MTVServicesEmbeddedIE
|
||||||
|
from .pladform import PladformIE
|
||||||
|
|
||||||
|
|
||||||
class GenericIE(InfoExtractor):
|
class GenericIE(InfoExtractor):
|
||||||
@@ -1741,10 +1742,9 @@ class GenericIE(InfoExtractor):
|
|||||||
return self.url_result('eagleplatform:%(host)s:%(id)s' % mobj.groupdict(), 'EaglePlatform')
|
return self.url_result('eagleplatform:%(host)s:%(id)s' % mobj.groupdict(), 'EaglePlatform')
|
||||||
|
|
||||||
# Look for Pladform embeds
|
# Look for Pladform embeds
|
||||||
mobj = re.search(
|
pladform_url = PladformIE._extract_url(webpage)
|
||||||
r'<iframe[^>]+src="(?P<url>https?://out\.pladform\.ru/player\?.+?)"', webpage)
|
if pladform_url:
|
||||||
if mobj is not None:
|
return self.url_result(pladform_url)
|
||||||
return self.url_result(mobj.group('url'), 'Pladform')
|
|
||||||
|
|
||||||
# Look for Playwire embeds
|
# Look for Playwire embeds
|
||||||
mobj = re.search(
|
mobj = re.search(
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ from __future__ import unicode_literals
|
|||||||
import base64
|
import base64
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from ..compat import (
|
from ..compat import compat_urllib_parse_unquote
|
||||||
compat_urllib_parse_unquote,
|
|
||||||
compat_urlparse,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class InfoQIE(InfoExtractor):
|
class InfoQIE(InfoExtractor):
|
||||||
@@ -45,9 +42,11 @@ class InfoQIE(InfoExtractor):
|
|||||||
video_filename = playpath.split('/')[-1]
|
video_filename = playpath.split('/')[-1]
|
||||||
video_id, extension = video_filename.split('.')
|
video_id, extension = video_filename.split('.')
|
||||||
|
|
||||||
http_base = self._search_regex(
|
http_video_url = self._search_regex(r'P\.s\s*=\s*\'([^\']+)\'', webpage, 'video URL')
|
||||||
r'EXPRESSINSTALL_SWF\s*=\s*[^"]*"((?:https?:)?//[^/"]+/)', webpage,
|
|
||||||
'HTTP base URL')
|
policy = self._search_regex(r'InfoQConstants.scp\s*=\s*\'([^\']+)\'', webpage, 'policy')
|
||||||
|
signature = self._search_regex(r'InfoQConstants.scs\s*=\s*\'([^\']+)\'', webpage, 'signature')
|
||||||
|
key_pair_id = self._search_regex(r'InfoQConstants.sck\s*=\s*\'([^\']+)\'', webpage, 'key-pair-id')
|
||||||
|
|
||||||
formats = [{
|
formats = [{
|
||||||
'format_id': 'rtmp',
|
'format_id': 'rtmp',
|
||||||
@@ -56,7 +55,11 @@ class InfoQIE(InfoExtractor):
|
|||||||
'play_path': playpath,
|
'play_path': playpath,
|
||||||
}, {
|
}, {
|
||||||
'format_id': 'http',
|
'format_id': 'http',
|
||||||
'url': compat_urlparse.urljoin(url, http_base) + real_id,
|
'url': http_video_url,
|
||||||
|
'http_headers': {
|
||||||
|
'Cookie': 'CloudFront-Policy=%s; CloudFront-Signature=%s; CloudFront-Key-Pair-Id=%s' % (
|
||||||
|
policy, signature, key_pair_id),
|
||||||
|
},
|
||||||
}]
|
}]
|
||||||
self._sort_formats(formats)
|
self._sort_formats(formats)
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from ..utils import (
|
|||||||
ExtractorError,
|
ExtractorError,
|
||||||
find_xpath_attr,
|
find_xpath_attr,
|
||||||
lowercase_escape,
|
lowercase_escape,
|
||||||
|
smuggle_url,
|
||||||
unescapeHTML,
|
unescapeHTML,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -62,12 +63,13 @@ class NBCIE(InfoExtractor):
|
|||||||
theplatform_url = unescapeHTML(lowercase_escape(self._html_search_regex(
|
theplatform_url = unescapeHTML(lowercase_escape(self._html_search_regex(
|
||||||
[
|
[
|
||||||
r'(?:class="video-player video-player-full" data-mpx-url|class="player" src)="(.*?)"',
|
r'(?:class="video-player video-player-full" data-mpx-url|class="player" src)="(.*?)"',
|
||||||
|
r'<iframe[^>]+src="((?:https?:)?//player\.theplatform\.com/[^"]+)"',
|
||||||
r'"embedURL"\s*:\s*"([^"]+)"'
|
r'"embedURL"\s*:\s*"([^"]+)"'
|
||||||
],
|
],
|
||||||
webpage, 'theplatform url').replace('_no_endcard', '').replace('\\/', '/')))
|
webpage, 'theplatform url').replace('_no_endcard', '').replace('\\/', '/')))
|
||||||
if theplatform_url.startswith('//'):
|
if theplatform_url.startswith('//'):
|
||||||
theplatform_url = 'http:' + theplatform_url
|
theplatform_url = 'http:' + theplatform_url
|
||||||
return self.url_result(theplatform_url)
|
return self.url_result(smuggle_url(theplatform_url, {'source_url': url}))
|
||||||
|
|
||||||
|
|
||||||
class NBCSportsVPlayerIE(InfoExtractor):
|
class NBCSportsVPlayerIE(InfoExtractor):
|
||||||
|
|||||||
@@ -23,9 +23,10 @@ class NovaMovIE(InfoExtractor):
|
|||||||
_HOST = 'www.novamov.com'
|
_HOST = 'www.novamov.com'
|
||||||
|
|
||||||
_FILE_DELETED_REGEX = r'This file no longer exists on our servers!</h2>'
|
_FILE_DELETED_REGEX = r'This file no longer exists on our servers!</h2>'
|
||||||
_FILEKEY_REGEX = r'flashvars\.filekey="(?P<filekey>[^"]+)";'
|
_FILEKEY_REGEX = r'flashvars\.filekey=(?P<filekey>"?[^"]+"?);'
|
||||||
_TITLE_REGEX = r'(?s)<div class="v_tab blockborder rounded5" id="v_tab1">\s*<h3>([^<]+)</h3>'
|
_TITLE_REGEX = r'(?s)<div class="v_tab blockborder rounded5" id="v_tab1">\s*<h3>([^<]+)</h3>'
|
||||||
_DESCRIPTION_REGEX = r'(?s)<div class="v_tab blockborder rounded5" id="v_tab1">\s*<h3>[^<]+</h3><p>([^<]+)</p>'
|
_DESCRIPTION_REGEX = r'(?s)<div class="v_tab blockborder rounded5" id="v_tab1">\s*<h3>[^<]+</h3><p>([^<]+)</p>'
|
||||||
|
_URL_TEMPLATE = 'http://%s/video/%s'
|
||||||
|
|
||||||
_TEST = {
|
_TEST = {
|
||||||
'url': 'http://www.novamov.com/video/4rurhn9x446jj',
|
'url': 'http://www.novamov.com/video/4rurhn9x446jj',
|
||||||
@@ -39,20 +40,28 @@ class NovaMovIE(InfoExtractor):
|
|||||||
'skip': '"Invalid token" errors abound (in web interface as well as youtube-dl, there is nothing we can do about it.)'
|
'skip': '"Invalid token" errors abound (in web interface as well as youtube-dl, there is nothing we can do about it.)'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _check_existence(self, webpage, video_id):
|
||||||
|
if re.search(self._FILE_DELETED_REGEX, webpage) is not None:
|
||||||
|
raise ExtractorError('Video %s does not exist' % video_id, expected=True)
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
video_id = self._match_id(url)
|
video_id = self._match_id(url)
|
||||||
|
|
||||||
url = 'http://%s/video/%s' % (self._HOST, video_id)
|
url = self._URL_TEMPLATE % (self._HOST, video_id)
|
||||||
|
|
||||||
webpage = self._download_webpage(
|
webpage = self._download_webpage(
|
||||||
url, video_id, 'Downloading video page')
|
url, video_id, 'Downloading video page')
|
||||||
|
|
||||||
if re.search(self._FILE_DELETED_REGEX, webpage) is not None:
|
self._check_existence(webpage, video_id)
|
||||||
raise ExtractorError('Video %s does not exist' % video_id, expected=True)
|
|
||||||
|
|
||||||
def extract_filekey(default=NO_DEFAULT):
|
def extract_filekey(default=NO_DEFAULT):
|
||||||
return self._search_regex(
|
filekey = self._search_regex(
|
||||||
self._FILEKEY_REGEX, webpage, 'filekey', default=default)
|
self._FILEKEY_REGEX, webpage, 'filekey', default=default)
|
||||||
|
if filekey is not default and (filekey[0] != '"' or filekey[-1] != '"'):
|
||||||
|
return self._search_regex(
|
||||||
|
r'var\s*%s\s*=\s*"([^"]+)"', webpage, 'filekey', default=default)
|
||||||
|
else:
|
||||||
|
return filekey
|
||||||
|
|
||||||
filekey = extract_filekey(default=None)
|
filekey = extract_filekey(default=None)
|
||||||
|
|
||||||
@@ -69,6 +78,7 @@ class NovaMovIE(InfoExtractor):
|
|||||||
request.add_header('Referer', post_url)
|
request.add_header('Referer', post_url)
|
||||||
webpage = self._download_webpage(
|
webpage = self._download_webpage(
|
||||||
request, video_id, 'Downloading continue to the video page')
|
request, video_id, 'Downloading continue to the video page')
|
||||||
|
self._check_existence(webpage, video_id)
|
||||||
|
|
||||||
filekey = extract_filekey()
|
filekey = extract_filekey()
|
||||||
|
|
||||||
@@ -127,7 +137,6 @@ class NowVideoIE(NovaMovIE):
|
|||||||
_HOST = 'www.nowvideo.to'
|
_HOST = 'www.nowvideo.to'
|
||||||
|
|
||||||
_FILE_DELETED_REGEX = r'>This file no longer exists on our servers.<'
|
_FILE_DELETED_REGEX = r'>This file no longer exists on our servers.<'
|
||||||
_FILEKEY_REGEX = r'var fkzd="([^"]+)";'
|
|
||||||
_TITLE_REGEX = r'<h4>([^<]+)</h4>'
|
_TITLE_REGEX = r'<h4>([^<]+)</h4>'
|
||||||
_DESCRIPTION_REGEX = r'</h4>\s*<p>([^<]+)</p>'
|
_DESCRIPTION_REGEX = r'</h4>\s*<p>([^<]+)</p>'
|
||||||
|
|
||||||
@@ -139,7 +148,8 @@ class NowVideoIE(NovaMovIE):
|
|||||||
'ext': 'flv',
|
'ext': 'flv',
|
||||||
'title': 'youtubedl test video _BaW_jenozKc.mp4',
|
'title': 'youtubedl test video _BaW_jenozKc.mp4',
|
||||||
'description': 'Description',
|
'description': 'Description',
|
||||||
}
|
},
|
||||||
|
'skip': 'Video 0mw0yow7b6dxa does not exist',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -153,6 +163,7 @@ class VideoWeedIE(NovaMovIE):
|
|||||||
|
|
||||||
_FILE_DELETED_REGEX = r'>This file no longer exists on our servers.<'
|
_FILE_DELETED_REGEX = r'>This file no longer exists on our servers.<'
|
||||||
_TITLE_REGEX = r'<h1 class="text_shadow">([^<]+)</h1>'
|
_TITLE_REGEX = r'<h1 class="text_shadow">([^<]+)</h1>'
|
||||||
|
_URL_TEMPLATE = 'http://%s/file/%s'
|
||||||
|
|
||||||
_TEST = {
|
_TEST = {
|
||||||
'url': 'http://www.videoweed.es/file/b42178afbea14',
|
'url': 'http://www.videoweed.es/file/b42178afbea14',
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class OoyalaBaseIE(InfoExtractor):
|
|||||||
'duration': float_or_none(metadata.get('duration'), 1000),
|
'duration': float_or_none(metadata.get('duration'), 1000),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
urls = []
|
||||||
formats = []
|
formats = []
|
||||||
for supported_format in ('mp4', 'm3u8', 'hds', 'rtmp'):
|
for supported_format in ('mp4', 'm3u8', 'hds', 'rtmp'):
|
||||||
auth_data = self._download_json(
|
auth_data = self._download_json(
|
||||||
@@ -38,20 +39,28 @@ class OoyalaBaseIE(InfoExtractor):
|
|||||||
if cur_auth_data['authorized']:
|
if cur_auth_data['authorized']:
|
||||||
for stream in cur_auth_data['streams']:
|
for stream in cur_auth_data['streams']:
|
||||||
url = base64.b64decode(stream['url']['data'].encode('ascii')).decode('utf-8')
|
url = base64.b64decode(stream['url']['data'].encode('ascii')).decode('utf-8')
|
||||||
|
if url in urls:
|
||||||
|
continue
|
||||||
|
urls.append(url)
|
||||||
delivery_type = stream['delivery_type']
|
delivery_type = stream['delivery_type']
|
||||||
if delivery_type == 'remote_asset':
|
if delivery_type == 'hls' or '.m3u8' in url:
|
||||||
video_info['url'] = url
|
m3u8_formats = self._extract_m3u8_formats(url, embed_code, 'mp4', 'm3u8_native', m3u8_id='hls', fatal=False)
|
||||||
return video_info
|
if m3u8_formats:
|
||||||
if delivery_type == 'hls':
|
formats.extend(m3u8_formats)
|
||||||
formats.extend(self._extract_m3u8_formats(url, embed_code, 'mp4', 'm3u8_native', m3u8_id='hls', fatal=False))
|
elif delivery_type == 'hds' or '.f4m' in url:
|
||||||
elif delivery_type == 'hds':
|
f4m_formats = self._extract_f4m_formats(url, embed_code, f4m_id='hds', fatal=False)
|
||||||
formats.extend(self._extract_f4m_formats(url, embed_code, -1, 'hds', fatal=False))
|
if f4m_formats:
|
||||||
|
formats.extend(f4m_formats)
|
||||||
|
elif '.smil' in url:
|
||||||
|
smil_formats = self._extract_smil_formats(url, embed_code, fatal=False)
|
||||||
|
if smil_formats:
|
||||||
|
formats.extend(smil_formats)
|
||||||
else:
|
else:
|
||||||
formats.append({
|
formats.append({
|
||||||
'url': url,
|
'url': url,
|
||||||
'ext': stream.get('delivery_type'),
|
'ext': stream.get('delivery_type'),
|
||||||
'vcodec': stream.get('video_codec'),
|
'vcodec': stream.get('video_codec'),
|
||||||
'format_id': '%s-%s-%sp' % (stream.get('profile'), delivery_type, stream.get('height')),
|
'format_id': delivery_type,
|
||||||
'width': int_or_none(stream.get('width')),
|
'width': int_or_none(stream.get('width')),
|
||||||
'height': int_or_none(stream.get('height')),
|
'height': int_or_none(stream.get('height')),
|
||||||
'abr': int_or_none(stream.get('audio_bitrate')),
|
'abr': int_or_none(stream.get('audio_bitrate')),
|
||||||
|
|||||||
@@ -15,16 +15,181 @@ from ..utils import (
|
|||||||
|
|
||||||
|
|
||||||
class PBSIE(InfoExtractor):
|
class PBSIE(InfoExtractor):
|
||||||
|
_STATIONS = (
|
||||||
|
('video.pbs.org', 'PBS: Public Broadcasting Service'), # http://www.pbs.org/
|
||||||
|
('video.aptv.org', 'APT - Alabama Public Television (WBIQ)'), # http://aptv.org/
|
||||||
|
('video.gpb.org', 'GPB/Georgia Public Broadcasting (WGTV)'), # http://www.gpb.org/
|
||||||
|
('video.mpbonline.org', 'Mississippi Public Broadcasting (WMPN)'), # http://www.mpbonline.org
|
||||||
|
('video.wnpt.org', 'Nashville Public Television (WNPT)'), # http://www.wnpt.org
|
||||||
|
('video.wfsu.org', 'WFSU-TV (WFSU)'), # http://wfsu.org/
|
||||||
|
('video.wsre.org', 'WSRE (WSRE)'), # http://www.wsre.org
|
||||||
|
('video.wtcitv.org', 'WTCI (WTCI)'), # http://www.wtcitv.org
|
||||||
|
('video.pba.org', 'WPBA/Channel 30 (WPBA)'), # http://pba.org/
|
||||||
|
('video.alaskapublic.org', 'Alaska Public Media (KAKM)'), # http://alaskapublic.org/kakm
|
||||||
|
# ('kuac.org', 'KUAC (KUAC)'), # http://kuac.org/kuac-tv/
|
||||||
|
# ('ktoo.org', '360 North (KTOO)'), # http://www.ktoo.org/
|
||||||
|
# ('azpm.org', 'KUAT 6 (KUAT)'), # http://www.azpm.org/
|
||||||
|
('video.azpbs.org', 'Arizona PBS (KAET)'), # http://www.azpbs.org
|
||||||
|
('portal.knme.org', 'KNME-TV/Channel 5 (KNME)'), # http://www.newmexicopbs.org/
|
||||||
|
('video.vegaspbs.org', 'Vegas PBS (KLVX)'), # http://vegaspbs.org/
|
||||||
|
('watch.aetn.org', 'AETN/ARKANSAS ETV NETWORK (KETS)'), # http://www.aetn.org/
|
||||||
|
('video.ket.org', 'KET (WKLE)'), # http://www.ket.org/
|
||||||
|
('video.wkno.org', 'WKNO/Channel 10 (WKNO)'), # http://www.wkno.org/
|
||||||
|
('video.lpb.org', 'LPB/LOUISIANA PUBLIC BROADCASTING (WLPB)'), # http://www.lpb.org/
|
||||||
|
('videos.oeta.tv', 'OETA (KETA)'), # http://www.oeta.tv
|
||||||
|
('video.optv.org', 'Ozarks Public Television (KOZK)'), # http://www.optv.org/
|
||||||
|
('watch.wsiu.org', 'WSIU Public Broadcasting (WSIU)'), # http://www.wsiu.org/
|
||||||
|
('video.keet.org', 'KEET TV (KEET)'), # http://www.keet.org
|
||||||
|
('pbs.kixe.org', 'KIXE/Channel 9 (KIXE)'), # http://kixe.org/
|
||||||
|
('video.kpbs.org', 'KPBS San Diego (KPBS)'), # http://www.kpbs.org/
|
||||||
|
('video.kqed.org', 'KQED (KQED)'), # http://www.kqed.org
|
||||||
|
('vids.kvie.org', 'KVIE Public Television (KVIE)'), # http://www.kvie.org
|
||||||
|
('video.pbssocal.org', 'PBS SoCal/KOCE (KOCE)'), # http://www.pbssocal.org/
|
||||||
|
('video.valleypbs.org', 'ValleyPBS (KVPT)'), # http://www.valleypbs.org/
|
||||||
|
('video.cptv.org', 'CONNECTICUT PUBLIC TELEVISION (WEDH)'), # http://cptv.org
|
||||||
|
('watch.knpb.org', 'KNPB Channel 5 (KNPB)'), # http://www.knpb.org/
|
||||||
|
('video.soptv.org', 'SOPTV (KSYS)'), # http://www.soptv.org
|
||||||
|
# ('klcs.org', 'KLCS/Channel 58 (KLCS)'), # http://www.klcs.org
|
||||||
|
# ('krcb.org', 'KRCB Television & Radio (KRCB)'), # http://www.krcb.org
|
||||||
|
# ('kvcr.org', 'KVCR TV/DT/FM :: Vision for the Future (KVCR)'), # http://kvcr.org
|
||||||
|
('video.rmpbs.org', 'Rocky Mountain PBS (KRMA)'), # http://www.rmpbs.org
|
||||||
|
('video.kenw.org', 'KENW-TV3 (KENW)'), # http://www.kenw.org
|
||||||
|
('video.kued.org', 'KUED Channel 7 (KUED)'), # http://www.kued.org
|
||||||
|
('video.wyomingpbs.org', 'Wyoming PBS (KCWC)'), # http://www.wyomingpbs.org
|
||||||
|
('video.cpt12.org', 'Colorado Public Television / KBDI 12 (KBDI)'), # http://www.cpt12.org/
|
||||||
|
('video.kbyueleven.org', 'KBYU-TV (KBYU)'), # http://www.kbyutv.org/
|
||||||
|
('video.thirteen.org', 'Thirteen/WNET New York (WNET)'), # http://www.thirteen.org
|
||||||
|
('video.wgbh.org', 'WGBH/Channel 2 (WGBH)'), # http://wgbh.org
|
||||||
|
('video.wgby.org', 'WGBY (WGBY)'), # http://www.wgby.org
|
||||||
|
('watch.njtvonline.org', 'NJTV Public Media NJ (WNJT)'), # http://www.njtvonline.org/
|
||||||
|
# ('ripbs.org', 'Rhode Island PBS (WSBE)'), # http://www.ripbs.org/home/
|
||||||
|
('watch.wliw.org', 'WLIW21 (WLIW)'), # http://www.wliw.org/
|
||||||
|
('video.mpt.tv', 'mpt/Maryland Public Television (WMPB)'), # http://www.mpt.org
|
||||||
|
('watch.weta.org', 'WETA Television and Radio (WETA)'), # http://www.weta.org
|
||||||
|
('video.whyy.org', 'WHYY (WHYY)'), # http://www.whyy.org
|
||||||
|
('video.wlvt.org', 'PBS 39 (WLVT)'), # http://www.wlvt.org/
|
||||||
|
('video.wvpt.net', 'WVPT - Your Source for PBS and More! (WVPT)'), # http://www.wvpt.net
|
||||||
|
('video.whut.org', 'Howard University Television (WHUT)'), # http://www.whut.org
|
||||||
|
('video.wedu.org', 'WEDU PBS (WEDU)'), # http://www.wedu.org
|
||||||
|
('video.wgcu.org', 'WGCU Public Media (WGCU)'), # http://www.wgcu.org/
|
||||||
|
# ('wjct.org', 'WJCT Public Broadcasting (WJCT)'), # http://www.wjct.org
|
||||||
|
('video.wpbt2.org', 'WPBT2 (WPBT)'), # http://www.wpbt2.org
|
||||||
|
('video.wucftv.org', 'WUCF TV (WUCF)'), # http://wucftv.org
|
||||||
|
('video.wuft.org', 'WUFT/Channel 5 (WUFT)'), # http://www.wuft.org
|
||||||
|
('watch.wxel.org', 'WXEL/Channel 42 (WXEL)'), # http://www.wxel.org/home/
|
||||||
|
('video.wlrn.org', 'WLRN/Channel 17 (WLRN)'), # http://www.wlrn.org/
|
||||||
|
('video.wusf.usf.edu', 'WUSF Public Broadcasting (WUSF)'), # http://wusf.org/
|
||||||
|
('video.scetv.org', 'ETV (WRLK)'), # http://www.scetv.org
|
||||||
|
('video.unctv.org', 'UNC-TV (WUNC)'), # http://www.unctv.org/
|
||||||
|
# ('pbsguam.org', 'PBS Guam (KGTF)'), # http://www.pbsguam.org/
|
||||||
|
('video.pbshawaii.org', 'PBS Hawaii - Oceanic Cable Channel 10 (KHET)'), # http://www.pbshawaii.org/
|
||||||
|
('video.idahoptv.org', 'Idaho Public Television (KAID)'), # http://idahoptv.org
|
||||||
|
('video.ksps.org', 'KSPS (KSPS)'), # http://www.ksps.org/home/
|
||||||
|
('watch.opb.org', 'OPB (KOPB)'), # http://www.opb.org
|
||||||
|
('watch.nwptv.org', 'KWSU/Channel 10 & KTNW/Channel 31 (KWSU)'), # http://www.kwsu.org
|
||||||
|
('video.will.illinois.edu', 'WILL-TV (WILL)'), # http://will.illinois.edu/
|
||||||
|
('video.networkknowledge.tv', 'Network Knowledge - WSEC/Springfield (WSEC)'), # http://www.wsec.tv
|
||||||
|
('video.wttw.com', 'WTTW11 (WTTW)'), # http://www.wttw.com/
|
||||||
|
# ('wtvp.org', 'WTVP & WTVP.org, Public Media for Central Illinois (WTVP)'), # http://www.wtvp.org/
|
||||||
|
('video.iptv.org', 'Iowa Public Television/IPTV (KDIN)'), # http://www.iptv.org/
|
||||||
|
('video.ninenet.org', 'Nine Network (KETC)'), # http://www.ninenet.org
|
||||||
|
('video.wfwa.org', 'PBS39 Fort Wayne (WFWA)'), # http://wfwa.org/
|
||||||
|
('video.wfyi.org', 'WFYI Indianapolis (WFYI)'), # http://www.wfyi.org
|
||||||
|
('video.mptv.org', 'Milwaukee Public Television (WMVS)'), # http://www.mptv.org
|
||||||
|
('video.wnin.org', 'WNIN (WNIN)'), # http://www.wnin.org/
|
||||||
|
('video.wnit.org', 'WNIT Public Television (WNIT)'), # http://www.wnit.org/
|
||||||
|
('video.wpt.org', 'WPT (WPNE)'), # http://www.wpt.org/
|
||||||
|
('video.wvut.org', 'WVUT/Channel 22 (WVUT)'), # http://wvut.org/
|
||||||
|
('video.weiu.net', 'WEIU/Channel 51 (WEIU)'), # http://www.weiu.net
|
||||||
|
('video.wqpt.org', 'WQPT-TV (WQPT)'), # http://www.wqpt.org
|
||||||
|
('video.wycc.org', 'WYCC PBS Chicago (WYCC)'), # http://www.wycc.org
|
||||||
|
# ('lakeshorepublicmedia.org', 'Lakeshore Public Television (WYIN)'), # http://lakeshorepublicmedia.org/
|
||||||
|
('video.wipb.org', 'WIPB-TV (WIPB)'), # http://wipb.org
|
||||||
|
('video.indianapublicmedia.org', 'WTIU (WTIU)'), # http://indianapublicmedia.org/tv/
|
||||||
|
('watch.cetconnect.org', 'CET (WCET)'), # http://www.cetconnect.org
|
||||||
|
('video.thinktv.org', 'ThinkTVNetwork (WPTD)'), # http://www.thinktv.org
|
||||||
|
('video.wbgu.org', 'WBGU-TV (WBGU)'), # http://wbgu.org
|
||||||
|
('video.wgvu.org', 'WGVU TV (WGVU)'), # http://www.wgvu.org/
|
||||||
|
('video.netnebraska.org', 'NET1 (KUON)'), # http://netnebraska.org
|
||||||
|
('video.pioneer.org', 'Pioneer Public Television (KWCM)'), # http://www.pioneer.org
|
||||||
|
('watch.sdpb.org', 'SDPB Television (KUSD)'), # http://www.sdpb.org
|
||||||
|
('video.tpt.org', 'TPT (KTCA)'), # http://www.tpt.org
|
||||||
|
('watch.ksmq.org', 'KSMQ (KSMQ)'), # http://www.ksmq.org/
|
||||||
|
('watch.kpts.org', 'KPTS/Channel 8 (KPTS)'), # http://www.kpts.org/
|
||||||
|
('watch.ktwu.org', 'KTWU/Channel 11 (KTWU)'), # http://ktwu.org
|
||||||
|
# ('shptv.org', 'Smoky Hills Public Television (KOOD)'), # http://www.shptv.org
|
||||||
|
# ('kcpt.org', 'KCPT Kansas City Public Television (KCPT)'), # http://kcpt.org/
|
||||||
|
# ('blueridgepbs.org', 'Blue Ridge PBS (WBRA)'), # http://www.blueridgepbs.org/
|
||||||
|
('watch.easttennesseepbs.org', 'East Tennessee PBS (WSJK)'), # http://easttennesseepbs.org
|
||||||
|
('video.wcte.tv', 'WCTE-TV (WCTE)'), # http://www.wcte.org
|
||||||
|
('video.wljt.org', 'WLJT, Channel 11 (WLJT)'), # http://wljt.org/
|
||||||
|
('video.wosu.org', 'WOSU TV (WOSU)'), # http://wosu.org/
|
||||||
|
('video.woub.org', 'WOUB/WOUC (WOUB)'), # http://woub.org/tv/index.php?section=5
|
||||||
|
('video.wvpublic.org', 'WVPB (WVPB)'), # http://wvpublic.org/
|
||||||
|
('video.wkyupbs.org', 'WKYU-PBS (WKYU)'), # http://www.wkyupbs.org
|
||||||
|
# ('wyes.org', 'WYES-TV/New Orleans (WYES)'), # http://www.wyes.org
|
||||||
|
('video.kera.org', 'KERA 13 (KERA)'), # http://www.kera.org/
|
||||||
|
('video.mpbn.net', 'MPBN (WCBB)'), # http://www.mpbn.net/
|
||||||
|
('video.mountainlake.org', 'Mountain Lake PBS (WCFE)'), # http://www.mountainlake.org/
|
||||||
|
('video.nhptv.org', 'NHPTV (WENH)'), # http://nhptv.org/
|
||||||
|
('video.vpt.org', 'Vermont PBS (WETK)'), # http://www.vpt.org
|
||||||
|
('video.witf.org', 'witf (WITF)'), # http://www.witf.org
|
||||||
|
('watch.wqed.org', 'WQED Multimedia (WQED)'), # http://www.wqed.org/
|
||||||
|
('video.wmht.org', 'WMHT Educational Telecommunications (WMHT)'), # http://www.wmht.org/home/
|
||||||
|
('video.deltabroadcasting.org', 'Q-TV (WDCQ)'), # http://www.deltabroadcasting.org
|
||||||
|
('video.dptv.org', 'WTVS Detroit Public TV (WTVS)'), # http://www.dptv.org/
|
||||||
|
('video.wcmu.org', 'CMU Public Television (WCMU)'), # http://www.wcmu.org
|
||||||
|
('video.wkar.org', 'WKAR-TV (WKAR)'), # http://wkar.org/
|
||||||
|
('wnmuvideo.nmu.edu', 'WNMU-TV Public TV 13 (WNMU)'), # http://wnmutv.nmu.edu
|
||||||
|
('video.wdse.org', 'WDSE - WRPT (WDSE)'), # http://www.wdse.org/
|
||||||
|
('video.wgte.org', 'WGTE TV (WGTE)'), # http://www.wgte.org
|
||||||
|
('video.lptv.org', 'Lakeland Public Television (KAWE)'), # http://www.lakelandptv.org
|
||||||
|
# ('prairiepublic.org', 'PRAIRIE PUBLIC (KFME)'), # http://www.prairiepublic.org/
|
||||||
|
('video.kmos.org', 'KMOS-TV - Channels 6.1, 6.2 and 6.3 (KMOS)'), # http://www.kmos.org/
|
||||||
|
('watch.montanapbs.org', 'MontanaPBS (KUSM)'), # http://montanapbs.org
|
||||||
|
('video.krwg.org', 'KRWG/Channel 22 (KRWG)'), # http://www.krwg.org
|
||||||
|
('video.kacvtv.org', 'KACV (KACV)'), # http://www.panhandlepbs.org/home/
|
||||||
|
('video.kcostv.org', 'KCOS/Channel 13 (KCOS)'), # www.kcostv.org
|
||||||
|
('video.wcny.org', 'WCNY/Channel 24 (WCNY)'), # http://www.wcny.org
|
||||||
|
('video.wned.org', 'WNED (WNED)'), # http://www.wned.org/
|
||||||
|
('watch.wpbstv.org', 'WPBS (WPBS)'), # http://www.wpbstv.org
|
||||||
|
('video.wskg.org', 'WSKG Public TV (WSKG)'), # http://wskg.org
|
||||||
|
('video.wxxi.org', 'WXXI (WXXI)'), # http://wxxi.org
|
||||||
|
('video.wpsu.org', 'WPSU (WPSU)'), # http://www.wpsu.org
|
||||||
|
# ('wqln.org', 'WQLN/Channel 54 (WQLN)'), # http://www.wqln.org
|
||||||
|
('on-demand.wvia.org', 'WVIA Public Media Studios (WVIA)'), # http://www.wvia.org/
|
||||||
|
('video.wtvi.org', 'WTVI (WTVI)'), # http://www.wtvi.org/
|
||||||
|
# ('whro.org', 'WHRO (WHRO)'), # http://whro.org
|
||||||
|
('video.westernreservepublicmedia.org', 'Western Reserve PBS (WNEO)'), # http://www.WesternReservePublicMedia.org/
|
||||||
|
('video.ideastream.org', 'WVIZ/PBS ideastream (WVIZ)'), # http://www.wviz.org/
|
||||||
|
('video.kcts9.org', 'KCTS 9 (KCTS)'), # http://kcts9.org/
|
||||||
|
('video.basinpbs.org', 'Basin PBS (KPBT)'), # http://www.basinpbs.org
|
||||||
|
('video.houstonpbs.org', 'KUHT / Channel 8 (KUHT)'), # http://www.houstonpublicmedia.org/
|
||||||
|
# ('tamu.edu', 'KAMU - TV (KAMU)'), # http://KAMU.tamu.edu
|
||||||
|
# ('kedt.org', 'KEDT/Channel 16 (KEDT)'), # http://www.kedt.org
|
||||||
|
('video.klrn.org', 'KLRN (KLRN)'), # http://www.klrn.org
|
||||||
|
('video.klru.tv', 'KLRU (KLRU)'), # http://www.klru.org
|
||||||
|
# ('kmbh.org', 'KMBH-TV (KMBH)'), # http://www.kmbh.org
|
||||||
|
# ('knct.org', 'KNCT (KNCT)'), # http://www.knct.org
|
||||||
|
# ('ktxt.org', 'KTTZ-TV (KTXT)'), # http://www.ktxt.org
|
||||||
|
('video.wtjx.org', 'WTJX Channel 12 (WTJX)'), # http://www.wtjx.org/
|
||||||
|
('video.ideastations.org', 'WCVE PBS (WCVE)'), # http://ideastations.org/
|
||||||
|
('video.kbtc.org', 'KBTC Public Television (KBTC)'), # http://kbtc.org
|
||||||
|
)
|
||||||
|
|
||||||
|
IE_NAME = 'pbs'
|
||||||
|
IE_DESC = 'Public Broadcasting Service (PBS) and member stations: %s' % ', '.join(list(zip(*_STATIONS))[1])
|
||||||
|
|
||||||
_VALID_URL = r'''(?x)https?://
|
_VALID_URL = r'''(?x)https?://
|
||||||
(?:
|
(?:
|
||||||
# Direct video URL
|
# Direct video URL
|
||||||
video\.pbs\.org/(?:viralplayer|video)/(?P<id>[0-9]+)/? |
|
(?:%s)/(?:viralplayer|video)/(?P<id>[0-9]+)/? |
|
||||||
# Article with embedded player (or direct video)
|
# Article with embedded player (or direct video)
|
||||||
(?:www\.)?pbs\.org/(?:[^/]+/){2,5}(?P<presumptive_id>[^/]+?)(?:\.html)?/?(?:$|[?\#]) |
|
(?:www\.)?pbs\.org/(?:[^/]+/){2,5}(?P<presumptive_id>[^/]+?)(?:\.html)?/?(?:$|[?\#]) |
|
||||||
# Player
|
# Player
|
||||||
(?:video|player)\.pbs\.org/(?:widget/)?partnerplayer/(?P<player_id>[^/]+)/
|
(?:video|player)\.pbs\.org/(?:widget/)?partnerplayer/(?P<player_id>[^/]+)/
|
||||||
)
|
)
|
||||||
'''
|
''' % '|'.join(re.escape(p) for p in list(zip(*_STATIONS))[0])
|
||||||
|
|
||||||
_TESTS = [
|
_TESTS = [
|
||||||
{
|
{
|
||||||
@@ -174,6 +339,10 @@ class PBSIE(InfoExtractor):
|
|||||||
{
|
{
|
||||||
'url': 'http://player.pbs.org/widget/partnerplayer/2365297708/?start=0&end=0&chapterbar=false&endscreen=false&topbar=true',
|
'url': 'http://player.pbs.org/widget/partnerplayer/2365297708/?start=0&end=0&chapterbar=false&endscreen=false&topbar=true',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url': 'http://watch.knpb.org/video/2365616055/',
|
||||||
|
'only_matching': True,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
_ERRORS = {
|
_ERRORS = {
|
||||||
@@ -204,6 +373,7 @@ class PBSIE(InfoExtractor):
|
|||||||
MEDIA_ID_REGEXES = [
|
MEDIA_ID_REGEXES = [
|
||||||
r"div\s*:\s*'videoembed'\s*,\s*mediaid\s*:\s*'(\d+)'", # frontline video embed
|
r"div\s*:\s*'videoembed'\s*,\s*mediaid\s*:\s*'(\d+)'", # frontline video embed
|
||||||
r'class="coveplayerid">([^<]+)<', # coveplayer
|
r'class="coveplayerid">([^<]+)<', # coveplayer
|
||||||
|
r'<section[^>]+data-coveid="(\d+)"', # coveplayer from http://www.pbs.org/wgbh/frontline/film/real-csi/
|
||||||
r'<input type="hidden" id="pbs_video_id_[0-9]+" value="([0-9]+)"/>', # jwplayer
|
r'<input type="hidden" id="pbs_video_id_[0-9]+" value="([0-9]+)"/>', # jwplayer
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
ExtractorError,
|
ExtractorError,
|
||||||
@@ -44,6 +46,13 @@ class PladformIE(InfoExtractor):
|
|||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _extract_url(webpage):
|
||||||
|
mobj = re.search(
|
||||||
|
r'<iframe[^>]+src="(?P<url>(?:https?:)?//out\.pladform\.ru/player\?.+?)"', webpage)
|
||||||
|
if mobj:
|
||||||
|
return mobj.group('url')
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
video_id = self._match_id(url)
|
video_id = self._match_id(url)
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import re
|
|||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from .brightcove import BrightcoveLegacyIE
|
from .brightcove import BrightcoveLegacyIE
|
||||||
|
|
||||||
from ..compat import compat_urllib_parse
|
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
ExtractorError,
|
ExtractorError,
|
||||||
sanitized_Request,
|
sanitized_Request,
|
||||||
smuggle_url,
|
smuggle_url,
|
||||||
std_headers,
|
std_headers,
|
||||||
|
urlencode_postdata,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ class SafariBaseIE(InfoExtractor):
|
|||||||
}
|
}
|
||||||
|
|
||||||
request = sanitized_Request(
|
request = sanitized_Request(
|
||||||
self._LOGIN_URL, compat_urllib_parse.urlencode(login_form), headers=headers)
|
self._LOGIN_URL, urlencode_postdata(login_form), headers=headers)
|
||||||
login_page = self._download_webpage(
|
login_page = self._download_webpage(
|
||||||
request, None, 'Logging in as %s' % username)
|
request, None, 'Logging in as %s' % username)
|
||||||
|
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ class SohuIE(InfoExtractor):
|
|||||||
'file': clips_url[i],
|
'file': clips_url[i],
|
||||||
'new': su[i],
|
'new': su[i],
|
||||||
'prod': 'flash',
|
'prod': 'flash',
|
||||||
|
'rb': 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
if cdnId is not None:
|
if cdnId is not None:
|
||||||
|
|||||||
@@ -16,11 +16,12 @@ from ..compat import (
|
|||||||
from ..utils import (
|
from ..utils import (
|
||||||
determine_ext,
|
determine_ext,
|
||||||
ExtractorError,
|
ExtractorError,
|
||||||
xpath_with_ns,
|
|
||||||
unsmuggle_url,
|
|
||||||
int_or_none,
|
|
||||||
url_basename,
|
|
||||||
float_or_none,
|
float_or_none,
|
||||||
|
int_or_none,
|
||||||
|
sanitized_Request,
|
||||||
|
unsmuggle_url,
|
||||||
|
url_basename,
|
||||||
|
xpath_with_ns,
|
||||||
)
|
)
|
||||||
|
|
||||||
default_ns = 'http://www.w3.org/2005/SMIL21/Language'
|
default_ns = 'http://www.w3.org/2005/SMIL21/Language'
|
||||||
@@ -204,7 +205,12 @@ class ThePlatformIE(ThePlatformBaseIE):
|
|||||||
smil_url = url
|
smil_url = url
|
||||||
# Explicitly specified SMIL (see https://github.com/rg3/youtube-dl/issues/7385)
|
# Explicitly specified SMIL (see https://github.com/rg3/youtube-dl/issues/7385)
|
||||||
elif '/guid/' in url:
|
elif '/guid/' in url:
|
||||||
webpage = self._download_webpage(url, video_id)
|
headers = {}
|
||||||
|
source_url = smuggled_data.get('source_url')
|
||||||
|
if source_url:
|
||||||
|
headers['Referer'] = source_url
|
||||||
|
request = sanitized_Request(url, headers=headers)
|
||||||
|
webpage = self._download_webpage(request, video_id)
|
||||||
smil_url = self._search_regex(
|
smil_url = self._search_regex(
|
||||||
r'<link[^>]+href=(["\'])(?P<url>.+?)\1[^>]+type=["\']application/smil\+xml',
|
r'<link[^>]+href=(["\'])(?P<url>.+?)\1[^>]+type=["\']application/smil\+xml',
|
||||||
webpage, 'smil url', group='url')
|
webpage, 'smil url', group='url')
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ from __future__ import unicode_literals
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from ..compat import compat_etree_fromstring
|
from ..compat import (
|
||||||
|
compat_etree_fromstring,
|
||||||
|
compat_urlparse,
|
||||||
|
)
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
ExtractorError,
|
ExtractorError,
|
||||||
int_or_none,
|
int_or_none,
|
||||||
@@ -67,6 +70,17 @@ class VevoIE(InfoExtractor):
|
|||||||
'params': {
|
'params': {
|
||||||
'skip_download': 'true',
|
'skip_download': 'true',
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
'note': 'No video_info',
|
||||||
|
'url': 'http://www.vevo.com/watch/k-camp-1/Till-I-Die/USUV71503000',
|
||||||
|
'md5': '8b83cc492d72fc9cf74a02acee7dc1b0',
|
||||||
|
'info_dict': {
|
||||||
|
'id': 'USUV71503000',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Till I Die - K Camp ft. T.I.',
|
||||||
|
'duration': 193,
|
||||||
|
},
|
||||||
|
'expected_warnings': ['Unable to download SMIL file'],
|
||||||
}]
|
}]
|
||||||
_SMIL_BASE_URL = 'http://smil.lvl3.vevo.com/'
|
_SMIL_BASE_URL = 'http://smil.lvl3.vevo.com/'
|
||||||
|
|
||||||
@@ -81,11 +95,17 @@ class VevoIE(InfoExtractor):
|
|||||||
if webpage is False:
|
if webpage is False:
|
||||||
self._oauth_token = None
|
self._oauth_token = None
|
||||||
else:
|
else:
|
||||||
|
if 'THIS PAGE IS CURRENTLY UNAVAILABLE IN YOUR REGION' in webpage:
|
||||||
|
raise ExtractorError('%s said: This page is currently unavailable in your region.' % self.IE_NAME, expected=True)
|
||||||
|
|
||||||
self._oauth_token = self._search_regex(
|
self._oauth_token = self._search_regex(
|
||||||
r'access_token":\s*"([^"]+)"',
|
r'access_token":\s*"([^"]+)"',
|
||||||
webpage, 'access token', fatal=False)
|
webpage, 'access token', fatal=False)
|
||||||
|
|
||||||
def _formats_from_json(self, video_info):
|
def _formats_from_json(self, video_info):
|
||||||
|
if not video_info:
|
||||||
|
return []
|
||||||
|
|
||||||
last_version = {'version': -1}
|
last_version = {'version': -1}
|
||||||
for version in video_info['videoVersions']:
|
for version in video_info['videoVersions']:
|
||||||
# These are the HTTP downloads, other types are for different manifests
|
# These are the HTTP downloads, other types are for different manifests
|
||||||
@@ -110,9 +130,8 @@ class VevoIE(InfoExtractor):
|
|||||||
})
|
})
|
||||||
return formats
|
return formats
|
||||||
|
|
||||||
def _formats_from_smil(self, smil_xml):
|
def _formats_from_smil(self, smil_doc):
|
||||||
formats = []
|
formats = []
|
||||||
smil_doc = compat_etree_fromstring(smil_xml.encode('utf-8'))
|
|
||||||
els = smil_doc.findall('.//{http://www.w3.org/2001/SMIL20/Language}video')
|
els = smil_doc.findall('.//{http://www.w3.org/2001/SMIL20/Language}video')
|
||||||
for el in els:
|
for el in els:
|
||||||
src = el.attrib['src']
|
src = el.attrib['src']
|
||||||
@@ -145,14 +164,14 @@ class VevoIE(InfoExtractor):
|
|||||||
})
|
})
|
||||||
return formats
|
return formats
|
||||||
|
|
||||||
def _download_api_formats(self, video_id):
|
def _download_api_formats(self, video_id, video_url):
|
||||||
if not self._oauth_token:
|
if not self._oauth_token:
|
||||||
self._downloader.report_warning(
|
self._downloader.report_warning(
|
||||||
'No oauth token available, skipping API HLS download')
|
'No oauth token available, skipping API HLS download')
|
||||||
return []
|
return []
|
||||||
|
|
||||||
api_url = 'https://apiv2.vevo.com/video/%s/streams/hls?token=%s' % (
|
api_url = compat_urlparse.urljoin(video_url, '//apiv2.vevo.com/video/%s/streams/hls?token=%s' % (
|
||||||
video_id, self._oauth_token)
|
video_id, self._oauth_token))
|
||||||
api_data = self._download_json(
|
api_data = self._download_json(
|
||||||
api_url, video_id,
|
api_url, video_id,
|
||||||
note='Downloading HLS formats',
|
note='Downloading HLS formats',
|
||||||
@@ -166,18 +185,26 @@ class VevoIE(InfoExtractor):
|
|||||||
preference=0)
|
preference=0)
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
video_id = self._match_id(url)
|
||||||
video_id = mobj.group('id')
|
|
||||||
|
webpage = None
|
||||||
|
|
||||||
json_url = 'http://videoplayer.vevo.com/VideoService/AuthenticateVideo?isrc=%s' % video_id
|
json_url = 'http://videoplayer.vevo.com/VideoService/AuthenticateVideo?isrc=%s' % video_id
|
||||||
response = self._download_json(json_url, video_id)
|
response = self._download_json(json_url, video_id)
|
||||||
video_info = response['video']
|
video_info = response['video'] or {}
|
||||||
|
|
||||||
if not video_info:
|
if not video_info and response.get('statusCode') != 909:
|
||||||
if 'statusMessage' in response:
|
if 'statusMessage' in response:
|
||||||
raise ExtractorError('%s said: %s' % (self.IE_NAME, response['statusMessage']), expected=True)
|
raise ExtractorError('%s said: %s' % (self.IE_NAME, response['statusMessage']), expected=True)
|
||||||
raise ExtractorError('Unable to extract videos')
|
raise ExtractorError('Unable to extract videos')
|
||||||
|
|
||||||
|
if not video_info:
|
||||||
|
if url.startswith('vevo:'):
|
||||||
|
raise ExtractorError('Please specify full Vevo URL for downloading', expected=True)
|
||||||
|
webpage = self._download_webpage(url, video_id)
|
||||||
|
|
||||||
|
title = video_info.get('title') or self._og_search_title(webpage)
|
||||||
|
|
||||||
formats = self._formats_from_json(video_info)
|
formats = self._formats_from_json(video_info)
|
||||||
|
|
||||||
is_explicit = video_info.get('isExplicit')
|
is_explicit = video_info.get('isExplicit')
|
||||||
@@ -189,11 +216,11 @@ class VevoIE(InfoExtractor):
|
|||||||
age_limit = None
|
age_limit = None
|
||||||
|
|
||||||
# Download via HLS API
|
# Download via HLS API
|
||||||
formats.extend(self._download_api_formats(video_id))
|
formats.extend(self._download_api_formats(video_id, url))
|
||||||
|
|
||||||
# Download SMIL
|
# Download SMIL
|
||||||
smil_blocks = sorted((
|
smil_blocks = sorted((
|
||||||
f for f in video_info['videoVersions']
|
f for f in video_info.get('videoVersions', [])
|
||||||
if f['sourceType'] == 13),
|
if f['sourceType'] == 13),
|
||||||
key=lambda f: f['version'])
|
key=lambda f: f['version'])
|
||||||
smil_url = '%s/Video/V2/VFILE/%s/%sr.smil' % (
|
smil_url = '%s/Video/V2/VFILE/%s/%sr.smil' % (
|
||||||
@@ -205,23 +232,26 @@ class VevoIE(InfoExtractor):
|
|||||||
if smil_url_m is not None:
|
if smil_url_m is not None:
|
||||||
smil_url = smil_url_m
|
smil_url = smil_url_m
|
||||||
if smil_url:
|
if smil_url:
|
||||||
smil_xml = self._download_webpage(
|
smil_doc = self._download_smil(smil_url, video_id, fatal=False)
|
||||||
smil_url, video_id, 'Downloading SMIL info', fatal=False)
|
if smil_doc:
|
||||||
if smil_xml:
|
formats.extend(self._formats_from_smil(smil_doc))
|
||||||
formats.extend(self._formats_from_smil(smil_xml))
|
|
||||||
|
|
||||||
self._sort_formats(formats)
|
self._sort_formats(formats)
|
||||||
timestamp_ms = int_or_none(self._search_regex(
|
timestamp = int_or_none(self._search_regex(
|
||||||
r'/Date\((\d+)\)/',
|
r'/Date\((\d+)\)/',
|
||||||
video_info['launchDate'], 'launch date', fatal=False))
|
video_info['launchDate'], 'launch date', fatal=False),
|
||||||
|
scale=1000) if video_info else None
|
||||||
|
|
||||||
|
duration = video_info.get('duration') or int_or_none(
|
||||||
|
self._html_search_meta('video:duration', webpage))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
'title': video_info['title'],
|
'title': title,
|
||||||
'formats': formats,
|
'formats': formats,
|
||||||
'thumbnail': video_info['imageUrl'],
|
'thumbnail': video_info.get('imageUrl'),
|
||||||
'timestamp': timestamp_ms // 1000,
|
'timestamp': timestamp,
|
||||||
'uploader': video_info['mainArtists'][0]['artistName'],
|
'uploader': video_info['mainArtists'][0]['artistName'] if video_info else None,
|
||||||
'duration': video_info['duration'],
|
'duration': duration,
|
||||||
'age_limit': age_limit,
|
'age_limit': age_limit,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from ..utils import (
|
|||||||
unified_strdate,
|
unified_strdate,
|
||||||
)
|
)
|
||||||
from .vimeo import VimeoIE
|
from .vimeo import VimeoIE
|
||||||
|
from .pladform import PladformIE
|
||||||
|
|
||||||
|
|
||||||
class VKIE(InfoExtractor):
|
class VKIE(InfoExtractor):
|
||||||
@@ -164,6 +165,11 @@ class VKIE(InfoExtractor):
|
|||||||
# vk wrapper
|
# vk wrapper
|
||||||
'url': 'http://www.biqle.ru/watch/847655_160197695',
|
'url': 'http://www.biqle.ru/watch/847655_160197695',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# pladform embed
|
||||||
|
'url': 'https://vk.com/video-76116461_171554880',
|
||||||
|
'only_matching': True,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -254,10 +260,13 @@ class VKIE(InfoExtractor):
|
|||||||
if vimeo_url is not None:
|
if vimeo_url is not None:
|
||||||
return self.url_result(vimeo_url)
|
return self.url_result(vimeo_url)
|
||||||
|
|
||||||
|
pladform_url = PladformIE._extract_url(info_page)
|
||||||
|
if pladform_url:
|
||||||
|
return self.url_result(pladform_url)
|
||||||
|
|
||||||
m_rutube = re.search(
|
m_rutube = re.search(
|
||||||
r'\ssrc="((?:https?:)?//rutube\.ru\\?/video\\?/embed(?:.*?))\\?"', info_page)
|
r'\ssrc="((?:https?:)?//rutube\.ru\\?/video\\?/embed(?:.*?))\\?"', info_page)
|
||||||
if m_rutube is not None:
|
if m_rutube is not None:
|
||||||
self.to_screen('rutube video detected')
|
|
||||||
rutube_url = self._proto_relative_url(
|
rutube_url = self._proto_relative_url(
|
||||||
m_rutube.group(1).replace('\\', ''))
|
m_rutube.group(1).replace('\\', ''))
|
||||||
return self.url_result(rutube_url)
|
return self.url_result(rutube_url)
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ from ..compat import (
|
|||||||
compat_urlparse,
|
compat_urlparse,
|
||||||
)
|
)
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
determine_ext,
|
|
||||||
unified_strdate,
|
unified_strdate,
|
||||||
|
qualities,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +33,7 @@ class WDRIE(InfoExtractor):
|
|||||||
'params': {
|
'params': {
|
||||||
'skip_download': True,
|
'skip_download': True,
|
||||||
},
|
},
|
||||||
|
'skip': 'Page Not Found',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'url': 'http://www1.wdr.de/themen/av/videomargaspiegelisttot101-videoplayer.html',
|
'url': 'http://www1.wdr.de/themen/av/videomargaspiegelisttot101-videoplayer.html',
|
||||||
@@ -47,6 +48,7 @@ class WDRIE(InfoExtractor):
|
|||||||
'params': {
|
'params': {
|
||||||
'skip_download': True,
|
'skip_download': True,
|
||||||
},
|
},
|
||||||
|
'skip': 'Page Not Found',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'url': 'http://www1.wdr.de/themen/kultur/audioerlebtegeschichtenmargaspiegel100-audioplayer.html',
|
'url': 'http://www1.wdr.de/themen/kultur/audioerlebtegeschichtenmargaspiegel100-audioplayer.html',
|
||||||
@@ -71,6 +73,7 @@ class WDRIE(InfoExtractor):
|
|||||||
'upload_date': '20140717',
|
'upload_date': '20140717',
|
||||||
'is_live': False
|
'is_live': False
|
||||||
},
|
},
|
||||||
|
'skip': 'Page Not Found',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'url': 'http://www1.wdr.de/mediathek/video/sendungen/quarks_und_co/filterseite-quarks-und-co100.html',
|
'url': 'http://www1.wdr.de/mediathek/video/sendungen/quarks_und_co/filterseite-quarks-und-co100.html',
|
||||||
@@ -83,10 +86,10 @@ class WDRIE(InfoExtractor):
|
|||||||
'url': 'http://www1.wdr.de/mediathek/video/livestream/index.html',
|
'url': 'http://www1.wdr.de/mediathek/video/livestream/index.html',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'mdb-103364',
|
'id': 'mdb-103364',
|
||||||
'title': 're:^WDR Fernsehen [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$',
|
'title': 're:^WDR Fernsehen Live [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$',
|
||||||
'description': 'md5:ae2ff888510623bf8d4b115f95a9b7c9',
|
'description': 'md5:ae2ff888510623bf8d4b115f95a9b7c9',
|
||||||
'ext': 'flv',
|
'ext': 'flv',
|
||||||
'upload_date': '20150212',
|
'upload_date': '20150101',
|
||||||
'is_live': True
|
'is_live': True
|
||||||
},
|
},
|
||||||
'params': {
|
'params': {
|
||||||
@@ -150,25 +153,52 @@ class WDRIE(InfoExtractor):
|
|||||||
if upload_date:
|
if upload_date:
|
||||||
upload_date = unified_strdate(upload_date)
|
upload_date = unified_strdate(upload_date)
|
||||||
|
|
||||||
|
formats = []
|
||||||
|
preference = qualities(['S', 'M', 'L', 'XL'])
|
||||||
|
|
||||||
if video_url.endswith('.f4m'):
|
if video_url.endswith('.f4m'):
|
||||||
video_url += '?hdcore=3.2.0&plugin=aasp-3.2.0.77.18'
|
f4m_formats = self._extract_f4m_formats(video_url + '?hdcore=3.2.0&plugin=aasp-3.2.0.77.18', page_id, f4m_id='hds', fatal=False)
|
||||||
ext = 'flv'
|
if f4m_formats:
|
||||||
|
formats.extend(f4m_formats)
|
||||||
elif video_url.endswith('.smil'):
|
elif video_url.endswith('.smil'):
|
||||||
fmt = self._extract_smil_formats(video_url, page_id)[0]
|
smil_formats = self._extract_smil_formats(video_url, page_id, False, {
|
||||||
video_url = fmt['url']
|
'hdcore': '3.3.0',
|
||||||
sep = '&' if '?' in video_url else '?'
|
'plugin': 'aasp-3.3.0.99.43',
|
||||||
video_url += sep
|
})
|
||||||
video_url += 'hdcore=3.3.0&plugin=aasp-3.3.0.99.43'
|
if smil_formats:
|
||||||
ext = fmt['ext']
|
formats.extend(smil_formats)
|
||||||
else:
|
else:
|
||||||
ext = determine_ext(video_url)
|
formats.append({
|
||||||
|
'url': video_url,
|
||||||
|
'http_headers': {
|
||||||
|
'User-Agent': 'mobile',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
m3u8_url = self._search_regex(r'rel="adaptiv"[^>]+href="([^"]+)"', webpage, 'm3u8 url', default=None)
|
||||||
|
if m3u8_url:
|
||||||
|
m3u8_formats = self._extract_m3u8_formats(m3u8_url, page_id, 'mp4', 'm3u8_native', m3u8_id='hls', fatal=False)
|
||||||
|
if m3u8_formats:
|
||||||
|
formats.extend(m3u8_formats)
|
||||||
|
|
||||||
|
direct_urls = re.findall(r'rel="web(S|M|L|XL)"[^>]+href="([^"]+)"', webpage)
|
||||||
|
if direct_urls:
|
||||||
|
for quality, video_url in direct_urls:
|
||||||
|
formats.append({
|
||||||
|
'url': video_url,
|
||||||
|
'preference': preference(quality),
|
||||||
|
'http_headers': {
|
||||||
|
'User-Agent': 'mobile',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
self._sort_formats(formats)
|
||||||
|
|
||||||
description = self._html_search_meta('Description', webpage, 'description')
|
description = self._html_search_meta('Description', webpage, 'description')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id': page_id,
|
'id': page_id,
|
||||||
'url': video_url,
|
'formats': formats,
|
||||||
'ext': ext,
|
|
||||||
'title': title,
|
'title': title,
|
||||||
'description': description,
|
'description': description,
|
||||||
'thumbnail': thumbnail,
|
'thumbnail': thumbnail,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from .youtube import YoutubeIE
|
|||||||
|
|
||||||
|
|
||||||
class WimpIE(InfoExtractor):
|
class WimpIE(InfoExtractor):
|
||||||
_VALID_URL = r'http://(?:www\.)?wimp\.com/(?P<id>[^/]+)/'
|
_VALID_URL = r'http://(?:www\.)?wimp\.com/(?P<id>[^/]+)'
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
'url': 'http://www.wimp.com/maruexhausted/',
|
'url': 'http://www.wimp.com/maruexhausted/',
|
||||||
'md5': 'ee21217ffd66d058e8b16be340b74883',
|
'md5': 'ee21217ffd66d058e8b16be340b74883',
|
||||||
@@ -28,18 +28,23 @@ class WimpIE(InfoExtractor):
|
|||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
video_id = self._match_id(url)
|
video_id = self._match_id(url)
|
||||||
|
|
||||||
webpage = self._download_webpage(url, video_id)
|
webpage = self._download_webpage(url, video_id)
|
||||||
video_url = self._search_regex(
|
|
||||||
[r"[\"']file[\"']\s*[:,]\s*[\"'](.+?)[\"']", r"videoId\s*:\s*[\"']([^\"']+)[\"']"],
|
youtube_id = self._search_regex(
|
||||||
webpage, 'video URL')
|
r"videoId\s*:\s*[\"']([0-9A-Za-z_-]{11})[\"']",
|
||||||
if YoutubeIE.suitable(video_url):
|
webpage, 'video URL', default=None)
|
||||||
self.to_screen('Found YouTube video')
|
if youtube_id:
|
||||||
return {
|
return {
|
||||||
'_type': 'url',
|
'_type': 'url',
|
||||||
'url': video_url,
|
'url': youtube_id,
|
||||||
'ie_key': YoutubeIE.ie_key(),
|
'ie_key': YoutubeIE.ie_key(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
video_url = self._search_regex(
|
||||||
|
r'<video[^>]+>\s*<source[^>]+src=(["\'])(?P<url>.+?)\1',
|
||||||
|
webpage, 'video URL', group='url')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
'url': video_url,
|
'url': video_url,
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ class YoukuIE(InfoExtractor):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
|
# MD5 is unstable
|
||||||
'url': 'http://v.youku.com/v_show/id_XMTc1ODE5Njcy.html',
|
'url': 'http://v.youku.com/v_show/id_XMTc1ODE5Njcy.html',
|
||||||
'md5': '5f3af4192eabacc4501508d54a8cabd7',
|
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'XMTc1ODE5Njcy_part1',
|
'id': 'XMTc1ODE5Njcy_part1',
|
||||||
'title': '★Smile﹗♡ Git Fresh -Booty Music舞蹈.',
|
'title': '★Smile﹗♡ Git Fresh -Booty Music舞蹈.',
|
||||||
@@ -42,6 +42,7 @@ class YoukuIE(InfoExtractor):
|
|||||||
'title': '武媚娘传奇 85',
|
'title': '武媚娘传奇 85',
|
||||||
},
|
},
|
||||||
'playlist_count': 11,
|
'playlist_count': 11,
|
||||||
|
'skip': 'Available in China only',
|
||||||
}, {
|
}, {
|
||||||
'url': 'http://v.youku.com/v_show/id_XMTI1OTczNDM5Mg==.html',
|
'url': 'http://v.youku.com/v_show/id_XMTI1OTczNDM5Mg==.html',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
@@ -49,7 +50,6 @@ class YoukuIE(InfoExtractor):
|
|||||||
'title': '花千骨 04',
|
'title': '花千骨 04',
|
||||||
},
|
},
|
||||||
'playlist_count': 13,
|
'playlist_count': 13,
|
||||||
'skip': 'Available in China only',
|
|
||||||
}, {
|
}, {
|
||||||
'url': 'http://v.youku.com/v_show/id_XNjA1NzA2Njgw.html',
|
'url': 'http://v.youku.com/v_show/id_XNjA1NzA2Njgw.html',
|
||||||
'note': 'Video protected with password',
|
'note': 'Video protected with password',
|
||||||
@@ -63,7 +63,7 @@ class YoukuIE(InfoExtractor):
|
|||||||
},
|
},
|
||||||
}]
|
}]
|
||||||
|
|
||||||
def construct_video_urls(self, data1, data2):
|
def construct_video_urls(self, data):
|
||||||
# get sid, token
|
# get sid, token
|
||||||
def yk_t(s1, s2):
|
def yk_t(s1, s2):
|
||||||
ls = list(range(256))
|
ls = list(range(256))
|
||||||
@@ -81,34 +81,24 @@ class YoukuIE(InfoExtractor):
|
|||||||
return bytes(s)
|
return bytes(s)
|
||||||
|
|
||||||
sid, token = yk_t(
|
sid, token = yk_t(
|
||||||
b'becaf9be', base64.b64decode(data2['ep'].encode('ascii'))
|
b'becaf9be', base64.b64decode(data['security']['encrypt_string'].encode('ascii'))
|
||||||
).decode('ascii').split('_')
|
).decode('ascii').split('_')
|
||||||
|
|
||||||
# get oip
|
# get oip
|
||||||
oip = data2['ip']
|
oip = data['security']['ip']
|
||||||
|
|
||||||
# get fileid
|
|
||||||
string_ls = list(
|
|
||||||
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/\:._-1234567890')
|
|
||||||
shuffled_string_ls = []
|
|
||||||
seed = data1['seed']
|
|
||||||
N = len(string_ls)
|
|
||||||
for ii in range(N):
|
|
||||||
seed = (seed * 0xd3 + 0x754f) % 0x10000
|
|
||||||
idx = seed * len(string_ls) // 0x10000
|
|
||||||
shuffled_string_ls.append(string_ls[idx])
|
|
||||||
del string_ls[idx]
|
|
||||||
|
|
||||||
fileid_dict = {}
|
fileid_dict = {}
|
||||||
for format in data1['streamtypes']:
|
for stream in data['stream']:
|
||||||
streamfileid = [
|
format = stream.get('stream_type')
|
||||||
int(i) for i in data1['streamfileids'][format].strip('*').split('*')]
|
fileid = stream['stream_fileid']
|
||||||
fileid = ''.join(
|
fileid_dict[format] = fileid
|
||||||
[shuffled_string_ls[i] for i in streamfileid])
|
|
||||||
fileid_dict[format] = fileid[:8] + '%s' + fileid[10:]
|
|
||||||
|
|
||||||
def get_fileid(format, n):
|
def get_fileid(format, n):
|
||||||
fileid = fileid_dict[format] % hex(int(n))[2:].upper().zfill(2)
|
number = hex(int(str(n), 10))[2:].upper()
|
||||||
|
if len(number) == 1:
|
||||||
|
number = '0' + number
|
||||||
|
streamfileids = fileid_dict[format]
|
||||||
|
fileid = streamfileids[0:8] + number + streamfileids[10:]
|
||||||
return fileid
|
return fileid
|
||||||
|
|
||||||
# get ep
|
# get ep
|
||||||
@@ -123,15 +113,15 @@ class YoukuIE(InfoExtractor):
|
|||||||
|
|
||||||
# generate video_urls
|
# generate video_urls
|
||||||
video_urls_dict = {}
|
video_urls_dict = {}
|
||||||
for format in data1['streamtypes']:
|
for stream in data['stream']:
|
||||||
|
format = stream.get('stream_type')
|
||||||
video_urls = []
|
video_urls = []
|
||||||
for dt in data1['segs'][format]:
|
for dt in stream['segs']:
|
||||||
n = str(int(dt['no']))
|
n = str(stream['segs'].index(dt))
|
||||||
param = {
|
param = {
|
||||||
'K': dt['k'],
|
'K': dt['key'],
|
||||||
'hd': self.get_hd(format),
|
'hd': self.get_hd(format),
|
||||||
'myp': 0,
|
'myp': 0,
|
||||||
'ts': dt['seconds'],
|
|
||||||
'ypp': 0,
|
'ypp': 0,
|
||||||
'ctype': 12,
|
'ctype': 12,
|
||||||
'ev': 1,
|
'ev': 1,
|
||||||
@@ -142,7 +132,7 @@ class YoukuIE(InfoExtractor):
|
|||||||
video_url = \
|
video_url = \
|
||||||
'http://k.youku.com/player/getFlvPath/' + \
|
'http://k.youku.com/player/getFlvPath/' + \
|
||||||
'sid/' + sid + \
|
'sid/' + sid + \
|
||||||
'_' + str(int(n) + 1).zfill(2) + \
|
'_00' + \
|
||||||
'/st/' + self.parse_ext_l(format) + \
|
'/st/' + self.parse_ext_l(format) + \
|
||||||
'/fileid/' + get_fileid(format, n) + '?' + \
|
'/fileid/' + get_fileid(format, n) + '?' + \
|
||||||
compat_urllib_parse.urlencode(param)
|
compat_urllib_parse.urlencode(param)
|
||||||
@@ -153,23 +143,31 @@ class YoukuIE(InfoExtractor):
|
|||||||
|
|
||||||
def get_hd(self, fm):
|
def get_hd(self, fm):
|
||||||
hd_id_dict = {
|
hd_id_dict = {
|
||||||
|
'3gp': '0',
|
||||||
|
'3gphd': '1',
|
||||||
'flv': '0',
|
'flv': '0',
|
||||||
|
'flvhd': '0',
|
||||||
'mp4': '1',
|
'mp4': '1',
|
||||||
|
'mp4hd': '1',
|
||||||
|
'mp4hd2': '1',
|
||||||
|
'mp4hd3': '1',
|
||||||
'hd2': '2',
|
'hd2': '2',
|
||||||
'hd3': '3',
|
'hd3': '3',
|
||||||
'3gp': '0',
|
|
||||||
'3gphd': '1'
|
|
||||||
}
|
}
|
||||||
return hd_id_dict[fm]
|
return hd_id_dict[fm]
|
||||||
|
|
||||||
def parse_ext_l(self, fm):
|
def parse_ext_l(self, fm):
|
||||||
ext_dict = {
|
ext_dict = {
|
||||||
|
'3gp': 'flv',
|
||||||
|
'3gphd': 'mp4',
|
||||||
'flv': 'flv',
|
'flv': 'flv',
|
||||||
|
'flvhd': 'flv',
|
||||||
'mp4': 'mp4',
|
'mp4': 'mp4',
|
||||||
|
'mp4hd': 'mp4',
|
||||||
|
'mp4hd2': 'flv',
|
||||||
|
'mp4hd3': 'flv',
|
||||||
'hd2': 'flv',
|
'hd2': 'flv',
|
||||||
'hd3': 'flv',
|
'hd3': 'flv',
|
||||||
'3gp': 'flv',
|
|
||||||
'3gphd': 'mp4'
|
|
||||||
}
|
}
|
||||||
return ext_dict[fm]
|
return ext_dict[fm]
|
||||||
|
|
||||||
@@ -178,9 +176,13 @@ class YoukuIE(InfoExtractor):
|
|||||||
'3gp': 'h6',
|
'3gp': 'h6',
|
||||||
'3gphd': 'h5',
|
'3gphd': 'h5',
|
||||||
'flv': 'h4',
|
'flv': 'h4',
|
||||||
|
'flvhd': 'h4',
|
||||||
'mp4': 'h3',
|
'mp4': 'h3',
|
||||||
|
'mp4hd': 'h3',
|
||||||
|
'mp4hd2': 'h4',
|
||||||
|
'mp4hd3': 'h4',
|
||||||
'hd2': 'h2',
|
'hd2': 'h2',
|
||||||
'hd3': 'h1'
|
'hd3': 'h1',
|
||||||
}
|
}
|
||||||
return _dict[fm]
|
return _dict[fm]
|
||||||
|
|
||||||
@@ -188,45 +190,46 @@ class YoukuIE(InfoExtractor):
|
|||||||
video_id = self._match_id(url)
|
video_id = self._match_id(url)
|
||||||
|
|
||||||
def retrieve_data(req_url, note):
|
def retrieve_data(req_url, note):
|
||||||
req = sanitized_Request(req_url)
|
headers = {
|
||||||
|
'Referer': req_url,
|
||||||
|
}
|
||||||
|
self._set_cookie('youku.com', 'xreferrer', 'http://www.youku.com')
|
||||||
|
req = sanitized_Request(req_url, headers=headers)
|
||||||
|
|
||||||
cn_verification_proxy = self._downloader.params.get('cn_verification_proxy')
|
cn_verification_proxy = self._downloader.params.get('cn_verification_proxy')
|
||||||
if cn_verification_proxy:
|
if cn_verification_proxy:
|
||||||
req.add_header('Ytdl-request-proxy', cn_verification_proxy)
|
req.add_header('Ytdl-request-proxy', cn_verification_proxy)
|
||||||
|
|
||||||
raw_data = self._download_json(req, video_id, note=note)
|
raw_data = self._download_json(req, video_id, note=note)
|
||||||
return raw_data['data'][0]
|
|
||||||
|
return raw_data['data']
|
||||||
|
|
||||||
video_password = self._downloader.params.get('videopassword', None)
|
video_password = self._downloader.params.get('videopassword', None)
|
||||||
|
|
||||||
# request basic data
|
# request basic data
|
||||||
basic_data_url = 'http://v.youku.com/player/getPlayList/VideoIDS/%s' % video_id
|
basic_data_url = "http://play.youku.com/play/get.json?vid=%s&ct=12" % video_id
|
||||||
if video_password:
|
if video_password:
|
||||||
basic_data_url += '?password=%s' % video_password
|
basic_data_url += '&pwd=%s' % video_password
|
||||||
|
|
||||||
data1 = retrieve_data(
|
data = retrieve_data(basic_data_url, 'Downloading JSON metadata')
|
||||||
basic_data_url,
|
|
||||||
'Downloading JSON metadata 1')
|
|
||||||
data2 = retrieve_data(
|
|
||||||
'http://v.youku.com/player/getPlayList/VideoIDS/%s/Pf/4/ctype/12/ev/1' % video_id,
|
|
||||||
'Downloading JSON metadata 2')
|
|
||||||
|
|
||||||
error_code = data1.get('error_code')
|
error = data.get('error')
|
||||||
if error_code:
|
if error:
|
||||||
error = data1.get('error')
|
error_note = error.get('note')
|
||||||
if error is not None and '因版权原因无法观看此视频' in error:
|
if error_note is not None and '因版权原因无法观看此视频' in error_note:
|
||||||
raise ExtractorError(
|
raise ExtractorError(
|
||||||
'Youku said: Sorry, this video is available in China only', expected=True)
|
'Youku said: Sorry, this video is available in China only', expected=True)
|
||||||
else:
|
else:
|
||||||
msg = 'Youku server reported error %i' % error_code
|
msg = 'Youku server reported error %i' % error.get('code')
|
||||||
if error is not None:
|
if error is not None:
|
||||||
msg += ': ' + error
|
msg += ': ' + error_note
|
||||||
raise ExtractorError(msg)
|
raise ExtractorError(msg)
|
||||||
|
|
||||||
title = data1['title']
|
# get video title
|
||||||
|
title = data['video']['title']
|
||||||
|
|
||||||
# generate video_urls_dict
|
# generate video_urls_dict
|
||||||
video_urls_dict = self.construct_video_urls(data1, data2)
|
video_urls_dict = self.construct_video_urls(data)
|
||||||
|
|
||||||
# construct info
|
# construct info
|
||||||
entries = [{
|
entries = [{
|
||||||
@@ -235,10 +238,11 @@ class YoukuIE(InfoExtractor):
|
|||||||
'formats': [],
|
'formats': [],
|
||||||
# some formats are not available for all parts, we have to detect
|
# some formats are not available for all parts, we have to detect
|
||||||
# which one has all
|
# which one has all
|
||||||
} for i in range(max(len(v) for v in data1['segs'].values()))]
|
} for i in range(max(len(v.get('segs')) for v in data['stream']))]
|
||||||
for fm in data1['streamtypes']:
|
for stream in data['stream']:
|
||||||
|
fm = stream.get('stream_type')
|
||||||
video_urls = video_urls_dict[fm]
|
video_urls = video_urls_dict[fm]
|
||||||
for video_url, seg, entry in zip(video_urls, data1['segs'][fm], entries):
|
for video_url, seg, entry in zip(video_urls, stream['segs'], entries):
|
||||||
entry['formats'].append({
|
entry['formats'].append({
|
||||||
'url': video_url,
|
'url': video_url,
|
||||||
'format_id': self.get_format_name(fm),
|
'format_id': self.get_format_name(fm),
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class FFmpegPostProcessor(PostProcessor):
|
|||||||
|
|
||||||
def _determine_executables(self):
|
def _determine_executables(self):
|
||||||
programs = ['avprobe', 'avconv', 'ffmpeg', 'ffprobe']
|
programs = ['avprobe', 'avconv', 'ffmpeg', 'ffprobe']
|
||||||
prefer_ffmpeg = self._downloader.params.get('prefer_ffmpeg', False)
|
prefer_ffmpeg = False
|
||||||
|
|
||||||
self.basename = None
|
self.basename = None
|
||||||
self.probe_basename = None
|
self.probe_basename = None
|
||||||
@@ -60,6 +60,7 @@ class FFmpegPostProcessor(PostProcessor):
|
|||||||
self._paths = None
|
self._paths = None
|
||||||
self._versions = None
|
self._versions = None
|
||||||
if self._downloader:
|
if self._downloader:
|
||||||
|
prefer_ffmpeg = self._downloader.params.get('prefer_ffmpeg', False)
|
||||||
location = self._downloader.params.get('ffmpeg_location')
|
location = self._downloader.params.get('ffmpeg_location')
|
||||||
if location is not None:
|
if location is not None:
|
||||||
if not os.path.exists(location):
|
if not os.path.exists(location):
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
__version__ = '2015.12.06'
|
__version__ = '2015.12.13'
|
||||||
|
|||||||
Reference in New Issue
Block a user