pytube: [BUG] 'NoneType' object has no attribute 'span'

arr = yt.streams.filter(only_video=True, file_extension='mp4')
line 292, in streams
    return StreamQuery(self.fmt_streams)
  File "...\Python39\lib\site-packages\pytube\__main__.py", line 177, in fmt_streams
    extract.apply_signature(stream_manifest, self.vid_info, self.js)
  File "...\Python39\lib\site-packages\pytube\extract.py", line 409, in apply_signature
    cipher = Cipher(js=js)
  File "...\Python39\lib\site-packages\pytube\cipher.py", line 44, in __init__
    self.throttling_array = get_throttling_function_array(js)
  File "...\Python39\lib\site-packages\pytube\cipher.py", line 323, in get_throttling_function_array
    str_array = throttling_array_split(array_raw)
  File "...\Python39\lib\site-packages\pytube\parser.py", line 158, in throttling_array_split
    match_start, match_end = match.span()
AttributeError: 'NoneType' object has no attribute 'span'

Pytube version: 11.0.1 Python 3.9.7

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 15
  • Comments: 53 (2 by maintainers)

Most upvoted comments

Please re open this issue, I encountered the same error

seems to happen, because YouTube added functions without parameters in the javascript. e.g.:

function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 58:d-=14;case 91:case 92:case 93:continue;case 123:d=47;case 94:case 95:case 96:continue;case 46:d=95}e.push(String.fromCharCode(d))}return e}

So in my opinion the best fix would be to allow the regex to accept these too. That is, change the regex function\([^)]+\) to function\([^)]*\). The * allows the function to have no parameters.

So https://github.com/pytube/pytube/blob/f06e0710dcf5089e582487fee94f7bb0afbf7ba9/pytube/parser.py#L152 should be changed to

func_regex = re.compile(r"function\([^)]*\)")

Any opinion about that?

Literally yesterday everything worked, but today it gives this error.

I have create a pull request to fix this error. checkout here https://github.com/pytube/pytube/pull/1166

Please re open this issue, I encountered the same error

Please update to the latest version.

11.0.2 is the latest right? I am having the same issue on that version.

Please re open this issue, I encountered the same error

Please update to the latest version.

seems to happen, because YouTube added functions without parameters in the javascript. e.g.:

function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 58:d-=14;case 91:case 92:case 93:continue;case 123:d=47;case 94:case 95:case 96:continue;case 46:d=95}e.push(String.fromCharCode(d))}return e}

So in my opinion the best fix would be to allow the regex to accept these too. That is, change the regex function\([^)]+\) to function\([^)]*\). The * allows the function to have no parameters.

So

https://github.com/pytube/pytube/blob/f06e0710dcf5089e582487fee94f7bb0afbf7ba9/pytube/parser.py#L152

should be changed to

func_regex = re.compile(r"function\([^)]*\)")

Any opinion about that?

I implemented this in my environment and it works! Hopefully we can get it merged into master. Thanks for posting this.

there is a writing error in the line from @Reaperswag this is the correct line to change line 268 in cipher.py: r'([A-Za-z]{3})=function\(a\){var b=a\.split\(""\)\,'

Traceback (most recent call last): File “d:\Fils\Python\bin\tets.py”, line 5, in stream = url.streams.get_by_resolution(“720p”) File “C:\Users\clone\AppData\Local\Programs\Python\Python39\lib\site-packages\pytube__main__.py”, line 292, in streams return StreamQuery(self.fmt_streams) File “C:\Users\clone\AppData\Local\Programs\Python\Python39\lib\site-packages\pytube__main__.py”, line 177, in fmt_streams extract.apply_signature(stream_manifest, self.vid_info, self.js) File “C:\Users\clone\AppData\Local\Programs\Python\Python39\lib\site-packages\pytube\extract.py”, line 409, in apply_signature cipher = Cipher(js=js) File “C:\Users\clone\AppData\Local\Programs\Python\Python39\lib\site-packages\pytube\cipher.py”, line 43, in init self.throttling_plan = get_throttling_plan(js) File “C:\Users\clone\AppData\Local\Programs\Python\Python39\lib\site-packages\pytube\cipher.py”, line 387, in get_throttling_plan raw_code = get_throttling_function_code(js) File “C:\Users\clone\AppData\Local\Programs\Python\Python39\lib\site-packages\pytube\cipher.py”, line 301, in get_throttling_function_code code_lines_list = find_object_from_startpoint(js, match.span()[1]).split(‘\n’) AttributeError: ‘NoneType’ object has no attribute ‘span’

How to fix ?

here’s what worked for me, courtesy of czarnoff (although glubsy is correct that this is a temporary workaround). Hopefully it will last until an update can be released that lets removes this vulnerability.

"I think the javascipt changed. If you search for Bpa, you don’t find a function. Instead you get

var Bpa=[iha];g.k=Jz.prototype;g.k.GC=function(a){this.segments.push(a)}; Thus Bpa is an array with the function “iha” in location zero . If you use iha for the name, you get a function. I kludged line 293 of cipher.py to go from

name = re.escape(get_throttling_function_name(js)) to

name = “iha” And I now its working.

I’m not sure how to correctly change the code yet, but if I figure out a proper patch I’ll post it."

EVINRONMENT
  pytube: 11.0.2
  Python: 3.8.10
Error : 
  Traceback (most recent call last):
  File "main.py", line 55, in <module>
    stream = my_video.streams.get_highest_resolution()
  File "/mnt/d/wsl/python/ytdl_1.0/venv/lib/python3.8/site-packages/pytube/__main__.py", line 292, in streams
    return StreamQuery(self.fmt_streams)
  File "/mnt/d/wsl/python/ytdl_1.0/venv/lib/python3.8/site-packages/pytube/__main__.py", line 177, in fmt_streams
    extract.apply_signature(stream_manifest, self.vid_info, self.js)
  File "/mnt/d/wsl/python/ytdl_1.0/venv/lib/python3.8/site-packages/pytube/extract.py", line 409, in apply_signature
    cipher = Cipher(js=js)
  File "/mnt/d/wsl/python/ytdl_1.0/venv/lib/python3.8/site-packages/pytube/cipher.py", line 43, in __init__
    self.throttling_plan = get_throttling_plan(js)
  File "/mnt/d/wsl/python/ytdl_1.0/venv/lib/python3.8/site-packages/pytube/cipher.py", line 388, in get_throttling_plan
    raw_code = get_throttling_function_code(js)
  File "/mnt/d/wsl/python/ytdl_1.0/venv/lib/python3.8/site-packages/pytube/cipher.py", line 302, in get_throttling_function_code
    code_lines_list = find_object_from_startpoint(js, match.span()[1]).split('\n')
AttributeError: 'NoneType' object has no attribute 'span'
FIX

comment from @seekwest

there is a writing error in the line from @Reaperswag this is the correct line to change line 268 in cipher.py: r’([A-Za-z]{3})=function(a){var b=a.split(“”),’

I tried pytube today and I still get the error stating that NoneType object has no attribute Span

Happening here as well. I reckon it’s probably because Youtube changed something on their end just now and it’s caused pytube to stop working. I don’t know, but I think pytube is essentially a battle between a community trying to develop ways to download vs the Youtube devs who are trying to stop the downloading of videos.

I made an EXE of my project about 2 days ago and that doesn’t work anymore, so it definitely isn’t any code that any of us have changed that caused the issues, it’s to do with pytube.

I summarize:

If your are using the latest version pytube: 11.0.2 the fix: old: func_regex = re.compile(r"function([^)]+)")

new: func_regex = re.compile(r"function([^)]*)")

in pytube/pytube/parser.py Line 152 is already INCLUDED!

So update to pytube: 11.0.2 if you havent done it yet.

If you already changed line 293 of pytube/pytube/cipher.py old: name = re.escape(get_throttling_function_name(js)) to new: name = "iha"

change it back to: name = re.escape(get_throttling_function_name(js))

Just change line 268 in pytube/pytube/cipher.py: old: r'a\.[A-Z]&&\(b=a\.get\("n"\)\)&&\(b=([^(]+)\(b\)',

to new: r'([A-Za-z]{3})=function\(a\){var b=a\.split\(""\)\,'

pay attention that the code is correct and the special characters are correct encoded/masked!! WRONG: r'([A-Za-z]{3})=function(a){var b=a.split(""),'

RIGHT: r'([A-Za-z]{3})=function\(a\){var b=a\.split\(""\)\,'

That should work, i downloaded 3.000 Videos from Youtube yesterday with these settings.

regards Chris

Hello! I just want to tell You, that I’ve implemented @seekwest solution for cipher.py from 2022-02-09:

there is a writing error in the line from @Reaperswag this is the correct line to change line 268 in cipher.py: r’([A-Za-z]{3})=function(a){var b=a.split(“”),’

and alexeichhorn solution for parser.py from 2021-11-22:

seems to happen, because YouTube added functions without parameters in the javascript. e.g.:

function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 58:d-=14;case 91:case 92:case 93:continue;case 123:d=47;case 94:case 95:case 96:continue;case 46:d=95}e.push(String.fromCharCode(d))}return e} So in my opinion the best fix would be to allow the regex to accept these too. That is, change the regex function([^)]+) to function([^)]*). The * allows the function to have no parameters.

So

pytube/pytube/parser.py

Line 152 in f06e071

func_regex = re.compile(r"function([^)]+)")

should be changed to func_regex = re.compile(r"function([^)]*)") Any opinion about that?

It worked! I’m useing pytube version of 11.0.2

Anyone can share git branch pull, so that we can use that branch to pull python package for the fix. for eg. pip3 install git+https://github.com/… It would be a great help for all. Thanks!

You can use my branch

pip install git+https://github.com/mytja/pytube

Thanks for sharing , it worked, kudos to you! @mytja

Həmiyə salam. Mən də bu gün eyni xətanı aldım. Bunun səbəbi baş verdiyindən deyiləm. Ancaq mən sadəcə bir istisna əlavə etdim və onu yükləmək mümkün idi. https://github.com/pytube/pytube/blob/master/pytube/parser.py#L158

while len(curr_substring) > 0:
        if curr_substring.startswith('function'):
            # Handle functions separately. These can contain commas
            match = func_regex.search(curr_substring)
            match_start, match_end = match.span()

üçün

while len(curr_substring) > 0:
        if curr_substring.startswith('function'):
            # Handle functions separately. These can contain commas
            match = func_regex.search(curr_substring)
            if not match:
                        break        
            match_start, match_end = match.span()

Ancaq bu bir şəkildə bir yoldur, daha yaxşı bir şəkildə əlavə olaraq.

bu addımdan sonra və voila, yenidən işləyir. çox sağ olun

True

I was trying to fix the bug before I found this pull request. It hasn’t been approved/merged yet but when I tried that change in my code, it worked.

In Cipher.py, line 411: transform_plan_raw = find_object_from_startpoint(raw_code, match.span()[1] - 1) Change it to: transform_plan_raw = js

I don’t know when this pull request will get merged into the main module, but for anyone facing this problem, you can try doing the above changes.

Okay, I also faced this problem lately and maybe at least could get a step ahead. In Cipher.py, at line 401, 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'.

This could be caused due to a recent change in YouTube’s code (which is not new, I’ve faced such bugs in the past year a couple of times as well. It broke my app that is based on this module, now I’m thinking shifting to yt-dlp for my app).

I might be wrong about it since I’m not a professional programmer and my theory might prove wrong, but this is the best explanation I could give as for now. I don’t know what the search method was supposed to find in the original code so I don’t think I can find a direct fix for now, however I’m working on it.

pytube 12.1.2 Python 3.7.6

Traceback (most recent call last): File “F:\PyCharm Community Edition 2022.3.1\Robin2bin_Youtube\test.py”, line 4, in <module> print(link.streams.all()) File “C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\pytube_main_.py”, line 296, in streams return StreamQuery(self.fmt_streams) File “C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\pytube_main_.py”, line 181, in fmt_streams extract.apply_signature(stream_manifest, self.vid_info, self.js) File “C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\pytube\extract.py”, line 409, in apply_signature cipher = Cipher(js=js) File “C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\pytube\cipher.py”, line 43, in init self.throttling_plan = get_throttling_plan(js) File “C:\Users\User\AppData\Local\Programs\Python\Python37\lib\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 summarize:

If your are using the latest version pytube: 11.0.2 the fix: old: func_regex = re.compile(r"function([^)]+)")

new: func_regex = re.compile(r"function([^)]*)")

in pytube/pytube/parser.py Line 152 is already INCLUDED!

So update to pytube: 11.0.2 if you havent done it yet.

If you already changed line 293 of pytube/pytube/cipher.py old: name = re.escape(get_throttling_function_name(js)) to new: name = "iha"

change it back to: name = re.escape(get_throttling_function_name(js))

Just change line 268 in pytube/pytube/cipher.py: old: r'a\.[A-Z]&&\(b=a\.get\("n"\)\)&&\(b=([^(]+)\(b\)',

to new: r'([A-Za-z]{3})=function\(a\){var b=a\.split\(""\)\,'

pay attention that the code is correct and the special characters are correct encoded/masked!! WRONG: r'([A-Za-z]{3})=function(a){var b=a.split(""),'

RIGHT: r'([A-Za-z]{3})=function\(a\){var b=a\.split\(""\)\,'

That should work, i downloaded 3.000 Videos from Youtube yesterday with these settings.

regards Chris

thanks, man. your answer was right for me this day. i get back the string: name = re.escape(get_throttling_function_name(js))

and added regex r’([A-Za-z]{3})=function(a){var b=a.split(“”),’

instead of r’a.[A-Z]&&(b=a.get(“n”))&&(b=([^(]+)(b)',

Thanks.

Presento otro error a estas alturas no se que es lo que pasa porque solo escribí lo más básico posible en pytube pero igual no funciono 😦 me salio el mismo error#1218 les paso el error Este el código que ejecute from pytube import YouTube YouTube("https://youtu.be/96L5sV7rqX0").streams.first().download()

les paso el error

Traceback (most recent call last): File "C:\Users\Fam. Cose Rojas\Desktop\Py-TUBE-Proyect\test2.py", line 3, in <module> YouTube("https://youtu.be/96L5sV7rqX0").streams.first().download() File "C:\Users\Fam. Cose Rojas\AppData\Local\Programs\Python\Python310\lib\site-packages\pytube\__main__.py", line 292, in streams return StreamQuery(self.fmt_streams) File "C:\Users\Fam. Cose Rojas\AppData\Local\Programs\Python\Python310\lib\site-packages\pytube\__main__.py", line 177, in fmt_streams extract.apply_signature(stream_manifest, self.vid_info, self.js) File "C:\Users\Fam. Cose Rojas\AppData\Local\Programs\Python\Python310\lib\site-packages\pytube\extract.py", line 409, in apply_signature cipher = Cipher(js=js) File "C:\Users\Fam. Cose Rojas\AppData\Local\Programs\Python\Python310\lib\site-packages\pytube\cipher.py", line 43, in __init__ self.throttling_plan = get_throttling_plan(js) File "C:\Users\Fam. Cose Rojas\AppData\Local\Programs\Python\Python310\lib\site-packages\pytube\cipher.py", line 387, in get_throttling_plan raw_code = get_throttling_function_code(js) File "C:\Users\Fam. Cose Rojas\AppData\Local\Programs\Python\Python310\lib\site-packages\pytube\cipher.py", line 301, in get_throttling_function_code code_lines_list = find_object_from_startpoint(js, match.span()[1]).split('\n') AttributeError: 'NoneType' object has no attribute 'span'