Can't play YouTube videos from Watch Later in Plex Web App in Google Chrome

Issue:
Trying to play a YouTube videos from the Watch Later list, using the Web app in Google Chrome, doesn’t work.
I just see a loading animation, and nothing happens.
Trying to play the same YouTube video from the Watch Later list in Plex Media Player, from the same client computer, works correctly. Same when trying using the Plex web app in Safari.
The issue seems to be only with Chrome.

This has been an issue for many months, in various Google Chrome and PMS versions.

Google Chrome: Version 60.0.3112.66
Plex Web: Version 3.11.0
Plex Server: Version 1.7.6.4058
OS: 4.9.0-3-amd64 #1 SMP Debian 4.9.30-2+deb9u2

Chrome Developer Console shows this (I also attached this image as ChromeDevConsole.png):


The POST to PlayVideo just hangs.

On the server (see attached logs):

  • Excerpt from Plex Media Server.log (attached):
Jul 18, 2017 11:44:15.633 [0x7f8efe3fe700] DEBUG - [com.plexapp.system] Sending command over HTTP (POST): /:/plugins/com.plexapp.system/serviceFunction/url/com.plexapp.plugins.youtube/YouTube/PlayVideo?args=...&kwargs=...
Jul 18, 2017 11:44:15.633 [0x7f8efe3fe700] DEBUG - HTTP requesting POST http://127.0.0.1:42259/:/plugins/com.plexapp.system/serviceFunction/url/com.plexapp.plugins.youtube/YouTube/PlayVideo?args=...&kwargs=...
Jul 18, 2017 11:44:35.105 [0x7f8f037fe700] VERBOSE - We didn't receive any data from 127.0.0.1:36432 in time, dropping connection.
Jul 18, 2017 11:44:35.161 [0x7f8f037fe700] VERBOSE - We didn't receive any data from 127.0.0.1:36436 in time, dropping connection.
  • Excerpt from com.plexapp.system.log (attached):
2017-07-18 11:44:15,010 (7f4b5d7fa700) :  DEBUG (networking:166) - Requesting 'https://www.youtube.com/watch?v=E4U3TeY2wtM'
2017-07-18 11:44:15,492 (7f4b5d7fa700) :  DEBUG (runtime:88) - Sending packed state data (1391 bytes)
2017-07-18 11:44:15,493 (7f4b5d7fa700) :  DEBUG (runtime:924) - Response: [200] str, 45435 bytes

I tried deleting the following folders & files, and restarting PMS. Those folders & files are NOT re-created when I try to play a YouTube video from the Watch Later list.

  • Logs/PMS Plugin Logs/com.plexapp.plugins.youtube.log*
  • Plug-in Support/Caches/com.plexapp.plugins.youtube
  • Plug-in Support/Data/com.plexapp.plugins.youtube
  • Plug-in Support/Preferences/com.plexapp.plugins.youtube.xml

I tried using curl on the command line of my server running PMS, to test the last URL seen in Plex Media Server.log, and it seems to work fine:

$ curl -X POST 'http://127.0.0.1:42259/:/plugins/com.plexapp.system/serviceFunction/url/com.plexapp.plugins.youtube/YouTube/PlayVideo?args=...&kwargs=...'
<?xml version='1.0' encoding='utf-8'?>
<MediaContainer size="1" identifier="com.plexapp.system" mediaTagPrefix="/system/bundle/media/flags/">
  <Video sourceIcon="http://resources-cdn.plexapp.com/image/source/com.plexapp.plugins.youtube.jpg?h=3d66c94" key="https://r2---sn-cxaaj5o5q5-t0az.googlevideo.com/videoplayback?mime=video%2Fmp4&pcm2cms=yes&dur=109.203&itag=22&ipbits=0&expire=1500415085&signature=...&initcwndbps=2942500&key=yt6&sparams=dur%2Cei%2Cid%2Cinitcwndbps%2Cip%2Cipbits%2Citag%2Clmt%2Cmime%2Cmm%2Cmn%2Cms%2Cmv%2Cpcm2cms%2Cpl%2Cratebypass%2Crequiressl%2Csource%2Cexpire&lmt=1500060431103530&requiressl=yes&ip=70.30.232.183&ratebypass=yes&mn=sn-cxaaj5o5q5-t0az&mm=31&source=youtube&pl=22&mv=m&mt=1500393362&ms=au&ei=DTBuWZy1JommugK1_YiIDA&id=o-ANE3r52mIRH7Vmny0HMAkCJEjLuf6CZiIDaVKdfa3pV8" type="clip">
    <Media optimizedForStreaming="1" height="1080" width="1920" container="mp4" audioCodec="aac" videoCodec="h264" videoResolution="1080">
      <Part container="mp4" key="https://r2---sn-cxaaj5o5q5-t0az.googlevideo.com/videoplayback?mime=video%2Fmp4&pcm2cms=yes&dur=109.203&itag=22&ipbits=0&expire=1500415085&signature=...&initcwndbps=2942500&key=yt6&sparams=dur%2Cei%2Cid%2Cinitcwndbps%2Cip%2Cipbits%2Citag%2Clmt%2Cmime%2Cmm%2Cmn%2Cms%2Cmv%2Cpcm2cms%2Cpl%2Cratebypass%2Crequiressl%2Csource%2Cexpire&lmt=1500060431103530&requiressl=yes&ip=70.30.232.183&ratebypass=yes&mn=sn-cxaaj5o5q5-t0az&mm=31&source=youtube&pl=22&mv=m&mt=1500393362&ms=au&ei=DTBuWZy1JommugK1_YiIDA&id=o-ANE3r52mIRH7Vmny0HMAkCJEjLuf6CZiIDaVKdfa3pV8" file="" optimizedForStreaming="1">
        <Stream index="0" selected="1" streamType="1" height="1080" width="1920" codec="h264" id="1"/>
        <Stream index="1" selected="1" streamType="2" codec="aac" id="2"/>
      </Part>
    </Media>
  </Video>
</MediaContainer>

I also attached the Plex Media Server.log for when this YouTube video played correctly in Safari (see Plex Media Server-working-in-Safari.log). It looks like transcoding is used for Safari, but in Chrome, I thinks it tries to play the video as-is, and I think that is what is broken.
The Cache/Data files I deleted are not re-created when the YouTube videos is played successfully, so I don’t think those are created anymore, or they are just created when a video is played directly, instead of being transcoded.

Might be relevant: the last log in the Chrome Developer Console is this:

[Log] [PDE] Resolving indirect item

In Safari I get:

[Log] [PDE] Resolving indirect item
[...]
[Log] [PDE] Player decision (main-0-e4d7a2b78a0957c060dc-plex-3.11.0-1fe7810.js, line 2791)
[Info] Player: html (main-0-e4d7a2b78a0957c060dc-plex-3.11.0-1fe7810.js, line 2791)
[Info] Protocol: http (main-0-e4d7a2b78a0957c060dc-plex-3.11.0-1fe7810.js, line 2791)
[Info] Direct Play: true (main-0-e4d7a2b78a0957c060dc-plex-3.11.0-1fe7810.js, line 2791)
[PDE] DASH and HLS should seek forward by default, offset=0
[Log] [Transcoder] Video (decision) options (main-0-e4d7a2b78a0957c060dc-plex-3.11.0-1fe7810.js, line 2791)
[...]

And the POST to PlayVideo that hangs in Chrome works fine.

Something I noticed that is different between the PlayVideo POST made in Chrome and the one made in Safari:
In Safari, the request body is plain-text HTML, while in Chrome, it is binary data, which I would assume to be the same data, but compressed.

If I had to guess, I would think this is where the problem comes from. PMS expects plain-text HTML, and when it receives compressed data, it doesn’t know how to handle that.

There is a known issue with the POST request necessary for YouTube video to properly play, but only on the Plex Web App on the Chrome browser. They believe it is an issue within Plex Media Server, but since it only affects the Plex Web app on Chrome, this thread is the best place to add your comments and check on any progress resolving the issue - forums.plex.tv/discussion/272005/unable-to-play-watch-later-youtube-videos-on-plex-web.

I found that the POSTed data is the response of the GET /system/proxy HTTP call.

Looking for differences in the HTTP requests in both browsers, I see this the Accept-Encoding header sent by Chrome is what seems to be causing the issues.

In Chrome:

GET https://70-30-232-183.bc0b6a8408d14bb884727d4b325d1059.plex.direct:34200/system/proxy
[...]
Accept-Encoding: gzip, deflate, br

Results in those headers in the response:

Content-Encoding: gzip
X-Plex-Content-Original-Length: 44260
X-Plex-Content-Compressed-Length: 44268
Content-Length: 44268

While in Safari, I see this:

GET https://70-30-232-183.bc0b6a8408d14bb884727d4b325d1059.plex.direct:34200/system/proxy
[...]
Accept-Encoding: gzip, deflate

And the HTTP response headers:

Content-Encoding: gzip
X-Plex-Content-Original-Length: 203417
X-Plex-Content-Compressed-Length: 50598
Content-Length: 50598

And I confirmed, by sending the same request using CURL on a command line:

  • This request correctly returns HTML in plain-text:
$ curl -v -H 'Accept-Encoding: gzip, deflate' --compress "https://70-30-232-183.bc0b6a8408d14bb884727d4b325d1059.plex.direct:34200/system/proxy?X-Plex-Product=Plex%20Web&X-Plex-Version=3.11.0&X-Plex-Client-Identifier=0549acef-ec50-4611-9391-8954275faaf8&X-Plex-Platform=Safari&X-Plex-Platform-Version=10.1&X-Plex-Device=OSX&X-Plex-Device-Name=Plex%20Web%20%28Safari%29&X-Plex-Device-Screen-Resolution=1362x817%2C2560x1440&X-Plex-Token=${PLEX_TOKEN}&X-Plex-Url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DE4U3TeY2wtM"

While this request incorrectly returns double-compressed data (I only added , br to the Accept-Encoding header):

curl -v -H 'Accept-Encoding: gzip, deflate, br' --compress "https://70-30-232-183.bc0b6a8408d14bb884727d4b325d1059.plex.direct:34200/system/proxy?X-Plex-Product=Plex%20Web&X-Plex-Version=3.11.0&X-Plex-Client-Identifier=0549acef-ec50-4611-9391-8954275faaf8&X-Plex-Platform=Safari&X-Plex-Platform-Version=10.1&X-Plex-Device=OSX&X-Plex-Device-Name=Plex%20Web%20%28Safari%29&X-Plex-Device-Screen-Resolution=1362x817%2C2560x1440&X-Plex-Token=${PLEX_TOKEN}&X-Plex-Url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DE4U3TeY2wtM"

My guess: PMS is compressing an already compressed response it got from YouTube, and returns that double-compressed data to the web app, which then decompresses it (but only once), and send the still compressed (once) data to the PMS, using the PlayVideo POST.

And I confirmed the fix is as simple as preventing Chrome from sending the br in Accept-Encoding.
I used Charles proxy to place a breakpoint on the GET /system/proxy HTTP request, I edited the request headers by removing the , br in Accept-Encoding, and Chrome successfully played my YouTube video.

@Plex: not sure exactly how you are using the headers sent with the GET /system/proxy request, but I would suggest a fix on PMS that only keeps gzip, deflate in there, even if the client browser sends more values.

For end-users who can’t wait for Plex to fix this issue, you can install a Chrome extension that allows you to modify the HTTP headers sent to servers, and force the Accept-Encoding header to always send the value gzip, deflate

I tested with the Requestly extension, and the following settings:

You can import this rule in Requestly by visiting this URL after installing Requestly. Use the Import List button in the top-right corner.

And I (and you!) can now play YouTube videos without problems in Chrome. Yay!

Complement of information:

Looks like Accept-Encoding: br, AKA Brotli, is a new compression method enabled in Chrome starting in v50.

Advantages of Brotli over gzip: - significantly better compression density - comparable decompression speed
Ref

This would explain why I was never able to “gunzip” the data Chrome received, in the response to GET /system/proxy; it was compressed using a very funkily-named compression method!

Also probably explains why nothing else but YouTube was affected by this bug; nobody else is using Brotli except Google, so Chrome (the browser) and YouTube (the server), both supporting it, used it when talking to each other, but nobody else was understanding the conversation!

@gboudreau Thank you so much for your work on this! Indeed the problem is with the br encoding. I found a fix in the proxy code to make the backend not accept br encoded data and on my test PMS all YouTube videos started working in Chrome! I’m tying to find out who is currently maintaining the System bundle so (s)he can pull in the fix.

Update: I’ve been told that the info and fix have been passed on to the PMS dev team.

Versino 1.9.1.4272 of PMS seems to have broken the Requestly fix to force Accept-Encoding. Or something else went wrong and Watch Later is again broken.

@markwilliams said:
Versino 1.9.1.4272 of PMS seems to have broken the Requestly fix to force Accept-Encoding. Or something else went wrong and Watch Later is again broken.

The fix did not make it into PMS 1.9.1.4272-b207937f1. I’ve been promised that it will be in 1.9.3 (finally…, I kept track of the issue here).

I have PMS 1.9.4 and I can’t play YouTube Watch Later videos in Chrome or Edge or PMP.

@rmunday said:
I have PMS 1.9.4 and I can’t play YouTube Watch Later videos in Chrome or Edge or PMP.

Installed 1.9.4.4325 yesterday and it is still broken for me.