Open kimcheolgi opened 4 years ago
I've just start receiving this error as well. I assume its from a different js response from YouTube and isn't actually a pytube3/X change. Specifically it looks like the get_transform_plan
isn't working as intended anymore, it returns a value like var b=[-1215677809,null,-1744521562,833462946,694270393,function(c,d){d=(d%c.length+c.length)%c.length
. When we split in line 31 of cipher.py, we get: ['var b=[-1215677809,null,-1744521562,833462946,694270393,function(c,d){d=(d%c', 'length+c', 'length)%c', 'length']
Yep, I am getting issues with this module as well. It seems to be a change that occurred today in the js response from YouTube. It looks like alot of the regex may need to be re-written.
This is mildly infuriating as I've also just received the same error running pytube3 v9.6.4, then switched over to pytubeX and encountered the same problems. I went into cipher.py
myself to take a look and tried changing the way var was unpacked, switching from var, _ = self.transform_plan[0].split('.')
to directly using index 0 to access self.transform_play[0].split('.')
, avoiding the tuple unpacking to no avail, as after the ValueError
was avoided, it seems deeper down there's a RegexMatchError
too. Unfortunately, this might boil down to a regex problem more than anything. YouTube likely changed something on their side as well to cause these problems.
@kpister @KLRussell @Cafeepy Yes. This is an error caused by the change of youtube js. I chose pytubeX because it is a recently updated source. And since I think modifying regex by myself is inefficient, I wanted to help. Thanks for the kind answer.
Hopefully, we can collectively write a pull request that properly addresses this issue, as it pretty much cripples the entire library. I will continue looking into this myself in the meantime. Thanks everyone here for the help, we now know what we're looking at, and that's one step closer to fixing it.
I was about to report the same error. Good to see that there is already a thread about it. Hope to get a fix soon. I can help with testing.
Looks like at the most basic, the sample code from the PyPi docs for pytubeX will trigger it:
>>> from pytube import YouTube
>>> YouTube('http://youtube.com/watch?v=9bZkp7q19f0').streams[0].download()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\MyComputer\.virtualenvs\ytdownloader-9dI2ZJxb\lib\site-packages\pytube\__main__.py", line 92, in __init__
self.descramble()
File "C:\Users\MyComputer\.virtualenvs\ytdownloader-9dI2ZJxb\lib\site-packages\pytube\__main__.py", line 140, in descramble
apply_signature(self.player_config_args, fmt, self.js)
File "C:\Users\MyComputer\.virtualenvs\ytdownloader-9dI2ZJxb\lib\site-packages\pytube\extract.py", line 225, in apply_signature
cipher = Cipher(js=js)
File "C:\Users\MyComputer\.virtualenvs\ytdownloader-9dI2ZJxb\lib\site-packages\pytube\cipher.py", line 31, in __init__
var, _ = self.transform_plan[0].split(".")
ValueError: too many values to unpack (expected 2)
I would recommend another method until the problem is solved. Just use the youtube_dl library. Options(ydl_opts) can be changed according to the user needs.
def download_video_and_subtitle(output_dir, video_url):
download_path = os.path.join(output_dir, '%(title)s.%(ext)s')
# youtube_dl options
ydl_opts = {
'format': '137', # 1080p
'outtmpl': download_path # download path
}
try:
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
ydl.download([video_url])
except Exception as e:
print('error', e)
https://github.com/ytdl-org/youtube-dl/blob/master/README.md#readme
+++ This method cannot solve the issue. However, it can replace the download function.(It is recommended as a temporary measure.) You can also refer to regex.
@kimcheolgi why does the youtube_dl lib avoid this problem?
... reading thru the documentation.
<https://github.com/ytdl-org/youtube-dl/blob/master/README.md#installation>
Now I ask myself why do I bother with pytube and just work with ytdl?
I think I've found the solution from the youtube-dl package mentioned above. Looks like it was a simple change to the regex in the get_initial_function_name
function of cipher.py
Sorry for the extra comment, but just to answer @peterrenshaw's question, pytube is much more lightweight than youtube_dl. Even just by looking at the directories, you can tell that while ytdl has hundreds of Python scripts, pytube only has about 15 or so that run the whole operation. As a result, the creators of pytube had to use much more clever and concise code that, while initially working, may not be able to fully account for the wide range of errors possible when downloading videos from YouTube. I, personally, don't use pytube for the express purpose of downloading YouTube videos, I actually use youtube_dl for that, since I need them in mp3 format, which is not yet supported. However, I do need pytube to load the video data, because while youtube_dl may download videos better, it's designed to be a command-line program and a separate library, namely, pytube, created for use in a script, is required for me to actually get the video title, channel, description, etc. That's why it's kinda hard to compare youtube_dl with pytube, because they're both designed to fit in different applications. Hopefully, in the future, pytube will be able to use mp3 with ffmpeg but, for now, this is the best I've got for now.
"As a result, the ^creators of pytube had to use much more clever and concise code^ that, while initially working, may not be able to fully account for the wide range of errors possible when downloading videos from YouTube."
On point.
Pytube user since '16. I use PT to s pull YT videos with sound, mainly music. Last night I quickly hacked some code to use the youtube_dl lib. Works. On a MBP using ports it tool quite a hefty series of applications, libs and time to configure. YTDL is a hefty thing to download, understand. PyTube, it is a work of art because of its succinctness. The less code there is, the easier it is to fix and understand. It's worth persisting with.
Q. Is there any way to create some code that adapts to the youtube inputs to craft the outputs?
Hey guys! Thanks for all the help on this project. I've merged your PR, and will now commit this to the full pip version.
Cheers!!
@peterrenshaw I won't close the issue just yet, as I know you have an unanswered question.
Theoretically, I don't see why not. It's just HTML and JS at the end of the day, which can be read and toyed with to the heart's content. I'll look in to a way that we could implement that, but I'm not the best programmer out there. Any other ideas anyone?
I'm pretty much just a Python guy, but I have a few friends I could ask for HTML/JS help. By "adapting" the YouTube inputs, do you mean writing code that looks for the data we need, even when the formatting changes? That sounds like a job for advanced regex and maybe even BeautifulSoup, but it's not going to be easy. I'm not that good at these kinds of things, but maybe with BeautifulSoup, we could potentially sift YouTube for tags/classes (or whatever they call it in the HTML world), helping us more efficiently target what we need. However, if YouTube changes the names of their classes or whatnot, like I believe they did with the cipher last time, it'll be back to square one. For now, the best we can do is change our code to match whenever YouTube changes theirs. Because of the nature of this package, we can't guarantee how YouTube's going to change itself and that makes it rather difficult to predict. For now, if we're fast enough, we can adapt pytube to the new formatting in a matter of hours, but it will take programming more advanced than what I can think of right now to be able to "adapt" in the way you suggest.
While we're on this topic, just another idea: at some point, maybe it would be a good idea to write an asynchronous version of pytube
, taking its current structure and replacing the current urllib
and related packages with aiohttp
, allowing use with other async libraries like discord.py
and possibly increasing performance? mp3 support would be pretty awesome too.
@Cafeepy Yes, I agree. It would be a case of manually changing the code anyway in most cases.
An asynchronous version of pytube sounds amazing! It could be where we take this project, as a legitimate alternative to pytube that isn't just better maintained - it's asynchronous. I'll look in to those libraries, but it does sound like a massive task. Would love some help on it!
mp3 support would also be good. Don't think YouTube has mp3s streaming from their site, so it would have to be a local conversion. I'll look in to how I could do that.
Thanks for the suggestions!!!
Sorry for such a late reply!
I'd love to help out with making thing asynchronous, especially since the frame of the library already exists and works. Now, it would just be a matter of replacing all the I/O with asyncio
and asyncio
-related packages, like aiohttp
. However, I can't pretend it isn't a big undertaking. Just feel free tell me if you need my help!
from pytube import YouTube yt = YouTube('https://www.youtube.com/watch?v=8HHlMhYQ-Zc') Traceback (most recent call last): File "/home/kkk/anaconda3/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3331, in run_code exec(code_obj, self.user_global_ns, self.user_ns) File "", line 1, in
yt = YouTube('https://www.youtube.com/watch?v=8HHlMhYQ-Zc')
File "/home/kkk/anaconda3/lib/python3.7/site-packages/pytube/main.py", line 92, in init
self.descramble()
File "/home/kkk/anaconda3/lib/python3.7/site-packages/pytube/main.py", line 140, in descramble
apply_signature(self.player_config_args, fmt, self.js)
File "/home/kkk/anaconda3/lib/python3.7/site-packages/pytube/extract.py", line 225, in applysignature
cipher = Cipher(js=js)
File "/home/kkk/anaconda3/lib/python3.7/site-packages/pytube/cipher.py", line 31, in init
var, = self.transform_plan[0].split(".")
ValueError: too many values to unpack (expected 2)
There are the following value error issues. pytube3 seems to have no more updates, so I came to pytubeX. Please tell me how to solve the above error.