三行代码  ›  专栏  ›  技术社区  ›  Jiehfeng

如何将内容范围HTTP请求中的字节连接到完全工作的MP4文件?

  •  0
  • Jiehfeng  · 技术社区  · 3 周前

    到目前为止,这是我的代码,但当它将请求中的临时文件连接到一个MP4文件时,MP4文件不会播放。但是,该文件与上载的文件大小相同。

    @app.route('/admin/upload', methods=['POST'])
    @app_key
    def admin_dashboard_upload_endpoint():
        # Headers
        file_name = request.headers.get('Filename')
        title = request.headers.get('Title')
        path = f'something/path'
    
        # Get the Content-Range header
        content_range = request.headers.get('Content-Range')
    
        # Parse the Content-Range header to get start and end bytes
        start_byte, end_byte, total_size = parse_content_range(content_range)
    
        # Get the uploaded file from the request
        uploaded_file = request.files.get('File')
    
        # Save the received bytes to a temporary file
        os.makedirs('uploads', exist_ok=True)
        save_to_temporary_file(uploaded_file, start_byte, end_byte)
    
        # Check if all parts have been received
        if end_byte == total_size - 1:
            # If all parts are received, combine the temporary files into one
            combine_temporary_files(file_name)
    
            with open(f'uploads/{file_name}', 'rb') as combined_file:
                return upload_to_storage_dashboard(combined_file, title=title, path=path, file_remove=f'uploads/{file_name}')
    
        return "OK", 206
    
    def parse_content_range(content_range):
        # Example of content_range: 'bytes 0-999/2000'
        match = re.match(r'bytes (\d+)-(\d+)/(\d+)', content_range)
        if match:
            start_byte, end_byte, total_size = map(int, match.groups())
            return start_byte, end_byte, total_size
        else:
            # Handle invalid Content-Range header
            return None, None, None
    
    def save_to_temporary_file(uploaded_file, start_byte, end_byte):
        temp_file_path = f'uploads/temporary_file_{start_byte}_{end_byte}.mp4'
        with open(temp_file_path, 'ab') as temp_file:
            temp_file.write(uploaded_file.read())
    
    def combine_temporary_files(file_name):
        combined_file_path = f'uploads/{file_name}'
        temp_files = sorted([f for f in os.listdir('uploads') if f.startswith('temporary_file_')])
    
        with open(combined_file_path, 'wb') as combined_file:
            for temp_file_path in temp_files:
                with open(os.path.join('uploads', temp_file_path), 'rb') as temp_file:
                    combined_file.write(temp_file.read())
                os.remove(os.path.join('uploads', temp_file_path))
    

    实际的代码可以连接我的Flutter应用程序发送的几个内容范围请求,但当它将最终的MP4放在一起时,它就不会播放了。我的方法正确吗?或者我如何才能做到这一点?我这样做是为了上传大文件。

    1 回复  |  直到 3 周前
        1
  •  1
  •   AKX    3 周前

    让我的评论成为一个答案,并对此进行一点扩展:

    您可能没有正确地对块进行排序。 sorted() 对字符串进行排序 lexicographical order ;如果你像现在这样命名你的区块,你会得到

    >>> sorted([f'chunk{x}' for x in range(1, 105) if x < 5 or x >= 100])
    ['chunk1', 'chunk100', 'chunk101', 'chunk102', 'chunk103', 'chunk104', 'chunk2', 'chunk3', 'chunk4']
    

    所以1100、101、102、103、104、2、5。哦,不!

    相反,您需要为块命名,以便它们可以按字典排序,例如。

    >>> sorted([f'chunk{x:08d}' for x in range(1, 105) if x < 5 or x >= 100])
    ['chunk00000001', 'chunk00000002', 'chunk00000003', 'chunk00000004', 'chunk00000100', 'chunk00000101', 'chunk00000102', 'chunk00000103', 'chunk00000104']
    

    或者完全使用另一个排序键。