mirror of
https://codeberg.org/polarisfm/youtube-dl
synced 2024-12-04 14:27:53 +01:00
Merge branch 'master' of https://github.com/speakerender/youtube-dl into directvnow-auth-fix
This commit is contained in:
commit
502bc3fec9
61
.github/ISSUE_TEMPLATE.md
vendored
61
.github/ISSUE_TEMPLATE.md
vendored
@ -1,61 +0,0 @@
|
|||||||
## Please follow the guide below
|
|
||||||
|
|
||||||
- You will be asked some questions and requested to provide some information, please read them **carefully** and answer honestly
|
|
||||||
- Put an `x` into all the boxes [ ] relevant to your *issue* (like this: `[x]`)
|
|
||||||
- Use the *Preview* tab to see what your issue will actually look like
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Make sure you are using the *latest* version: run `youtube-dl --version` and ensure your version is *2019.04.17*. If it's not, read [this FAQ entry](https://github.com/ytdl-org/youtube-dl/blob/master/README.md#how-do-i-update-youtube-dl) and update. Issues with outdated version will be rejected.
|
|
||||||
- [ ] I've **verified** and **I assure** that I'm running youtube-dl **2019.04.17**
|
|
||||||
|
|
||||||
### Before submitting an *issue* make sure you have:
|
|
||||||
- [ ] At least skimmed through the [README](https://github.com/ytdl-org/youtube-dl/blob/master/README.md), **most notably** the [FAQ](https://github.com/ytdl-org/youtube-dl#faq) and [BUGS](https://github.com/ytdl-org/youtube-dl#bugs) sections
|
|
||||||
- [ ] [Searched](https://github.com/ytdl-org/youtube-dl/search?type=Issues) the bugtracker for similar issues including closed ones
|
|
||||||
- [ ] Checked that provided video/audio/playlist URLs (if any) are alive and playable in a browser
|
|
||||||
|
|
||||||
### What is the purpose of your *issue*?
|
|
||||||
- [ ] Bug report (encountered problems with youtube-dl)
|
|
||||||
- [ ] Site support request (request for adding support for a new site)
|
|
||||||
- [ ] Feature request (request for a new functionality)
|
|
||||||
- [ ] Question
|
|
||||||
- [ ] Other
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### The following sections concretize particular purposed issues, you can erase any section (the contents between triple ---) not applicable to your *issue*
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### If the purpose of this *issue* is a *bug report*, *site support request* or you are not completely sure provide the full verbose output as follows:
|
|
||||||
|
|
||||||
Add the `-v` flag to **your command line** you run youtube-dl with (`youtube-dl -v <your command line>`), copy the **whole** output and insert it here. It should look similar to one below (replace it with **your** log inserted between triple ```):
|
|
||||||
|
|
||||||
```
|
|
||||||
[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 2019.04.17
|
|
||||||
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
|
||||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
|
||||||
[debug] Proxy map: {}
|
|
||||||
...
|
|
||||||
<end of log>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### If the purpose of this *issue* is a *site support request* please provide all kinds of example URLs support for which should be included (replace following example URLs by **yours**):
|
|
||||||
- Single video: https://www.youtube.com/watch?v=BaW_jenozKc
|
|
||||||
- Single video: https://youtu.be/BaW_jenozKc
|
|
||||||
- Playlist: https://www.youtube.com/playlist?list=PL4lCao7KL_QFVb7Iudeipvc2BCavECqzc
|
|
||||||
|
|
||||||
Note that **youtube-dl does not support sites dedicated to [copyright infringement](https://github.com/ytdl-org/youtube-dl#can-you-add-support-for-this-anime-video-site-or-site-which-shows-current-movies-for-free)**. In order for site support request to be accepted all provided example URLs should not violate any copyrights.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Description of your *issue*, suggested solution and other information
|
|
||||||
|
|
||||||
Explanation of your *issue* in arbitrary form goes here. Please make sure the [description is worded well enough to be understood](https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient). Provide as much context and examples as possible.
|
|
||||||
If work on your *issue* requires account credentials please provide them or explain how one can obtain them.
|
|
63
.github/ISSUE_TEMPLATE/1_broken_site.md
vendored
Normal file
63
.github/ISSUE_TEMPLATE/1_broken_site.md
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
name: Broken site support
|
||||||
|
about: Report broken or misfunctioning site
|
||||||
|
title: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
WARNING!
|
||||||
|
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2019.04.30. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
|
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
||||||
|
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in http://yt-dl.org/escape.
|
||||||
|
- Search the bugtracker for similar issues: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] I'm reporting a broken site support
|
||||||
|
- [ ] I've verified that I'm running youtube-dl version **2019.04.30**
|
||||||
|
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
||||||
|
- [ ] I've searched the bugtracker for similar issues including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
## Verbose log
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide the complete verbose output of youtube-dl that clearly demonstrates the problem.
|
||||||
|
Add the `-v` flag to your command line you run youtube-dl with (`youtube-dl -v <your command line>`), copy the WHOLE output and insert it below. It should look similar to this:
|
||||||
|
[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 2019.04.30
|
||||||
|
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
||||||
|
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
<more lines>
|
||||||
|
-->
|
||||||
|
|
||||||
|
```
|
||||||
|
PASTE VERBOSE LOG HERE
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide an explanation of your issue in an arbitrary form. Provide any additional information, suggested solution and as much context and examples as possible.
|
||||||
|
If work on your issue requires account credentials please provide them or explain how one can obtain them.
|
||||||
|
-->
|
||||||
|
|
||||||
|
WRITE DESCRIPTION HERE
|
54
.github/ISSUE_TEMPLATE/2_site_support_request.md
vendored
Normal file
54
.github/ISSUE_TEMPLATE/2_site_support_request.md
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
name: Site support request
|
||||||
|
about: Request support for a new site
|
||||||
|
title: ''
|
||||||
|
labels: 'site-support-request'
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
WARNING!
|
||||||
|
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2019.04.30. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
|
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
||||||
|
- Make sure that site you are requesting is not dedicated to copyright infringement, see https://yt-dl.org/copyright-infringement. youtube-dl does not support such sites. In order for site support request to be accepted all provided example URLs should not violate any copyrights.
|
||||||
|
- Search the bugtracker for similar site support requests: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] I'm reporting a new site support request
|
||||||
|
- [ ] I've verified that I'm running youtube-dl version **2019.04.30**
|
||||||
|
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
- [ ] I've checked that none of provided URLs violate any copyrights
|
||||||
|
- [ ] I've searched the bugtracker for similar site support requests including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
## Example URLs
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide all kinds of example URLs support for which should be included. Replace following example URLs by yours.
|
||||||
|
-->
|
||||||
|
|
||||||
|
- Single video: https://www.youtube.com/watch?v=BaW_jenozKc
|
||||||
|
- Single video: https://youtu.be/BaW_jenozKc
|
||||||
|
- Playlist: https://www.youtube.com/playlist?list=PL4lCao7KL_QFVb7Iudeipvc2BCavECqzc
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide any additional information.
|
||||||
|
If work on your issue requires account credentials please provide them or explain how one can obtain them.
|
||||||
|
-->
|
||||||
|
|
||||||
|
WRITE DESCRIPTION HERE
|
37
.github/ISSUE_TEMPLATE/3_site_feature_request.md
vendored
Normal file
37
.github/ISSUE_TEMPLATE/3_site_feature_request.md
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
name: Site feature request
|
||||||
|
about: Request a new functionality for a site
|
||||||
|
title: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
WARNING!
|
||||||
|
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2019.04.30. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
|
- Search the bugtracker for similar site feature requests: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] I'm reporting a site feature request
|
||||||
|
- [ ] I've verified that I'm running youtube-dl version **2019.04.30**
|
||||||
|
- [ ] I've searched the bugtracker for similar site feature requests including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide an explanation of your site feature request in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
|
||||||
|
-->
|
||||||
|
|
||||||
|
WRITE DESCRIPTION HERE
|
65
.github/ISSUE_TEMPLATE/4_bug_report.md
vendored
Normal file
65
.github/ISSUE_TEMPLATE/4_bug_report.md
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Report a bug unrelated to any particular site or extractor
|
||||||
|
title: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
WARNING!
|
||||||
|
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2019.04.30. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
|
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
||||||
|
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in http://yt-dl.org/escape.
|
||||||
|
- Search the bugtracker for similar issues: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
|
- Read bugs section in FAQ: http://yt-dl.org/reporting
|
||||||
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] I'm reporting a broken site support issue
|
||||||
|
- [ ] I've verified that I'm running youtube-dl version **2019.04.30**
|
||||||
|
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
||||||
|
- [ ] I've searched the bugtracker for similar bug reports including closed ones
|
||||||
|
- [ ] I've read bugs section in FAQ
|
||||||
|
|
||||||
|
|
||||||
|
## Verbose log
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide the complete verbose output of youtube-dl that clearly demonstrates the problem.
|
||||||
|
Add the `-v` flag to your command line you run youtube-dl with (`youtube-dl -v <your command line>`), copy the WHOLE output and insert it below. It should look similar to this:
|
||||||
|
[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 2019.04.30
|
||||||
|
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
||||||
|
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
<more lines>
|
||||||
|
-->
|
||||||
|
|
||||||
|
```
|
||||||
|
PASTE VERBOSE LOG HERE
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide an explanation of your issue in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
|
||||||
|
If work on your issue requires account credentials please provide them or explain how one can obtain them.
|
||||||
|
-->
|
||||||
|
|
||||||
|
WRITE DESCRIPTION HERE
|
38
.github/ISSUE_TEMPLATE/5_feature_request.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/5_feature_request.md
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Request a new functionality unrelated to any particular site or extractor
|
||||||
|
title: ''
|
||||||
|
labels: 'request'
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
WARNING!
|
||||||
|
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2019.04.30. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
|
- Search the bugtracker for similar feature requests: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] I'm reporting a feature request
|
||||||
|
- [ ] I've verified that I'm running youtube-dl version **2019.04.30**
|
||||||
|
- [ ] I've searched the bugtracker for similar feature requests including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide an explanation of your issue in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
|
||||||
|
-->
|
||||||
|
|
||||||
|
WRITE DESCRIPTION HERE
|
38
.github/ISSUE_TEMPLATE/6_question.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/6_question.md
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
name: Ask question
|
||||||
|
about: Ask youtube-dl related question
|
||||||
|
title: ''
|
||||||
|
labels: 'question'
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
WARNING!
|
||||||
|
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
|
- Look through the README (http://yt-dl.org/readme) and FAQ (http://yt-dl.org/faq) for similar questions
|
||||||
|
- Search the bugtracker for similar questions: http://yt-dl.org/search-issues
|
||||||
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] I'm asking a question
|
||||||
|
- [ ] I've looked through the README and FAQ for similar questions
|
||||||
|
- [ ] I've searched the bugtracker for similar questions including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
## Question
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Ask your question in an arbitrary form. Please make sure it's worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient.
|
||||||
|
-->
|
||||||
|
|
||||||
|
WRITE QUESTION HERE
|
61
.github/ISSUE_TEMPLATE_tmpl.md
vendored
61
.github/ISSUE_TEMPLATE_tmpl.md
vendored
@ -1,61 +0,0 @@
|
|||||||
## Please follow the guide below
|
|
||||||
|
|
||||||
- You will be asked some questions and requested to provide some information, please read them **carefully** and answer honestly
|
|
||||||
- Put an `x` into all the boxes [ ] relevant to your *issue* (like this: `[x]`)
|
|
||||||
- Use the *Preview* tab to see what your issue will actually look like
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Make sure you are using the *latest* version: run `youtube-dl --version` and ensure your version is *%(version)s*. If it's not, read [this FAQ entry](https://github.com/ytdl-org/youtube-dl/blob/master/README.md#how-do-i-update-youtube-dl) and update. Issues with outdated version will be rejected.
|
|
||||||
- [ ] I've **verified** and **I assure** that I'm running youtube-dl **%(version)s**
|
|
||||||
|
|
||||||
### Before submitting an *issue* make sure you have:
|
|
||||||
- [ ] At least skimmed through the [README](https://github.com/ytdl-org/youtube-dl/blob/master/README.md), **most notably** the [FAQ](https://github.com/ytdl-org/youtube-dl#faq) and [BUGS](https://github.com/ytdl-org/youtube-dl#bugs) sections
|
|
||||||
- [ ] [Searched](https://github.com/ytdl-org/youtube-dl/search?type=Issues) the bugtracker for similar issues including closed ones
|
|
||||||
- [ ] Checked that provided video/audio/playlist URLs (if any) are alive and playable in a browser
|
|
||||||
|
|
||||||
### What is the purpose of your *issue*?
|
|
||||||
- [ ] Bug report (encountered problems with youtube-dl)
|
|
||||||
- [ ] Site support request (request for adding support for a new site)
|
|
||||||
- [ ] Feature request (request for a new functionality)
|
|
||||||
- [ ] Question
|
|
||||||
- [ ] Other
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### The following sections concretize particular purposed issues, you can erase any section (the contents between triple ---) not applicable to your *issue*
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### If the purpose of this *issue* is a *bug report*, *site support request* or you are not completely sure provide the full verbose output as follows:
|
|
||||||
|
|
||||||
Add the `-v` flag to **your command line** you run youtube-dl with (`youtube-dl -v <your command line>`), copy the **whole** output and insert it here. It should look similar to one below (replace it with **your** log inserted between triple ```):
|
|
||||||
|
|
||||||
```
|
|
||||||
[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 %(version)s
|
|
||||||
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
|
||||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
|
||||||
[debug] Proxy map: {}
|
|
||||||
...
|
|
||||||
<end of log>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### If the purpose of this *issue* is a *site support request* please provide all kinds of example URLs support for which should be included (replace following example URLs by **yours**):
|
|
||||||
- Single video: https://www.youtube.com/watch?v=BaW_jenozKc
|
|
||||||
- Single video: https://youtu.be/BaW_jenozKc
|
|
||||||
- Playlist: https://www.youtube.com/playlist?list=PL4lCao7KL_QFVb7Iudeipvc2BCavECqzc
|
|
||||||
|
|
||||||
Note that **youtube-dl does not support sites dedicated to [copyright infringement](https://github.com/ytdl-org/youtube-dl#can-you-add-support-for-this-anime-video-site-or-site-which-shows-current-movies-for-free)**. In order for site support request to be accepted all provided example URLs should not violate any copyrights.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Description of your *issue*, suggested solution and other information
|
|
||||||
|
|
||||||
Explanation of your *issue* in arbitrary form goes here. Please make sure the [description is worded well enough to be understood](https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient). Provide as much context and examples as possible.
|
|
||||||
If work on your *issue* requires account credentials please provide them or explain how one can obtain them.
|
|
63
.github/ISSUE_TEMPLATE_tmpl/1_broken_site.md
vendored
Normal file
63
.github/ISSUE_TEMPLATE_tmpl/1_broken_site.md
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
name: Broken site support
|
||||||
|
about: Report broken or misfunctioning site
|
||||||
|
title: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
WARNING!
|
||||||
|
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is %(version)s. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
|
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
||||||
|
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in http://yt-dl.org/escape.
|
||||||
|
- Search the bugtracker for similar issues: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] I'm reporting a broken site support
|
||||||
|
- [ ] I've verified that I'm running youtube-dl version **%(version)s**
|
||||||
|
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
||||||
|
- [ ] I've searched the bugtracker for similar issues including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
## Verbose log
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide the complete verbose output of youtube-dl that clearly demonstrates the problem.
|
||||||
|
Add the `-v` flag to your command line you run youtube-dl with (`youtube-dl -v <your command line>`), copy the WHOLE output and insert it below. It should look similar to this:
|
||||||
|
[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 %(version)s
|
||||||
|
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
||||||
|
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
<more lines>
|
||||||
|
-->
|
||||||
|
|
||||||
|
```
|
||||||
|
PASTE VERBOSE LOG HERE
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide an explanation of your issue in an arbitrary form. Provide any additional information, suggested solution and as much context and examples as possible.
|
||||||
|
If work on your issue requires account credentials please provide them or explain how one can obtain them.
|
||||||
|
-->
|
||||||
|
|
||||||
|
WRITE DESCRIPTION HERE
|
54
.github/ISSUE_TEMPLATE_tmpl/2_site_support_request.md
vendored
Normal file
54
.github/ISSUE_TEMPLATE_tmpl/2_site_support_request.md
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
name: Site support request
|
||||||
|
about: Request support for a new site
|
||||||
|
title: ''
|
||||||
|
labels: 'site-support-request'
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
WARNING!
|
||||||
|
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is %(version)s. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
|
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
||||||
|
- Make sure that site you are requesting is not dedicated to copyright infringement, see https://yt-dl.org/copyright-infringement. youtube-dl does not support such sites. In order for site support request to be accepted all provided example URLs should not violate any copyrights.
|
||||||
|
- Search the bugtracker for similar site support requests: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] I'm reporting a new site support request
|
||||||
|
- [ ] I've verified that I'm running youtube-dl version **%(version)s**
|
||||||
|
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
- [ ] I've checked that none of provided URLs violate any copyrights
|
||||||
|
- [ ] I've searched the bugtracker for similar site support requests including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
## Example URLs
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide all kinds of example URLs support for which should be included. Replace following example URLs by yours.
|
||||||
|
-->
|
||||||
|
|
||||||
|
- Single video: https://www.youtube.com/watch?v=BaW_jenozKc
|
||||||
|
- Single video: https://youtu.be/BaW_jenozKc
|
||||||
|
- Playlist: https://www.youtube.com/playlist?list=PL4lCao7KL_QFVb7Iudeipvc2BCavECqzc
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide any additional information.
|
||||||
|
If work on your issue requires account credentials please provide them or explain how one can obtain them.
|
||||||
|
-->
|
||||||
|
|
||||||
|
WRITE DESCRIPTION HERE
|
37
.github/ISSUE_TEMPLATE_tmpl/3_site_feature_request.md
vendored
Normal file
37
.github/ISSUE_TEMPLATE_tmpl/3_site_feature_request.md
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
name: Site feature request
|
||||||
|
about: Request a new functionality for a site
|
||||||
|
title: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
WARNING!
|
||||||
|
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is %(version)s. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
|
- Search the bugtracker for similar site feature requests: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] I'm reporting a site feature request
|
||||||
|
- [ ] I've verified that I'm running youtube-dl version **%(version)s**
|
||||||
|
- [ ] I've searched the bugtracker for similar site feature requests including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide an explanation of your site feature request in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
|
||||||
|
-->
|
||||||
|
|
||||||
|
WRITE DESCRIPTION HERE
|
65
.github/ISSUE_TEMPLATE_tmpl/4_bug_report.md
vendored
Normal file
65
.github/ISSUE_TEMPLATE_tmpl/4_bug_report.md
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Report a bug unrelated to any particular site or extractor
|
||||||
|
title: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
WARNING!
|
||||||
|
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is %(version)s. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
|
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
||||||
|
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in http://yt-dl.org/escape.
|
||||||
|
- Search the bugtracker for similar issues: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
|
- Read bugs section in FAQ: http://yt-dl.org/reporting
|
||||||
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] I'm reporting a broken site support issue
|
||||||
|
- [ ] I've verified that I'm running youtube-dl version **%(version)s**
|
||||||
|
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
||||||
|
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
||||||
|
- [ ] I've searched the bugtracker for similar bug reports including closed ones
|
||||||
|
- [ ] I've read bugs section in FAQ
|
||||||
|
|
||||||
|
|
||||||
|
## Verbose log
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide the complete verbose output of youtube-dl that clearly demonstrates the problem.
|
||||||
|
Add the `-v` flag to your command line you run youtube-dl with (`youtube-dl -v <your command line>`), copy the WHOLE output and insert it below. It should look similar to this:
|
||||||
|
[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 %(version)s
|
||||||
|
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
||||||
|
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||||
|
[debug] Proxy map: {}
|
||||||
|
<more lines>
|
||||||
|
-->
|
||||||
|
|
||||||
|
```
|
||||||
|
PASTE VERBOSE LOG HERE
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide an explanation of your issue in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
|
||||||
|
If work on your issue requires account credentials please provide them or explain how one can obtain them.
|
||||||
|
-->
|
||||||
|
|
||||||
|
WRITE DESCRIPTION HERE
|
38
.github/ISSUE_TEMPLATE_tmpl/5_feature_request.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE_tmpl/5_feature_request.md
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Request a new functionality unrelated to any particular site or extractor
|
||||||
|
title: ''
|
||||||
|
labels: 'request'
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
WARNING!
|
||||||
|
IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is %(version)s. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
|
- Search the bugtracker for similar feature requests: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] I'm reporting a feature request
|
||||||
|
- [ ] I've verified that I'm running youtube-dl version **%(version)s**
|
||||||
|
- [ ] I've searched the bugtracker for similar feature requests including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide an explanation of your issue in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
|
||||||
|
-->
|
||||||
|
|
||||||
|
WRITE DESCRIPTION HERE
|
43
ChangeLog
43
ChangeLog
@ -1,3 +1,46 @@
|
|||||||
|
version 2019.04.30
|
||||||
|
|
||||||
|
Extractors
|
||||||
|
* [openload] Use real Chrome versions (#20902)
|
||||||
|
- [youtube] Remove info el for get_video_info request
|
||||||
|
* [youtube] Improve extraction robustness
|
||||||
|
- [dramafever] Remove extractor (#20868)
|
||||||
|
* [adn] Fix subtitle extraction (#12724)
|
||||||
|
+ [ccc] Extract creator (#20355)
|
||||||
|
+ [ccc:playlist] Add support for media.ccc.de playlists (#14601, #20355)
|
||||||
|
+ [sverigesradio] Add support for sverigesradio.se (#18635)
|
||||||
|
+ [cinemax] Add support for cinemax.com
|
||||||
|
* [sixplay] Try extracting non-DRM protected manifests (#20849)
|
||||||
|
+ [youtube] Extract Youtube Music Auto-generated metadata (#20599, #20742)
|
||||||
|
- [wrzuta] Remove extractor (#20684, #20801)
|
||||||
|
* [twitch] Prefer source format (#20850)
|
||||||
|
+ [twitcasting] Add support for private videos (#20843)
|
||||||
|
* [reddit] Validate thumbnail URL (#20030)
|
||||||
|
* [yandexmusic] Fix track URL extraction (#20820)
|
||||||
|
|
||||||
|
|
||||||
|
version 2019.04.24
|
||||||
|
|
||||||
|
Extractors
|
||||||
|
* [youtube] Fix extraction (#20758, #20759, #20761, #20762, #20764, #20766,
|
||||||
|
#20767, #20769, #20771, #20768, #20770)
|
||||||
|
* [toutv] Fix extraction and extract series info (#20757)
|
||||||
|
+ [vrv] Add support for movie listings (#19229)
|
||||||
|
+ [youtube] Print error when no data is available (#20737)
|
||||||
|
+ [soundcloud] Add support for new rendition and improve extraction (#20699)
|
||||||
|
+ [ooyala] Add support for geo verification proxy
|
||||||
|
+ [nrl] Add support for nrl.com (#15991)
|
||||||
|
+ [vimeo] Extract live archive source format (#19144)
|
||||||
|
+ [vimeo] Add support for live streams and improve info extraction (#19144)
|
||||||
|
+ [ntvcojp] Add support for cu.ntv.co.jp
|
||||||
|
+ [nhk] Extract RTMPT format
|
||||||
|
+ [nhk] Add support for audio URLs
|
||||||
|
+ [udemy] Add another course id extraction pattern (#20491)
|
||||||
|
+ [openload] Add support for oload.services (#20691)
|
||||||
|
+ [openload] Add support for openloed.co (#20691, #20693)
|
||||||
|
* [bravotv] Fix extraction (#19213)
|
||||||
|
|
||||||
|
|
||||||
version 2019.04.17
|
version 2019.04.17
|
||||||
|
|
||||||
Extractors
|
Extractors
|
||||||
|
10
Makefile
10
Makefile
@ -1,7 +1,7 @@
|
|||||||
all: youtube-dl README.md CONTRIBUTING.md README.txt youtube-dl.1 youtube-dl.bash-completion youtube-dl.zsh youtube-dl.fish supportedsites
|
all: youtube-dl README.md CONTRIBUTING.md README.txt youtube-dl.1 youtube-dl.bash-completion youtube-dl.zsh youtube-dl.fish supportedsites
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf youtube-dl.1.temp.md youtube-dl.1 youtube-dl.bash-completion README.txt MANIFEST build/ dist/ .coverage cover/ youtube-dl.tar.gz youtube-dl.zsh youtube-dl.fish youtube_dl/extractor/lazy_extractors.py *.dump *.part* *.ytdl *.info.json *.mp4 *.m4a *.flv *.mp3 *.avi *.mkv *.webm *.3gp *.wav *.ape *.swf *.jpg *.png CONTRIBUTING.md.tmp ISSUE_TEMPLATE.md.tmp youtube-dl youtube-dl.exe
|
rm -rf youtube-dl.1.temp.md youtube-dl.1 youtube-dl.bash-completion README.txt MANIFEST build/ dist/ .coverage cover/ youtube-dl.tar.gz youtube-dl.zsh youtube-dl.fish youtube_dl/extractor/lazy_extractors.py *.dump *.part* *.ytdl *.info.json *.mp4 *.m4a *.flv *.mp3 *.avi *.mkv *.webm *.3gp *.wav *.ape *.swf *.jpg *.png CONTRIBUTING.md.tmp youtube-dl youtube-dl.exe
|
||||||
find . -name "*.pyc" -delete
|
find . -name "*.pyc" -delete
|
||||||
find . -name "*.class" -delete
|
find . -name "*.class" -delete
|
||||||
|
|
||||||
@ -78,8 +78,12 @@ README.md: youtube_dl/*.py youtube_dl/*/*.py
|
|||||||
CONTRIBUTING.md: README.md
|
CONTRIBUTING.md: README.md
|
||||||
$(PYTHON) devscripts/make_contributing.py README.md CONTRIBUTING.md
|
$(PYTHON) devscripts/make_contributing.py README.md CONTRIBUTING.md
|
||||||
|
|
||||||
.github/ISSUE_TEMPLATE.md: devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl.md youtube_dl/version.py
|
issuetemplates: devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/1_broken_site.md .github/ISSUE_TEMPLATE_tmpl/2_site_support_request.md .github/ISSUE_TEMPLATE_tmpl/3_site_feature_request.md .github/ISSUE_TEMPLATE_tmpl/4_bug_report.md .github/ISSUE_TEMPLATE_tmpl/5_feature_request.md youtube_dl/version.py
|
||||||
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl.md .github/ISSUE_TEMPLATE.md
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/1_broken_site.md .github/ISSUE_TEMPLATE/1_broken_site.md
|
||||||
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/2_site_support_request.md .github/ISSUE_TEMPLATE/2_site_support_request.md
|
||||||
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/3_site_feature_request.md .github/ISSUE_TEMPLATE/3_site_feature_request.md
|
||||||
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/4_bug_report.md .github/ISSUE_TEMPLATE/4_bug_report.md
|
||||||
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/5_feature_request.md .github/ISSUE_TEMPLATE/5_feature_request.md
|
||||||
|
|
||||||
supportedsites:
|
supportedsites:
|
||||||
$(PYTHON) devscripts/make_supportedsites.py docs/supportedsites.md
|
$(PYTHON) devscripts/make_supportedsites.py docs/supportedsites.md
|
||||||
|
@ -78,8 +78,8 @@ sed -i "s/__version__ = '.*'/__version__ = '$version'/" youtube_dl/version.py
|
|||||||
sed -i "s/<unreleased>/$version/" ChangeLog
|
sed -i "s/<unreleased>/$version/" ChangeLog
|
||||||
|
|
||||||
/bin/echo -e "\n### Committing documentation, templates and youtube_dl/version.py..."
|
/bin/echo -e "\n### Committing documentation, templates and youtube_dl/version.py..."
|
||||||
make README.md CONTRIBUTING.md .github/ISSUE_TEMPLATE.md supportedsites
|
make README.md CONTRIBUTING.md issuetemplates supportedsites
|
||||||
git add README.md CONTRIBUTING.md .github/ISSUE_TEMPLATE.md docs/supportedsites.md youtube_dl/version.py ChangeLog
|
git add README.md CONTRIBUTING.md .github/ISSUE_TEMPLATE/1_broken_site.md .github/ISSUE_TEMPLATE/2_site_support_request.md .github/ISSUE_TEMPLATE/3_site_feature_request.md .github/ISSUE_TEMPLATE/4_bug_report.md .github/ISSUE_TEMPLATE/5_feature_request.md .github/ISSUE_TEMPLATE/6_question.md docs/supportedsites.md youtube_dl/version.py ChangeLog
|
||||||
git commit $gpg_sign_commits -m "release $version"
|
git commit $gpg_sign_commits -m "release $version"
|
||||||
|
|
||||||
/bin/echo -e "\n### Now tagging, signing and pushing..."
|
/bin/echo -e "\n### Now tagging, signing and pushing..."
|
||||||
|
@ -164,6 +164,7 @@
|
|||||||
- **chirbit**
|
- **chirbit**
|
||||||
- **chirbit:profile**
|
- **chirbit:profile**
|
||||||
- **Cinchcast**
|
- **Cinchcast**
|
||||||
|
- **Cinemax**
|
||||||
- **CiscoLiveSearch**
|
- **CiscoLiveSearch**
|
||||||
- **CiscoLiveSession**
|
- **CiscoLiveSession**
|
||||||
- **CJSW**
|
- **CJSW**
|
||||||
@ -201,6 +202,7 @@
|
|||||||
- **CSpan**: C-SPAN
|
- **CSpan**: C-SPAN
|
||||||
- **CtsNews**: 華視新聞
|
- **CtsNews**: 華視新聞
|
||||||
- **CTVNews**
|
- **CTVNews**
|
||||||
|
- **cu.ntv.co.jp**: Nippon Television Network
|
||||||
- **Culturebox**
|
- **Culturebox**
|
||||||
- **CultureUnplugged**
|
- **CultureUnplugged**
|
||||||
- **curiositystream**
|
- **curiositystream**
|
||||||
@ -236,8 +238,6 @@
|
|||||||
- **DouyuTV**: 斗鱼
|
- **DouyuTV**: 斗鱼
|
||||||
- **DPlay**
|
- **DPlay**
|
||||||
- **DPlayIt**
|
- **DPlayIt**
|
||||||
- **dramafever**
|
|
||||||
- **dramafever:series**
|
|
||||||
- **DRBonanza**
|
- **DRBonanza**
|
||||||
- **Dropbox**
|
- **Dropbox**
|
||||||
- **DrTuber**
|
- **DrTuber**
|
||||||
@ -487,6 +487,7 @@
|
|||||||
- **MatchTV**
|
- **MatchTV**
|
||||||
- **MDR**: MDR.DE and KiKA
|
- **MDR**: MDR.DE and KiKA
|
||||||
- **media.ccc.de**
|
- **media.ccc.de**
|
||||||
|
- **media.ccc.de:lists**
|
||||||
- **Medialaan**
|
- **Medialaan**
|
||||||
- **Mediaset**
|
- **Mediaset**
|
||||||
- **Mediasite**
|
- **Mediasite**
|
||||||
@ -624,6 +625,7 @@
|
|||||||
- **NRKTVEpisodes**
|
- **NRKTVEpisodes**
|
||||||
- **NRKTVSeason**
|
- **NRKTVSeason**
|
||||||
- **NRKTVSeries**
|
- **NRKTVSeries**
|
||||||
|
- **NRLTV**
|
||||||
- **ntv.ru**
|
- **ntv.ru**
|
||||||
- **Nuvid**
|
- **Nuvid**
|
||||||
- **NYTimes**
|
- **NYTimes**
|
||||||
@ -855,6 +857,8 @@
|
|||||||
- **StretchInternet**
|
- **StretchInternet**
|
||||||
- **stv:player**
|
- **stv:player**
|
||||||
- **SunPorno**
|
- **SunPorno**
|
||||||
|
- **sverigesradio:episode**
|
||||||
|
- **sverigesradio:publication**
|
||||||
- **SVT**
|
- **SVT**
|
||||||
- **SVTPage**
|
- **SVTPage**
|
||||||
- **SVTPlay**: SVT Play and Öppet arkiv
|
- **SVTPlay**: SVT Play and Öppet arkiv
|
||||||
@ -1100,8 +1104,6 @@
|
|||||||
- **Wistia**
|
- **Wistia**
|
||||||
- **wnl**: npo.nl, ntr.nl, omroepwnl.nl, zapp.nl and npo3.nl
|
- **wnl**: npo.nl, ntr.nl, omroepwnl.nl, zapp.nl and npo3.nl
|
||||||
- **WorldStarHipHop**
|
- **WorldStarHipHop**
|
||||||
- **wrzuta.pl**
|
|
||||||
- **wrzuta.pl:playlist**
|
|
||||||
- **WSJ**: Wall Street Journal
|
- **WSJ**: Wall Street Journal
|
||||||
- **WSJArticle**
|
- **WSJArticle**
|
||||||
- **WWE**
|
- **WWE**
|
||||||
|
@ -65,14 +65,15 @@ class ADNIE(InfoExtractor):
|
|||||||
if subtitle_location:
|
if subtitle_location:
|
||||||
enc_subtitles = self._download_webpage(
|
enc_subtitles = self._download_webpage(
|
||||||
urljoin(self._BASE_URL, subtitle_location),
|
urljoin(self._BASE_URL, subtitle_location),
|
||||||
video_id, 'Downloading subtitles data', fatal=False)
|
video_id, 'Downloading subtitles data', fatal=False,
|
||||||
|
headers={'Origin': 'https://animedigitalnetwork.fr'})
|
||||||
if not enc_subtitles:
|
if not enc_subtitles:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# http://animedigitalnetwork.fr/components/com_vodvideo/videojs/adn-vjs.min.js
|
# http://animedigitalnetwork.fr/components/com_vodvideo/videojs/adn-vjs.min.js
|
||||||
dec_subtitles = intlist_to_bytes(aes_cbc_decrypt(
|
dec_subtitles = intlist_to_bytes(aes_cbc_decrypt(
|
||||||
bytes_to_intlist(compat_b64decode(enc_subtitles[24:])),
|
bytes_to_intlist(compat_b64decode(enc_subtitles[24:])),
|
||||||
bytes_to_intlist(binascii.unhexlify(self._K + '4421de0a5f0814ba')),
|
bytes_to_intlist(binascii.unhexlify(self._K + '4b8ef13ec1872730')),
|
||||||
bytes_to_intlist(compat_b64decode(enc_subtitles[:24]))
|
bytes_to_intlist(compat_b64decode(enc_subtitles[:24]))
|
||||||
))
|
))
|
||||||
subtitles_json = self._parse_json(
|
subtitles_json = self._parse_json(
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
# coding: utf-8
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
int_or_none,
|
int_or_none,
|
||||||
parse_iso8601,
|
parse_iso8601,
|
||||||
|
try_get,
|
||||||
|
url_or_none,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -18,11 +21,13 @@ class CCCIE(InfoExtractor):
|
|||||||
'id': '1839',
|
'id': '1839',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'title': 'Introduction to Processor Design',
|
'title': 'Introduction to Processor Design',
|
||||||
|
'creator': 'byterazor',
|
||||||
'description': 'md5:df55f6d073d4ceae55aae6f2fd98a0ac',
|
'description': 'md5:df55f6d073d4ceae55aae6f2fd98a0ac',
|
||||||
'thumbnail': r're:^https?://.*\.jpg$',
|
'thumbnail': r're:^https?://.*\.jpg$',
|
||||||
'upload_date': '20131228',
|
'upload_date': '20131228',
|
||||||
'timestamp': 1388188800,
|
'timestamp': 1388188800,
|
||||||
'duration': 3710,
|
'duration': 3710,
|
||||||
|
'tags': list,
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
'url': 'https://media.ccc.de/v/32c3-7368-shopshifting#download',
|
'url': 'https://media.ccc.de/v/32c3-7368-shopshifting#download',
|
||||||
@ -68,6 +73,7 @@ class CCCIE(InfoExtractor):
|
|||||||
'id': event_id,
|
'id': event_id,
|
||||||
'display_id': display_id,
|
'display_id': display_id,
|
||||||
'title': event_data['title'],
|
'title': event_data['title'],
|
||||||
|
'creator': try_get(event_data, lambda x: ', '.join(x['persons'])),
|
||||||
'description': event_data.get('description'),
|
'description': event_data.get('description'),
|
||||||
'thumbnail': event_data.get('thumb_url'),
|
'thumbnail': event_data.get('thumb_url'),
|
||||||
'timestamp': parse_iso8601(event_data.get('date')),
|
'timestamp': parse_iso8601(event_data.get('date')),
|
||||||
@ -75,3 +81,31 @@ class CCCIE(InfoExtractor):
|
|||||||
'tags': event_data.get('tags'),
|
'tags': event_data.get('tags'),
|
||||||
'formats': formats,
|
'formats': formats,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CCCPlaylistIE(InfoExtractor):
|
||||||
|
IE_NAME = 'media.ccc.de:lists'
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?media\.ccc\.de/c/(?P<id>[^/?#&]+)'
|
||||||
|
_TESTS = [{
|
||||||
|
'url': 'https://media.ccc.de/c/30c3',
|
||||||
|
'info_dict': {
|
||||||
|
'title': '30C3',
|
||||||
|
'id': '30c3',
|
||||||
|
},
|
||||||
|
'playlist_count': 135,
|
||||||
|
}]
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
playlist_id = self._match_id(url).lower()
|
||||||
|
|
||||||
|
conf = self._download_json(
|
||||||
|
'https://media.ccc.de/public/conferences/' + playlist_id,
|
||||||
|
playlist_id)
|
||||||
|
|
||||||
|
entries = []
|
||||||
|
for e in conf['events']:
|
||||||
|
event_url = url_or_none(e.get('frontend_link'))
|
||||||
|
if event_url:
|
||||||
|
entries.append(self.url_result(event_url, ie=CCCIE.ie_key()))
|
||||||
|
|
||||||
|
return self.playlist_result(entries, playlist_id, conf.get('title'))
|
||||||
|
29
youtube_dl/extractor/cinemax.py
Normal file
29
youtube_dl/extractor/cinemax.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from .hbo import HBOBaseIE
|
||||||
|
|
||||||
|
|
||||||
|
class CinemaxIE(HBOBaseIE):
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?cinemax\.com/(?P<path>[^/]+/video/[0-9a-z-]+-(?P<id>\d+))'
|
||||||
|
_TESTS = [{
|
||||||
|
'url': 'https://www.cinemax.com/warrior/video/s1-ep-1-recap-20126903',
|
||||||
|
'md5': '82e0734bba8aa7ef526c9dd00cf35a05',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '20126903',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'S1 Ep 1: Recap',
|
||||||
|
},
|
||||||
|
'expected_warnings': ['Unknown MIME type application/mp4 in DASH manifest'],
|
||||||
|
}, {
|
||||||
|
'url': 'https://www.cinemax.com/warrior/video/s1-ep-1-recap-20126903.embed',
|
||||||
|
'only_matching': True,
|
||||||
|
}]
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
path, video_id = re.match(self._VALID_URL, url).groups()
|
||||||
|
info = self._extract_info('https://www.cinemax.com/%s.xml' % path, video_id)
|
||||||
|
info['id'] = video_id
|
||||||
|
return info
|
@ -2019,6 +2019,8 @@ class InfoExtractor(object):
|
|||||||
if res is False:
|
if res is False:
|
||||||
return []
|
return []
|
||||||
mpd_doc, urlh = res
|
mpd_doc, urlh = res
|
||||||
|
if mpd_doc is None:
|
||||||
|
return []
|
||||||
mpd_base_url = base_url(urlh.geturl())
|
mpd_base_url = base_url(urlh.geturl())
|
||||||
|
|
||||||
return self._parse_mpd_formats(
|
return self._parse_mpd_formats(
|
||||||
|
@ -1,266 +0,0 @@
|
|||||||
# coding: utf-8
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import itertools
|
|
||||||
import json
|
|
||||||
|
|
||||||
from .common import InfoExtractor
|
|
||||||
from ..compat import (
|
|
||||||
compat_HTTPError,
|
|
||||||
compat_urlparse,
|
|
||||||
)
|
|
||||||
from ..utils import (
|
|
||||||
clean_html,
|
|
||||||
ExtractorError,
|
|
||||||
int_or_none,
|
|
||||||
parse_age_limit,
|
|
||||||
parse_duration,
|
|
||||||
unified_timestamp,
|
|
||||||
url_or_none,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class DramaFeverBaseIE(InfoExtractor):
|
|
||||||
_NETRC_MACHINE = 'dramafever'
|
|
||||||
|
|
||||||
_CONSUMER_SECRET = 'DA59dtVXYLxajktV'
|
|
||||||
|
|
||||||
_consumer_secret = None
|
|
||||||
|
|
||||||
def _get_consumer_secret(self):
|
|
||||||
mainjs = self._download_webpage(
|
|
||||||
'http://www.dramafever.com/static/51afe95/df2014/scripts/main.js',
|
|
||||||
None, 'Downloading main.js', fatal=False)
|
|
||||||
if not mainjs:
|
|
||||||
return self._CONSUMER_SECRET
|
|
||||||
return self._search_regex(
|
|
||||||
r"var\s+cs\s*=\s*'([^']+)'", mainjs,
|
|
||||||
'consumer secret', default=self._CONSUMER_SECRET)
|
|
||||||
|
|
||||||
def _real_initialize(self):
|
|
||||||
self._consumer_secret = self._get_consumer_secret()
|
|
||||||
self._login()
|
|
||||||
|
|
||||||
def _login(self):
|
|
||||||
username, password = self._get_login_info()
|
|
||||||
if username is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
login_form = {
|
|
||||||
'username': username,
|
|
||||||
'password': password,
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
response = self._download_json(
|
|
||||||
'https://www.dramafever.com/api/users/login', None, 'Logging in',
|
|
||||||
data=json.dumps(login_form).encode('utf-8'), headers={
|
|
||||||
'x-consumer-key': self._consumer_secret,
|
|
||||||
})
|
|
||||||
except ExtractorError as e:
|
|
||||||
if isinstance(e.cause, compat_HTTPError) and e.cause.code in (403, 404):
|
|
||||||
response = self._parse_json(
|
|
||||||
e.cause.read().decode('utf-8'), None)
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
|
|
||||||
# Successful login
|
|
||||||
if response.get('result') or response.get('guid') or response.get('user_guid'):
|
|
||||||
return
|
|
||||||
|
|
||||||
errors = response.get('errors')
|
|
||||||
if errors and isinstance(errors, list):
|
|
||||||
error = errors[0]
|
|
||||||
message = error.get('message') or error['reason']
|
|
||||||
raise ExtractorError('Unable to login: %s' % message, expected=True)
|
|
||||||
raise ExtractorError('Unable to log in')
|
|
||||||
|
|
||||||
|
|
||||||
class DramaFeverIE(DramaFeverBaseIE):
|
|
||||||
IE_NAME = 'dramafever'
|
|
||||||
_VALID_URL = r'https?://(?:www\.)?dramafever\.com/(?:[^/]+/)?drama/(?P<id>[0-9]+/[0-9]+)(?:/|$)'
|
|
||||||
_TESTS = [{
|
|
||||||
'url': 'https://www.dramafever.com/drama/4274/1/Heirs/',
|
|
||||||
'info_dict': {
|
|
||||||
'id': '4274.1',
|
|
||||||
'ext': 'wvm',
|
|
||||||
'title': 'Heirs - Episode 1',
|
|
||||||
'description': 'md5:362a24ba18209f6276e032a651c50bc2',
|
|
||||||
'thumbnail': r're:^https?://.*\.jpg',
|
|
||||||
'duration': 3783,
|
|
||||||
'timestamp': 1381354993,
|
|
||||||
'upload_date': '20131009',
|
|
||||||
'series': 'Heirs',
|
|
||||||
'season_number': 1,
|
|
||||||
'episode': 'Episode 1',
|
|
||||||
'episode_number': 1,
|
|
||||||
},
|
|
||||||
'params': {
|
|
||||||
# m3u8 download
|
|
||||||
'skip_download': True,
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
'url': 'http://www.dramafever.com/drama/4826/4/Mnet_Asian_Music_Awards_2015/?ap=1',
|
|
||||||
'info_dict': {
|
|
||||||
'id': '4826.4',
|
|
||||||
'ext': 'flv',
|
|
||||||
'title': 'Mnet Asian Music Awards 2015',
|
|
||||||
'description': 'md5:3ff2ee8fedaef86e076791c909cf2e91',
|
|
||||||
'episode': 'Mnet Asian Music Awards 2015 - Part 3',
|
|
||||||
'episode_number': 4,
|
|
||||||
'thumbnail': r're:^https?://.*\.jpg',
|
|
||||||
'timestamp': 1450213200,
|
|
||||||
'upload_date': '20151215',
|
|
||||||
'duration': 5359,
|
|
||||||
},
|
|
||||||
'params': {
|
|
||||||
# m3u8 download
|
|
||||||
'skip_download': True,
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
'url': 'https://www.dramafever.com/zh-cn/drama/4972/15/Doctor_Romantic/',
|
|
||||||
'only_matching': True,
|
|
||||||
}]
|
|
||||||
|
|
||||||
def _call_api(self, path, video_id, note, fatal=False):
|
|
||||||
return self._download_json(
|
|
||||||
'https://www.dramafever.com/api/5/' + path,
|
|
||||||
video_id, note=note, headers={
|
|
||||||
'x-consumer-key': self._consumer_secret,
|
|
||||||
}, fatal=fatal)
|
|
||||||
|
|
||||||
def _get_subtitles(self, video_id):
|
|
||||||
subtitles = {}
|
|
||||||
subs = self._call_api(
|
|
||||||
'video/%s/subtitles/webvtt/' % video_id, video_id,
|
|
||||||
'Downloading subtitles JSON', fatal=False)
|
|
||||||
if not subs or not isinstance(subs, list):
|
|
||||||
return subtitles
|
|
||||||
for sub in subs:
|
|
||||||
if not isinstance(sub, dict):
|
|
||||||
continue
|
|
||||||
sub_url = url_or_none(sub.get('url'))
|
|
||||||
if not sub_url:
|
|
||||||
continue
|
|
||||||
subtitles.setdefault(
|
|
||||||
sub.get('code') or sub.get('language') or 'en', []).append({
|
|
||||||
'url': sub_url
|
|
||||||
})
|
|
||||||
return subtitles
|
|
||||||
|
|
||||||
def _real_extract(self, url):
|
|
||||||
video_id = self._match_id(url).replace('/', '.')
|
|
||||||
|
|
||||||
series_id, episode_number = video_id.split('.')
|
|
||||||
|
|
||||||
video = self._call_api(
|
|
||||||
'series/%s/episodes/%s/' % (series_id, episode_number), video_id,
|
|
||||||
'Downloading video JSON')
|
|
||||||
|
|
||||||
formats = []
|
|
||||||
download_assets = video.get('download_assets')
|
|
||||||
if download_assets and isinstance(download_assets, dict):
|
|
||||||
for format_id, format_dict in download_assets.items():
|
|
||||||
if not isinstance(format_dict, dict):
|
|
||||||
continue
|
|
||||||
format_url = url_or_none(format_dict.get('url'))
|
|
||||||
if not format_url:
|
|
||||||
continue
|
|
||||||
formats.append({
|
|
||||||
'url': format_url,
|
|
||||||
'format_id': format_id,
|
|
||||||
'filesize': int_or_none(video.get('filesize')),
|
|
||||||
})
|
|
||||||
|
|
||||||
stream = self._call_api(
|
|
||||||
'video/%s/stream/' % video_id, video_id, 'Downloading stream JSON',
|
|
||||||
fatal=False)
|
|
||||||
if stream:
|
|
||||||
stream_url = stream.get('stream_url')
|
|
||||||
if stream_url:
|
|
||||||
formats.extend(self._extract_m3u8_formats(
|
|
||||||
stream_url, video_id, 'mp4', entry_protocol='m3u8_native',
|
|
||||||
m3u8_id='hls', fatal=False))
|
|
||||||
self._sort_formats(formats)
|
|
||||||
|
|
||||||
title = video.get('title') or 'Episode %s' % episode_number
|
|
||||||
description = video.get('description')
|
|
||||||
thumbnail = video.get('thumbnail')
|
|
||||||
timestamp = unified_timestamp(video.get('release_date'))
|
|
||||||
duration = parse_duration(video.get('duration'))
|
|
||||||
age_limit = parse_age_limit(video.get('tv_rating'))
|
|
||||||
series = video.get('series_title')
|
|
||||||
season_number = int_or_none(video.get('season'))
|
|
||||||
|
|
||||||
if series:
|
|
||||||
title = '%s - %s' % (series, title)
|
|
||||||
|
|
||||||
subtitles = self.extract_subtitles(video_id)
|
|
||||||
|
|
||||||
return {
|
|
||||||
'id': video_id,
|
|
||||||
'title': title,
|
|
||||||
'description': description,
|
|
||||||
'thumbnail': thumbnail,
|
|
||||||
'duration': duration,
|
|
||||||
'timestamp': timestamp,
|
|
||||||
'age_limit': age_limit,
|
|
||||||
'series': series,
|
|
||||||
'season_number': season_number,
|
|
||||||
'episode_number': int_or_none(episode_number),
|
|
||||||
'formats': formats,
|
|
||||||
'subtitles': subtitles,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class DramaFeverSeriesIE(DramaFeverBaseIE):
|
|
||||||
IE_NAME = 'dramafever:series'
|
|
||||||
_VALID_URL = r'https?://(?:www\.)?dramafever\.com/(?:[^/]+/)?drama/(?P<id>[0-9]+)(?:/(?:(?!\d+(?:/|$)).+)?)?$'
|
|
||||||
_TESTS = [{
|
|
||||||
'url': 'http://www.dramafever.com/drama/4512/Cooking_with_Shin/',
|
|
||||||
'info_dict': {
|
|
||||||
'id': '4512',
|
|
||||||
'title': 'Cooking with Shin',
|
|
||||||
'description': 'md5:84a3f26e3cdc3fb7f500211b3593b5c1',
|
|
||||||
},
|
|
||||||
'playlist_count': 4,
|
|
||||||
}, {
|
|
||||||
'url': 'http://www.dramafever.com/drama/124/IRIS/',
|
|
||||||
'info_dict': {
|
|
||||||
'id': '124',
|
|
||||||
'title': 'IRIS',
|
|
||||||
'description': 'md5:b3a30e587cf20c59bd1c01ec0ee1b862',
|
|
||||||
},
|
|
||||||
'playlist_count': 20,
|
|
||||||
}]
|
|
||||||
|
|
||||||
_PAGE_SIZE = 60 # max is 60 (see http://api.drama9.com/#get--api-4-episode-series-)
|
|
||||||
|
|
||||||
def _real_extract(self, url):
|
|
||||||
series_id = self._match_id(url)
|
|
||||||
|
|
||||||
series = self._download_json(
|
|
||||||
'http://www.dramafever.com/api/4/series/query/?cs=%s&series_id=%s'
|
|
||||||
% (self._consumer_secret, series_id),
|
|
||||||
series_id, 'Downloading series JSON')['series'][series_id]
|
|
||||||
|
|
||||||
title = clean_html(series['name'])
|
|
||||||
description = clean_html(series.get('description') or series.get('description_short'))
|
|
||||||
|
|
||||||
entries = []
|
|
||||||
for page_num in itertools.count(1):
|
|
||||||
episodes = self._download_json(
|
|
||||||
'http://www.dramafever.com/api/4/episode/series/?cs=%s&series_id=%s&page_size=%d&page_number=%d'
|
|
||||||
% (self._consumer_secret, series_id, self._PAGE_SIZE, page_num),
|
|
||||||
series_id, 'Downloading episodes JSON page #%d' % page_num)
|
|
||||||
for episode in episodes.get('value', []):
|
|
||||||
episode_url = episode.get('episode_url')
|
|
||||||
if not episode_url:
|
|
||||||
continue
|
|
||||||
entries.append(self.url_result(
|
|
||||||
compat_urlparse.urljoin(url, episode_url),
|
|
||||||
'DramaFever', episode.get('guid')))
|
|
||||||
if page_num == episodes['num_pages']:
|
|
||||||
break
|
|
||||||
|
|
||||||
return self.playlist_result(entries, series_id, title, description)
|
|
@ -177,7 +177,10 @@ from .cbsnews import (
|
|||||||
CBSNewsLiveVideoIE,
|
CBSNewsLiveVideoIE,
|
||||||
)
|
)
|
||||||
from .cbssports import CBSSportsIE
|
from .cbssports import CBSSportsIE
|
||||||
from .ccc import CCCIE
|
from .ccc import (
|
||||||
|
CCCIE,
|
||||||
|
CCCPlaylistIE,
|
||||||
|
)
|
||||||
from .ccma import CCMAIE
|
from .ccma import CCMAIE
|
||||||
from .cctv import CCTVIE
|
from .cctv import CCTVIE
|
||||||
from .cda import CDAIE
|
from .cda import CDAIE
|
||||||
@ -194,6 +197,7 @@ from .chirbit import (
|
|||||||
ChirbitProfileIE,
|
ChirbitProfileIE,
|
||||||
)
|
)
|
||||||
from .cinchcast import CinchcastIE
|
from .cinchcast import CinchcastIE
|
||||||
|
from .cinemax import CinemaxIE
|
||||||
from .ciscolive import (
|
from .ciscolive import (
|
||||||
CiscoLiveSessionIE,
|
CiscoLiveSessionIE,
|
||||||
CiscoLiveSearchIE,
|
CiscoLiveSearchIE,
|
||||||
@ -283,10 +287,6 @@ from .dplay import (
|
|||||||
DPlayIE,
|
DPlayIE,
|
||||||
DPlayItIE,
|
DPlayItIE,
|
||||||
)
|
)
|
||||||
from .dramafever import (
|
|
||||||
DramaFeverIE,
|
|
||||||
DramaFeverSeriesIE,
|
|
||||||
)
|
|
||||||
from .dreisat import DreiSatIE
|
from .dreisat import DreiSatIE
|
||||||
from .drbonanza import DRBonanzaIE
|
from .drbonanza import DRBonanzaIE
|
||||||
from .drtuber import DrTuberIE
|
from .drtuber import DrTuberIE
|
||||||
@ -808,6 +808,8 @@ from .nrk import (
|
|||||||
NRKTVSeasonIE,
|
NRKTVSeasonIE,
|
||||||
NRKTVSeriesIE,
|
NRKTVSeriesIE,
|
||||||
)
|
)
|
||||||
|
from .nrl import NRLTVIE
|
||||||
|
from .ntvcojp import NTVCoJpCUIE
|
||||||
from .ntvde import NTVDeIE
|
from .ntvde import NTVDeIE
|
||||||
from .ntvru import NTVRuIE
|
from .ntvru import NTVRuIE
|
||||||
from .nytimes import (
|
from .nytimes import (
|
||||||
@ -1095,6 +1097,10 @@ from .streetvoice import StreetVoiceIE
|
|||||||
from .stretchinternet import StretchInternetIE
|
from .stretchinternet import StretchInternetIE
|
||||||
from .stv import STVPlayerIE
|
from .stv import STVPlayerIE
|
||||||
from .sunporno import SunPornoIE
|
from .sunporno import SunPornoIE
|
||||||
|
from .sverigesradio import (
|
||||||
|
SverigesRadioEpisodeIE,
|
||||||
|
SverigesRadioPublicationIE,
|
||||||
|
)
|
||||||
from .svt import (
|
from .svt import (
|
||||||
SVTIE,
|
SVTIE,
|
||||||
SVTPageIE,
|
SVTPageIE,
|
||||||
@ -1416,10 +1422,6 @@ from .weiqitv import WeiqiTVIE
|
|||||||
from .wimp import WimpIE
|
from .wimp import WimpIE
|
||||||
from .wistia import WistiaIE
|
from .wistia import WistiaIE
|
||||||
from .worldstarhiphop import WorldStarHipHopIE
|
from .worldstarhiphop import WorldStarHipHopIE
|
||||||
from .wrzuta import (
|
|
||||||
WrzutaIE,
|
|
||||||
WrzutaPlaylistIE,
|
|
||||||
)
|
|
||||||
from .wsj import (
|
from .wsj import (
|
||||||
WSJIE,
|
WSJIE,
|
||||||
WSJArticleIE,
|
WSJArticleIE,
|
||||||
|
@ -66,7 +66,7 @@ class FOXIE(AdobePassIE):
|
|||||||
'https://api2.fox.com/v2.0/' + path,
|
'https://api2.fox.com/v2.0/' + path,
|
||||||
video_id, data=data, headers=headers)
|
video_id, data=data, headers=headers)
|
||||||
except ExtractorError as e:
|
except ExtractorError as e:
|
||||||
if isinstance(e.cause, compat_HTTPError) and e.cause.status == 403:
|
if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
|
||||||
entitlement_issues = self._parse_json(
|
entitlement_issues = self._parse_json(
|
||||||
e.cause.read().decode(), video_id)['entitlementIssues']
|
e.cause.read().decode(), video_id)['entitlementIssues']
|
||||||
for e in entitlement_issues:
|
for e in entitlement_issues:
|
||||||
@ -100,7 +100,7 @@ class FOXIE(AdobePassIE):
|
|||||||
try:
|
try:
|
||||||
m3u8_url = self._download_json(release_url, video_id)['playURL']
|
m3u8_url = self._download_json(release_url, video_id)['playURL']
|
||||||
except ExtractorError as e:
|
except ExtractorError as e:
|
||||||
if isinstance(e.cause, compat_HTTPError) and e.cause.status == 403:
|
if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
|
||||||
error = self._parse_json(e.cause.read().decode(), video_id)
|
error = self._parse_json(e.cause.read().decode(), video_id)
|
||||||
if error.get('exception') == 'GeoLocationBlocked':
|
if error.get('exception') == 'GeoLocationBlocked':
|
||||||
self.raise_geo_restricted(countries=['US'])
|
self.raise_geo_restricted(countries=['US'])
|
||||||
|
@ -13,19 +13,7 @@ from ..utils import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class HBOIE(InfoExtractor):
|
class HBOBaseIE(InfoExtractor):
|
||||||
IE_NAME = 'hbo'
|
|
||||||
_VALID_URL = r'https?://(?:www\.)?hbo\.com/(?:video|embed)(?:/[^/]+)*/(?P<id>[^/?#]+)'
|
|
||||||
_TEST = {
|
|
||||||
'url': 'https://www.hbo.com/video/game-of-thrones/seasons/season-8/videos/trailer',
|
|
||||||
'md5': '8126210656f433c452a21367f9ad85b3',
|
|
||||||
'info_dict': {
|
|
||||||
'id': '22113301',
|
|
||||||
'ext': 'mp4',
|
|
||||||
'title': 'Game of Thrones - Trailer',
|
|
||||||
},
|
|
||||||
'expected_warnings': ['Unknown MIME type application/mp4 in DASH manifest'],
|
|
||||||
}
|
|
||||||
_FORMATS_INFO = {
|
_FORMATS_INFO = {
|
||||||
'pro7': {
|
'pro7': {
|
||||||
'width': 1280,
|
'width': 1280,
|
||||||
@ -65,12 +53,8 @@ class HBOIE(InfoExtractor):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _extract_info(self, url, display_id):
|
||||||
display_id = self._match_id(url)
|
video_data = self._download_xml(url, display_id)
|
||||||
webpage = self._download_webpage(url, display_id)
|
|
||||||
location_path = self._parse_json(self._html_search_regex(
|
|
||||||
r'data-state="({.+?})"', webpage, 'state'), display_id)['video']['locationUrl']
|
|
||||||
video_data = self._download_xml(urljoin(url, location_path), display_id)
|
|
||||||
video_id = xpath_text(video_data, 'id', fatal=True)
|
video_id = xpath_text(video_data, 'id', fatal=True)
|
||||||
episode_title = title = xpath_text(video_data, 'title', fatal=True)
|
episode_title = title = xpath_text(video_data, 'title', fatal=True)
|
||||||
series = xpath_text(video_data, 'program')
|
series = xpath_text(video_data, 'program')
|
||||||
@ -167,3 +151,25 @@ class HBOIE(InfoExtractor):
|
|||||||
'thumbnails': thumbnails,
|
'thumbnails': thumbnails,
|
||||||
'subtitles': subtitles,
|
'subtitles': subtitles,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class HBOIE(HBOBaseIE):
|
||||||
|
IE_NAME = 'hbo'
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?hbo\.com/(?:video|embed)(?:/[^/]+)*/(?P<id>[^/?#]+)'
|
||||||
|
_TEST = {
|
||||||
|
'url': 'https://www.hbo.com/video/game-of-thrones/seasons/season-8/videos/trailer',
|
||||||
|
'md5': '8126210656f433c452a21367f9ad85b3',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '22113301',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Game of Thrones - Trailer',
|
||||||
|
},
|
||||||
|
'expected_warnings': ['Unknown MIME type application/mp4 in DASH manifest'],
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
display_id = self._match_id(url)
|
||||||
|
webpage = self._download_webpage(url, display_id)
|
||||||
|
location_path = self._parse_json(self._html_search_regex(
|
||||||
|
r'data-state="({.+?})"', webpage, 'state'), display_id)['video']['locationUrl']
|
||||||
|
return self._extract_info(urljoin(url, location_path), display_id)
|
||||||
|
@ -1,54 +1,81 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from ..utils import ExtractorError
|
|
||||||
|
|
||||||
|
|
||||||
class NhkVodIE(InfoExtractor):
|
class NhkVodIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://www3\.nhk\.or\.jp/nhkworld/en/(?:vod|ondemand)/(?P<id>[^/]+/[^/?#&]+)'
|
_VALID_URL = r'https?://www3\.nhk\.or\.jp/nhkworld/(?P<lang>[a-z]{2})/ondemand/(?P<type>video|audio)/(?P<id>\d{7}|[a-z]+-\d{8}-\d+)'
|
||||||
|
# Content available only for a limited period of time. Visit
|
||||||
|
# https://www3.nhk.or.jp/nhkworld/en/ondemand/ for working samples.
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
# Videos available only for a limited period of time. Visit
|
|
||||||
# http://www3.nhk.or.jp/nhkworld/en/vod/ for working samples.
|
|
||||||
'url': 'http://www3.nhk.or.jp/nhkworld/en/vod/tokyofashion/20160815',
|
|
||||||
'info_dict': {
|
|
||||||
'id': 'A1bnNiNTE6nY3jLllS-BIISfcC_PpvF5',
|
|
||||||
'ext': 'flv',
|
|
||||||
'title': 'TOKYO FASHION EXPRESS - The Kimono as Global Fashion',
|
|
||||||
'description': 'md5:db338ee6ce8204f415b754782f819824',
|
|
||||||
'series': 'TOKYO FASHION EXPRESS',
|
|
||||||
'episode': 'The Kimono as Global Fashion',
|
|
||||||
},
|
|
||||||
'skip': 'Videos available only for a limited period of time',
|
|
||||||
}, {
|
|
||||||
'url': 'https://www3.nhk.or.jp/nhkworld/en/ondemand/video/2015173/',
|
'url': 'https://www3.nhk.or.jp/nhkworld/en/ondemand/video/2015173/',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'https://www3.nhk.or.jp/nhkworld/en/ondemand/audio/plugin-20190404-1/',
|
||||||
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'https://www3.nhk.or.jp/nhkworld/fr/ondemand/audio/plugin-20190404-1/',
|
||||||
|
'only_matching': True,
|
||||||
}]
|
}]
|
||||||
_API_URL = 'http://api.nhk.or.jp/nhkworld/vodesdlist/v1/all/all/all.json?apikey=EJfK8jdS57GqlupFgAfAAwr573q01y6k'
|
_API_URL_TEMPLATE = 'https://api.nhk.or.jp/nhkworld/%sodesdlist/v7/episode/%s/%s/all%s.json'
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
video_id = self._match_id(url)
|
lang, m_type, episode_id = re.match(self._VALID_URL, url).groups()
|
||||||
|
if episode_id.isdigit():
|
||||||
data = self._download_json(self._API_URL, video_id)
|
episode_id = episode_id[:4] + '-' + episode_id[4:]
|
||||||
|
|
||||||
try:
|
|
||||||
episode = next(
|
|
||||||
e for e in data['data']['episodes']
|
|
||||||
if e.get('url') and video_id in e['url'])
|
|
||||||
except StopIteration:
|
|
||||||
raise ExtractorError('Unable to find episode')
|
|
||||||
|
|
||||||
embed_code = episode['vod_id']
|
|
||||||
|
|
||||||
|
is_video = m_type == 'video'
|
||||||
|
episode = self._download_json(
|
||||||
|
self._API_URL_TEMPLATE % ('v' if is_video else 'r', episode_id, lang, '/all' if is_video else ''),
|
||||||
|
episode_id, query={'apikey': 'EJfK8jdS57GqlupFgAfAAwr573q01y6k'})['data']['episodes'][0]
|
||||||
title = episode.get('sub_title_clean') or episode['sub_title']
|
title = episode.get('sub_title_clean') or episode['sub_title']
|
||||||
description = episode.get('description_clean') or episode.get('description')
|
|
||||||
series = episode.get('title_clean') or episode.get('title')
|
|
||||||
|
|
||||||
return {
|
def get_clean_field(key):
|
||||||
'_type': 'url_transparent',
|
return episode.get(key + '_clean') or episode.get(key)
|
||||||
'ie_key': 'Ooyala',
|
|
||||||
'url': 'ooyala:%s' % embed_code,
|
series = get_clean_field('title')
|
||||||
|
|
||||||
|
thumbnails = []
|
||||||
|
for s, w, h in [('', 640, 360), ('_l', 1280, 720)]:
|
||||||
|
img_path = episode.get('image' + s)
|
||||||
|
if not img_path:
|
||||||
|
continue
|
||||||
|
thumbnails.append({
|
||||||
|
'id': '%dp' % h,
|
||||||
|
'height': h,
|
||||||
|
'width': w,
|
||||||
|
'url': 'https://www3.nhk.or.jp' + img_path,
|
||||||
|
})
|
||||||
|
|
||||||
|
info = {
|
||||||
|
'id': episode_id + '-' + lang,
|
||||||
'title': '%s - %s' % (series, title) if series and title else title,
|
'title': '%s - %s' % (series, title) if series and title else title,
|
||||||
'description': description,
|
'description': get_clean_field('description'),
|
||||||
|
'thumbnails': thumbnails,
|
||||||
'series': series,
|
'series': series,
|
||||||
'episode': title,
|
'episode': title,
|
||||||
}
|
}
|
||||||
|
if is_video:
|
||||||
|
info.update({
|
||||||
|
'_type': 'url_transparent',
|
||||||
|
'ie_key': 'Ooyala',
|
||||||
|
'url': 'ooyala:' + episode['vod_id'],
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
audio = episode['audio']
|
||||||
|
audio_path = audio['audio']
|
||||||
|
info['formats'] = self._extract_m3u8_formats(
|
||||||
|
'https://nhks-vh.akamaihd.net/i%s/master.m3u8' % audio_path,
|
||||||
|
episode_id, 'm4a', m3u8_id='hls', fatal=False)
|
||||||
|
for proto in ('rtmpt', 'rtmp'):
|
||||||
|
info['formats'].append({
|
||||||
|
'ext': 'flv',
|
||||||
|
'format_id': proto,
|
||||||
|
'url': '%s://flv.nhk.or.jp/ondemand/mp4:flv%s' % (proto, audio_path),
|
||||||
|
'vcodec': 'none',
|
||||||
|
})
|
||||||
|
for f in info['formats']:
|
||||||
|
f['language'] = lang
|
||||||
|
return info
|
||||||
|
30
youtube_dl/extractor/nrl.py
Normal file
30
youtube_dl/extractor/nrl.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
|
||||||
|
|
||||||
|
class NRLTVIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?nrl\.com/tv(/[^/]+)*/(?P<id>[^/?&#]+)'
|
||||||
|
_TEST = {
|
||||||
|
'url': 'https://www.nrl.com/tv/news/match-highlights-titans-v-knights-862805/',
|
||||||
|
'info_dict': {
|
||||||
|
'id': 'YyNnFuaDE6kPJqlDhG4CGQ_w89mKTau4',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Match Highlights: Titans v Knights',
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
# m3u8 download
|
||||||
|
'skip_download': True,
|
||||||
|
'format': 'bestvideo',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
display_id = self._match_id(url)
|
||||||
|
webpage = self._download_webpage(url, display_id)
|
||||||
|
q_data = self._parse_json(self._search_regex(
|
||||||
|
r"(?s)q-data='({.+?})'", webpage, 'player data'), display_id)
|
||||||
|
ooyala_id = q_data['videoId']
|
||||||
|
return self.url_result(
|
||||||
|
'ooyala:' + ooyala_id, 'Ooyala', ooyala_id, q_data.get('title'))
|
49
youtube_dl/extractor/ntvcojp.py
Normal file
49
youtube_dl/extractor/ntvcojp.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import (
|
||||||
|
js_to_json,
|
||||||
|
smuggle_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class NTVCoJpCUIE(InfoExtractor):
|
||||||
|
IE_NAME = 'cu.ntv.co.jp'
|
||||||
|
IE_DESC = 'Nippon Television Network'
|
||||||
|
_VALID_URL = r'https?://cu\.ntv\.co\.jp/(?!program)(?P<id>[^/?&#]+)'
|
||||||
|
_TEST = {
|
||||||
|
'url': 'https://cu.ntv.co.jp/televiva-chill-gohan_181031/',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '5978891207001',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': '桜エビと炒り卵がポイント! 「中華風 エビチリおにぎり」──『美虎』五十嵐美幸',
|
||||||
|
'upload_date': '20181213',
|
||||||
|
'description': 'md5:211b52f4fd60f3e0e72b68b0c6ba52a9',
|
||||||
|
'uploader_id': '3855502814001',
|
||||||
|
'timestamp': 1544669941,
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
# m3u8 download
|
||||||
|
'skip_download': True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
BRIGHTCOVE_URL_TEMPLATE = 'http://players.brightcove.net/%s/default_default/index.html?videoId=%s'
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
display_id = self._match_id(url)
|
||||||
|
webpage = self._download_webpage(url, display_id)
|
||||||
|
player_config = self._parse_json(self._search_regex(
|
||||||
|
r'(?s)PLAYER_CONFIG\s*=\s*({.+?})',
|
||||||
|
webpage, 'player config'), display_id, js_to_json)
|
||||||
|
video_id = player_config['videoId']
|
||||||
|
account_id = player_config.get('account') or '3855502814001'
|
||||||
|
return {
|
||||||
|
'_type': 'url_transparent',
|
||||||
|
'id': video_id,
|
||||||
|
'display_id': display_id,
|
||||||
|
'title': self._search_regex(r'<h1[^>]+class="title"[^>]*>([^<]+)', webpage, 'title').strip(),
|
||||||
|
'description': self._html_search_meta(['description', 'og:description'], webpage),
|
||||||
|
'url': smuggle_url(self.BRIGHTCOVE_URL_TEMPLATE % (account_id, video_id), {'geo_countries': ['JP']}),
|
||||||
|
'ie_key': 'BrightcoveNew',
|
||||||
|
}
|
@ -36,7 +36,7 @@ class OoyalaBaseIE(InfoExtractor):
|
|||||||
'domain': domain,
|
'domain': domain,
|
||||||
'supportedFormats': supportedformats or 'mp4,rtmp,m3u8,hds,dash,smooth',
|
'supportedFormats': supportedformats or 'mp4,rtmp,m3u8,hds,dash,smooth',
|
||||||
'embedToken': embed_token,
|
'embedToken': embed_token,
|
||||||
}), video_id)
|
}), video_id, headers=self.geo_verification_headers())
|
||||||
|
|
||||||
cur_auth_data = auth_data['authorization_data'][embed_code]
|
cur_auth_data = auth_data['authorization_data'][embed_code]
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,7 @@ from ..utils import (
|
|||||||
|
|
||||||
|
|
||||||
class RedBullTVIE(InfoExtractor):
|
class RedBullTVIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://(?:www\.)?redbull(?:\.tv|\.com/(?:[^/]+/)?tv)/video/(?P<id>AP-\w+)'
|
_VALID_URL = r'https?://(?:www\.)?redbull(?:\.tv|\.com(?:/[^/]+)?(?:/tv)?)(?:/events/[^/]+)?/(?:videos?|live)/(?P<id>AP-\w+)'
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
# film
|
# film
|
||||||
'url': 'https://www.redbull.tv/video/AP-1Q6XCDTAN1W11',
|
'url': 'https://www.redbull.tv/video/AP-1Q6XCDTAN1W11',
|
||||||
@ -38,6 +38,12 @@ class RedBullTVIE(InfoExtractor):
|
|||||||
}, {
|
}, {
|
||||||
'url': 'https://www.redbull.com/int-en/tv/video/AP-1UWHCAR9S1W11/rob-meets-sam-gaze?playlist=playlists::3f81040a-2f31-4832-8e2e-545b1d39d173',
|
'url': 'https://www.redbull.com/int-en/tv/video/AP-1UWHCAR9S1W11/rob-meets-sam-gaze?playlist=playlists::3f81040a-2f31-4832-8e2e-545b1d39d173',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'https://www.redbull.com/us-en/videos/AP-1YM9QCYE52111',
|
||||||
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'https://www.redbull.com/us-en/events/AP-1XV2K61Q51W11/live/AP-1XUJ86FDH1W11',
|
||||||
|
'only_matching': True,
|
||||||
}]
|
}]
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
|
@ -7,6 +7,7 @@ from ..utils import (
|
|||||||
ExtractorError,
|
ExtractorError,
|
||||||
int_or_none,
|
int_or_none,
|
||||||
float_or_none,
|
float_or_none,
|
||||||
|
url_or_none,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -119,7 +120,7 @@ class RedditRIE(InfoExtractor):
|
|||||||
'_type': 'url_transparent',
|
'_type': 'url_transparent',
|
||||||
'url': video_url,
|
'url': video_url,
|
||||||
'title': data.get('title'),
|
'title': data.get('title'),
|
||||||
'thumbnail': data.get('thumbnail'),
|
'thumbnail': url_or_none(data.get('thumbnail')),
|
||||||
'timestamp': float_or_none(data.get('created_utc')),
|
'timestamp': float_or_none(data.get('created_utc')),
|
||||||
'uploader': data.get('author'),
|
'uploader': data.get('author'),
|
||||||
'like_count': int_or_none(data.get('ups')),
|
'like_count': int_or_none(data.get('ups')),
|
||||||
|
@ -65,7 +65,7 @@ class SixPlayIE(InfoExtractor):
|
|||||||
for asset in assets:
|
for asset in assets:
|
||||||
asset_url = asset.get('full_physical_path')
|
asset_url = asset.get('full_physical_path')
|
||||||
protocol = asset.get('protocol')
|
protocol = asset.get('protocol')
|
||||||
if not asset_url or protocol == 'primetime' or asset.get('type') == 'usp_hlsfp_h264' or asset_url in urls:
|
if not asset_url or ((protocol == 'primetime' or asset.get('type') == 'usp_hlsfp_h264') and not ('_drmnp.ism/' in asset_url or '_unpnp.ism/' in asset_url)) or asset_url in urls:
|
||||||
continue
|
continue
|
||||||
urls.append(asset_url)
|
urls.append(asset_url)
|
||||||
container = asset.get('video_container')
|
container = asset.get('video_container')
|
||||||
@ -82,6 +82,7 @@ class SixPlayIE(InfoExtractor):
|
|||||||
if not urlh:
|
if not urlh:
|
||||||
continue
|
continue
|
||||||
asset_url = urlh.geturl()
|
asset_url = urlh.geturl()
|
||||||
|
asset_url = asset_url.replace('_drmnp.ism/', '_unpnp.ism/')
|
||||||
for i in range(3, 0, -1):
|
for i in range(3, 0, -1):
|
||||||
asset_url = asset_url = asset_url.replace('_sd1/', '_sd%d/' % i)
|
asset_url = asset_url = asset_url.replace('_sd1/', '_sd%d/' % i)
|
||||||
m3u8_formats = self._extract_m3u8_formats(
|
m3u8_formats = self._extract_m3u8_formats(
|
||||||
|
@ -15,7 +15,12 @@ from ..compat import (
|
|||||||
)
|
)
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
ExtractorError,
|
ExtractorError,
|
||||||
|
float_or_none,
|
||||||
int_or_none,
|
int_or_none,
|
||||||
|
KNOWN_EXTENSIONS,
|
||||||
|
merge_dicts,
|
||||||
|
mimetype2ext,
|
||||||
|
str_or_none,
|
||||||
try_get,
|
try_get,
|
||||||
unified_timestamp,
|
unified_timestamp,
|
||||||
update_url_query,
|
update_url_query,
|
||||||
@ -57,7 +62,7 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
'uploader': 'E.T. ExTerrestrial Music',
|
'uploader': 'E.T. ExTerrestrial Music',
|
||||||
'timestamp': 1349920598,
|
'timestamp': 1349920598,
|
||||||
'upload_date': '20121011',
|
'upload_date': '20121011',
|
||||||
'duration': 143,
|
'duration': 143.216,
|
||||||
'license': 'all-rights-reserved',
|
'license': 'all-rights-reserved',
|
||||||
'view_count': int,
|
'view_count': int,
|
||||||
'like_count': int,
|
'like_count': int,
|
||||||
@ -100,7 +105,7 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
'uploader': 'jaimeMF',
|
'uploader': 'jaimeMF',
|
||||||
'timestamp': 1386604920,
|
'timestamp': 1386604920,
|
||||||
'upload_date': '20131209',
|
'upload_date': '20131209',
|
||||||
'duration': 9,
|
'duration': 9.927,
|
||||||
'license': 'all-rights-reserved',
|
'license': 'all-rights-reserved',
|
||||||
'view_count': int,
|
'view_count': int,
|
||||||
'like_count': int,
|
'like_count': int,
|
||||||
@ -120,7 +125,7 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
'uploader': 'jaimeMF',
|
'uploader': 'jaimeMF',
|
||||||
'timestamp': 1386604920,
|
'timestamp': 1386604920,
|
||||||
'upload_date': '20131209',
|
'upload_date': '20131209',
|
||||||
'duration': 9,
|
'duration': 9.927,
|
||||||
'license': 'all-rights-reserved',
|
'license': 'all-rights-reserved',
|
||||||
'view_count': int,
|
'view_count': int,
|
||||||
'like_count': int,
|
'like_count': int,
|
||||||
@ -140,7 +145,7 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
'uploader': 'oddsamples',
|
'uploader': 'oddsamples',
|
||||||
'timestamp': 1389232924,
|
'timestamp': 1389232924,
|
||||||
'upload_date': '20140109',
|
'upload_date': '20140109',
|
||||||
'duration': 17,
|
'duration': 17.346,
|
||||||
'license': 'cc-by-sa',
|
'license': 'cc-by-sa',
|
||||||
'view_count': int,
|
'view_count': int,
|
||||||
'like_count': int,
|
'like_count': int,
|
||||||
@ -160,7 +165,7 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
'uploader': 'Ori Uplift Music',
|
'uploader': 'Ori Uplift Music',
|
||||||
'timestamp': 1504206263,
|
'timestamp': 1504206263,
|
||||||
'upload_date': '20170831',
|
'upload_date': '20170831',
|
||||||
'duration': 7449,
|
'duration': 7449.096,
|
||||||
'license': 'all-rights-reserved',
|
'license': 'all-rights-reserved',
|
||||||
'view_count': int,
|
'view_count': int,
|
||||||
'like_count': int,
|
'like_count': int,
|
||||||
@ -180,7 +185,7 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
'uploader': 'garyvee',
|
'uploader': 'garyvee',
|
||||||
'timestamp': 1488152409,
|
'timestamp': 1488152409,
|
||||||
'upload_date': '20170226',
|
'upload_date': '20170226',
|
||||||
'duration': 207,
|
'duration': 207.012,
|
||||||
'thumbnail': r're:https?://.*\.jpg',
|
'thumbnail': r're:https?://.*\.jpg',
|
||||||
'license': 'all-rights-reserved',
|
'license': 'all-rights-reserved',
|
||||||
'view_count': int,
|
'view_count': int,
|
||||||
@ -192,9 +197,31 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
'skip_download': True,
|
'skip_download': True,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
# not avaialble via api.soundcloud.com/i1/tracks/id/streams
|
||||||
|
{
|
||||||
|
'url': 'https://soundcloud.com/giovannisarani/mezzo-valzer',
|
||||||
|
'md5': 'e22aecd2bc88e0e4e432d7dcc0a1abf7',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '583011102',
|
||||||
|
'ext': 'mp3',
|
||||||
|
'title': 'Mezzo Valzer',
|
||||||
|
'description': 'md5:4138d582f81866a530317bae316e8b61',
|
||||||
|
'uploader': 'Giovanni Sarani',
|
||||||
|
'timestamp': 1551394171,
|
||||||
|
'upload_date': '20190228',
|
||||||
|
'duration': 180.157,
|
||||||
|
'thumbnail': r're:https?://.*\.jpg',
|
||||||
|
'license': 'all-rights-reserved',
|
||||||
|
'view_count': int,
|
||||||
|
'like_count': int,
|
||||||
|
'comment_count': int,
|
||||||
|
'repost_count': int,
|
||||||
|
},
|
||||||
|
'expected_warnings': ['Unable to download JSON metadata'],
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
_CLIENT_ID = 'NmW1FlPaiL94ueEu7oziOWjYEzZzQDcK'
|
_CLIENT_ID = 'FweeGBOOEOYJWLJN3oEyToGLKhmSz0I7'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extract_urls(webpage):
|
def _extract_urls(webpage):
|
||||||
@ -202,10 +229,6 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
r'<iframe[^>]+src=(["\'])(?P<url>(?:https?://)?(?:w\.)?soundcloud\.com/player.+?)\1',
|
r'<iframe[^>]+src=(["\'])(?P<url>(?:https?://)?(?:w\.)?soundcloud\.com/player.+?)\1',
|
||||||
webpage)]
|
webpage)]
|
||||||
|
|
||||||
def report_resolve(self, video_id):
|
|
||||||
"""Report information extraction."""
|
|
||||||
self.to_screen('%s: Resolving id' % video_id)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _resolv_url(cls, url):
|
def _resolv_url(cls, url):
|
||||||
return 'https://api.soundcloud.com/resolve.json?url=' + url + '&client_id=' + cls._CLIENT_ID
|
return 'https://api.soundcloud.com/resolve.json?url=' + url + '&client_id=' + cls._CLIENT_ID
|
||||||
@ -224,6 +247,10 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
def extract_count(key):
|
def extract_count(key):
|
||||||
return int_or_none(info.get('%s_count' % key))
|
return int_or_none(info.get('%s_count' % key))
|
||||||
|
|
||||||
|
like_count = extract_count('favoritings')
|
||||||
|
if like_count is None:
|
||||||
|
like_count = extract_count('likes')
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
'id': track_id,
|
'id': track_id,
|
||||||
'uploader': username,
|
'uploader': username,
|
||||||
@ -231,15 +258,17 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
'title': title,
|
'title': title,
|
||||||
'description': info.get('description'),
|
'description': info.get('description'),
|
||||||
'thumbnail': thumbnail,
|
'thumbnail': thumbnail,
|
||||||
'duration': int_or_none(info.get('duration'), 1000),
|
'duration': float_or_none(info.get('duration'), 1000),
|
||||||
'webpage_url': info.get('permalink_url'),
|
'webpage_url': info.get('permalink_url'),
|
||||||
'license': info.get('license'),
|
'license': info.get('license'),
|
||||||
'view_count': extract_count('playback'),
|
'view_count': extract_count('playback'),
|
||||||
'like_count': extract_count('favoritings'),
|
'like_count': like_count,
|
||||||
'comment_count': extract_count('comment'),
|
'comment_count': extract_count('comment'),
|
||||||
'repost_count': extract_count('reposts'),
|
'repost_count': extract_count('reposts'),
|
||||||
'genre': info.get('genre'),
|
'genre': info.get('genre'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
format_urls = set()
|
||||||
formats = []
|
formats = []
|
||||||
query = {'client_id': self._CLIENT_ID}
|
query = {'client_id': self._CLIENT_ID}
|
||||||
if secret_token is not None:
|
if secret_token is not None:
|
||||||
@ -248,6 +277,7 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
# We can build a direct link to the song
|
# We can build a direct link to the song
|
||||||
format_url = update_url_query(
|
format_url = update_url_query(
|
||||||
'https://api.soundcloud.com/tracks/%s/download' % track_id, query)
|
'https://api.soundcloud.com/tracks/%s/download' % track_id, query)
|
||||||
|
format_urls.add(format_url)
|
||||||
formats.append({
|
formats.append({
|
||||||
'format_id': 'download',
|
'format_id': 'download',
|
||||||
'ext': info.get('original_format', 'mp3'),
|
'ext': info.get('original_format', 'mp3'),
|
||||||
@ -256,44 +286,91 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
'preference': 10,
|
'preference': 10,
|
||||||
})
|
})
|
||||||
|
|
||||||
# We have to retrieve the url
|
# Old API, does not work for some tracks (e.g.
|
||||||
|
# https://soundcloud.com/giovannisarani/mezzo-valzer)
|
||||||
format_dict = self._download_json(
|
format_dict = self._download_json(
|
||||||
'https://api.soundcloud.com/i1/tracks/%s/streams' % track_id,
|
'https://api.soundcloud.com/i1/tracks/%s/streams' % track_id,
|
||||||
track_id, 'Downloading track url', query=query)
|
track_id, 'Downloading track url', query=query, fatal=False)
|
||||||
|
|
||||||
for key, stream_url in format_dict.items():
|
if format_dict:
|
||||||
ext, abr = 'mp3', None
|
for key, stream_url in format_dict.items():
|
||||||
mobj = re.search(r'_([^_]+)_(\d+)_url', key)
|
if stream_url in format_urls:
|
||||||
if mobj:
|
continue
|
||||||
ext, abr = mobj.groups()
|
format_urls.add(stream_url)
|
||||||
abr = int(abr)
|
ext, abr = 'mp3', None
|
||||||
if key.startswith('http'):
|
mobj = re.search(r'_([^_]+)_(\d+)_url', key)
|
||||||
stream_formats = [{
|
if mobj:
|
||||||
'format_id': key,
|
ext, abr = mobj.groups()
|
||||||
'ext': ext,
|
abr = int(abr)
|
||||||
'url': stream_url,
|
if key.startswith('http'):
|
||||||
}]
|
stream_formats = [{
|
||||||
elif key.startswith('rtmp'):
|
'format_id': key,
|
||||||
# The url doesn't have an rtmp app, we have to extract the playpath
|
'ext': ext,
|
||||||
url, path = stream_url.split('mp3:', 1)
|
'url': stream_url,
|
||||||
stream_formats = [{
|
}]
|
||||||
'format_id': key,
|
elif key.startswith('rtmp'):
|
||||||
'url': url,
|
# The url doesn't have an rtmp app, we have to extract the playpath
|
||||||
'play_path': 'mp3:' + path,
|
url, path = stream_url.split('mp3:', 1)
|
||||||
'ext': 'flv',
|
stream_formats = [{
|
||||||
}]
|
'format_id': key,
|
||||||
elif key.startswith('hls'):
|
'url': url,
|
||||||
stream_formats = self._extract_m3u8_formats(
|
'play_path': 'mp3:' + path,
|
||||||
stream_url, track_id, ext, entry_protocol='m3u8_native',
|
'ext': 'flv',
|
||||||
m3u8_id=key, fatal=False)
|
}]
|
||||||
else:
|
elif key.startswith('hls'):
|
||||||
|
stream_formats = self._extract_m3u8_formats(
|
||||||
|
stream_url, track_id, ext, entry_protocol='m3u8_native',
|
||||||
|
m3u8_id=key, fatal=False)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if abr:
|
||||||
|
for f in stream_formats:
|
||||||
|
f['abr'] = abr
|
||||||
|
|
||||||
|
formats.extend(stream_formats)
|
||||||
|
|
||||||
|
# New API
|
||||||
|
transcodings = try_get(
|
||||||
|
info, lambda x: x['media']['transcodings'], list) or []
|
||||||
|
for t in transcodings:
|
||||||
|
if not isinstance(t, dict):
|
||||||
continue
|
continue
|
||||||
|
format_url = url_or_none(t.get('url'))
|
||||||
if abr:
|
if not format_url:
|
||||||
for f in stream_formats:
|
continue
|
||||||
f['abr'] = abr
|
stream = self._download_json(
|
||||||
|
update_url_query(format_url, query), track_id, fatal=False)
|
||||||
formats.extend(stream_formats)
|
if not isinstance(stream, dict):
|
||||||
|
continue
|
||||||
|
stream_url = url_or_none(stream.get('url'))
|
||||||
|
if not stream_url:
|
||||||
|
continue
|
||||||
|
if stream_url in format_urls:
|
||||||
|
continue
|
||||||
|
format_urls.add(stream_url)
|
||||||
|
protocol = try_get(t, lambda x: x['format']['protocol'], compat_str)
|
||||||
|
if protocol != 'hls' and '/hls' in format_url:
|
||||||
|
protocol = 'hls'
|
||||||
|
ext = None
|
||||||
|
preset = str_or_none(t.get('preset'))
|
||||||
|
if preset:
|
||||||
|
ext = preset.split('_')[0]
|
||||||
|
if ext not in KNOWN_EXTENSIONS:
|
||||||
|
mimetype = try_get(
|
||||||
|
t, lambda x: x['format']['mime_type'], compat_str)
|
||||||
|
ext = mimetype2ext(mimetype) or 'mp3'
|
||||||
|
format_id_list = []
|
||||||
|
if protocol:
|
||||||
|
format_id_list.append(protocol)
|
||||||
|
format_id_list.append(ext)
|
||||||
|
format_id = '_'.join(format_id_list)
|
||||||
|
formats.append({
|
||||||
|
'url': stream_url,
|
||||||
|
'format_id': format_id,
|
||||||
|
'ext': ext,
|
||||||
|
'protocol': 'm3u8_native' if protocol == 'hls' else 'http',
|
||||||
|
})
|
||||||
|
|
||||||
if not formats:
|
if not formats:
|
||||||
# We fallback to the stream_url in the original info, this
|
# We fallback to the stream_url in the original info, this
|
||||||
@ -303,11 +380,11 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
'url': update_url_query(info['stream_url'], query),
|
'url': update_url_query(info['stream_url'], query),
|
||||||
'ext': 'mp3',
|
'ext': 'mp3',
|
||||||
})
|
})
|
||||||
|
self._check_formats(formats, track_id)
|
||||||
|
|
||||||
for f in formats:
|
for f in formats:
|
||||||
f['vcodec'] = 'none'
|
f['vcodec'] = 'none'
|
||||||
|
|
||||||
self._check_formats(formats, track_id)
|
|
||||||
self._sort_formats(formats)
|
self._sort_formats(formats)
|
||||||
result['formats'] = formats
|
result['formats'] = formats
|
||||||
|
|
||||||
@ -319,6 +396,7 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
raise ExtractorError('Invalid URL: %s' % url)
|
raise ExtractorError('Invalid URL: %s' % url)
|
||||||
|
|
||||||
track_id = mobj.group('track_id')
|
track_id = mobj.group('track_id')
|
||||||
|
new_info = {}
|
||||||
|
|
||||||
if track_id is not None:
|
if track_id is not None:
|
||||||
info_json_url = 'https://api.soundcloud.com/tracks/' + track_id + '.json?client_id=' + self._CLIENT_ID
|
info_json_url = 'https://api.soundcloud.com/tracks/' + track_id + '.json?client_id=' + self._CLIENT_ID
|
||||||
@ -344,13 +422,31 @@ class SoundcloudIE(InfoExtractor):
|
|||||||
if token:
|
if token:
|
||||||
resolve_title += '/%s' % token
|
resolve_title += '/%s' % token
|
||||||
|
|
||||||
self.report_resolve(full_title)
|
webpage = self._download_webpage(url, full_title, fatal=False)
|
||||||
|
if webpage:
|
||||||
|
entries = self._parse_json(
|
||||||
|
self._search_regex(
|
||||||
|
r'var\s+c\s*=\s*(\[.+?\])\s*,\s*o\s*=Date\b', webpage,
|
||||||
|
'data', default='[]'), full_title, fatal=False)
|
||||||
|
if entries:
|
||||||
|
for e in entries:
|
||||||
|
if not isinstance(e, dict):
|
||||||
|
continue
|
||||||
|
if e.get('id') != 67:
|
||||||
|
continue
|
||||||
|
data = try_get(e, lambda x: x['data'][0], dict)
|
||||||
|
if data:
|
||||||
|
new_info = data
|
||||||
|
break
|
||||||
|
info_json_url = self._resolv_url(
|
||||||
|
'https://soundcloud.com/%s' % resolve_title)
|
||||||
|
|
||||||
url = 'https://soundcloud.com/%s' % resolve_title
|
# Contains some additional info missing from new_info
|
||||||
info_json_url = self._resolv_url(url)
|
info = self._download_json(
|
||||||
info = self._download_json(info_json_url, full_title, 'Downloading info JSON')
|
info_json_url, full_title, 'Downloading info JSON')
|
||||||
|
|
||||||
return self._extract_info_dict(info, full_title, secret_token=token)
|
return self._extract_info_dict(
|
||||||
|
merge_dicts(info, new_info), full_title, secret_token=token)
|
||||||
|
|
||||||
|
|
||||||
class SoundcloudPlaylistBaseIE(SoundcloudIE):
|
class SoundcloudPlaylistBaseIE(SoundcloudIE):
|
||||||
@ -396,8 +492,6 @@ class SoundcloudSetIE(SoundcloudPlaylistBaseIE):
|
|||||||
full_title += '/' + token
|
full_title += '/' + token
|
||||||
url += '/' + token
|
url += '/' + token
|
||||||
|
|
||||||
self.report_resolve(full_title)
|
|
||||||
|
|
||||||
resolv_url = self._resolv_url(url)
|
resolv_url = self._resolv_url(url)
|
||||||
info = self._download_json(resolv_url, full_title)
|
info = self._download_json(resolv_url, full_title)
|
||||||
|
|
||||||
|
115
youtube_dl/extractor/sverigesradio.py
Normal file
115
youtube_dl/extractor/sverigesradio.py
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import (
|
||||||
|
determine_ext,
|
||||||
|
int_or_none,
|
||||||
|
str_or_none,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SverigesRadioBaseIE(InfoExtractor):
|
||||||
|
_BASE_URL = 'https://sverigesradio.se/sida/playerajax/'
|
||||||
|
_QUALITIES = ['low', 'medium', 'high']
|
||||||
|
_EXT_TO_CODEC_MAP = {
|
||||||
|
'mp3': 'mp3',
|
||||||
|
'm4a': 'aac',
|
||||||
|
}
|
||||||
|
_CODING_FORMAT_TO_ABR_MAP = {
|
||||||
|
5: 128,
|
||||||
|
11: 192,
|
||||||
|
12: 32,
|
||||||
|
13: 96,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
audio_id = self._match_id(url)
|
||||||
|
query = {
|
||||||
|
'id': audio_id,
|
||||||
|
'type': self._AUDIO_TYPE,
|
||||||
|
}
|
||||||
|
|
||||||
|
item = self._download_json(
|
||||||
|
self._BASE_URL + 'audiometadata', audio_id,
|
||||||
|
'Downloading audio JSON metadata', query=query)['items'][0]
|
||||||
|
title = item['subtitle']
|
||||||
|
|
||||||
|
query['format'] = 'iis'
|
||||||
|
urls = []
|
||||||
|
formats = []
|
||||||
|
for quality in self._QUALITIES:
|
||||||
|
query['quality'] = quality
|
||||||
|
audio_url_data = self._download_json(
|
||||||
|
self._BASE_URL + 'getaudiourl', audio_id,
|
||||||
|
'Downloading %s format JSON metadata' % quality,
|
||||||
|
fatal=False, query=query) or {}
|
||||||
|
audio_url = audio_url_data.get('audioUrl')
|
||||||
|
if not audio_url or audio_url in urls:
|
||||||
|
continue
|
||||||
|
urls.append(audio_url)
|
||||||
|
ext = determine_ext(audio_url)
|
||||||
|
coding_format = audio_url_data.get('codingFormat')
|
||||||
|
abr = int_or_none(self._search_regex(
|
||||||
|
r'_a(\d+)\.m4a', audio_url, 'audio bitrate',
|
||||||
|
default=None)) or self._CODING_FORMAT_TO_ABR_MAP.get(coding_format)
|
||||||
|
formats.append({
|
||||||
|
'abr': abr,
|
||||||
|
'acodec': self._EXT_TO_CODEC_MAP.get(ext),
|
||||||
|
'ext': ext,
|
||||||
|
'format_id': str_or_none(coding_format),
|
||||||
|
'vcodec': 'none',
|
||||||
|
'url': audio_url,
|
||||||
|
})
|
||||||
|
self._sort_formats(formats)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'id': audio_id,
|
||||||
|
'title': title,
|
||||||
|
'formats': formats,
|
||||||
|
'series': item.get('title'),
|
||||||
|
'duration': int_or_none(item.get('duration')),
|
||||||
|
'thumbnail': item.get('displayimageurl'),
|
||||||
|
'description': item.get('description'),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class SverigesRadioPublicationIE(SverigesRadioBaseIE):
|
||||||
|
IE_NAME = 'sverigesradio:publication'
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?sverigesradio\.se/sida/(?:artikel|gruppsida)\.aspx\?.*?\bartikel=(?P<id>[0-9]+)'
|
||||||
|
_TESTS = [{
|
||||||
|
'url': 'https://sverigesradio.se/sida/artikel.aspx?programid=83&artikel=7038546',
|
||||||
|
'md5': '6a4917e1923fccb080e5a206a5afa542',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '7038546',
|
||||||
|
'ext': 'm4a',
|
||||||
|
'duration': 132,
|
||||||
|
'series': 'Nyheter (Ekot)',
|
||||||
|
'title': 'Esa Teittinen: Sanningen har inte kommit fram',
|
||||||
|
'description': 'md5:daf7ce66a8f0a53d5465a5984d3839df',
|
||||||
|
'thumbnail': r're:^https?://.*\.jpg',
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
'url': 'https://sverigesradio.se/sida/gruppsida.aspx?programid=3304&grupp=6247&artikel=7146887',
|
||||||
|
'only_matching': True,
|
||||||
|
}]
|
||||||
|
_AUDIO_TYPE = 'publication'
|
||||||
|
|
||||||
|
|
||||||
|
class SverigesRadioEpisodeIE(SverigesRadioBaseIE):
|
||||||
|
IE_NAME = 'sverigesradio:episode'
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?sverigesradio\.se/(?:sida/)?avsnitt/(?P<id>[0-9]+)'
|
||||||
|
_TEST = {
|
||||||
|
'url': 'https://sverigesradio.se/avsnitt/1140922?programid=1300',
|
||||||
|
'md5': '20dc4d8db24228f846be390b0c59a07c',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '1140922',
|
||||||
|
'ext': 'mp3',
|
||||||
|
'duration': 3307,
|
||||||
|
'series': 'Konflikt',
|
||||||
|
'title': 'Metoo och valen',
|
||||||
|
'description': 'md5:fcb5c1f667f00badcc702b196f10a27e',
|
||||||
|
'thumbnail': r're:^https?://.*\.jpg',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_AUDIO_TYPE = 'episode'
|
@ -66,7 +66,12 @@ class TouTvIE(RadioCanadaIE):
|
|||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
path = self._match_id(url)
|
path = self._match_id(url)
|
||||||
metadata = self._download_json('http://ici.tou.tv/presentation/%s' % path, path)
|
metadata = self._download_json(
|
||||||
|
'https://services.radio-canada.ca/toutv/presentation/%s' % path, path, query={
|
||||||
|
'client_key': self._CLIENT_KEY,
|
||||||
|
'device': 'web',
|
||||||
|
'version': 4,
|
||||||
|
})
|
||||||
# IsDrm does not necessarily mean the video is DRM protected (see
|
# IsDrm does not necessarily mean the video is DRM protected (see
|
||||||
# https://github.com/ytdl-org/youtube-dl/issues/13994).
|
# https://github.com/ytdl-org/youtube-dl/issues/13994).
|
||||||
if metadata.get('IsDrm'):
|
if metadata.get('IsDrm'):
|
||||||
@ -77,6 +82,12 @@ class TouTvIE(RadioCanadaIE):
|
|||||||
return merge_dicts({
|
return merge_dicts({
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
'title': details.get('OriginalTitle'),
|
'title': details.get('OriginalTitle'),
|
||||||
|
'description': details.get('Description'),
|
||||||
'thumbnail': details.get('ImageUrl'),
|
'thumbnail': details.get('ImageUrl'),
|
||||||
'duration': int_or_none(details.get('LengthInSeconds')),
|
'duration': int_or_none(details.get('LengthInSeconds')),
|
||||||
|
'series': metadata.get('ProgramTitle'),
|
||||||
|
'season_number': int_or_none(metadata.get('SeasonNumber')),
|
||||||
|
'season': metadata.get('SeasonTitle'),
|
||||||
|
'episode_number': int_or_none(metadata.get('EpisodeNumber')),
|
||||||
|
'episode': metadata.get('EpisodeTitle'),
|
||||||
}, self._extract_info(metadata.get('AppCode', 'toutv'), video_id))
|
}, self._extract_info(metadata.get('AppCode', 'toutv'), video_id))
|
||||||
|
@ -2,19 +2,20 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
|
from ..utils import urlencode_postdata
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
class TwitCastingIE(InfoExtractor):
|
class TwitCastingIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://(?:[^/]+\.)?twitcasting\.tv/(?P<uploader_id>[^/]+)/movie/(?P<id>\d+)'
|
_VALID_URL = r'https?://(?:[^/]+\.)?twitcasting\.tv/(?P<uploader_id>[^/]+)/movie/(?P<id>\d+)'
|
||||||
_TEST = {
|
_TESTS = [{
|
||||||
'url': 'https://twitcasting.tv/ivetesangalo/movie/2357609',
|
'url': 'https://twitcasting.tv/ivetesangalo/movie/2357609',
|
||||||
'md5': '745243cad58c4681dc752490f7540d7f',
|
'md5': '745243cad58c4681dc752490f7540d7f',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': '2357609',
|
'id': '2357609',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'title': 'Recorded Live #2357609',
|
'title': 'Live #2357609',
|
||||||
'uploader_id': 'ivetesangalo',
|
'uploader_id': 'ivetesangalo',
|
||||||
'description': "Moi! I'm live on TwitCasting from my iPhone.",
|
'description': "Moi! I'm live on TwitCasting from my iPhone.",
|
||||||
'thumbnail': r're:^https?://.*\.jpg$',
|
'thumbnail': r're:^https?://.*\.jpg$',
|
||||||
@ -22,14 +23,34 @@ class TwitCastingIE(InfoExtractor):
|
|||||||
'params': {
|
'params': {
|
||||||
'skip_download': True,
|
'skip_download': True,
|
||||||
},
|
},
|
||||||
}
|
}, {
|
||||||
|
'url': 'https://twitcasting.tv/mttbernardini/movie/3689740',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '3689740',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Live playing something #3689740',
|
||||||
|
'uploader_id': 'mttbernardini',
|
||||||
|
'description': "I'm live on TwitCasting from my iPad. password: abc (Santa Marinella/Lazio, Italia)",
|
||||||
|
'thumbnail': r're:^https?://.*\.jpg$',
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
'skip_download': True,
|
||||||
|
'videopassword': 'abc',
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
mobj = re.match(self._VALID_URL, url)
|
||||||
video_id = mobj.group('id')
|
video_id = mobj.group('id')
|
||||||
uploader_id = mobj.group('uploader_id')
|
uploader_id = mobj.group('uploader_id')
|
||||||
|
|
||||||
webpage = self._download_webpage(url, video_id)
|
video_password = self._downloader.params.get('videopassword')
|
||||||
|
request_data = None
|
||||||
|
if video_password:
|
||||||
|
request_data = urlencode_postdata({
|
||||||
|
'password': video_password,
|
||||||
|
})
|
||||||
|
webpage = self._download_webpage(url, video_id, data=request_data)
|
||||||
|
|
||||||
title = self._html_search_regex(
|
title = self._html_search_regex(
|
||||||
r'(?s)<[^>]+id=["\']movietitle[^>]+>(.+?)</',
|
r'(?s)<[^>]+id=["\']movietitle[^>]+>(.+?)</',
|
||||||
|
@ -134,12 +134,12 @@ class TwitchBaseIE(InfoExtractor):
|
|||||||
def _prefer_source(self, formats):
|
def _prefer_source(self, formats):
|
||||||
try:
|
try:
|
||||||
source = next(f for f in formats if f['format_id'] == 'Source')
|
source = next(f for f in formats if f['format_id'] == 'Source')
|
||||||
source['preference'] = 10
|
source['quality'] = 10
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
for f in formats:
|
for f in formats:
|
||||||
if '/chunked/' in f['url']:
|
if '/chunked/' in f['url']:
|
||||||
f.update({
|
f.update({
|
||||||
'source_preference': 10,
|
'quality': 10,
|
||||||
'format_note': 'Source',
|
'format_note': 'Source',
|
||||||
})
|
})
|
||||||
self._sort_formats(formats)
|
self._sort_formats(formats)
|
||||||
|
@ -76,7 +76,10 @@ class UdemyIE(InfoExtractor):
|
|||||||
webpage, 'course', default='{}')),
|
webpage, 'course', default='{}')),
|
||||||
video_id, fatal=False) or {}
|
video_id, fatal=False) or {}
|
||||||
course_id = course.get('id') or self._search_regex(
|
course_id = course.get('id') or self._search_regex(
|
||||||
r'data-course-id=["\'](\d+)', webpage, 'course id')
|
[
|
||||||
|
r'data-course-id=["\'](\d+)',
|
||||||
|
r'"courseId"\s*:\s*(\d+)'
|
||||||
|
], webpage, 'course id')
|
||||||
return course_id, course.get('title')
|
return course_id, course.get('title')
|
||||||
|
|
||||||
def _enroll_course(self, base_url, webpage, course_id):
|
def _enroll_course(self, base_url, webpage, course_id):
|
||||||
|
@ -109,23 +109,9 @@ class VimeoBaseInfoExtractor(InfoExtractor):
|
|||||||
|
|
||||||
def _parse_config(self, config, video_id):
|
def _parse_config(self, config, video_id):
|
||||||
video_data = config['video']
|
video_data = config['video']
|
||||||
# Extract title
|
|
||||||
video_title = video_data['title']
|
video_title = video_data['title']
|
||||||
|
live_event = video_data.get('live_event') or {}
|
||||||
# Extract uploader, uploader_url and uploader_id
|
is_live = live_event.get('status') == 'started'
|
||||||
video_uploader = video_data.get('owner', {}).get('name')
|
|
||||||
video_uploader_url = video_data.get('owner', {}).get('url')
|
|
||||||
video_uploader_id = video_uploader_url.split('/')[-1] if video_uploader_url else None
|
|
||||||
|
|
||||||
# Extract video thumbnail
|
|
||||||
video_thumbnail = video_data.get('thumbnail')
|
|
||||||
if video_thumbnail is None:
|
|
||||||
video_thumbs = video_data.get('thumbs')
|
|
||||||
if video_thumbs and isinstance(video_thumbs, dict):
|
|
||||||
_, video_thumbnail = sorted((int(width if width.isdigit() else 0), t_url) for (width, t_url) in video_thumbs.items())[-1]
|
|
||||||
|
|
||||||
# Extract video duration
|
|
||||||
video_duration = int_or_none(video_data.get('duration'))
|
|
||||||
|
|
||||||
formats = []
|
formats = []
|
||||||
config_files = video_data.get('files') or config['request'].get('files', {})
|
config_files = video_data.get('files') or config['request'].get('files', {})
|
||||||
@ -142,6 +128,7 @@ class VimeoBaseInfoExtractor(InfoExtractor):
|
|||||||
'tbr': int_or_none(f.get('bitrate')),
|
'tbr': int_or_none(f.get('bitrate')),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# TODO: fix handling of 308 status code returned for live archive manifest requests
|
||||||
for files_type in ('hls', 'dash'):
|
for files_type in ('hls', 'dash'):
|
||||||
for cdn_name, cdn_data in config_files.get(files_type, {}).get('cdns', {}).items():
|
for cdn_name, cdn_data in config_files.get(files_type, {}).get('cdns', {}).items():
|
||||||
manifest_url = cdn_data.get('url')
|
manifest_url = cdn_data.get('url')
|
||||||
@ -151,7 +138,7 @@ class VimeoBaseInfoExtractor(InfoExtractor):
|
|||||||
if files_type == 'hls':
|
if files_type == 'hls':
|
||||||
formats.extend(self._extract_m3u8_formats(
|
formats.extend(self._extract_m3u8_formats(
|
||||||
manifest_url, video_id, 'mp4',
|
manifest_url, video_id, 'mp4',
|
||||||
'm3u8_native', m3u8_id=format_id,
|
'm3u8' if is_live else 'm3u8_native', m3u8_id=format_id,
|
||||||
note='Downloading %s m3u8 information' % cdn_name,
|
note='Downloading %s m3u8 information' % cdn_name,
|
||||||
fatal=False))
|
fatal=False))
|
||||||
elif files_type == 'dash':
|
elif files_type == 'dash':
|
||||||
@ -164,6 +151,10 @@ class VimeoBaseInfoExtractor(InfoExtractor):
|
|||||||
else:
|
else:
|
||||||
mpd_manifest_urls = [(format_id, manifest_url)]
|
mpd_manifest_urls = [(format_id, manifest_url)]
|
||||||
for f_id, m_url in mpd_manifest_urls:
|
for f_id, m_url in mpd_manifest_urls:
|
||||||
|
if 'json=1' in m_url:
|
||||||
|
real_m_url = (self._download_json(m_url, video_id, fatal=False) or {}).get('url')
|
||||||
|
if real_m_url:
|
||||||
|
m_url = real_m_url
|
||||||
mpd_formats = self._extract_mpd_formats(
|
mpd_formats = self._extract_mpd_formats(
|
||||||
m_url.replace('/master.json', '/master.mpd'), video_id, f_id,
|
m_url.replace('/master.json', '/master.mpd'), video_id, f_id,
|
||||||
'Downloading %s MPD information' % cdn_name,
|
'Downloading %s MPD information' % cdn_name,
|
||||||
@ -175,6 +166,15 @@ class VimeoBaseInfoExtractor(InfoExtractor):
|
|||||||
f['preference'] = -40
|
f['preference'] = -40
|
||||||
formats.extend(mpd_formats)
|
formats.extend(mpd_formats)
|
||||||
|
|
||||||
|
live_archive = live_event.get('archive') or {}
|
||||||
|
live_archive_source_url = live_archive.get('source_url')
|
||||||
|
if live_archive_source_url and live_archive.get('status') == 'done':
|
||||||
|
formats.append({
|
||||||
|
'format_id': 'live-archive-source',
|
||||||
|
'url': live_archive_source_url,
|
||||||
|
'preference': 1,
|
||||||
|
})
|
||||||
|
|
||||||
subtitles = {}
|
subtitles = {}
|
||||||
text_tracks = config['request'].get('text_tracks')
|
text_tracks = config['request'].get('text_tracks')
|
||||||
if text_tracks:
|
if text_tracks:
|
||||||
@ -184,15 +184,33 @@ class VimeoBaseInfoExtractor(InfoExtractor):
|
|||||||
'url': 'https://vimeo.com' + tt['url'],
|
'url': 'https://vimeo.com' + tt['url'],
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
thumbnails = []
|
||||||
|
if not is_live:
|
||||||
|
for key, thumb in video_data.get('thumbs', {}).items():
|
||||||
|
thumbnails.append({
|
||||||
|
'id': key,
|
||||||
|
'width': int_or_none(key),
|
||||||
|
'url': thumb,
|
||||||
|
})
|
||||||
|
thumbnail = video_data.get('thumbnail')
|
||||||
|
if thumbnail:
|
||||||
|
thumbnails.append({
|
||||||
|
'url': thumbnail,
|
||||||
|
})
|
||||||
|
|
||||||
|
owner = video_data.get('owner') or {}
|
||||||
|
video_uploader_url = owner.get('url')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'title': video_title,
|
'title': self._live_title(video_title) if is_live else video_title,
|
||||||
'uploader': video_uploader,
|
'uploader': owner.get('name'),
|
||||||
'uploader_id': video_uploader_id,
|
'uploader_id': video_uploader_url.split('/')[-1] if video_uploader_url else None,
|
||||||
'uploader_url': video_uploader_url,
|
'uploader_url': video_uploader_url,
|
||||||
'thumbnail': video_thumbnail,
|
'thumbnails': thumbnails,
|
||||||
'duration': video_duration,
|
'duration': int_or_none(video_data.get('duration')),
|
||||||
'formats': formats,
|
'formats': formats,
|
||||||
'subtitles': subtitles,
|
'subtitles': subtitles,
|
||||||
|
'is_live': is_live,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _extract_original_format(self, url, video_id):
|
def _extract_original_format(self, url, video_id):
|
||||||
|
@ -102,6 +102,15 @@ class VRVIE(VRVBaseIE):
|
|||||||
# m3u8 download
|
# m3u8 download
|
||||||
'skip_download': True,
|
'skip_download': True,
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
# movie listing
|
||||||
|
'url': 'https://vrv.co/watch/G6NQXZ1J6/Lily-CAT',
|
||||||
|
'info_dict': {
|
||||||
|
'id': 'G6NQXZ1J6',
|
||||||
|
'title': 'Lily C.A.T',
|
||||||
|
'description': 'md5:988b031e7809a6aeb60968be4af7db07',
|
||||||
|
},
|
||||||
|
'playlist_count': 2,
|
||||||
}]
|
}]
|
||||||
_NETRC_MACHINE = 'vrv'
|
_NETRC_MACHINE = 'vrv'
|
||||||
|
|
||||||
@ -123,23 +132,23 @@ class VRVIE(VRVBaseIE):
|
|||||||
def _extract_vrv_formats(self, url, video_id, stream_format, audio_lang, hardsub_lang):
|
def _extract_vrv_formats(self, url, video_id, stream_format, audio_lang, hardsub_lang):
|
||||||
if not url or stream_format not in ('hls', 'dash'):
|
if not url or stream_format not in ('hls', 'dash'):
|
||||||
return []
|
return []
|
||||||
assert audio_lang or hardsub_lang
|
|
||||||
stream_id_list = []
|
stream_id_list = []
|
||||||
if audio_lang:
|
if audio_lang:
|
||||||
stream_id_list.append('audio-%s' % audio_lang)
|
stream_id_list.append('audio-%s' % audio_lang)
|
||||||
if hardsub_lang:
|
if hardsub_lang:
|
||||||
stream_id_list.append('hardsub-%s' % hardsub_lang)
|
stream_id_list.append('hardsub-%s' % hardsub_lang)
|
||||||
stream_id = '-'.join(stream_id_list)
|
format_id = stream_format
|
||||||
format_id = '%s-%s' % (stream_format, stream_id)
|
if stream_id_list:
|
||||||
|
format_id += '-' + '-'.join(stream_id_list)
|
||||||
if stream_format == 'hls':
|
if stream_format == 'hls':
|
||||||
adaptive_formats = self._extract_m3u8_formats(
|
adaptive_formats = self._extract_m3u8_formats(
|
||||||
url, video_id, 'mp4', m3u8_id=format_id,
|
url, video_id, 'mp4', m3u8_id=format_id,
|
||||||
note='Downloading %s m3u8 information' % stream_id,
|
note='Downloading %s information' % format_id,
|
||||||
fatal=False)
|
fatal=False)
|
||||||
elif stream_format == 'dash':
|
elif stream_format == 'dash':
|
||||||
adaptive_formats = self._extract_mpd_formats(
|
adaptive_formats = self._extract_mpd_formats(
|
||||||
url, video_id, mpd_id=format_id,
|
url, video_id, mpd_id=format_id,
|
||||||
note='Downloading %s MPD information' % stream_id,
|
note='Downloading %s information' % format_id,
|
||||||
fatal=False)
|
fatal=False)
|
||||||
if audio_lang:
|
if audio_lang:
|
||||||
for f in adaptive_formats:
|
for f in adaptive_formats:
|
||||||
@ -155,6 +164,23 @@ class VRVIE(VRVBaseIE):
|
|||||||
resource_path = object_data['__links__']['resource']['href']
|
resource_path = object_data['__links__']['resource']['href']
|
||||||
video_data = self._call_cms(resource_path, video_id, 'video')
|
video_data = self._call_cms(resource_path, video_id, 'video')
|
||||||
title = video_data['title']
|
title = video_data['title']
|
||||||
|
description = video_data.get('description')
|
||||||
|
|
||||||
|
if video_data.get('__class__') == 'movie_listing':
|
||||||
|
items = self._call_cms(
|
||||||
|
video_data['__links__']['movie_listing/movies']['href'],
|
||||||
|
video_id, 'movie listing').get('items') or []
|
||||||
|
if len(items) != 1:
|
||||||
|
entries = []
|
||||||
|
for item in items:
|
||||||
|
item_id = item.get('id')
|
||||||
|
if not item_id:
|
||||||
|
continue
|
||||||
|
entries.append(self.url_result(
|
||||||
|
'https://vrv.co/watch/' + item_id,
|
||||||
|
self.ie_key(), item_id, item.get('title')))
|
||||||
|
return self.playlist_result(entries, video_id, title, description)
|
||||||
|
video_data = items[0]
|
||||||
|
|
||||||
streams_path = video_data['__links__'].get('streams', {}).get('href')
|
streams_path = video_data['__links__'].get('streams', {}).get('href')
|
||||||
if not streams_path:
|
if not streams_path:
|
||||||
@ -198,7 +224,7 @@ class VRVIE(VRVBaseIE):
|
|||||||
'formats': formats,
|
'formats': formats,
|
||||||
'subtitles': subtitles,
|
'subtitles': subtitles,
|
||||||
'thumbnails': thumbnails,
|
'thumbnails': thumbnails,
|
||||||
'description': video_data.get('description'),
|
'description': description,
|
||||||
'duration': float_or_none(video_data.get('duration_ms'), 1000),
|
'duration': float_or_none(video_data.get('duration_ms'), 1000),
|
||||||
'uploader_id': video_data.get('channel_id'),
|
'uploader_id': video_data.get('channel_id'),
|
||||||
'series': video_data.get('series_title'),
|
'series': video_data.get('series_title'),
|
||||||
|
@ -1,158 +0,0 @@
|
|||||||
# coding: utf-8
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
from .common import InfoExtractor
|
|
||||||
from ..utils import (
|
|
||||||
ExtractorError,
|
|
||||||
int_or_none,
|
|
||||||
qualities,
|
|
||||||
remove_start,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class WrzutaIE(InfoExtractor):
|
|
||||||
IE_NAME = 'wrzuta.pl'
|
|
||||||
|
|
||||||
_VALID_URL = r'https?://(?P<uploader>[0-9a-zA-Z]+)\.wrzuta\.pl/(?P<typ>film|audio)/(?P<id>[0-9a-zA-Z]+)'
|
|
||||||
|
|
||||||
_TESTS = [{
|
|
||||||
'url': 'http://laboratoriumdextera.wrzuta.pl/film/aq4hIZWrkBu/nike_football_the_last_game',
|
|
||||||
'md5': '9e67e05bed7c03b82488d87233a9efe7',
|
|
||||||
'info_dict': {
|
|
||||||
'id': 'aq4hIZWrkBu',
|
|
||||||
'ext': 'mp4',
|
|
||||||
'title': 'Nike Football: The Last Game',
|
|
||||||
'duration': 307,
|
|
||||||
'uploader_id': 'laboratoriumdextera',
|
|
||||||
'description': 'md5:7fb5ef3c21c5893375fda51d9b15d9cd',
|
|
||||||
},
|
|
||||||
'skip': 'Redirected to wrzuta.pl',
|
|
||||||
}, {
|
|
||||||
'url': 'http://vexling.wrzuta.pl/audio/01xBFabGXu6/james_horner_-_into_the_na_39_vi_world_bonus',
|
|
||||||
'md5': 'f80564fb5a2ec6ec59705ae2bf2ba56d',
|
|
||||||
'info_dict': {
|
|
||||||
'id': '01xBFabGXu6',
|
|
||||||
'ext': 'mp3',
|
|
||||||
'title': 'James Horner - Into The Na\'vi World [Bonus]',
|
|
||||||
'description': 'md5:30a70718b2cd9df3120fce4445b0263b',
|
|
||||||
'duration': 95,
|
|
||||||
'uploader_id': 'vexling',
|
|
||||||
},
|
|
||||||
}]
|
|
||||||
|
|
||||||
def _real_extract(self, url):
|
|
||||||
mobj = re.match(self._VALID_URL, url)
|
|
||||||
video_id = mobj.group('id')
|
|
||||||
typ = mobj.group('typ')
|
|
||||||
uploader = mobj.group('uploader')
|
|
||||||
|
|
||||||
webpage, urlh = self._download_webpage_handle(url, video_id)
|
|
||||||
|
|
||||||
if urlh.geturl() == 'http://www.wrzuta.pl/':
|
|
||||||
raise ExtractorError('Video removed', expected=True)
|
|
||||||
|
|
||||||
quality = qualities(['SD', 'MQ', 'HQ', 'HD'])
|
|
||||||
|
|
||||||
audio_table = {'flv': 'mp3', 'webm': 'ogg', '???': 'mp3'}
|
|
||||||
|
|
||||||
embedpage = self._download_json('http://www.wrzuta.pl/npp/embed/%s/%s' % (uploader, video_id), video_id)
|
|
||||||
|
|
||||||
formats = []
|
|
||||||
for media in embedpage['url']:
|
|
||||||
fmt = media['type'].split('@')[0]
|
|
||||||
if typ == 'audio':
|
|
||||||
ext = audio_table.get(fmt, fmt)
|
|
||||||
else:
|
|
||||||
ext = fmt
|
|
||||||
|
|
||||||
formats.append({
|
|
||||||
'format_id': '%s_%s' % (ext, media['quality'].lower()),
|
|
||||||
'url': media['url'],
|
|
||||||
'ext': ext,
|
|
||||||
'quality': quality(media['quality']),
|
|
||||||
})
|
|
||||||
|
|
||||||
self._sort_formats(formats)
|
|
||||||
|
|
||||||
return {
|
|
||||||
'id': video_id,
|
|
||||||
'title': self._og_search_title(webpage),
|
|
||||||
'thumbnail': self._og_search_thumbnail(webpage),
|
|
||||||
'formats': formats,
|
|
||||||
'duration': int_or_none(embedpage['duration']),
|
|
||||||
'uploader_id': uploader,
|
|
||||||
'description': self._og_search_description(webpage),
|
|
||||||
'age_limit': embedpage.get('minimalAge', 0),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class WrzutaPlaylistIE(InfoExtractor):
|
|
||||||
"""
|
|
||||||
this class covers extraction of wrzuta playlist entries
|
|
||||||
the extraction process bases on following steps:
|
|
||||||
* collect information of playlist size
|
|
||||||
* download all entries provided on
|
|
||||||
the playlist webpage (the playlist is split
|
|
||||||
on two pages: first directly reached from webpage
|
|
||||||
second: downloaded on demand by ajax call and rendered
|
|
||||||
using the ajax call response)
|
|
||||||
* in case size of extracted entries not reached total number of entries
|
|
||||||
use the ajax call to collect the remaining entries
|
|
||||||
"""
|
|
||||||
|
|
||||||
IE_NAME = 'wrzuta.pl:playlist'
|
|
||||||
_VALID_URL = r'https?://(?P<uploader>[0-9a-zA-Z]+)\.wrzuta\.pl/playlista/(?P<id>[0-9a-zA-Z]+)'
|
|
||||||
_TESTS = [{
|
|
||||||
'url': 'http://miromak71.wrzuta.pl/playlista/7XfO4vE84iR/moja_muza',
|
|
||||||
'playlist_mincount': 14,
|
|
||||||
'info_dict': {
|
|
||||||
'id': '7XfO4vE84iR',
|
|
||||||
'title': 'Moja muza',
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
'url': 'http://heroesf70.wrzuta.pl/playlista/6Nj3wQHx756/lipiec_-_lato_2015_muzyka_swiata',
|
|
||||||
'playlist_mincount': 144,
|
|
||||||
'info_dict': {
|
|
||||||
'id': '6Nj3wQHx756',
|
|
||||||
'title': 'Lipiec - Lato 2015 Muzyka Świata',
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
'url': 'http://miromak71.wrzuta.pl/playlista/7XfO4vE84iR',
|
|
||||||
'only_matching': True,
|
|
||||||
}]
|
|
||||||
|
|
||||||
def _real_extract(self, url):
|
|
||||||
mobj = re.match(self._VALID_URL, url)
|
|
||||||
playlist_id = mobj.group('id')
|
|
||||||
uploader = mobj.group('uploader')
|
|
||||||
|
|
||||||
webpage = self._download_webpage(url, playlist_id)
|
|
||||||
|
|
||||||
playlist_size = int_or_none(self._html_search_regex(
|
|
||||||
(r'<div[^>]+class=["\']playlist-counter["\'][^>]*>\d+/(\d+)',
|
|
||||||
r'<div[^>]+class=["\']all-counter["\'][^>]*>(.+?)</div>'),
|
|
||||||
webpage, 'playlist size', default=None))
|
|
||||||
|
|
||||||
playlist_title = remove_start(
|
|
||||||
self._og_search_title(webpage), 'Playlista: ')
|
|
||||||
|
|
||||||
entries = []
|
|
||||||
if playlist_size:
|
|
||||||
entries = [
|
|
||||||
self.url_result(entry_url)
|
|
||||||
for _, entry_url in re.findall(
|
|
||||||
r'<a[^>]+href=(["\'])(http.+?)\1[^>]+class=["\']playlist-file-page',
|
|
||||||
webpage)]
|
|
||||||
if playlist_size > len(entries):
|
|
||||||
playlist_content = self._download_json(
|
|
||||||
'http://%s.wrzuta.pl/xhr/get_playlist_offset/%s' % (uploader, playlist_id),
|
|
||||||
playlist_id,
|
|
||||||
'Downloading playlist JSON',
|
|
||||||
'Unable to download playlist JSON')
|
|
||||||
entries.extend([
|
|
||||||
self.url_result(entry['filelink'])
|
|
||||||
for entry in playlist_content.get('files', []) if entry.get('filelink')])
|
|
||||||
|
|
||||||
return self.playlist_result(entries, playlist_id, playlist_title)
|
|
@ -69,25 +69,28 @@ class YandexMusicTrackIE(YandexMusicBaseIE):
|
|||||||
'skip': 'Travis CI servers blocked by YandexMusic',
|
'skip': 'Travis CI servers blocked by YandexMusic',
|
||||||
}
|
}
|
||||||
|
|
||||||
def _get_track_url(self, storage_dir, track_id):
|
def _real_extract(self, url):
|
||||||
data = self._download_json(
|
mobj = re.match(self._VALID_URL, url)
|
||||||
'http://music.yandex.ru/api/v1.5/handlers/api-jsonp.jsx?action=getTrackSrc&p=download-info/%s'
|
album_id, track_id = mobj.group('album_id'), mobj.group('id')
|
||||||
% storage_dir,
|
|
||||||
track_id, 'Downloading track location JSON')
|
|
||||||
|
|
||||||
# Each string is now wrapped in a list, this is probably only temporarily thus
|
track = self._download_json(
|
||||||
# supporting both scenarios (see https://github.com/ytdl-org/youtube-dl/issues/10193)
|
'http://music.yandex.ru/handlers/track.jsx?track=%s:%s' % (track_id, album_id),
|
||||||
for k, v in data.items():
|
track_id, 'Downloading track JSON')['track']
|
||||||
if v and isinstance(v, list):
|
track_title = track['title']
|
||||||
data[k] = v[0]
|
|
||||||
|
|
||||||
key = hashlib.md5(('XGRlBW9FXlekgbPrRHuSiA' + data['path'][1:] + data['s']).encode('utf-8')).hexdigest()
|
download_data = self._download_json(
|
||||||
storage = storage_dir.split('.')
|
'https://music.yandex.ru/api/v2.1/handlers/track/%s:%s/web-album_track-track-track-main/download/m' % (track_id, album_id),
|
||||||
|
track_id, 'Downloading track location url JSON',
|
||||||
|
headers={'X-Retpath-Y': url})
|
||||||
|
|
||||||
return ('http://%s/get-mp3/%s/%s?track-id=%s&from=service-10-track&similarities-experiment=default'
|
fd_data = self._download_json(
|
||||||
% (data['host'], key, data['ts'] + data['path'], storage[1]))
|
download_data['src'], track_id,
|
||||||
|
'Downloading track location JSON',
|
||||||
|
query={'format': 'json'})
|
||||||
|
key = hashlib.md5(('XGRlBW9FXlekgbPrRHuSiA' + fd_data['path'][1:] + fd_data['s']).encode('utf-8')).hexdigest()
|
||||||
|
storage = track['storageDir'].split('.')
|
||||||
|
f_url = 'http://%s/get-mp3/%s/%s?track-id=%s ' % (fd_data['host'], key, fd_data['ts'] + fd_data['path'], storage[1])
|
||||||
|
|
||||||
def _get_track_info(self, track):
|
|
||||||
thumbnail = None
|
thumbnail = None
|
||||||
cover_uri = track.get('albums', [{}])[0].get('coverUri')
|
cover_uri = track.get('albums', [{}])[0].get('coverUri')
|
||||||
if cover_uri:
|
if cover_uri:
|
||||||
@ -95,15 +98,16 @@ class YandexMusicTrackIE(YandexMusicBaseIE):
|
|||||||
if not thumbnail.startswith('http'):
|
if not thumbnail.startswith('http'):
|
||||||
thumbnail = 'http://' + thumbnail
|
thumbnail = 'http://' + thumbnail
|
||||||
|
|
||||||
track_title = track['title']
|
|
||||||
track_info = {
|
track_info = {
|
||||||
'id': track['id'],
|
'id': track_id,
|
||||||
'ext': 'mp3',
|
'ext': 'mp3',
|
||||||
'url': self._get_track_url(track['storageDir'], track['id']),
|
'url': f_url,
|
||||||
'filesize': int_or_none(track.get('fileSize')),
|
'filesize': int_or_none(track.get('fileSize')),
|
||||||
'duration': float_or_none(track.get('durationMs'), 1000),
|
'duration': float_or_none(track.get('durationMs'), 1000),
|
||||||
'thumbnail': thumbnail,
|
'thumbnail': thumbnail,
|
||||||
'track': track_title,
|
'track': track_title,
|
||||||
|
'acodec': download_data.get('codec'),
|
||||||
|
'abr': int_or_none(download_data.get('bitrate')),
|
||||||
}
|
}
|
||||||
|
|
||||||
def extract_artist(artist_list):
|
def extract_artist(artist_list):
|
||||||
@ -131,18 +135,9 @@ class YandexMusicTrackIE(YandexMusicBaseIE):
|
|||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
track_info['title'] = track_title
|
track_info['title'] = track_title
|
||||||
|
|
||||||
return track_info
|
return track_info
|
||||||
|
|
||||||
def _real_extract(self, url):
|
|
||||||
mobj = re.match(self._VALID_URL, url)
|
|
||||||
album_id, track_id = mobj.group('album_id'), mobj.group('id')
|
|
||||||
|
|
||||||
track = self._download_json(
|
|
||||||
'http://music.yandex.ru/handlers/track.jsx?track=%s:%s' % (track_id, album_id),
|
|
||||||
track_id, 'Downloading track JSON')['track']
|
|
||||||
|
|
||||||
return self._get_track_info(track)
|
|
||||||
|
|
||||||
|
|
||||||
class YandexMusicPlaylistBaseIE(YandexMusicBaseIE):
|
class YandexMusicPlaylistBaseIE(YandexMusicBaseIE):
|
||||||
def _build_playlist(self, tracks):
|
def _build_playlist(self, tracks):
|
||||||
|
@ -27,6 +27,7 @@ from ..compat import (
|
|||||||
)
|
)
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
clean_html,
|
clean_html,
|
||||||
|
dict_get,
|
||||||
error_to_compat_str,
|
error_to_compat_str,
|
||||||
ExtractorError,
|
ExtractorError,
|
||||||
float_or_none,
|
float_or_none,
|
||||||
@ -908,6 +909,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
'creator': 'Todd Haberman, Daniel Law Heath and Aaron Kaplan',
|
'creator': 'Todd Haberman, Daniel Law Heath and Aaron Kaplan',
|
||||||
'track': 'Dark Walk - Position Music',
|
'track': 'Dark Walk - Position Music',
|
||||||
'artist': 'Todd Haberman, Daniel Law Heath and Aaron Kaplan',
|
'artist': 'Todd Haberman, Daniel Law Heath and Aaron Kaplan',
|
||||||
|
'album': 'Position Music - Production Music Vol. 143 - Dark Walk',
|
||||||
},
|
},
|
||||||
'params': {
|
'params': {
|
||||||
'skip_download': True,
|
'skip_download': True,
|
||||||
@ -1086,7 +1088,95 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
'skip_download': True,
|
'skip_download': True,
|
||||||
'youtube_include_dash_manifest': False,
|
'youtube_include_dash_manifest': False,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
# Youtube Music Auto-generated description
|
||||||
|
'url': 'https://music.youtube.com/watch?v=MgNrAu2pzNs',
|
||||||
|
'info_dict': {
|
||||||
|
'id': 'MgNrAu2pzNs',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Voyeur Girl',
|
||||||
|
'description': 'md5:7ae382a65843d6df2685993e90a8628f',
|
||||||
|
'upload_date': '20190312',
|
||||||
|
'uploader': 'Various Artists - Topic',
|
||||||
|
'uploader_id': 'UCVWKBi1ELZn0QX2CBLSkiyw',
|
||||||
|
'artist': 'Stephen',
|
||||||
|
'track': 'Voyeur Girl',
|
||||||
|
'album': 'it\'s too much love to know my dear',
|
||||||
|
'release_date': '20190313',
|
||||||
|
'release_year': 2019,
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
'skip_download': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Youtube Music Auto-generated description
|
||||||
|
# Retrieve 'artist' field from 'Artist:' in video description
|
||||||
|
# when it is present on youtube music video
|
||||||
|
'url': 'https://www.youtube.com/watch?v=k0jLE7tTwjY',
|
||||||
|
'info_dict': {
|
||||||
|
'id': 'k0jLE7tTwjY',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Latch Feat. Sam Smith',
|
||||||
|
'description': 'md5:3cb1e8101a7c85fcba9b4fb41b951335',
|
||||||
|
'upload_date': '20150110',
|
||||||
|
'uploader': 'Various Artists - Topic',
|
||||||
|
'uploader_id': 'UCNkEcmYdjrH4RqtNgh7BZ9w',
|
||||||
|
'artist': 'Disclosure',
|
||||||
|
'track': 'Latch Feat. Sam Smith',
|
||||||
|
'album': 'Latch Featuring Sam Smith',
|
||||||
|
'release_date': '20121008',
|
||||||
|
'release_year': 2012,
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
'skip_download': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Youtube Music Auto-generated description
|
||||||
|
# handle multiple artists on youtube music video
|
||||||
|
'url': 'https://www.youtube.com/watch?v=74qn0eJSjpA',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '74qn0eJSjpA',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Eastside',
|
||||||
|
'description': 'md5:290516bb73dcbfab0dcc4efe6c3de5f2',
|
||||||
|
'upload_date': '20180710',
|
||||||
|
'uploader': 'Benny Blanco - Topic',
|
||||||
|
'uploader_id': 'UCzqz_ksRu_WkIzmivMdIS7A',
|
||||||
|
'artist': 'benny blanco, Halsey, Khalid',
|
||||||
|
'track': 'Eastside',
|
||||||
|
'album': 'Eastside',
|
||||||
|
'release_date': '20180713',
|
||||||
|
'release_year': 2018,
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
'skip_download': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Youtube Music Auto-generated description
|
||||||
|
# handle youtube music video with release_year and no release_date
|
||||||
|
'url': 'https://www.youtube.com/watch?v=-hcAI0g-f5M',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '-hcAI0g-f5M',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Put It On Me',
|
||||||
|
'description': 'md5:93c55acc682ae7b0c668f2e34e1c069e',
|
||||||
|
'upload_date': '20180426',
|
||||||
|
'uploader': 'Matt Maeson - Topic',
|
||||||
|
'uploader_id': 'UCnEkIGqtGcQMLk73Kp-Q5LQ',
|
||||||
|
'artist': 'Matt Maeson',
|
||||||
|
'track': 'Put It On Me',
|
||||||
|
'album': 'The Hearse',
|
||||||
|
'release_date': None,
|
||||||
|
'release_year': 2018,
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
'skip_download': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -1563,6 +1653,9 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
def extract_view_count(v_info):
|
def extract_view_count(v_info):
|
||||||
return int_or_none(try_get(v_info, lambda x: x['view_count'][0]))
|
return int_or_none(try_get(v_info, lambda x: x['view_count'][0]))
|
||||||
|
|
||||||
|
def extract_token(v_info):
|
||||||
|
return dict_get(v_info, ('account_playback_token', 'accountPlaybackToken', 'token'))
|
||||||
|
|
||||||
player_response = {}
|
player_response = {}
|
||||||
|
|
||||||
# Get video info
|
# Get video info
|
||||||
@ -1622,7 +1715,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
# The general idea is to take a union of itags of both DASH manifests (for example
|
# The general idea is to take a union of itags of both DASH manifests (for example
|
||||||
# video with such 'manifest behavior' see https://github.com/ytdl-org/youtube-dl/issues/6093)
|
# video with such 'manifest behavior' see https://github.com/ytdl-org/youtube-dl/issues/6093)
|
||||||
self.report_video_info_webpage_download(video_id)
|
self.report_video_info_webpage_download(video_id)
|
||||||
for el in ('info', 'embedded', 'detailpage', 'vevo', ''):
|
for el in ('embedded', 'detailpage', 'vevo', ''):
|
||||||
query = {
|
query = {
|
||||||
'video_id': video_id,
|
'video_id': video_id,
|
||||||
'ps': 'default',
|
'ps': 'default',
|
||||||
@ -1652,7 +1745,8 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
view_count = extract_view_count(get_video_info)
|
view_count = extract_view_count(get_video_info)
|
||||||
if not video_info:
|
if not video_info:
|
||||||
video_info = get_video_info
|
video_info = get_video_info
|
||||||
if 'token' in get_video_info:
|
get_token = extract_token(get_video_info)
|
||||||
|
if get_token:
|
||||||
# Different get_video_info requests may report different results, e.g.
|
# Different get_video_info requests may report different results, e.g.
|
||||||
# some may report video unavailability, but some may serve it without
|
# some may report video unavailability, but some may serve it without
|
||||||
# any complaint (see https://github.com/ytdl-org/youtube-dl/issues/7362,
|
# any complaint (see https://github.com/ytdl-org/youtube-dl/issues/7362,
|
||||||
@ -1662,7 +1756,8 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
# due to YouTube measures against IP ranges of hosting providers.
|
# due to YouTube measures against IP ranges of hosting providers.
|
||||||
# Working around by preferring the first succeeded video_info containing
|
# Working around by preferring the first succeeded video_info containing
|
||||||
# the token if no such video_info yet was found.
|
# the token if no such video_info yet was found.
|
||||||
if 'token' not in video_info:
|
token = extract_token(video_info)
|
||||||
|
if not token:
|
||||||
video_info = get_video_info
|
video_info = get_video_info
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -1671,26 +1766,12 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
r'(?s)<h1[^>]+id="unavailable-message"[^>]*>(.+?)</h1>',
|
r'(?s)<h1[^>]+id="unavailable-message"[^>]*>(.+?)</h1>',
|
||||||
video_webpage, 'unavailable message', default=None)
|
video_webpage, 'unavailable message', default=None)
|
||||||
|
|
||||||
if 'token' not in video_info:
|
if not video_info:
|
||||||
if 'reason' in video_info:
|
unavailable_message = extract_unavailable_message()
|
||||||
if 'The uploader has not made this video available in your country.' in video_info['reason']:
|
if not unavailable_message:
|
||||||
regions_allowed = self._html_search_meta(
|
unavailable_message = 'Unable to extract video data'
|
||||||
'regionsAllowed', video_webpage, default=None)
|
raise ExtractorError(
|
||||||
countries = regions_allowed.split(',') if regions_allowed else None
|
'YouTube said: %s' % unavailable_message, expected=True, video_id=video_id)
|
||||||
self.raise_geo_restricted(
|
|
||||||
msg=video_info['reason'][0], countries=countries)
|
|
||||||
reason = video_info['reason'][0]
|
|
||||||
if 'Invalid parameters' in reason:
|
|
||||||
unavailable_message = extract_unavailable_message()
|
|
||||||
if unavailable_message:
|
|
||||||
reason = unavailable_message
|
|
||||||
raise ExtractorError(
|
|
||||||
'YouTube said: %s' % reason,
|
|
||||||
expected=True, video_id=video_id)
|
|
||||||
else:
|
|
||||||
raise ExtractorError(
|
|
||||||
'"token" parameter not in video info for unknown reason',
|
|
||||||
video_id=video_id)
|
|
||||||
|
|
||||||
if video_info.get('license_info'):
|
if video_info.get('license_info'):
|
||||||
raise ExtractorError('This video is DRM protected.', expected=True)
|
raise ExtractorError('This video is DRM protected.', expected=True)
|
||||||
@ -2063,6 +2144,27 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
|
|
||||||
track = extract_meta('Song')
|
track = extract_meta('Song')
|
||||||
artist = extract_meta('Artist')
|
artist = extract_meta('Artist')
|
||||||
|
album = extract_meta('Album')
|
||||||
|
|
||||||
|
# Youtube Music Auto-generated description
|
||||||
|
release_date = release_year = None
|
||||||
|
if video_description:
|
||||||
|
mobj = re.search(r'(?s)Provided to YouTube by [^\n]+\n+(?P<track>[^·]+)·(?P<artist>[^\n]+)\n+(?P<album>[^\n]+)(?:.+?℗\s*(?P<release_year>\d{4})(?!\d))?(?:.+?Released on\s*:\s*(?P<release_date>\d{4}-\d{2}-\d{2}))?(.+?\nArtist\s*:\s*(?P<clean_artist>[^\n]+))?', video_description)
|
||||||
|
if mobj:
|
||||||
|
if not track:
|
||||||
|
track = mobj.group('track').strip()
|
||||||
|
if not artist:
|
||||||
|
artist = mobj.group('clean_artist') or ', '.join(a.strip() for a in mobj.group('artist').split('·'))
|
||||||
|
if not album:
|
||||||
|
album = mobj.group('album'.strip())
|
||||||
|
release_year = mobj.group('release_year')
|
||||||
|
release_date = mobj.group('release_date')
|
||||||
|
if release_date:
|
||||||
|
release_date = release_date.replace('-', '')
|
||||||
|
if not release_year:
|
||||||
|
release_year = int(release_date[:4])
|
||||||
|
if release_year:
|
||||||
|
release_year = int(release_year)
|
||||||
|
|
||||||
m_episode = re.search(
|
m_episode = re.search(
|
||||||
r'<div[^>]+id="watch7-headline"[^>]*>\s*<span[^>]*>.*?>(?P<series>[^<]+)</a></b>\s*S(?P<season>\d+)\s*•\s*E(?P<episode>\d+)</span>',
|
r'<div[^>]+id="watch7-headline"[^>]*>\s*<span[^>]*>.*?>(?P<series>[^<]+)</a></b>\s*S(?P<season>\d+)\s*•\s*E(?P<episode>\d+)</span>',
|
||||||
@ -2176,6 +2278,29 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
if f.get('vcodec') != 'none':
|
if f.get('vcodec') != 'none':
|
||||||
f['stretched_ratio'] = ratio
|
f['stretched_ratio'] = ratio
|
||||||
|
|
||||||
|
if not formats:
|
||||||
|
token = extract_token(video_info)
|
||||||
|
if not token:
|
||||||
|
if 'reason' in video_info:
|
||||||
|
if 'The uploader has not made this video available in your country.' in video_info['reason']:
|
||||||
|
regions_allowed = self._html_search_meta(
|
||||||
|
'regionsAllowed', video_webpage, default=None)
|
||||||
|
countries = regions_allowed.split(',') if regions_allowed else None
|
||||||
|
self.raise_geo_restricted(
|
||||||
|
msg=video_info['reason'][0], countries=countries)
|
||||||
|
reason = video_info['reason'][0]
|
||||||
|
if 'Invalid parameters' in reason:
|
||||||
|
unavailable_message = extract_unavailable_message()
|
||||||
|
if unavailable_message:
|
||||||
|
reason = unavailable_message
|
||||||
|
raise ExtractorError(
|
||||||
|
'YouTube said: %s' % reason,
|
||||||
|
expected=True, video_id=video_id)
|
||||||
|
else:
|
||||||
|
raise ExtractorError(
|
||||||
|
'"token" parameter not in video info for unknown reason',
|
||||||
|
video_id=video_id)
|
||||||
|
|
||||||
self._sort_formats(formats)
|
self._sort_formats(formats)
|
||||||
|
|
||||||
self.mark_watched(video_id, video_info, player_response)
|
self.mark_watched(video_id, video_info, player_response)
|
||||||
@ -2216,6 +2341,9 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
'episode_number': episode_number,
|
'episode_number': episode_number,
|
||||||
'track': track,
|
'track': track,
|
||||||
'artist': artist,
|
'artist': artist,
|
||||||
|
'album': album,
|
||||||
|
'release_date': release_date,
|
||||||
|
'release_year': release_year,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
__version__ = '2019.04.17'
|
__version__ = '2019.04.30'
|
||||||
|
Loading…
Reference in New Issue
Block a user