How to update html.Video content (src) without refreshing the page?

Hello everyone,

I have been working on a video editor dash app project. At one phase of the app user needs to input a time interval to which their full video get cut into. When they, submit their interval, a video player starts to play their freshly segmented video. Everything is fine so far. Things happens when they reset their time interval, although the code works as intended in the backend, for some reason, video on the html.video component is not updated.

In need of your help to fix that. I already set dev_tools_hot_reload=False to prevent possible hot reload that could get triggered by deleting and adding a video to asset folder.

Here is the callbacks that -I believe- work as intended:

#  callback to trim a video, and extract the audio of the trimmed video
@app.callback(
    [
    Output("audio-path", "data"), #tied to dcc.Store
    Output("video-player", "src" ), #tied to html.audio
    Output("audio-player", "src" ), #tied to html.video
    Output("reset-button", "n_clicks"),
    
    ],
    [
    State("full-video-name", "data"), #tied to another dcc.Store
    Input("set-button", "n_clicks"),
    State("start-time", "value"), #interval
    State("end-time", "value"),
    Input("reset-button", "n_clicks"),
    ],
    prevent_initial_call =True,
)
def time_interval(file_name, clicked, start, end, reset_n_clicked):
    
    # extract video segment
    extension = '.mp4'
    full_file_name = file_name + extension
    input_video = os.path.join(FULL_VIDEOS, full_file_name)
    print(reset_n_clicked)
    
    if reset_n_clicked is None or reset_n_clicked==0:
    
        if clicked is not None:

            # Parse the string to a datetime object
            datetime_obj_start = datetime.strptime(start, "%Y-%m-%dT%H:%M:%S")
            datetime_obj_end = datetime.strptime(end, "%Y-%m-%dT%H:%M:%S")

            # Extract the time component
            time_obj_start = datetime_obj_start.time().strftime("%H:%M:%S")
            time_obj_end = datetime_obj_end.time().strftime("%H:%M:%S")
            
            output_file_name = utility.extract_video_segment(input_video, time_obj_start, time_obj_end)
                
            #copy the segmented video to the assets folder for mediaplayer
            source_path = os.path.join(SEGMENTED_VIDEOS, (output_file_name + extension))
            destination_path = os.path.join(ROOT_FOLDER, 'assets', (output_file_name + extension))

            shutil.copy(source_path, destination_path)
            video_src="assets/"+output_file_name+extension
            
            #extract audio
            audio_path = utility.extract_audio(source_path, SEGMENTED_AUDIOS)
            audio_destination_path = os.path.join(ROOT_FOLDER, 'assets', (output_file_name + '.wav'))
            shutil.copy(audio_path, audio_destination_path)
            audio_src = "assets/"+output_file_name +'.wav'

            return audio_path, video_src, audio_src, 0

        else:
            raise PreventUpdate
    else:
        
        output_video_name = 'S_' + full_file_name
        output_video_path  = os.path.join(SEGMENTED_VIDEOS, output_video_name)

        # check if the file exists
        if os.path.isfile(output_video_path):
            # if the file exists, delete it both from segmented_videos and assets folders
            os.remove(output_video_path)
            os.remove(os.path.join(ROOT_FOLDER, 'assets', output_video_name))
            return no_update, no_update, no_update, 0
            
        else:
            # if the file does not exist, print a message
            print('The file does not exist')
            return no_update, no_update, no_update, 0    

I know it is not a minimal working example, however my app got too complicated to extract a mew from it. But will do by best to come up with one if needed.

Thank you all in advance!

Turns out, browsers cache the file name. I went around the problem by changing the name of the video file in the assets folder every time when the “time_interval” callback is triggered.

1 Like

I’m glad you got it to work, @Berbere

Thanks for sharing the solution with us.