Search code examples
pythonpytube

I failed to use pytube.Youtube.streams. It was still working few days ago


Recently, I've created a youtube video downloading tool for my bookmark. It is finished and still able to download youtube video. But today when I try to use it, it shows error when I try to run YouTube.streams.

Here's an example code:

from pytube import YouTube

yt = YouTube("https://www.youtube.com/watch?v=vEQ8CXFWLZU&t=525s")

yd = yt.streams.filter(only_audio=True).first()

error:

Traceback (most recent call last):
  File "C:\Users\Adrian\Desktop\hey.py", line 5, in <module>
    yd = yt.streams.filter(only_audio=True).first()
  File "C:\Users\Adrian\AppData\Roaming\Python\Python38\site-packages\pytube\__main__.py", line 296, in streams
    return StreamQuery(self.fmt_streams)
  File "C:\Users\Adrian\AppData\Roaming\Python\Python38\site-packages\pytube\__main__.py", line 181, in fmt_streams
    extract.apply_signature(stream_manifest, self.vid_info, self.js)
  File "C:\Users\Adrian\AppData\Roaming\Python\Python38\site-packages\pytube\extract.py", line 409, in apply_signature
    cipher = Cipher(js=js)
  File "C:\Users\Adrian\AppData\Roaming\Python\Python38\site-packages\pytube\cipher.py", line 43, in __init__
    self.throttling_plan = get_throttling_plan(js)
  File "C:\Users\Adrian\AppData\Roaming\Python\Python38\site-packages\pytube\cipher.py", line 411, in get_throttling_plan
    transform_plan_raw = find_object_from_startpoint(raw_code, match.span()[1] - 1)
AttributeError: 'NoneType' object has no attribute 'span'

I've also made a exe file of the python code and it also stop working. Looking forward to get an answer.


Solution

  • YouTube has most probably changed their code again.

    Quick Solution

    In Cipher.py, go to line 411:

    transform_plan_raw = find_object_from_startpoint(raw_code, match.span()[1] - 1)
    

    Change it to:

    transform_plan_raw = js
    

    Explanation

    In Cipher.py, at line 407,

    transform_start = r"try{" 
    plan_regex = re.compile(transform_start) 
    match = plan_regex.search(raw_code)
    

    In the above code snippet, the match object is defined as the regex matches of plan_regex (which is r"try{") found in the raw_code object. However, when I tried to get what the raw_code object actually returns, I got this value:

    mma=function(a){var b=a.split(""),c=[1298660008,function(d,e,f,h,l,m){return e(h,l,m)},968655468,function(){for(var d=64,e=[];++d-e.length-32;)switch(d){case 46:d=95;default:e.push(String.fromCharCode(d));case 94:case 95:case 96:break;case 123:d-=76;case 92:case 93:continue;case 58:d=44;case 91:}return e},56115230,-578061081,-516346513,b,-1739695292,-1031455761,/[,\]],[\]];}.
    

    As you can notice, there is not a single mention of try{ here, hence when the plan_regex.search method is called for raw_code, it finds no matches and return None. Therefore, while seeking for the span attribute of match object, it raises the Error: AttributeError: 'NoneType' object has no attribute 'span'.

    So basically, instead of searching for the try{ string in the raw_code, we're just passing the input js parameter to the transform_plan_raw object.