]> jfr.im git - yt-dlp.git/commitdiff
merge ytdl-master
authorUnknown <redacted>
Mon, 14 Sep 2020 10:50:56 +0000 (12:50 +0200)
committerUnknown <redacted>
Mon, 14 Sep 2020 10:50:56 +0000 (12:50 +0200)
16 files changed:
1  2 
.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
docs/supportedsites.md
youtube_dlc/extractor/extractors.py
youtube_dlc/extractor/googledrive.py
youtube_dlc/extractor/redbulltv.py
youtube_dlc/extractor/rtlnl.py
youtube_dlc/extractor/soundcloud.py
youtube_dlc/extractor/srgssr.py
youtube_dlc/extractor/svt.py
youtube_dlc/extractor/youtube.py
youtube_dlc/postprocessor/embedthumbnail.py
youtube_dlc/version.py

index f05aa66e67ac3b2625aa80028812c28a1ac108b4,352263789428d02be904ec7df2a7871fd6921454..e49e0749f156ef07516a63ed6de13d410e16ee51
@@@ -17,8 -17,8 +17,8 @@@ title: '
  ## 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 2020.09.06. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
 -- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.09.14. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
++Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
++- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2020.09.14. 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.
@@@ -26,7 -26,7 +26,7 @@@
  -->
  
  - [ ] I'm reporting a broken site support
- - [ ] I've verified that I'm running youtube-dl version **2020.09.06**
 -- [ ] I've verified that I'm running youtube-dl version **2020.09.14**
++- [ ] I've verified that I'm running youtube-dlc version **2020.09.14**
  - [ ] 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:
++Provide the complete verbose output of youtube-dlc that clearly demonstrates the problem.
++Add the `-v` flag to your command line you run youtube-dlc with (`youtube-dlc -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 2020.09.06
 - [debug] youtube-dl version 2020.09.14
++ [debug] youtube-dlc version 2020.09.14
   [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: {}
index 29beaf437eba4dd93a3b56485eaf42717a276b92,fa6509be3cbebdef5f61f269afb9c84d36cc0a28..77be9b360d869dd220cff5a5fb176b0a74bdeebd
@@@ -18,16 -18,16 +18,16 @@@ labels: 'site-support-request
  ## 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 2020.09.06. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
 -- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.09.14. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
++Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
++- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2020.09.14. 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.
++- Make sure that site you are requesting is not dedicated to copyright infringement, see https://yt-dl.org/copyright-infringement. youtube-dlc 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 **2020.09.06**
 -- [ ] I've verified that I'm running youtube-dl version **2020.09.14**
++- [ ] I've verified that I'm running youtube-dlcc version **2020.09.14**
  - [ ] 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
index f96b8d2bb504cc40fac267c9aef4d11ae0e46253,70b0f2f19fcfdc04c1a040c02df3571e2a079091..c1c5aa061f242b5f371c90bd8408dceea6891f71
@@@ -17,21 -17,21 +17,21 @@@ title: '
  ## 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 2020.09.06. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
 -- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.09.14. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
++Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
++- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2020.09.14. 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 **2020.09.06**
 -- [ ] I've verified that I'm running youtube-dl version **2020.09.14**
++- [ ] I've verified that I'm running youtube-dlc version **2020.09.14**
  - [ ] 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.
++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-dlc#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
index 3a175aa4d00327cf4ec7e145eedf9f7b645b6283,ec17e4a33ca592cf2de7bdac6679957a07997870..49a332c962b5d1356717e662df93ac31e6e2f5aa
@@@ -17,8 -17,8 +17,8 @@@ title: '
  ## 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 2020.09.06. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
 -- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.09.14. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
++Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
++- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2020.09.14. 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.
@@@ -27,7 -27,7 +27,7 @@@
  -->
  
  - [ ] I'm reporting a broken site support issue
- - [ ] I've verified that I'm running youtube-dl version **2020.09.06**
 -- [ ] I've verified that I'm running youtube-dl version **2020.09.14**
++- [ ] I've verified that I'm running youtube-dlc version **2020.09.14**
  - [ ] 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
  ## 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:
++Provide the complete verbose output of youtube-dlc that clearly demonstrates the problem.
++Add the `-v` flag to your command line you run youtube-dlc with (`youtube-dlc -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 2020.09.06
 - [debug] youtube-dl version 2020.09.14
++ [debug] youtube-dlc version 2020.09.14
   [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: {}
@@@ -58,7 -58,7 +58,7 @@@ PASTE VERBOSE LOG HER
  ## 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.
++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-dlc#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.
  -->
  
index 4977079deb765e2ccfe6ffa83aae9795c30103c4,6ac963206b6f7083a4730281ce0e39f0acf054d7..6356f998cff45f3454415fc6cbe2cc439b1891fc
@@@ -18,21 -18,21 +18,21 @@@ labels: 'request
  ## 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 2020.09.06. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
 -- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.09.14. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
++Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
++- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2020.09.14. 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 **2020.09.06**
 -- [ ] I've verified that I'm running youtube-dl version **2020.09.14**
++- [ ] I've verified that I'm running youtube-dlc version **2020.09.14**
  - [ ] 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.
++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-dlc#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
diff --combined docs/supportedsites.md
index 87c3d223294e6132f757798363038e5551eb82f1,367545a96b2988b8adef456710860fc05b564ec8..eb0760bb6888c4ee4d4043a3fde9c4a0f9244738
@@@ -6,6 -6,7 +6,6 @@@
   - **23video**
   - **24video**
   - **3qsdn**: 3Q SDN
 - - **3sat**
   - **4tube**
   - **56.com**
   - **5min**
@@@ -40,8 -41,6 +40,8 @@@
   - **AlJazeera**
   - **Allocine**
   - **AlphaPorno**
 + - **Alura**
 + - **AluraCourse**
   - **AMCNetworks**
   - **AmericasTestKitchen**
   - **anderetijden**: npo.nl, ntr.nl, omroepwnl.nl, zapp.nl and npo3.nl
   - **daum.net:user**
   - **DBTV**
   - **DctpTv**
 + - **DeezerAlbum**
   - **DeezerPlaylist**
   - **defense.gouv.fr**
   - **democracynow**
   - **Disney**
   - **dlive:stream**
   - **dlive:vod**
 + - **DoodStream**
   - **Dotsub**
   - **DouyuShow**
   - **DouyuTV**: æ–—é±¼
   - **drtv**
   - **drtv:live**
   - **DTube**
 + - **duboku**: www.duboku.co
 + - **duboku:list**: www.duboku.co entire series
   - **Dumpert**
   - **dvtv**: http://video.aktualne.cz/
   - **dw**
   - **hotstar:playlist**
   - **Howcast**
   - **HowStuffWorks**
 + - **hrfernsehen**
   - **HRTi**
   - **HRTiPlaylist**
   - **Huajiao**: èŠ±æ¤’ç›´æ’­
   - **lynda**: lynda.com videos
   - **lynda:course**: lynda.com online courses
   - **m6**
 + - **MagentaMusik360**
   - **mailru**: Ð’идео@Mail.Ru
   - **mailru:music**: ÐœÑƒÐ·Ñ‹ÐºÐ°@Mail.Ru
   - **mailru:music:search**: ÐœÑƒÐ·Ñ‹ÐºÐ°@Mail.Ru
   - **MySpace:album**
   - **MySpass**
   - **Myvi**
 + - **MyVideoGe**
   - **MyVidster**
   - **MyviEmbed**
   - **MyVisionTV**
   - **plus.google**: Google Plus
   - **podomatic**
   - **Pokemon**
 + - **PokemonWatch**
   - **PolskieRadio**
   - **PolskieRadioCategory**
   - **Popcorntimes**
   - **RayWenderlichCourse**
   - **RBMARadio**
   - **RDS**: RDS.ca
+  - **RedBull**
+  - **RedBullEmbed**
   - **RedBullTV**
   - **RedBullTVRrnContent**
   - **Reddit**
   - **stanfordoc**: Stanford Open ClassRoom
   - **Steam**
   - **Stitcher**
 + - **StoryFire**
 + - **StoryFireSeries**
 + - **StoryFireUser**
   - **Streamable**
   - **streamcloud.eu**
   - **StreamCZ**
   - **ThisAV**
   - **ThisOldHouse**
   - **TikTok**
 - - **TikTokUser**
   - **tinypic**: tinypic.com videos
   - **TMZ**
   - **TMZArticle**
   - **TVNoe**
   - **TVNow**
   - **TVNowAnnual**
 + - **TVNowFilm**
   - **TVNowNew**
   - **TVNowSeason**
   - **TVNowShow**
   - **Zaq1**
   - **Zattoo**
   - **ZattooLive**
 - - **ZDF**
 + - **ZDF-3sat**
   - **ZDFChannel**
   - **zingmp3**: mp3.zing.vn
   - **Zype**
index af1bc6e31d0c25693faaa0cfed62f657cda03ee9,ae7079a6a4d55550281d807e9eb30ad0e550a792..b971ace0a904a658238411d58f58ea8c1ffc830b
@@@ -36,10 -36,6 +36,10 @@@ from .afreecatv import AfreecaTVI
  from .airmozilla import AirMozillaIE
  from .aljazeera import AlJazeeraIE
  from .alphaporno import AlphaPornoIE
 +from .alura import (
 +    AluraIE,
 +    AluraCourseIE
 +)
  from .amcnetworks import AMCNetworksIE
  from .americastestkitchen import AmericasTestKitchenIE
  from .animeondemand import AnimeOnDemandIE
@@@ -266,10 -262,7 +266,10 @@@ from .daum import 
  )
  from .dbtv import DBTVIE
  from .dctp import DctpTvIE
 -from .deezer import DeezerPlaylistIE
 +from .deezer import (
 +    DeezerPlaylistIE,
 +    DeezerAlbumIE,
 +)
  from .democracynow import DemocracynowIE
  from .dfb import DFBIE
  from .dhm import DHMIE
@@@ -280,6 -273,7 +280,6 @@@ from .douyutv import 
      DouyuTVIE,
  )
  from .dplay import DPlayIE
 -from .dreisat import DreiSatIE
  from .drbonanza import DRBonanzaIE
  from .drtuber import DrTuberIE
  from .drtv import (
  )
  from .dtube import DTubeIE
  from .dvtv import DVTVIE
 +from .duboku import (
 +    DubokuIE,
 +    DubokuPlaylistIE
 +)
  from .dumpert import DumpertIE
  from .defense import DefenseGouvFrIE
  from .discovery import DiscoveryIE
@@@ -303,7 -293,6 +303,7 @@@ from .discoverynetworks import Discover
  from .discoveryvr import DiscoveryVRIE
  from .disney import DisneyIE
  from .dispeak import DigitallySpeakingIE
 +from .doodstream import DoodStreamIE
  from .dropbox import DropboxIE
  from .dw import (
      DWIE,
@@@ -451,7 -440,6 +451,7 @@@ from .hotstar import 
  )
  from .howcast import HowcastIE
  from .howstuffworks import HowStuffWorksIE
 +from .hrfensehen import HRFernsehenIE
  from .hrti import (
      HRTiIE,
      HRTiPlaylistIE,
@@@ -597,7 -585,6 +597,7 @@@ from .lynda import 
      LyndaCourseIE
  )
  from .m6 import M6IE
 +from .magentamusik360 import MagentaMusik360IE
  from .mailru import (
      MailRuIE,
      MailRuMusicIE,
@@@ -680,7 -667,6 +680,7 @@@ from .myvi import 
      MyviIE,
      MyviEmbedIE,
  )
 +from .myvideoge import MyVideoGeIE
  from .myvidster import MyVidsterIE
  from .nationalgeographic import (
      NationalGeographicVideoIE,
@@@ -872,10 -858,7 +872,10 @@@ from .pluralsight import 
      PluralsightCourseIE,
  )
  from .podomatic import PodomaticIE
 -from .pokemon import PokemonIE
 +from .pokemon import (
 +    PokemonIE,
 +    PokemonWatchIE,
 +)
  from .polskieradio import (
      PolskieRadioIE,
      PolskieRadioCategoryIE,
@@@ -935,7 -918,9 +935,9 @@@ from .rbmaradio import RBMARadioI
  from .rds import RDSIE
  from .redbulltv import (
      RedBullTVIE,
+     RedBullEmbedIE,
      RedBullTVRrnContentIE,
+     RedBullIE,
  )
  from .reddit import (
      RedditIE,
@@@ -1074,11 -1059,6 +1076,11 @@@ from .spike import 
      BellatorIE,
      ParamountNetworkIE,
  )
 +from .storyfire import (
 +    StoryFireIE,
 +    StoryFireUserIE,
 +    StoryFireSeriesIE,
 +)
  from .stitcher import StitcherIE
  from .sport5 import Sport5IE
  from .sportbox import SportBoxIE
@@@ -1165,7 -1145,10 +1167,7 @@@ from .thisamericanlife import ThisAmeri
  from .thisav import ThisAVIE
  from .thisoldhouse import ThisOldHouseIE
  from .threeqsdn import ThreeQSDNIE
 -from .tiktok import (
 -    TikTokIE,
 -    TikTokUserIE,
 -)
 +from .tiktok import TikTokIE
  from .tinypic import TinyPicIE
  from .tmz import (
      TMZIE,
@@@ -1226,7 -1209,6 +1228,7 @@@ from .tvnet import TVNetI
  from .tvnoe import TVNoeIE
  from .tvnow import (
      TVNowIE,
 +    TVNowFilmIE,
      TVNowNewIE,
      TVNowSeasonIE,
      TVNowAnnualIE,
index 886fdd5328dee16ee68edc292a12cdabc81f4a06,f2cc57e447660f2d047be5bc306aaa4397bbf6af..ec0d58a57b6a2b64de031516721f068afacdce92
@@@ -220,19 -220,27 +220,27 @@@ class GoogleDriveIE(InfoExtractor)
                  'id': video_id,
                  'export': 'download',
              })
-         urlh = self._request_webpage(
-             source_url, video_id, note='Requesting source file',
-             errnote='Unable to request source file', fatal=False)
+         def request_source_file(source_url, kind):
+             return self._request_webpage(
+                 source_url, video_id, note='Requesting %s file' % kind,
+                 errnote='Unable to request %s file' % kind, fatal=False)
+         urlh = request_source_file(source_url, 'source')
          if urlh:
-             def add_source_format(src_url):
+             def add_source_format(urlh):
                  formats.append({
-                     'url': src_url,
+                     # Use redirect URLs as download URLs in order to calculate
+                     # correct cookies in _calc_cookies.
+                     # Using original URLs may result in redirect loop due to
+                     # google.com's cookies mistakenly used for googleusercontent.com
+                     # redirect URLs (see #23919).
+                     'url': urlh.geturl(),
                      'ext': determine_ext(title, 'mp4').lower(),
                      'format_id': 'source',
                      'quality': 1,
                  })
              if urlh.headers.get('Content-Disposition'):
-                 add_source_format(source_url)
+                 add_source_format(urlh)
              else:
                  confirmation_webpage = self._webpage_read_content(
                      urlh, url, video_id, note='Downloading confirmation page',
                          r'confirm=([^&"\']+)', confirmation_webpage,
                          'confirmation code', fatal=False)
                      if confirm:
-                         add_source_format(update_url_query(source_url, {
+                         confirmed_source_url = update_url_query(source_url, {
                              'confirm': confirm,
-                         }))
+                         })
+                         urlh = request_source_file(confirmed_source_url, 'confirmed source')
+                         if urlh and urlh.headers.get('Content-Disposition'):
+                             add_source_format(urlh)
  
          if not formats:
              reason = self._search_regex(
              subtitles_id = ttsurl.encode('utf-8').decode(
                  'unicode_escape').split('=')[-1]
  
 +        self._downloader.cookiejar.clear(domain='.google.com', path='/', name='NID')
 +
          return {
              'id': video_id,
              'title': title,
index dbe1aaded5364f04d43180e86768ed7d9c6e4590,3aae79f5da2a0717c44991130738cfce00760c6b..3aae79f5da2a0717c44991130738cfce00760c6b
@@@ -1,6 -1,8 +1,8 @@@
  # coding: utf-8
  from __future__ import unicode_literals
  
+ import re
  from .common import InfoExtractor
  from ..compat import compat_HTTPError
  from ..utils import (
@@@ -10,7 -12,7 +12,7 @@@
  
  
  class RedBullTVIE(InfoExtractor):
-     _VALID_URL = r'https?://(?:www\.)?redbull(?:\.tv|\.com(?:/[^/]+)?(?:/tv)?)(?:/events/[^/]+)?/(?:videos?|live)/(?P<id>AP-\w+)'
+     _VALID_URL = r'https?://(?:www\.)?redbull(?:\.tv|\.com(?:/[^/]+)?(?:/tv)?)(?:/events/[^/]+)?/(?:videos?|live|(?:film|episode)s)/(?P<id>AP-\w+)'
      _TESTS = [{
          # film
          'url': 'https://www.redbull.tv/video/AP-1Q6XCDTAN1W11',
@@@ -29,8 -31,8 +31,8 @@@
              'id': 'AP-1PMHKJFCW1W11',
              'ext': 'mp4',
              'title': 'Grime - Hashtags S2E4',
-             'description': 'md5:b5f522b89b72e1e23216e5018810bb25',
-             'duration': 904.6,
+             'description': 'md5:5546aa612958c08a98faaad4abce484d',
+             'duration': 904,
          },
          'params': {
              'skip_download': True,
      }, {
          'url': 'https://www.redbull.com/us-en/events/AP-1XV2K61Q51W11/live/AP-1XUJ86FDH1W11',
          'only_matching': True,
+     }, {
+         'url': 'https://www.redbull.com/int-en/films/AP-1ZSMAW8FH2111',
+         'only_matching': True,
+     }, {
+         'url': 'https://www.redbull.com/int-en/episodes/AP-1TQWK7XE11W11',
+         'only_matching': True,
      }]
  
-     def _real_extract(self, url):
-         video_id = self._match_id(url)
+     def extract_info(self, video_id):
          session = self._download_json(
              'https://api.redbull.tv/v3/session', video_id,
              note='Downloading access token', query={
              'subtitles': subtitles,
          }
  
+     def _real_extract(self, url):
+         video_id = self._match_id(url)
+         return self.extract_info(video_id)
+ class RedBullEmbedIE(RedBullTVIE):
+     _VALID_URL = r'https?://(?:www\.)?redbull\.com/embed/(?P<id>rrn:content:[^:]+:[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}:[a-z]{2}-[A-Z]{2,3})'
+     _TESTS = [{
+         # HLS manifest accessible only using assetId
+         'url': 'https://www.redbull.com/embed/rrn:content:episode-videos:f3021f4f-3ed4-51ac-915a-11987126e405:en-INT',
+         'only_matching': True,
+     }]
+     _VIDEO_ESSENSE_TMPL = '''... on %s {
+       videoEssence {
+         attributes
+       }
+     }'''
+     def _real_extract(self, url):
+         rrn_id = self._match_id(url)
+         asset_id = self._download_json(
+             'https://edge-graphql.crepo-production.redbullaws.com/v1/graphql',
+             rrn_id, headers={'API-KEY': 'e90a1ff11335423998b100c929ecc866'},
+             query={
+                 'query': '''{
+   resource(id: "%s", enforceGeoBlocking: false) {
+     %s
+     %s
+   }
+ }''' % (rrn_id, self._VIDEO_ESSENSE_TMPL % 'LiveVideo', self._VIDEO_ESSENSE_TMPL % 'VideoResource'),
+             })['data']['resource']['videoEssence']['attributes']['assetId']
+         return self.extract_info(asset_id)
  
  class RedBullTVRrnContentIE(InfoExtractor):
-     _VALID_URL = r'https?://(?:www\.)?redbull(?:\.tv|\.com(?:/[^/]+)?(?:/tv)?)/(?:video|live)/rrn:content:[^:]+:(?P<id>[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12})'
+     _VALID_URL = r'https?://(?:www\.)?redbull\.com/(?P<region>[a-z]{2,3})-(?P<lang>[a-z]{2})/tv/(?:video|live|film)/(?P<id>rrn:content:[^:]+:[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12})'
      _TESTS = [{
          'url': 'https://www.redbull.com/int-en/tv/video/rrn:content:live-videos:e3e6feb4-e95f-50b7-962a-c70f8fd13c73/mens-dh-finals-fort-william',
          'only_matching': True,
      }, {
          'url': 'https://www.redbull.com/int-en/tv/video/rrn:content:videos:a36a0f36-ff1b-5db8-a69d-ee11a14bf48b/tn-ts-style?playlist=rrn:content:event-profiles:83f05926-5de8-5389-b5e4-9bb312d715e8:extras',
          'only_matching': True,
+     }, {
+         'url': 'https://www.redbull.com/int-en/tv/film/rrn:content:films:d1f4d00e-4c04-5d19-b510-a805ffa2ab83/follow-me',
+         'only_matching': True,
      }]
  
      def _real_extract(self, url):
-         display_id = self._match_id(url)
+         region, lang, rrn_id = re.search(self._VALID_URL, url).groups()
+         rrn_id += ':%s-%s' % (lang, region.upper())
+         return self.url_result(
+             'https://www.redbull.com/embed/' + rrn_id,
+             RedBullEmbedIE.ie_key(), rrn_id)
  
-         webpage = self._download_webpage(url, display_id)
  
-         video_url = self._og_search_url(webpage)
+ class RedBullIE(InfoExtractor):
+     _VALID_URL = r'https?://(?:www\.)?redbull\.com/(?P<region>[a-z]{2,3})-(?P<lang>[a-z]{2})/(?P<type>(?:episode|film|(?:(?:recap|trailer)-)?video)s|live)/(?!AP-|rrn:content:)(?P<id>[^/?#&]+)'
+     _TESTS = [{
+         'url': 'https://www.redbull.com/int-en/episodes/grime-hashtags-s02-e04',
+         'md5': 'db8271a7200d40053a1809ed0dd574ff',
+         'info_dict': {
+             'id': 'AA-1MT8DQWA91W14',
+             'ext': 'mp4',
+             'title': 'Grime - Hashtags S2E4',
+             'description': 'md5:5546aa612958c08a98faaad4abce484d',
+         },
+     }, {
+         'url': 'https://www.redbull.com/int-en/films/kilimanjaro-mountain-of-greatness',
+         'only_matching': True,
+     }, {
+         'url': 'https://www.redbull.com/int-en/recap-videos/uci-mountain-bike-world-cup-2017-mens-xco-finals-from-vallnord',
+         'only_matching': True,
+     }, {
+         'url': 'https://www.redbull.com/int-en/trailer-videos/kings-of-content',
+         'only_matching': True,
+     }, {
+         'url': 'https://www.redbull.com/int-en/videos/tnts-style-red-bull-dance-your-style-s1-e12',
+         'only_matching': True,
+     }, {
+         'url': 'https://www.redbull.com/int-en/live/mens-dh-finals-fort-william',
+         'only_matching': True,
+     }, {
+         # only available on the int-en website so a fallback is need for the API
+         # https://www.redbull.com/v3/api/graphql/v1/v3/query/en-GB>en-INT?filter[uriSlug]=fia-wrc-saturday-recap-estonia&rb3Schema=v1:hero
+         'url': 'https://www.redbull.com/gb-en/live/fia-wrc-saturday-recap-estonia',
+         'only_matching': True,
+     }]
+     _INT_FALLBACK_LIST = ['de', 'en', 'es', 'fr']
+     _LAT_FALLBACK_MAP = ['ar', 'bo', 'car', 'cl', 'co', 'mx', 'pe']
+     def _real_extract(self, url):
+         region, lang, filter_type, display_id = re.search(self._VALID_URL, url).groups()
+         if filter_type == 'episodes':
+             filter_type = 'episode-videos'
+         elif filter_type == 'live':
+             filter_type = 'live-videos'
+         regions = [region.upper()]
+         if region != 'int':
+             if region in self._LAT_FALLBACK_MAP:
+                 regions.append('LAT')
+             if lang in self._INT_FALLBACK_LIST:
+                 regions.append('INT')
+         locale = '>'.join(['%s-%s' % (lang, reg) for reg in regions])
+         rrn_id = self._download_json(
+             'https://www.redbull.com/v3/api/graphql/v1/v3/query/' + locale,
+             display_id, query={
+                 'filter[type]': filter_type,
+                 'filter[uriSlug]': display_id,
+                 'rb3Schema': 'v1:hero',
+             })['data']['id']
  
          return self.url_result(
-             video_url, ie=RedBullTVIE.ie_key(),
-             video_id=RedBullTVIE._match_id(video_url))
+             'https://www.redbull.com/embed/' + rrn_id,
+             RedBullEmbedIE.ie_key(), rrn_id)
index 8be5ca236e1cf3f5351e47cc68ba3420888b7d34,9eaa06f25dce87bf67e9533e41b0a3e478cf45eb..9eaa06f25dce87bf67e9533e41b0a3e478cf45eb
@@@ -14,13 -14,14 +14,14 @@@ class RtlNlIE(InfoExtractor)
      _VALID_URL = r'''(?x)
          https?://(?:(?:www|static)\.)?
          (?:
-             rtlxl\.nl/[^\#]*\#!/[^/]+/|
-             rtlxl\.nl/programma/[^/]+/|
-             rtl\.nl/(?:(?:system/videoplayer/(?:[^/]+/)+(?:video_)?embed\.html|embed)\b.+?\buuid=|video/)
+             rtlxl\.nl/(?:[^\#]*\#!|programma)/[^/]+/|
+             rtl\.nl/(?:(?:system/videoplayer/(?:[^/]+/)+(?:video_)?embed\.html|embed)\b.+?\buuid=|video/)|
+             embed\.rtl\.nl/\#uuid=
          )
          (?P<id>[0-9a-f-]+)'''
  
      _TESTS = [{
+         # new URL schema
          'url': 'https://www.rtlxl.nl/programma/rtl-nieuws/0bd1384d-d970-3086-98bb-5c104e10c26f',
          'md5': '490428f1187b60d714f34e1f2e3af0b6',
          'info_dict': {
@@@ -33,7 -34,7 +34,7 @@@
              'duration': 661.08,
          },
      }, {
-         # old url pattern. Tests does not pass
+         # old URL schema
          'url': 'http://www.rtlxl.nl/#!/rtl-nieuws-132237/82b1aad1-4a14-3d7b-b554-b0aed1b2c416',
          'md5': '473d1946c1fdd050b2c0161a4b13c373',
          'info_dict': {
@@@ -45,6 -46,7 +46,7 @@@
              'upload_date': '20160429',
              'duration': 1167.96,
          },
+         'skip': '404',
      }, {
          # best format available a3t
          'url': 'http://www.rtl.nl/system/videoplayer/derden/rtlnieuws/video_embed.html#uuid=84ae5571-ac25-4225-ae0c-ef8d9efb2aed/autoplay=false',
      }, {
          'url': 'https://static.rtl.nl/embed/?uuid=1a2970fc-5c0b-43ff-9fdc-927e39e6d1bc&autoplay=false&publicatiepunt=rtlnieuwsnl',
          'only_matching': True,
+     }, {
+         # new embed URL schema
+         'url': 'https://embed.rtl.nl/#uuid=84ae5571-ac25-4225-ae0c-ef8d9efb2aed/autoplay=false',
+         'only_matching': True,
      }]
  
      def _real_extract(self, url):
index 04b70c1193b0d8aa5c74ff5cb00fe32941a88d6f,a2fddf6d90f0e6775c9ed97565fb76e37d7308c2..ed70b71691220780e65b629c49af71f2415cd240
@@@ -3,8 -3,6 +3,8 @@@ from __future__ import unicode_literal
  
  import itertools
  import re
 +import json
 +import random
  
  from .common import (
      InfoExtractor,
@@@ -30,7 -28,6 +30,7 @@@ from ..utils import 
      update_url_query,
      url_or_none,
      urlhandle_detect_ext,
 +    sanitized_Request,
  )
  
  
@@@ -122,7 -119,7 +122,7 @@@ class SoundcloudIE(InfoExtractor)
          },
          # private link
          {
 -            'url': 'https://soundcloud.com/jaimemf/youtube-dl-test-video-a-y-baw/s-8Pjrp',
 +            'url': 'https://soundcloud.com/jaimemf/youtube-dlc-test-video-a-y-baw/s-8Pjrp',
              'md5': 'aa0dd32bfea9b0c5ef4f02aacd080604',
              'info_dict': {
                  'id': '123998367',
              },
          },
          {
 -            # with AAC HQ format available via OAuth token
 +            # AAC HQ format available (account with active subscription needed)
              'url': 'https://soundcloud.com/wandw/the-chainsmokers-ft-daya-dont-let-me-down-ww-remix-1',
              'only_matching': True,
          },
 +        {
 +            # Go+ (account with active subscription needed)
 +            'url': 'https://soundcloud.com/taylorswiftofficial/look-what-you-made-me-do',
 +            'only_matching': True,
 +        },
      ]
  
      _API_V2_BASE = 'https://api-v2.soundcloud.com/'
                  raise
  
      def _real_initialize(self):
 -        self._CLIENT_ID = self._downloader.cache.load('soundcloud', 'client_id') or 'YUKXoArFcqrlQn9tfNHvvyfnDISj04zk'
 +        self._CLIENT_ID = self._downloader.cache.load('soundcloud', 'client_id') or "T5R4kgWS2PRf6lzLyIravUMnKlbIxQag"  # 'EXLwg5lHTO2dslU5EePe3xkw0m1h86Cd' # 'YUKXoArFcqrlQn9tfNHvvyfnDISj04zk'
 +        self._login()
 +
 +    _USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"
 +    _API_AUTH_QUERY_TEMPLATE = '?client_id=%s'
 +    _API_AUTH_URL_PW = 'https://api-auth.soundcloud.com/web-auth/sign-in/password%s'
 +    _access_token = None
 +    _HEADERS = {}
 +    _NETRC_MACHINE = 'soundcloud'
 +
 +    def _login(self):
 +        username, password = self._get_login_info()
 +        if username is None:
 +            return
 +
 +        def genDevId():
 +            def genNumBlock():
 +                return ''.join([str(random.randrange(10)) for i in range(6)])
 +            return '-'.join([genNumBlock() for i in range(4)])
 +
 +        payload = {
 +            'client_id': self._CLIENT_ID,
 +            'recaptcha_pubkey': 'null',
 +            'recaptcha_response': 'null',
 +            'credentials': {
 +                'identifier': username,
 +                'password': password
 +            },
 +            'signature': self.sign(username, password, self._CLIENT_ID),
 +            'device_id': genDevId(),
 +            'user_agent': self._USER_AGENT
 +        }
 +
 +        query = self._API_AUTH_QUERY_TEMPLATE % self._CLIENT_ID
 +        login = sanitized_Request(self._API_AUTH_URL_PW % query, json.dumps(payload).encode('utf-8'))
 +        response = self._download_json(login, None)
 +        self._access_token = response.get('session').get('access_token')
 +        if not self._access_token:
 +            self.report_warning('Unable to get access token, login may has failed')
 +        else:
 +            self._HEADERS = {'Authorization': 'OAuth ' + self._access_token}
 +
 +    # signature generation
 +    def sign(self, user, pw, clid):
 +        a = 33
 +        i = 1
 +        s = 440123
 +        w = 117
 +        u = 1800000
 +        l = 1042
 +        b = 37
 +        k = 37
 +        c = 5
 +        n = "0763ed7314c69015fd4a0dc16bbf4b90"  # _KEY
 +        y = "8"  # _REV
 +        r = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"  # _USER_AGENT
 +        e = user  # _USERNAME
 +        t = clid  # _CLIENT_ID
 +
 +        d = '-'.join([str(mInt) for mInt in [a, i, s, w, u, l, b, k]])
 +        p = n + y + d + r + e + t + d + n
 +        h = p
 +
 +        m = 8011470
 +        f = 0
 +
 +        for f in range(f, len(h)):
 +            m = (m >> 1) + ((1 & m) << 23)
 +            m += ord(h[f])
 +            m &= 16777215
 +
 +        # c is not even needed
 +        out = str(y) + ':' + str(d) + ':' + format(m, 'x') + ':' + str(c)
 +
 +        return out
  
      @classmethod
      def _resolv_url(cls, url):
              if not format_url:
                  continue
              stream = self._download_json(
 -                format_url, track_id, query=query, fatal=False)
 +                format_url, track_id, query=query, fatal=False, headers=self._HEADERS)
              if not isinstance(stream, dict):
                  continue
              stream_url = url_or_none(stream.get('url'))
              info_json_url = self._resolv_url(self._BASE_URL + resolve_title)
  
          info = self._download_json(
 -            info_json_url, full_title, 'Downloading info JSON', query=query)
 +            info_json_url, full_title, 'Downloading info JSON', query=query, headers=self._HEADERS)
  
          return self._extract_info_dict(info, full_title, token)
  
@@@ -585,7 -503,7 +585,7 @@@ class SoundcloudPlaylistBaseIE(Soundclo
                      'ids': ','.join([compat_str(t['id']) for t in tracks]),
                      'playlistId': playlist_id,
                      'playlistSecretToken': token,
 -                })
 +                }, headers=self._HEADERS)
          entries = []
          for track in tracks:
              track_id = str_or_none(track.get('id'))
  
  
  class SoundcloudSetIE(SoundcloudPlaylistBaseIE):
 -    _VALID_URL = r'https?://(?:(?:www|m)\.)?soundcloud\.com/(?P<uploader>[\w\d-]+)/sets/(?P<slug_title>[\w\d-]+)(?:/(?P<token>[^?/]+))?'
 +    _VALID_URL = r'https?://(?:(?:www|m)\.)?soundcloud\.com/(?P<uploader>[\w\d-]+)/sets/(?P<slug_title>[:\w\d-]+)(?:/(?P<token>[^?/]+))?'
      IE_NAME = 'soundcloud:set'
      _TESTS = [{
          'url': 'https://soundcloud.com/the-concept-band/sets/the-royal-concept-ep',
      }, {
          'url': 'https://soundcloud.com/the-concept-band/sets/the-royal-concept-ep/token',
          'only_matching': True,
 +    }, {
 +        'url': 'https://soundcloud.com/discover/sets/weekly::flacmatic',
 +        'only_matching': True,
 +    }, {
 +        'url': 'https://soundcloud.com/discover/sets/charts-top:all-music:de',
 +        'only_matching': True,
 +    }, {
 +        'url': 'https://soundcloud.com/discover/sets/charts-top:hiphoprap:kr',
 +        'only_matching': True,
      }]
  
      def _real_extract(self, url):
              full_title += '/' + token
  
          info = self._download_json(self._resolv_url(
 -            self._BASE_URL + full_title), full_title)
 +            self._BASE_URL + full_title), full_title, headers=self._HEADERS)
  
          if 'errors' in info:
              msgs = (compat_str(err['error_message']) for err in info['errors'])
  
  class SoundcloudPagedPlaylistBaseIE(SoundcloudIE):
      def _extract_playlist(self, base_url, playlist_id, playlist_title):
+         # Per the SoundCloud documentation, the maximum limit for a linked partioning query is 200.
+         # https://developers.soundcloud.com/blog/offset-pagination-deprecated
          COMMON_QUERY = {
              'limit': 200,
              'linked_partitioning': '1',
          for i in itertools.count():
              response = self._download_json(
                  next_href, playlist_id,
 -                'Downloading track page %s' % (i + 1), query=query)
 +                'Downloading track page %s' % (i + 1), query=query, headers=self._HEADERS)
  
              collection = response['collection']
  
@@@ -785,7 -696,7 +787,7 @@@ class SoundcloudUserIE(SoundcloudPagedP
  
          user = self._download_json(
              self._resolv_url(self._BASE_URL + uploader),
 -            uploader, 'Downloading user info')
 +            uploader, 'Downloading user info', headers=self._HEADERS)
  
          resource = mobj.group('rsrc') or 'all'
  
@@@ -810,7 -721,7 +812,7 @@@ class SoundcloudTrackStationIE(Soundclo
      def _real_extract(self, url):
          track_name = self._match_id(url)
  
 -        track = self._download_json(self._resolv_url(url), track_name)
 +        track = self._download_json(self._resolv_url(url), track_name, headers=self._HEADERS)
          track_id = self._search_regex(
              r'soundcloud:track-stations:(\d+)', track['id'], 'track id')
  
@@@ -843,7 -754,7 +845,7 @@@ class SoundcloudPlaylistIE(SoundcloudPl
  
          data = self._download_json(
              self._API_V2_BASE + 'playlists/' + playlist_id,
 -            playlist_id, 'Downloading playlist', query=query)
 +            playlist_id, 'Downloading playlist', query=query, headers=self._HEADERS)
  
          return self._extract_set(data, token)
  
@@@ -880,7 -791,7 +882,7 @@@ class SoundcloudSearchIE(SearchInfoExtr
          for i in itertools.count(1):
              response = self._download_json(
                  next_url, collection_id, 'Downloading page {0}'.format(i),
 -                'Unable to download API page')
 +                'Unable to download API page', headers=self._HEADERS)
  
              collection = response.get('collection', [])
              if not collection:
index 170dce87f1b2161c244c08014e4f18591f626db3,f63a1359aed6620af8c42cd9d4652f5ec379c7c0..f63a1359aed6620af8c42cd9d4652f5ec379c7c0
@@@ -114,7 -114,7 +114,7 @@@ class SRGSSRPlayIE(InfoExtractor)
                              [^/]+/(?P<type>video|audio)/[^?]+|
                              popup(?P<type_2>video|audio)player
                          )
-                         \?id=(?P<id>[0-9a-f\-]{36}|\d+)
+                         \?.*?\b(?:id=|urn=urn:[^:]+:video:)(?P<id>[0-9a-f\-]{36}|\d+)
                      '''
  
      _TESTS = [{
      }, {
          'url': 'https://www.srf.ch/play/tv/popupvideoplayer?id=c4dba0ca-e75b-43b2-a34f-f708a4932e01',
          'only_matching': True,
+     }, {
+         'url': 'https://www.srf.ch/play/tv/10vor10/video/snowden-beantragt-asyl-in-russland?urn=urn:srf:video:28e1a57d-5b76-4399-8ab3-9097f071e6c5',
+         'only_matching': True,
+     }, {
+         'url': 'https://www.rts.ch/play/tv/19h30/video/le-19h30?urn=urn:rts:video:6348260',
+         'only_matching': True,
      }]
  
      def _real_extract(self, url):
index 8e9ec2ca3cbe1880ee96d83594af3bbb49f90dce,2f6887d86cb915713e9047b766d5d5741b5d4e77..2f6887d86cb915713e9047b766d5d5741b5d4e77
@@@ -231,7 -231,9 +231,9 @@@ class SVTPlayIE(SVTPlayBaseIE)
          if not svt_id:
              svt_id = self._search_regex(
                  (r'<video[^>]+data-video-id=["\']([\da-zA-Z-]+)',
-                  r'"content"\s*:\s*{.*?"id"\s*:\s*"([\da-zA-Z-]+)"'),
+                  r'["\']videoSvtId["\']\s*:\s*["\']([\da-zA-Z-]+)',
+                  r'"content"\s*:\s*{.*?"id"\s*:\s*"([\da-zA-Z-]+)"',
+                  r'["\']svtId["\']\s*:\s*["\']([\da-zA-Z-]+)'),
                  webpage, 'video id')
  
          return self._extract_by_video_id(svt_id, webpage)
index a979210606fd802a781dc3f15a0cb3b5ba96a80a,02f3ab61aef7be11e68f7f16985823b9d908e70e..1c19377213f9e725863d9bbc93bcea0a48d8691e
@@@ -549,7 -549,7 +549,7 @@@ class YoutubeIE(YoutubeBaseInfoExtracto
          '396': {'acodec': 'none', 'vcodec': 'av01.0.05M.08'},
          '397': {'acodec': 'none', 'vcodec': 'av01.0.05M.08'},
      }
 -    _SUBTITLE_FORMATS = ('srv1', 'srv2', 'srv3', 'ttml', 'vtt')
 +    _SUBTITLE_FORMATS = ('json3', 'srv1', 'srv2', 'srv3', 'ttml', 'vtt')
  
      _GEO_BYPASS = False
  
              'params': {
                  'skip_download': True,
              },
-         }
+         },
+         {
+             # empty description results in an empty string
+             'url': 'https://www.youtube.com/watch?v=x41yOUIvK2k',
+             'info_dict': {
+                 'id': 'x41yOUIvK2k',
+                 'ext': 'mp4',
+                 'title': 'IMG 3456',
+                 'description': '',
+                 'upload_date': '20170613',
+                 'uploader_id': 'ElevageOrVert',
+                 'uploader': 'ElevageOrVert',
+             },
+             'params': {
+                 'skip_download': True,
+             },
+         },
      ]
  
      def __init__(self, *args, **kwargs):
              raise ExtractorError(
                  'Signature extraction failed: ' + tb, cause=e)
  
 -    def _get_subtitles(self, video_id, webpage):
 +    def _get_subtitles(self, video_id, webpage, has_live_chat_replay):
          try:
              subs_doc = self._download_xml(
                  'https://video.google.com/timedtext?hl=en&type=list&v=%s' % video_id,
                      'ext': ext,
                  })
              sub_lang_list[lang] = sub_formats
 +        if has_live_chat_replay:
 +            sub_lang_list['live_chat'] = [
 +                {
 +                    'video_id': video_id,
 +                    'ext': 'json',
 +                    'protocol': 'youtube_live_chat_replay',
 +                },
 +            ]
          if not sub_lang_list:
              self._downloader.report_warning('video doesn\'t have subtitles')
              return {}
              return self._parse_json(
                  uppercase_escape(config), video_id, fatal=False)
  
 +    def _get_yt_initial_data(self, video_id, webpage):
 +        config = self._search_regex(
 +            (r'window\["ytInitialData"\]\s*=\s*(.*?)(?<=});',
 +             r'var\s+ytInitialData\s*=\s*(.*?)(?<=});'),
 +            webpage, 'ytInitialData', default=None)
 +        if config:
 +            return self._parse_json(
 +                uppercase_escape(config), video_id, fatal=False)
 +
      def _get_automatic_captions(self, video_id, webpage):
          """We need the webpage for getting the captions url, pass it as an
             argument to speed up the process."""
                      player_response, video_id, fatal=False)
                  if player_response:
                      renderer = player_response['captions']['playerCaptionsTracklistRenderer']
 -                    base_url = renderer['captionTracks'][0]['baseUrl']
 -                    sub_lang_list = []
 -                    for lang in renderer['translationLanguages']:
 -                        lang_code = lang.get('languageCode')
 -                        if lang_code:
 -                            sub_lang_list.append(lang_code)
 -                    return make_captions(base_url, sub_lang_list)
 -
 +                    caption_tracks = renderer['captionTracks']
 +                    for caption_track in caption_tracks:
 +                        if 'kind' not in caption_track:
 +                            # not an automatic transcription
 +                            continue
 +                        base_url = caption_track['baseUrl']
 +                        sub_lang_list = []
 +                        for lang in renderer['translationLanguages']:
 +                            lang_code = lang.get('languageCode')
 +                            if lang_code:
 +                                sub_lang_list.append(lang_code)
 +                        return make_captions(base_url, sub_lang_list)
 +
 +                    self._downloader.report_warning("Couldn't find automatic captions for %s" % video_id)
 +                    return {}
              # Some videos don't provide ttsurl but rather caption_tracks and
              # caption_translation_languages (e.g. 20LmZk1hakA)
              # Does not used anymore as of 22.06.2017
      def _extract_chapters_from_json(self, webpage, video_id, duration):
          if not webpage:
              return
 -        player = self._parse_json(
 +        initial_data = self._parse_json(
              self._search_regex(
 -                r'RELATED_PLAYER_ARGS["\']\s*:\s*({.+})\s*,?\s*\n', webpage,
 +                r'window\["ytInitialData"\] = (.+);\n', webpage,
                  'player args', default='{}'),
              video_id, fatal=False)
 -        if not player or not isinstance(player, dict):
 -            return
 -        watch_next_response = player.get('watch_next_response')
 -        if not isinstance(watch_next_response, compat_str):
 -            return
 -        response = self._parse_json(watch_next_response, video_id, fatal=False)
 -        if not response or not isinstance(response, dict):
 +        if not initial_data or not isinstance(initial_data, dict):
              return
          chapters_list = try_get(
 -            response,
 +            initial_data,
              lambda x: x['playerOverlays']
                         ['playerOverlayRenderer']
                         ['decoratedPlayerBarRenderer']
              ''', replace_url, video_description)
              video_description = clean_html(video_description)
          else:
-             video_description = video_details.get('shortDescription') or self._html_search_meta('description', video_webpage)
+             video_description = video_details.get('shortDescription')
+             if video_description is None:
+                 video_description = self._html_search_meta('description', video_webpage)
  
          if not smuggled_data.get('force_singlefeed', False):
              if not self._downloader.params.get('noplaylist'):
          if is_live is None:
              is_live = bool_or_none(video_details.get('isLive'))
  
 +        has_live_chat_replay = False
 +        if not is_live:
 +            yt_initial_data = self._get_yt_initial_data(video_id, video_webpage)
 +            try:
 +                yt_initial_data['contents']['twoColumnWatchNextResults']['conversationBar']['liveChatRenderer']['continuations'][0]['reloadContinuationData']['continuation']
 +                has_live_chat_replay = True
 +            except (KeyError, IndexError, TypeError):
 +                pass
 +
          # Check for "rental" videos
          if 'ypc_video_rental_bar_text' in video_info and 'author' not in video_info:
              raise ExtractorError('"rental" videos not supported. See https://github.com/ytdl-org/youtube-dl/issues/359 for more information.', expected=True)
              or try_get(video_info, lambda x: float_or_none(x['avg_rating'][0])))
  
          # subtitles
 -        video_subtitles = self.extract_subtitles(video_id, video_webpage)
 +        video_subtitles = self.extract_subtitles(
 +            video_id, video_webpage, has_live_chat_replay)
          automatic_captions = self.extract_automatic_captions(video_id, video_webpage)
  
          video_duration = try_get(
index e66558ea6fe249bd90d860d818912592be0651e3,5a33595886853e95c52ffbfa465193260d8f8893..4a0d02fc4a226a0d096965019d24c8eab76780c3
@@@ -13,6 -13,7 +13,7 @@@ from ..utils import 
      encodeFilename,
      PostProcessingError,
      prepend_extension,
+     replace_extension,
      shell_quote
  )
  
@@@ -41,27 -42,37 +42,37 @@@ class EmbedThumbnailPP(FFmpegPostProces
                  'Skipping embedding the thumbnail because the file is missing.')
              return [], info
  
-         # Check for mislabeled webp file
-         with open(encodeFilename(thumbnail_filename), "rb") as f:
-             b = f.read(16)
-         if b'\x57\x45\x42\x50' in b:  # Binary for WEBP
-             [thumbnail_filename_path, thumbnail_filename_extension] = os.path.splitext(thumbnail_filename)
-             if not thumbnail_filename_extension == ".webp":
-                 webp_thumbnail_filename = thumbnail_filename_path + ".webp"
-                 os.rename(encodeFilename(thumbnail_filename), encodeFilename(webp_thumbnail_filename))
-                 thumbnail_filename = webp_thumbnail_filename
-         # If not a jpg or png thumbnail, convert it to jpg using ffmpeg
-         if not os.path.splitext(thumbnail_filename)[1].lower() in ['.jpg', '.png']:
-             jpg_thumbnail_filename = os.path.splitext(thumbnail_filename)[0] + ".jpg"
-             jpg_thumbnail_filename = os.path.join(os.path.dirname(jpg_thumbnail_filename), os.path.basename(jpg_thumbnail_filename).replace('%', '_'))  # ffmpeg interprets % as image sequence
-             self._downloader.to_screen('[ffmpeg] Converting thumbnail "%s" to JPEG' % thumbnail_filename)
-             self.run_ffmpeg(thumbnail_filename, jpg_thumbnail_filename, ['-bsf:v', 'mjpeg2jpeg'])
-             os.remove(encodeFilename(thumbnail_filename))
-             thumbnail_filename = jpg_thumbnail_filename
+         def is_webp(path):
+             with open(encodeFilename(path), 'rb') as f:
+                 b = f.read(12)
+             return b[0:4] == b'RIFF' and b[8:] == b'WEBP'
+         # Correct extension for WebP file with wrong extension (see #25687, #25717)
+         _, thumbnail_ext = os.path.splitext(thumbnail_filename)
+         if thumbnail_ext:
+             thumbnail_ext = thumbnail_ext[1:].lower()
+             if thumbnail_ext != 'webp' and is_webp(thumbnail_filename):
+                 self._downloader.to_screen(
+                     '[ffmpeg] Correcting extension to webp and escaping path for thumbnail "%s"' % thumbnail_filename)
+                 thumbnail_webp_filename = replace_extension(thumbnail_filename, 'webp')
+                 os.rename(encodeFilename(thumbnail_filename), encodeFilename(thumbnail_webp_filename))
+                 thumbnail_filename = thumbnail_webp_filename
+                 thumbnail_ext = 'webp'
+         # Convert unsupported thumbnail formats to JPEG (see #25687, #25717)
+         if thumbnail_ext not in ['jpg', 'png']:
+             # NB: % is supposed to be escaped with %% but this does not work
+             # for input files so working around with standard substitution
+             escaped_thumbnail_filename = thumbnail_filename.replace('%', '#')
+             os.rename(encodeFilename(thumbnail_filename), encodeFilename(escaped_thumbnail_filename))
+             escaped_thumbnail_jpg_filename = replace_extension(escaped_thumbnail_filename, 'jpg')
+             self._downloader.to_screen('[ffmpeg] Converting thumbnail "%s" to JPEG' % escaped_thumbnail_filename)
+             self.run_ffmpeg(escaped_thumbnail_filename, escaped_thumbnail_jpg_filename, ['-bsf:v', 'mjpeg2jpeg'])
+             os.remove(encodeFilename(escaped_thumbnail_filename))
+             thumbnail_jpg_filename = replace_extension(thumbnail_filename, 'jpg')
+             # Rename back to unescaped for further processing
+             os.rename(encodeFilename(escaped_thumbnail_jpg_filename), encodeFilename(thumbnail_jpg_filename))
+             thumbnail_filename = thumbnail_jpg_filename
  
          if info['ext'] == 'mp3':
              options = [
              os.remove(encodeFilename(filename))
              os.rename(encodeFilename(temp_filename), encodeFilename(filename))
  
 +        elif info['ext'] == 'mkv':
 +            os.rename(encodeFilename(thumbnail_filename), encodeFilename('cover.jpg'))
 +            old_thumbnail_filename = thumbnail_filename
 +            thumbnail_filename = 'cover.jpg'
 +
 +            options = [
 +                '-c', 'copy', '-attach', thumbnail_filename, '-metadata:s:t', 'mimetype=image/jpeg']
 +
 +            self._downloader.to_screen('[ffmpeg] Adding thumbnail to "%s"' % filename)
 +
 +            self.run_ffmpeg_multiple_files([filename], temp_filename, options)
 +
 +            if not self._already_have_thumbnail:
 +                os.remove(encodeFilename(thumbnail_filename))
 +            else:
 +                os.rename(encodeFilename(thumbnail_filename), encodeFilename(old_thumbnail_filename))
 +            os.remove(encodeFilename(filename))
 +            os.rename(encodeFilename(temp_filename), encodeFilename(filename))
 +
          elif info['ext'] in ['m4a', 'mp4']:
              if not check_executable('AtomicParsley', ['-v']):
                  raise EmbedThumbnailPPError('AtomicParsley was not found. Please install.')
diff --combined youtube_dlc/version.py
index af04ea8b94588c0fcc9fd86f20b52f212598d140,5625b8324ce0e901c95c8401d06d03341fd3b937..5625b8324ce0e901c95c8401d06d03341fd3b937
@@@ -1,3 -1,3 +1,3 @@@
  from __future__ import unicode_literals
  
- __version__ = '2020.09.13'
+ __version__ = '2020.09.14'