Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No playback of certain videos, infinite loading for HLS/DASH streams #2415

Closed
3 tasks
obfripper opened this issue Jun 21, 2019 · 69 comments · Fixed by #8153
Closed
3 tasks

No playback of certain videos, infinite loading for HLS/DASH streams #2415

obfripper opened this issue Jun 21, 2019 · 69 comments · Fixed by #8153
Labels
bug Issue is related to a bug requires extractor change This issue requires a change to the extractor

Comments

@obfripper
Copy link

obfripper commented Jun 21, 2019

I am having issues playing certain videos, they all exhibit the same problem by sitting with the spinning wheel and nothing happening. If i select an external player, there is a pause followed by an error notification, which I have screencapped and says 'the location.......full screen url....cannot be played'. The fault occurs only on some resolutions, and it has been observed that in most cases the qualities 720p or 360p always work (e.g. https://youtu.be/zCGouRiflIw).

For example videos;
https://www.youtube.com/watch?v=2NT-MRkYeSo
All the recent videos on his channel exhibit the same issue.

https://www.youtube.com/watch?v=ZHeqOwV5bow
Some of the video on this channel play, some do not.

@Stypox
Copy link
Member

Stypox commented Jun 21, 2019

Why are there both "&sig=" and "&lsig="? I think the second one makes no sense, but I could be wrong. I'll investigate

@theScrabi
Copy link
Member

Which version are u using?

@obfripper
Copy link
Author

0.16.2

@Stypox
Copy link
Member

Stypox commented Jun 21, 2019

It doesn't work for me either, but only on the WebM format. Here is the url I got from the extractor (I replaced my IP with X):

https://r16---sn-nx5cvox-hpae7.googlevideo.com/videoplayback?expire=1561147001&ei=GeIMXYzZF9bugAfg15b4Dw&ip=XX.XXX.XXX.X&id=o-AG0ApOUZOJ33f4ajMQAG7YiNYK1JvEH6BYveBSSKPGHM&itag=247&aitags=133%2C134%2C135%2C136%2C160%2C242%2C243%2C244%2C247%2C278&source=yt_otf&requiressl=yes&mm=31%2C26&mn=sn-nx5cvox-hpae7%2Csn-4g5e6nlk&ms=au%2Conr&mv=m&nh=EAE%2C&pcm2cms=yes&pl=19&initcwndbps=770000&mime=video%2Fwebm&otf=1&otfp=1&dur=0.000&lmt=1561056919842256&mt=1561125283&fvip=6&keepalive=yes&c=WEB&sparams=expire%2Cei%2Cip%2Cid%2Caitags%2Csource%2Crequiressl%2Cmime%2Cotf%2Cotfp%2Cdur%2Clmt&lsparams=mm%2Cmn%2Cms%2Cmv%2Cnh%2Cpcm2cms%2Cpl%2Cinitcwndbps&lsig=AHylml4wRQIhAOv1OJtRCSX85JZ-myiK-KrotoD6YcSE-2KeKUqWNJsNAiBLYXkNmxGviHtuyE_YXQbGW4lkbwkkxAwZ1OmZOoFqrg%3D%3D

Decoded:

https://r16---sn-nx5cvox-hpae7.googlevideo.com/videoplayback?expire=1561147001&ei=GeIMXYzZF9bugAfg15b4Dw&ip=XX.XXX.XXX.X&id=o-AG0ApOUZOJ33f4ajMQAG7YiNYK1JvEH6BYveBSSKPGHM&itag=247&aitags=133,134,135,136,160,242,243,244,247,278&source=yt_otf&requiressl=yes&mm=31,26&mn=sn-nx5cvox-hpae7,sn-4g5e6nlk&ms=au,onr&mv=m&nh=EAE,&pcm2cms=yes&pl=19&initcwndbps=770000&mime=video/webm&otf=1&otfp=1&dur=0.000&lmt=1561056919842256&mt=1561125283&fvip=6&keepalive=yes&c=WEB&sparams=expire,ei,ip,id,aitags,source,requiressl,mime,otf,otfp,dur,lmt&lsparams=mm,mn,ms,mv,nh,pcm2cms,pl,initcwndbps&lsig=AHylml4wRQIhAOv1OJtRCSX85JZ-myiK-KrotoD6YcSE-2KeKUqWNJsNAiBLYXkNmxGviHtuyE_YXQbGW4lkbwkkxAwZ1OmZOoFqrg==

@omarroth
Copy link

omarroth commented Jun 21, 2019

Appears jdf76/plugin.video.youtube#624 fixes this by adding r'(?P<name>[a-zA-Z0-9$]+)\(', to the list of function patterns it uses.

I'd recommend changing DECYRYPTION_SIGNATURE_FUNCTION_REGEX to what Invidious uses (/^(?<name>[^=]+)=function\(a\){a=a\.split\(""\)/m) to see if it fixes the issue.

@Stypox
Copy link
Member

Stypox commented Jun 21, 2019

I can't convert that regex to the java dialect... this is the regex I tried:

"/^([^=]+)=function\\(a\\)\\{a=a\\.split\\(\"\"\\)/m"

I removed the ?<name> part since the java parser currently matches the first group (it should give the same resoult, shouldn't it?). Also I put a \ before the {, otherwise it would have given this error: PatternSyntaxException: Error in {min,max} interval near index 25, where 25 pointed to the = in {a=. The current error I get is RegexException: failed to find pattern "/^([^=]+)=function\(a\)\{a=a\.split\(""\)/m (I don't know why " is missing at the end)

@omarroth
Copy link

Try removing the leading and trailing slashes (/, /m).

@luca233
Copy link

luca233 commented Jun 21, 2019

cannot resolve with "/^([^=]+)=function(a){a=a.split("")/m and
^([^=]+)=function(a){a=a.split("")

@theScrabi
Copy link
Member

theScrabi commented Jun 21, 2019

@TobiGr this calls for an emergency release shall i take care of release once it it fixed or will you?

@Stypox
Copy link
Member

Stypox commented Jun 22, 2019

By using only the first part of the regex ^([^=]+)=function\(a\)\{a=a\.split\(\" against playerCode I manually found two matches:

Aq=function(a){a=a.split("&");for(var b={},c=0,d=a.length;c<d;c++){var e=a[c].split("=");if(1==e.length&&e[0]||2==e.length)try{var f=Xc(e[0]||""),k=Xc(e[1]||"");f in b?g.Ka(b[f])?ib(b[f],k):b[f]=[b[f],k]:b[f]=k}catch(m){var l=Error("Error decoding URL component");l.params="key: "+e[0]+", value: "+e[1];"q"==e[0]?g.Vp(l):g.L(l)}}return b};
Dq=function(a){a=a.split(",");return a=a.map(function(b){return g.Cq(b)})};

But both of them have something between the " ", so it can't be matched by `^([^=]+)=function(a){a=a.split(""). Using the old regex truncated before the " " I get the same result.

If I, instead, use this part of the regex \.split\(""\) I get these four lines:

jaa=function(a,b){for(var c=g.Da(a)?a.split(""):a,d=a.length-1;0<=d;--d)d in c&&b.call(void 0,c[d],d,a)};
g.Wa=function(a,b,c){for(var d=a.length,e=g.Da(a)?a.split(""):a,f=0;f<d;f++)if(f in e&&b.call(c,e[f],f,a))return f;return-1};
g.Ya=function(a,b,c){for(var d=g.Da(a)?a.split(""):a,e=a.length-1;0<=e;e--)if(e in d&&b.call(c,d[e],e,a))return e;return-1};
xi=function(a,b,c,d,e){if(null==a)return"";b=b||"&";c=c||",$";"string"==typeof c&&(c=c.split(""));if(a instanceof Array){if(d=d||0,d<c.length){for(var f=[],k=0;k<a.length;k++)f.push(xi(a[k],b,c,d+1,e));return f.join(c[d])}}else if("object"==typeof a)return e=e||0,2>e?encodeURIComponent(yi(a,b,c,d,e+1)):"...";return encodeURIComponent(String(a))};

I also tried this regex but it only works if I use the part before " ", as above.

@Stypox Stypox added bug Issue is related to a bug requires extractor change This issue requires a change to the extractor labels Jun 22, 2019
@TobiGr
Copy link
Contributor

TobiGr commented Jun 23, 2019

@theScrabi That's a good question. I currently have little time due to upcoming exams. So it would be better if you take care of it. Nevertheless, we need a fix before we release something :D

@theScrabi
Copy link
Member

I'll take care of it. @Stypox has a fix already been send to the extractor?

@Stypox
Copy link
Member

Stypox commented Jun 27, 2019

No, I'm sorry, but I wasn't able to get the regex to work (see comment above). Maybe @omarroth can help? :-)
I have playerCode in a plain text file, if needed.

@omarroth
Copy link

omarroth commented Jun 28, 2019

Would you mind testing with omarroth/NewPipeExtractor@098b835 to see if it works as expected? Currently it appears NewPipe has no trouble with the existing regex, so please do provide the saved playerCode to test with.

@Stypox
Copy link
Member

Stypox commented Jun 28, 2019

omarroth/NewPipeExtractor@098b835 seems to have the same problems (Error 404)...
Here is the playerCode: playercode.txt. Strings are in italian language since I am in Italy, but I don't think that matters.
Hope not to bother you :)

@Stypox
Copy link
Member

Stypox commented Jun 28, 2019

I just tried downloading on invidious the same video and the only video format that can be downloaded is 360pMPEG4 (the same as NewPipe) so I don't think that new regex will fix this problem

@omarroth
Copy link

omarroth commented Jun 28, 2019

Taking another look, the video in question is likely a livestream that was uploaded later as a normal video. Playback appears to work as expected, download I expect doesn't work since the file itself is split up into ~90 segments (from looking at the DASH manifest).

@papb
Copy link

papb commented Jul 13, 2019

I am also having this problem, almost any music-related video stays forever in the spinner for me... (Note: background play doesn't work too.)

Example of video that plays: https://www.youtube.com/watch?v=kpk2tdsPh0A
Example of video that stays in the spinner forever: https://www.youtube.com/watch?v=JGwWNGJdvx8

@drh48
Copy link

drh48 commented Jul 25, 2019

I've been dealing with this problem for quite some time now. Nearly all music-related videos stay spinning, but no non-music videos do. Any updates?

@theScrabi
Copy link
Member

@omarroth @Stypox have you tried to take a look at youtube-dl? Best guess is that it works there, if not we have ptoblems.

@Stypox
Copy link
Member

Stypox commented Jul 26, 2019

youtube-dl has this issue, too.
By doing youtube-dl --get-url --all-formats https://youtube.com/watch?v=umdZD8zRj4A I got 14 different urls, and I opened them all in Firefox:

  • 3 of them were working audio-only streams
  • 3 of them were working video-only streams
  • the other 8 urls did not work (error 404)

@Stypox
Copy link
Member

Stypox commented Jul 26, 2019

🤔 The 8 urls that do not work in the browser are DASH-videos, and they download fine with youtube-dl. By looking through the dash manifests I found an url that works in the browser. Is the NewPipeExtractor downloading dash manifests and parsing them?

@Stypox
Copy link
Member

Stypox commented Jul 26, 2019

After some hours of reading code I understand what's wrong. The extractor correctly extracts the urls, but those links lead to DASH playbacks. I will call those DASH urls "base url"s.

By adding &sq=0 to the base url we get the DASH "Initialization" url and when a request is sent to it the response is something along these lines (after decoding from UTF7-base64):

ftypdashiso6avc1mp41moovlmvhdXgXg_@(mvex trextraktkhdXgXg@mdia mdhdXgXg_U_hdlrvideISO Media file produced by Google Inc. Created on: 07/20/2019.2minf$dinfdrefurl stblstsdavc1HH0avcCM@gM@
(U@hsttsstscstcostszstssvmhdemsghttp://youtube.com/streaming/otf/durations/112015*Segment-Count: 55
Segment-Durations-Ms: 5339(r=53),2736,

There is some junk (probably UTF7-base64 is not the correct encoding), but some useful DASH information can be extracted anyway: Segment-Count tells us that there are 55 DASH fragments. This means that by adding &sq=N with 1<=N<=55 to the base url we can get the 55 fragments. YAY!

The base url works even after replacing all params separators (i.e. '&', '?', '=') with '/'. In this case the initialization url would be BaseUrl+"/" + "sq/0" and the fragment urls would be BaseUrl+"/" + "sq/N". This new url is required to build a valid XML file that has no unescaped characters like '&' (MPD uses XML).
Using this information I was able to build a valid MPD file (playable by vlc, although not seekable):

<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns:yt="http://youtube.com/yt/2012/10/10" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" minBufferTime="PT1.500S" profiles="urn:mpeg:dash:profile:isoff-main:2011" type="static" mediaPresentationDuration="PT291.131S">
	<Period>
		<AdaptationSet id="2" mimeType="video/mp4" subsegmentAlignment="true">
			<Representation id="135" codecs="avc1.4d4014" width="854" height="480" startWithSAP="1" maxPlayoutRate="1" bandwidth="1155000" frameRate="30">
				<BaseURL>DECODED_AND_ESCAPED_BASE_URL</BaseURL>
				<SegmentList>
					<Initialization sourceURL="sq/0"/>
					<SegmentURL media="sq/1"/>
					<SegmentURL media="sq/2"/>
					<SegmentURL media="sq/3"/>
					<SegmentURL media="sq/4"/>
					<SegmentURL media="sq/5"/>
					<SegmentURL media="sq/6"/>
					<SegmentURL media="sq/7"/>
					<SegmentURL media="sq/8"/>
					<SegmentURL media="sq/9"/>
					<SegmentURL media="sq/10"/>
					<SegmentURL media="sq/11"/>
					<SegmentURL media="sq/12"/>
					<SegmentURL media="sq/13"/>
					<SegmentURL media="sq/14"/>
					<SegmentURL media="sq/15"/>
					<SegmentURL media="sq/16"/>
					<SegmentURL media="sq/17"/>
					<SegmentURL media="sq/18"/>
					<SegmentURL media="sq/19"/>
					<SegmentURL media="sq/20"/>
					<SegmentURL media="sq/21"/>
					<SegmentURL media="sq/22"/>
					<SegmentURL media="sq/23"/>
					<SegmentURL media="sq/24"/>
					<SegmentURL media="sq/25"/>
					<SegmentURL media="sq/26"/>
					<SegmentURL media="sq/27"/>
					<SegmentURL media="sq/28"/>
					<SegmentURL media="sq/29"/>
					<SegmentURL media="sq/30"/>
					<SegmentURL media="sq/31"/>
					<SegmentURL media="sq/32"/>
					<SegmentURL media="sq/33"/>
					<SegmentURL media="sq/34"/>
					<SegmentURL media="sq/35"/>
					<SegmentURL media="sq/36"/>
					<SegmentURL media="sq/37"/>
					<SegmentURL media="sq/38"/>
					<SegmentURL media="sq/39"/>
					<SegmentURL media="sq/40"/>
					<SegmentURL media="sq/41"/>
					<SegmentURL media="sq/42"/>
					<SegmentURL media="sq/43"/>
					<SegmentURL media="sq/44"/>
					<SegmentURL media="sq/45"/>
					<SegmentURL media="sq/46"/>
					<SegmentURL media="sq/47"/>
					<SegmentURL media="sq/48"/>
					<SegmentURL media="sq/49"/>
					<SegmentURL media="sq/50"/>
					<SegmentURL media="sq/51"/>
					<SegmentURL media="sq/52"/>
					<SegmentURL media="sq/53"/>
					<SegmentURL media="sq/54"/>
					<SegmentURL media="sq/55"/>
				</SegmentList>
			</Representation>
		</AdaptationSet>
	</Period>
</MPD>

DECODED_AND_ESCAPED_BASE_URL is created by doing this (in pseudocode): baseUrl.decodeUrl().replace('&', '/').replace('?', '/').replace('=', '/').append('/')

Note: youtube-dl does something different with DASH files. It downloads the MPD file provided in ytPlayerConfig["args"]["player_response"]["streamingData"]["dashManifestUrl"], that contains all of the supported formats (even non-DASH ones, it seems like). That file is ready to be played by a DASH player: vlc opened it just fine. Then ytdl extracts the formats along with their segment data: every extracted DASH stream has:

  • the "BaseUrl": same as the base url from above, but in the XML-compatible format
  • the "Initialization" string always equal to sq/0 to append to the base url (same as above, but in the other format).
  • many SegmentURLs: they are sq/N/dur/DURATION. /dur/DURATION seems to be useless and can be removed, but ytdl does not do it. Notice the similarity with &sq=N from above?

When ytdl wants to download a DASH file it just downloads all the fragments by concatenating the base url with the url of the segment (it just ignores initialization).

@Stypox
Copy link
Member

Stypox commented Jul 26, 2019

@TobiGr @theScrabi @omarroth how should I proceed?
The ExoPlayer is able to play DASH MPD files, so we could just do the same procedure as above to generate a MPD file and feed it to the player.

But I don't think this can be implemented with the current NewPipeExtractor infrastructure, since a Stream can only provide an url.

An option would be to add the function getDashFile() to Stream (that returns the MPD file content or null) along with the boolean isDashStream() function.

Another option would be to treat DASH files as a completely different stream type and create a new DashStream class extending Stream, that provides getDashFile(). Would this be feasible? I don't think so, since NewPipe uses all stream instances through the base class.

Another option still would be to ignore DASH streams. Very few videos have this problem with DASH video streams, and as far as I know there is always an alternative to that (e.g. the video from @obfripper has the 360p format that works)

youtube-dl currently has a list of possible protocols and chooses the needed one based on the stream format.

@Pentaphon
Copy link

Would it not be possible to give an option to use ytdl on our backend?

I wish Newpipe would just use yt-dl and let us update it ourselves instead of having to maintain their own extractor

@Flam3z
Copy link

Flam3z commented Aug 29, 2020

I appreciate the team using their own extractor, it also gives room to improve on it.

@seniorm0ment
Copy link

seniorm0ment commented Aug 29, 2020

@Pentaphon I agree, but I'm not entirely sure if there's a specific reason why they choose not to do that, because it seems like it'd be the easiest.
That being said, I still think it would be a good option if we could have it. At the very least as an option. Even if we like Newpipes extractor, it's clear it's not stable. Maybe adding the option for ytdl if one chooses, or as a fallback.

@Pentaphon
Copy link

I appreciate the team using their own extractor, it also gives room to improve on it.

Or everybody with extraction skills can just focus on improving youtube-dl while people with other skills work on Newpipe as a yt-dl frontend only. Every time Google breaks Newpipe, yt-dl fixes it first and then we have to wait for Newpipe to basically adapt the fix to the extractor. It makes way more sense to just download the latest yt-dl to Newpipe instead of rolling out a new version of Newpipe every time something breaks.

I've raised the topic here: #4202

Hopefully, enough people can agree that we are just creating more work and the project can turn to that direction.

@opusforlife2
Copy link
Collaborator

mpv-android is adding youtube-dl support. You can use that as an external player now.

@seniorm0ment
Copy link

@opusforlife2 It would be nice however not needing to use an external player.

@ghost
Copy link

ghost commented Aug 31, 2020

Wouldn't it be hard to implement yt-dl for Android since they are written in python?

@opusforlife2
Copy link
Collaborator

mpv-android is adding youtube-dl support. You can use that as an external player now.

Correction: it's actually been available since 2017 or so. The apk is available in the PR. It's just that the NanoDroid version of mpv-android was updated to include youtube-dl, which is where I learned of it.

@wb9688
Copy link
Contributor

wb9688 commented Oct 2, 2020

In v0.20.0, we still won't be able to play those streams, but the non-playing streams won't be shown in the app.

@opusforlife2
Copy link
Collaborator

Which means you won't have to get irritated, then try the 1080p stream, see if it works or not, then try 360p.

@Atemu
Copy link
Contributor

Atemu commented Oct 12, 2020

I haven't experienced this issue in quite a while eventhough I regularly watch smaller channels (views in the tens or hundreds) and this used to happen very often.

The videos in this thread that are still available and some other ones I remember not working play just fine now.

Is anyone still able to reproduce?

I've noticed that the streams are now the 1080p h264 versions eventhough vp9 ones are available according to ytdl but, while not optimal, it's a rather minor issue compared to not playing at all.

@Stypox
Copy link
Member

Stypox commented Oct 13, 2020

@Atemu this issue was fixed in 0.20.0, but only as a workaround, i.e. detecting the failing streams and hiding them. A real fix, allowing to play dash streams, needs to be implemented.

@opusforlife2
Copy link
Collaborator

I keep saying to close this and open a new issue for implementing DASH playback. <(`^´)>

@Pentaphon
Copy link

I keep saying to close this and open a new issue for implementing DASH playback. <(`^´)>

Or just edit the title to say "Implement DASH playback"

@AudricV
Copy link
Member

AudricV commented Jun 1, 2021

Just a small update that TeamNewPipe/NewPipeExtractor#604 will make further qualities available in the app:

  • for URLs protected with signatureCiphers (like music videos), you will now get a MP4 720p stream with audio and video embedded in the same file (itag 22 of YouTube) (if the extraction of the mobile API success, otherwise, it will fallback on the desktop version of the streams: in this case, you will get a MP4 720p stream with separated audio and video streams);
  • for videos which have streams not supported by NewPipe (OTF streams), you will get one two video streams returned on the mobile website and on the Android app in the 3GPP format: they have a very low quality: a 144p stream (8fps, very low audio bitrate) (itag 17) and a 180/240p stream with a low audio quality (itag 36) (edit: this itag is now removed by YouTube) ;
  • if the stream is protected by signatureCiphers or has OTF streams, you will now get a 48kbps M4A audio stream (itag 139).

(Try by yourself using the APK linked in this PR (note that there are some bugs that prevent it to be merged as it is).)

@AudricV
Copy link
Member

AudricV commented Jun 19, 2021

Can you please test the APK in #6537 and check if you have all the qualities available on YouTube in MP4 and WEBM formats, even those that are not currently available in the current version of NewPipe? Thank you in advance!

@opusforlife2
Copy link
Collaborator

@TiA4f8R It works! The WebM and MP4 streams both load fine. The only downside is that they take much more time to load than progressive streams.

Also, all video items in lists are marked LIVE for some reason.

@TobiGr
Copy link
Contributor

TobiGr commented Jun 19, 2021

@TiA4f8R Works good!

Also, all video items in lists are marked LIVE for some reason.

@opusforlife2 That's my fault. See TeamNewPipe/NewPipeExtractor#658

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue is related to a bug requires extractor change This issue requires a change to the extractor
Projects
None yet