Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

vinubangs's avatar

How to add realtime progress bar while submitting a form

I am using laravel to upload a video file. I want to show realtime progress bar there.

There is a form for video upload with many extra inputs. For the video I am using FFMPEG to crop and encrypt videos. This takes time.

My form is:

<div class="row" style="margin-top: 10px;">
<div class="col-lg-6">
    <div class="form-group">
        <label for="video_price">Select Video<b class="red">*</b></label>
        <input id="vide_Upload" type="file" name="vide_Upload"
            style="opacity: 0; position: absolute; z-index: -1;" accept="video/*" />
        <label for="vide_Upload" id="file-drag">
            Select a file to upload (Maximum allowed mp4 file size is 100 MB)
            <br />OR
            <br />Drag a file into this box

            <br /><br /><span id="vide_Upload-btn" class="button">Add a video</span>
        </label>
    </div>
</div>
<div class="col-lg-6 video-details">
    <div class="form-group">
        <div class="custom-control">
            <div id="file-details"></div>
        </div>
        <div class="progress videoProgressBar mt-2" style="display:none;">
            <div class="progress-bar" role="progressbar" aria-valuenow="" aria-valuemin="0" aria-valuemax="100"></div>
        </div>
    </div>
</div>

Showing only file upload input field. There are some other fields as well.

I am using ajax to submit:

$.ajax({
url: '{{ route('video.store') }}',
type: "POST",
data: formData,
processData: false,
contentType: false,
cache: false,
beforeSend: function () {
    $('.videoProgressBar').show();
    // Start the interval to update the progress bar
    progressBarInterval = setInterval(function() {
        // Increment the progress bar by a fixed amount
        var currentWidth = $('.progress .progress-bar').width();
        var maxWidth = $('.progress .progress-bar').parent().width();
        var increment = maxWidth / 100; // Assuming 100 intervals for 100%

        if (currentWidth + increment <= maxWidth) {
            $('.progress .progress-bar').css('width', currentWidth + increment);
        } else {
            clearInterval(progressBarInterval);
        }
    }, 5000); // Update every second
},

success: function(response) {
    clearInterval(progressBarInterval); // Stop the progress bar interval
    $('#videoSubmit').html('Submit Your Video');
    $("#videoSubmit"). attr("disabled", false);
    if (response.success == 'error') {
        var currentWidth = '0';
        var increment = '0'; // Assuming 100 intervals for 100%
        $('.progress .progress-bar').css('width', currentWidth + increment);
        $('#videoSubmit').html('Submit Your Video');
        $("#videoSubmit").attr("disabled", false);
        $('.errorDisplayDiv').html(response.message);
        $('html, body').animate({
            scrollTop: 0
        }, 0);
        $('.successDiv').slideDown('slow', function() {
            /*setTimeout(function() {
            $('.successDiv').slideUp('slow');
            }, 5000);*/
        });
    } else {
        var currentWidth = '100';
        var increment = '100'; // Assuming 100 intervals for 100%
        $('.progress .progress-bar').css('width', currentWidth + increment);
        window.location.href = response.redirect;
    }
},
error: function(xhr, status, error) {
    var errors = JSON.parse(xhr.responseText).errors;
    $.each(errors, function(key, value) {
        if(key == 'captcha')
        {
            $("#" + key + "_videos-error").html(value[0]);
        }
        else
        {
            $('.errorDisplayDiv').html('Something went wrong. Please try again');
            $('.successDiv').show();
            $('html, body').animate({
                scrollTop: 0
            }, 0);
        }
    });
    reloadCaptcha_video();
    setTimeout(function() {
        // Clear the interval when the error occurs
        clearInterval(progressBarInterval);
    }, 1000); // Stop the interval after 10 seconds (adjust as needed)
    var currentWidth = '';
    var increment = ''; // Assuming 100 intervals for 100%
    $('.progress .progress-bar').css('width', currentWidth + increment);
    $('#videoSubmit').html('Submit Your Video');
    $("#videoSubmit").attr("disabled", false);
}
});

Currently progress bar increases on every 5 seconds. If video file takes time then progress bar shows complete. Because progress bar increases on every 5 seconds.

controller is:

ublic function store(Request $request)
{
$validatedData = $request->validate([
    'video_title' => 'required',  
    'keywords' => 'required',  
    'references' => 'required',  
    'abstract' => 'required',  
    'declaration_of_interests' => 'required',  
    'declaration_remark' => 'required_if:declaration_of_interests,2',
    'videotype_id' => 'required',  
    'videosubtype_id' => 'required',  
    'majorcategory_id' => 'required',        
    'subcategory_id' => 'required',        
    'terms_n_conditions' => 'required',        
    'membershipplan_id' => 'required',            
    'vide_Upload' => 'required|mimes:mp4|max:100000', 
    'captcha' => 'required|captcha' 
], [        
    'required' => 'This field is required',        
    'declaration_remark.required_if' => 'This field is required',  
    'captcha.captcha' => 'Invalid captcha'
]);


DB::beginTransaction();
try {
$filteredKeywords = array_filter($request->keywords, function ($value) {
    // Remove null values from the array
    return $value !== null;
});
$uniquen_number = $this->generateUniqueNumber();
$videoupload = new Videoupload();
$videoupload->user_id = Auth::id();
$videoupload->unique_number = $uniquen_number;
$videoupload->videostatus_id = 1;
$videoupload->videotype_id = $request->videotype_id;
$videoupload->videosubtype_id = $request->videosubtype_id;
$videoupload->majorcategory_id = $request->majorcategory_id;
$videoupload->subcategory_id = json_encode($request->subcategory_id);
$videoupload->video_title = $request->video_title;
$videoupload->keywords = json_encode($filteredKeywords);
$videoupload->references = $request->references;
$videoupload->abstract = $request->abstract;
$videoupload->declaration_of_interests1 = $request->declaration_of_interests;
$videoupload->acknowledge = $request->acknowledge;
$videoupload->doi_link = $request->doi_link;
if($videoupload->declaration_of_interests1 == 2)
{
    $videoupload->declaration_remark = $request->declaration_remark;
}  
$videoupload->membershipplan_id = $request->membershipplan_id;
$videoupload->terms_n_conditions = $request->terms_n_conditions;

if($request->hasFile('vide_Upload')){

        $major_category_details = get_majorcategories($request->majorcategory_id);
        $folderName = str_replace(' ', '_', $major_category_details->category_name);
        $vide_Upload2_image = $request->file('vide_Upload');
        $extension = $vide_Upload2_image->getClientOriginalExtension();
        $newFileName = $uniquen_number . '.' . $extension;
        $newFileName_cropped_file = $uniquen_number . '_cropped.' . $extension;
        //$new_directory = mkdir('app/public/uploads/Videos_to_Revise/'.$folderName.'/'.$uniquen_number, 0777, true);
        $filePath = $vide_Upload2_image->storeAs('uploads/Videos_to_Revise/'.$folderName.'/'.$uniquen_number, $newFileName, 'public');
        $video_path_url = asset(Storage::url($filePath));
   
    // Start crop the video
        $video_path = storage_path('app/public/uploads/Videos_to_Revise/'.$folderName.'/'.$uniquen_number.'/'.$newFileName);
        $croppedVideoPath = storage_path('app/public/uploads/Videos_to_Revise/'.$folderName.'/'.$uniquen_number.'/'.$newFileName_cropped_file);
        $cropped_video_path_url = url('/storage/uploads/Videos_to_Revise/' . $folderName.'/'.$uniquen_number . '/' . $newFileName_cropped_file);
    
        //$ffmpegCommand = "C:/FFmpeg/bin/ffmpeg -i " . $video_path . " -ss 00:00:00 -t 00:00:20 " . $croppedVideoPath;
        $ffmpegCommand = "ffmpeg -i " . $video_path . " -ss 00:00:00 -t 00:00:20 " . $croppedVideoPath;
        $test = exec($ffmpegCommand);
    // End crop the video

    // start encrypting the videos
    $highBitrate = (new X264)->setKiloBitrate(1000);
    //start encrypting fulllength files
    FFMpeg::fromDisk('public')
        ->open($filePath) // Provide the path relative to the 'local' disk
        ->exportForHLS()
        ->withRotatingEncryptionKey(function ($filename, $contents) use ($folderName,$uniquen_number) {
            Storage::disk('public')->put('uploads/Videos_to_Revise/'.$folderName.'/'.$uniquen_number . '/encrypted_files/' . $filename, $contents);
        })
        ->addFormat($highBitrate)
        ->save('uploads/Videos_to_Revise/'.$folderName.'/'.$uniquen_number . '/encrypted_files/'.$uniquen_number.'.m3u8');
    //end encrypting fulllength files
    //start encrypting cropped files
    FFMpeg::fromDisk('public')
        ->open('uploads/Videos_to_Revise/'.$folderName.'/'.$uniquen_number.'/'.$newFileName_cropped_file) // Provide the path relative to the 'local' disk
        ->exportForHLS()
        ->withRotatingEncryptionKey(function ($filename, $contents) use ($folderName,$uniquen_number) {
            Storage::disk('public')->put('uploads/Videos_to_Revise/'.$folderName.'/'.$uniquen_number . '/encrypted_files/' . $filename, $contents);
        })
        ->addFormat($highBitrate)
        ->save('uploads/Videos_to_Revise/'.$folderName.'/'.$uniquen_number . '/encrypted_files/'.$uniquen_number.'_cropped.m3u8');

    FFMpeg::fromDisk('public')
        ->open('uploads/Videos_to_Revise/'.$folderName.'/'.$uniquen_number.'/'.$newFileName_cropped_file) // Provide the path relative to the 'local' disk
        ->getFrameFromSeconds(3)
        ->export()
        ->save('uploads/Videos_to_Revise/'.$folderName.'/'.$uniquen_number . '/'.$uniquen_number.'_screenshot.webp');
    //end encrypting cropped files
    // end encrypting the videos

    $videoupload->full_video_url = $video_path_url;
    $videoupload->short_video_url = $cropped_video_path_url;
    $videoupload->main_folder_name = 'Videos_to_Revise';
    $videoupload->category_folder_name = $folderName;
    $videoupload->uploaded_video = $newFileName;
}
$videoupload->save();

DB::commit();
return response()->json(['success'=>'Successfully','redirect' => route('my.account')]);
} catch (\Exception $e) {
    // Rollback the transaction if any operation fails
    DB::rollBack();

    // Log or handle the exception
    // For example:
    // Log::error($e->getMessage());

    // Return error response
    return response()->json(['error' => $e->getMessage()]);
}
}

Into the method there is using FFMEG to crop, encrypt and take screenshot of the videos.

How can I add here real time progressbar. Thank you in advance!

0 likes
2 replies
mabdullahsari's avatar

Set up a bidirectional communication channel using Reverb. If you want real-time client comms, you'll need the appropriate infrastructure for it.

Please or to participate in this conversation.