但是它扔了
TypeError: write() argument must be str, not <class 'bytes'>
我感谢任何帮助。Edit:完整的追溯:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[4], line 27
24 # Download video and upload to Azure Blob Storage
25 with YoutubeDL(ydl_opts) as ydl, io.BytesIO() as byte_stream:
26 # Redirect yt-dlp's stdout to the byte stream
---> 27 ydl.download([video_url])
28 byte_stream.seek(0)
29 blob_client.upload_blob(byte_stream, overwrite=True)
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/YoutubeDL.py:3618, in YoutubeDL.download(self, url_list)
3615 raise SameFileError(outtmpl)
3617 for url in url_list:
-> 3618 self.__download_wrapper(self.extract_info)(
3619 url, force_generic_extractor=self.params.get('force_generic_extractor', False))
3621 return self._download_retcode
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/YoutubeDL.py:3591, in YoutubeDL.__download_wrapper.<locals>.wrapper(*args, **kwargs)
3588 @functools.wraps(func)
3589 def wrapper(*args, **kwargs):
3590 try:
-> 3591 res = func(*args, **kwargs)
3592 except CookieLoadError:
3593 raise
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/YoutubeDL.py:1626, in YoutubeDL.extract_info(self, url, download, ie_key, extra_info, process, force_generic_extractor)
1624 raise ExistingVideoReached
1625 break
-> 1626 return self.__extract_info(url, self.get_info_extractor(key), download, extra_info, process)
1627 else:
1628 extractors_restricted = self.params.get('allowed_extractors') not in (None, ['default'])
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/YoutubeDL.py:1637, in YoutubeDL._handle_extraction_exceptions.<locals>.wrapper(self, *args, **kwargs)
1635 while True:
1636 try:
-> 1637 return func(self, *args, **kwargs)
1638 except (CookieLoadError, DownloadCancelled, LazyList.IndexError, PagedList.IndexError):
1639 raise
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/YoutubeDL.py:1793, in YoutubeDL.__extract_info(self, url, ie, download, extra_info, process)
1791 if process:
1792 self._wait_for_video(ie_result)
-> 1793 return self.process_ie_result(ie_result, download, extra_info)
1794 else:
1795 return ie_result
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/YoutubeDL.py:1852, in YoutubeDL.process_ie_result(self, ie_result, download, extra_info)
1850 if result_type == 'video':
1851 self.add_extra_info(ie_result, extra_info)
-> 1852 ie_result = self.process_video_result(ie_result, download=download)
1853 self._raise_pending_errors(ie_result)
1854 additional_urls = (ie_result or {}).get('additional_urls')
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/YoutubeDL.py:3024, in YoutubeDL.process_video_result(self, info_dict, download)
3022 downloaded_formats.append(new_info)
3023 try:
-> 3024 self.process_info(new_info)
3025 except MaxDownloadsReached:
3026 max_downloads_reached = True
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/YoutubeDL.py:177, in _catch_unsafe_extension_error.<locals>.wrapper(self, *args, **kwargs)
174 @functools.wraps(func)
175 def wrapper(self, *args, **kwargs):
176 try:
--> 177 return func(self, *args, **kwargs)
178 except _UnsafeExtensionError as error:
179 self.report_error(
180 f'The extracted extension ({error.extension!r}) is unusual '
181 'and will be skipped for safety reasons. '
182 f'If you believe this is an error{bug_reports_message(",")}')
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/YoutubeDL.py:3492, in YoutubeDL.process_info(self, info_dict)
3488 dl_filename = existing_video_file(full_filename, temp_filename)
3489 if dl_filename is None or dl_filename == temp_filename:
3490 # dl_filename == temp_filename could mean that the file was partially downloaded with --no-part.
3491 # So we should try to resume the download
-> 3492 success, real_download = self.dl(temp_filename, info_dict)
3493 info_dict['__real_download'] = real_download
3494 else:
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/YoutubeDL.py:3212, in YoutubeDL.dl(self, name, info, subtitle, test)
3210 if new_info.get('http_headers') is None:
3211 new_info['http_headers'] = self._calc_headers(new_info)
-> 3212 return fd.download(name, new_info, subtitle)
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/downloader/common.py:464, in FileDownloader.download(self, filename, info_dict, subtitle)
461 self.to_screen(f'[download] Sleeping {sleep_interval:.2f} seconds ...')
462 time.sleep(sleep_interval)
--> 464 ret = self.real_download(filename, info_dict)
465 self._finish_multiline_status()
466 return ret, True
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/downloader/http.py:368, in HttpFD.real_download(self, filename, info_dict)
366 try:
367 establish_connection()
--> 368 return download()
369 except RetryDownload as err:
370 retry.error = err.source_error
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/yt_dlp/downloader/http.py:279, in HttpFD.real_download.<locals>.download()
276 self.report_error(f'unable to set filesize xattr: {err}')
278 try:
--> 279 ctx.stream.write(data_block)
280 except OSError as err:
281 self.to_stderr('\n')
File ~/.virtualenvs/myenv/lib/python3.12/site-packages/ipykernel/iostream.py:668, in OutStream.write(self, string)
666 if not isinstance(string, str):
667 msg = f"write() argument must be str, not {type(string)}" # type:ignore[unreachable]
--> 668 raise TypeError(msg)
670 if self.echo is not None:
671 try:
TypeError: write() argument must be str, not <class 'bytes'>
您面临此错误,因为
yt-dlp
将视频数据写为
bytes,但它是指向
stdout
,它默认情况下会引起String
io.BytesIO()
用作内存缓冲区并修改
outtmpl
和postprocessors
设置以直接编写字节。
import io
from yt_dlp import YoutubeDL
from azure.storage.blob import BlobServiceClient
video_url = 'https://www.youtube.com/watch?v=<video_id>'
connect_str = 'DefaultEndpointsProtocol=https;AccountName=accountname;AccountKey=accountkey;EndpointSuffix=core.windows.net'
container_name = 'container_name'
blob_name = 'video_name.mp4'
blob_service_client = BlobServiceClient.from_connection_string(connect_str)
blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob_name)
class BytesIOWrapper(io.BytesIO):
""" Custom wrapper to handle yt-dlp writing video data into memory """
def write(self, b):
super().write(b)
return len(b) # yt-dlp expects write() to return the number of bytes written
# yt-dlp optionsto write video as bytes
ydl_opts = {
'format': 'best',
'quiet': True,
'outtmpl': '-',
'noprogress': True,
'postprocessors': [{
'key': 'FFmpegVideoConvertor',
'preferedformat': 'mp4' # ensure the output format is mp4
}],
'logger': None
}
# stream video directly to azure blob storege
with YoutubeDL(ydl_opts) as ydl, BytesIOWrapper() as byte_stream:
ydl.download([video_url]) # Download the video
byte_stream.seek(0) # Reset stream pointer to start
blob_client.upload_blob(byte_stream, overwrite=True) #uploading to azure
print(f'Uploaded {blob_name} to Azure Blob Storage successfully.')