Duplicate Recording Requests in Browser Extension for Mic/Screen sourced Audio Transcription

I have a website where a function is the user can transcribe audio from their mic and pc audio at the same time, to run other things (core function). Since he browser won’t let computer audio to be recorded through it, I need to have this done through an extension.

The extension does this, and sends the chunks to the API, this happens perfectly.

What happens that shouldn’t, though, is it appears to keep duplicating recording requests on itself. This leads to a lot of errors in transcription, and corrupt audio files.

So, in a nut shell, if someone can help me find a way to make it loop without erroneous/duplicate blobs being sent, while not duplicating processes to it is light on the computer memory, I would be very greatful!

Here’s the contentScript.js code (where these functions are happening)

// contentScript.js
console.log("Content script has loaded.");

let mediaRecorder;
let isRecording = false;
let audioContext = new AudioContext();
let mixedStream = null;
let recording = false;
let recordingCount = 0; // Variable to count how many times startRecording has been invoked
let lastAudioHash = null;
let audioQueue = [];
let processingAudio = false;
let mediaRecording = 0;
const MIN_TIME_GAP = 5000; // Minimum time difference (in milliseconds) to consider non-duplicate
let lastAudioSentTime = null; // Stores the timestamp of the last sent audio

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    console.log("Received command:", request.command);
    switch (request.command) {
        case "startRecording":
            if (!isRecording) {
                startRecording(sendResponse);
            } else {
                console.log("Recording already in progress.");
                sendResponse({ status: 'success', message: 'Recording already started.' });
            }
            break;
        case "stopRecording":
            stopRecording();
            sendResponse({ status: 'success', message: 'Recording stopped.' });
            console.log("Recording stopped.");
            break;
    }
    return true; // This keeps the sendResponse callback valid for asynchronous use
});

async function startRecording(sendResponse) {
    console.log(`Starting recording`);
    if (recordingCount > 1) {
        console.log("Exiting function because recordingCount is greater than 1.");
        return; // Exit the function
    }
    
    try {
        if (!mixedStream || !isStreamActive(mixedStream)) {
            mixedStream = await initializeStreams();
        }
        if (audioContext.state === 'suspended') {
            await audioContext.resume();
        }
        setupRecorder(mixedStream);
        //isRecording = true;
        recording = true;
        
        console.log("Recording started successfully.");
    } catch (error) {
        console.error("Failed to start media capture:", error);
    }
}

async function initializeStreams() {
    let micStream = await navigator.mediaDevices.getUserMedia({ audio: true });
    let displayStream = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: true });
    return mixStreams(micStream, displayStream);
}

function mixStreams(micStream, displayStream) {
    const micSource = audioContext.createMediaStreamSource(micStream);
    const displaySource = audioContext.createMediaStreamSource(displayStream);
    const destination = audioContext.createMediaStreamDestination();
    micSource.connect(destination);
    displaySource.connect(destination);
    return destination.stream;
}

function setupRecorder(stream) {

    mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm; codecs=opus' });
    mediaRecorder.ondataavailable = handleDataAvailable;
    if (mediaRecording === 0){
        mediaRecording = 1;
        mediaRecorder.start(20000); // Record in 10-second chunks
    }

    mediaRecorder.addEventListener("dataavailable", event => {
        if (event.data.size > 0 && recording) {
            if (recording) { // If still recording, restart immediately
                mediaRecording = 0;
                mediaRecorder.stop; // Record in 10-second chunks
                setupRecorder(stream);
            }
            processQueue(event.data); // Pass episodeId to function
        }
    });

    mediaRecorder.onstop = () => {
        console.log("Recorder stopped.");
        if (isRecording) {
            console.log("Restarting recording...");
        }
    };
}

function handleDataAvailable(event) {
    if (event.data.size > 0) {
        enqueueAudio(event.data); // Changed to enqueue audio for processing
    }
}

function enqueueAudio(blob) {
    audioQueue.push(blob);
    if (!processingAudio) {
        processQueue();
    }
}

function processQueue() {
    if (audioQueue.length === 0) {
        processingAudio = false;
        return;
    }
    
    processingAudio = true;
    const blob = audioQueue.shift();
    sendAudioToServer(blob);
}

function sendAudioToServer(blob) {
    // Basic check for valid blob size (avoid empty blobs)
    if (!blob || blob.size === 0) {
      console.log("Empty audio blob detected. Skipping sending.");
      processingAudio = false;
      processQueue(); // Process next item in the queue
      return;
    }
  
    // Check for content type (MIME type) if available
    if (blob.type && !blob.type.startsWith('audio/')) {
      console.log("Invalid audio file type:", blob.type, ". Skipping sending.");
      processingAudio = false;
      processQueue(); // Process next item in the queue
      return;
    }
  
    // Basic silence detection
    const audioContext = new AudioContext();
    const reader = new FileReader();
    reader.onload = () => {
      const arrayBuffer = reader.result;
      audioContext.decodeAudioData(arrayBuffer, (decodedAudio) => {
        const channelData = decodedAudio.getChannelData(0); // Assuming single channel audio
  
        let isSilent = true;
        for (let i = 0; i < channelData.length; i++) {
          if (Math.abs(channelData[i]) > SILENCE_THRESHOLD) {
            isSilent = false;
            break;
          }
        }
  
        if (isSilent) {
          console.log("Audio clip appears silent. Skipping sending.");
          processingAudio = false;
          processQueue(); // Process next item in the queue
          return;
        } else {

            const currentAudioHash = simpleHash(blob); // Hash the blob directly
            const currentTime = Date.now(); // Get current timestamp
        
            // Check for duplicate based on hash and time difference
            if (currentAudioHash === lastAudioHash && currentTime - lastAudioSentTime < MIN_TIME_GAP) {
            console.log("Duplicate audio detected (within time threshold). Skipping...");
            processingAudio = false;
            processQueue(); // Process next item in the queue
            return;
            }

            lastAudioHash = currentAudioHash;
            lastAudioSentTime = currentTime;
        
            lastAudioHash = currentAudioHash;
        
            const reader = new FileReader();
            reader.onloadend = () => {
            const base64AudioMessage = reader.result.split(',')[1];
        
            console.log("Sending new audio data to background for transcription...");
        
            chrome.runtime.sendMessage({
                command: "transcribeAudio",
                audioData: reader.result
            }, response => {
                if (chrome.runtime.lastError) {
                console.error("Error sending audio data:", chrome.runtime.lastError.message);
                } else {
                console.log("Transcription response received:", response);
                sendTranscription(response);
                }
            });
            };
        
            // Read data only if not a duplicate
            reader.readAsDataURL(blob);
        
      }
    }, (error) => {
      console.error("Error decoding false audio file (ignore this and the DOM Exception):", error);
      processingAudio = false;
      processQueue(); // Process next item in the queue
      return;
    });
  };
  reader.readAsArrayBuffer(blob);

  // Silence detection constants (adjust as needed)
  const SILENCE_THRESHOLD = 0.001; // Adjust based on your audio levels and noise floor
  }
  
  // Function to compute a simple hash from a string
  function simpleHash(str) {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
  }
  
  function sendTranscription(transcription) {
    console.log("Sending transcription to background...");
    chrome.runtime.sendMessage({
        command: "sendTranscription",
        transcription: transcription
    }, response => {
        if (chrome.runtime.lastError) {
            console.error("Error sending transcription data:", chrome.runtime.lastError.message);
        } else {
            console.log("Transcription response received:", response);
        }
    });
}

async function stopRecording() {
    if (mediaRecorder && mediaRecorder.state === 'recording') {
        mediaRecorder.stop();
    }
    isRecording = false;
    recording = false;
    audioContext.close(); // Clean up the audio context
    audioContext = new AudioContext(); // Reinitialize the audio context
    mixedStream = null; // Reset the mixed stream
}

function isStreamActive(stream) {
    return stream && stream.active;
}

After implementing some filters for this issue, the transcription happens as needed, however, because the duplication is ongoing, it keeps doubling the processes, even though they’re being exited it not used.

This uses a LOT of memory on the user’s computer, leading it to crash in a few minutes.

I can’t make the chunks bigger to reduce process duplication as the transcription needs to be pretty stable. The website adds time stamps according to when the audio transcription is added, so a streaming voice-to-text won’t work. So I have to do the chunking.

I’ve tried for days to fix this, but it either does this, or doesn’t transcribe past the first audio chunk when I implement any safeguards other than the below.

I’m sorry for the amount of code, but I want you to have all of the context to see what could be wrong.

I can’t have it request premission every time it loops for another chunk to record, because this won’t allow seamless transcription, as the user will keep having to select the screen sharing options and approve, which is a terrible UX.

Fatal error: Uncaught ArgumentCountError: Too few arguments to function twig_split_filter(), 2 passed

i’working on a project php/twig and i got problem in my template while calling the split function of Twig
here is my admin.twig

{% set safeties = ["allg", "labor", "s1"] %}
{% set suArrRequire = ("1" ~ data.pflichtSU)|split('') %}
{% for safety in safeties %}
    <div class="col-xs-4 col-sm-3">
        <div class="btn-group btn-group-toggle" data-toggle="buttons">
            <label class="btn btn-secondary radio-inline {% if suArrRequire[loop.index0] == 1 %}active{% endif %}" for="yes{{ loop.index0 }}">
                <input type="radio" name="data[suRequire][{{ safety }}]" id="yes{{ loop.index0 }}" value="1" autocomplete="off" {% if suArrRequire[loop.index0] == 1 %}checked{% endif %}><span class="tr" key="yes"></span>
            </label>
            <label class="btn btn-secondary radio-inline {% if suArrRequire[loop.index0] == 0 %}active{% endif %}" for="no{{ loop.index0 }}">
                <input type="radio" name="data[suRequire][{{ safety }}]" id="no{{ loop.index0 }}" value="0" autocomplete="off" {% if suArrRequire[loop.index0] == 0 %}checked{% endif %}><span class="tr" key="no"></span>
            </label>
        </div>
    </div>
{% endfor %}
</div>

and here is the function from Twig class CoreExtension.php:

function twig_split_filter(Environment $env, $value, $delimiter, $limit = null)
{
    if (strlen($delimiter) > 0) {
        return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
    }

    if ($limit <= 1) {
        return preg_split('/(?<!^)(?!$)/u', $value);
    }

    $length = mb_strlen($value, $env->getCharset());
    if ($length < $limit) {
        return [$value];
    }

    $r = [];
    for ($i = 0; $i < $length; $i += $limit) {
        $r[] = mb_substr($value, $i, $limit, $env->getCharset());
    }

    return $r;
}

    public function getFilters(): array
    {
        return [
            // formatting filters
            new TwigFilter('date', 'twig_date_format_filter', ['needs_environment' => true]),
            new TwigFilter('date_modify', 'twig_date_modify_filter', ['needs_environment' => true]),
            new TwigFilter('format', 'sprintf'),
            new TwigFilter('replace', 'twig_replace_filter'),
            new TwigFilter('number_format', 'twig_number_format_filter', ['needs_environment' => true]),
            new TwigFilter('abs', 'abs'),
            new TwigFilter('round', 'twig_round'),

            // encoding
            new TwigFilter('url_encode', 'twig_urlencode_filter'),
            new TwigFilter('json_encode', 'json_encode'),
            new TwigFilter('convert_encoding', 'twig_convert_encoding'),

            // string filters
            new TwigFilter('title', 'twig_title_string_filter', ['needs_environment' => true]),
            new TwigFilter('capitalize', 'twig_capitalize_string_filter', ['needs_environment' => true]),
            new TwigFilter('upper', 'twig_upper_filter', ['needs_environment' => true]),
            new TwigFilter('lower', 'twig_lower_filter', ['needs_environment' => true]),
            new TwigFilter('striptags', 'strip_tags'),
            new TwigFilter('trim', 'twig_trim_filter'),
            new TwigFilter('nl2br', 'nl2br', ['pre_escape' => 'html', 'is_safe' => ['html']]),
            new TwigFilter('spaceless', 'twig_spaceless', ['is_safe' => ['html']]),

            // array helpers
            new TwigFilter('join', 'twig_join_filter'),
            new TwigFilter('split', 'twig_split_filter', ['needs_environment' => true]),
            new TwigFilter('sort', 'twig_sort_filter'),
            new TwigFilter('merge', 'twig_array_merge'),
            new TwigFilter('batch', 'twig_array_batch'),
            new TwigFilter('column', 'twig_array_column'),
            new TwigFilter('filter', 'twig_array_filter'),
            new TwigFilter('map', 'twig_array_map'),
            new TwigFilter('reduce', 'twig_array_reduce'),

            // string/array filters
            new TwigFilter('reverse', 'twig_reverse_filter', ['needs_environment' => true]),
            new TwigFilter('length', 'twig_length_filter', ['needs_environment' => true]),
            new TwigFilter('slice', 'twig_slice', ['needs_environment' => true]),
            new TwigFilter('first', 'twig_first', ['needs_environment' => true]),
            new TwigFilter('last', 'twig_last', ['needs_environment' => true]),

            // iteration and runtime
            new TwigFilter('default', '_twig_default_filter', ['node_class' => DefaultFilter::class]),
            new TwigFilter('keys', 'twig_get_array_keys_filter'),
        ];
    }

the Error i get is
enter image description here

i tried to wrok on the parametrs but still get the same problem

Cookies are empty inside getServerSideProps when in production but works on development(localhost)?

/pages/post/[id].tsx

export async function getServerSideProps(context: GetServerSidePropsContext) {
  const { id } = context.params as Params
  const { req, res } = context
  //this cookie is undefined in vercel deployment
  const { cookie } = req?.headers

  const parsedCookie = cookie && parse(cookie as string)
  res.setHeader('Cache-Control', 's-maxage=20, stale-while-revalidate')
 
    const postDetails = await getPostDetails(id as string)

    if (parsedCookie) {
      return {
        props: {
          postDetail: postDetails,
          cookie: parsedCookie
        }
      }
    } else {
//this statement runs in deployed site because of no cookies
      return {
        props: {
          postDetail: postDetails,
          cookie: {
            accessToken: '',
            refreshToken: ''
          }
        }
      }
    }
}

This is how I am setting http only cookie from my separate express api.

//server/auth.ts

   const environment = process.env.NODE_ENV // it is "production" in .env file of production

   res.cookie('refreshToken', refreshToken, {
          httpOnly: true,
          secure: environment === 'production',
          sameSite: environment === 'production' ? 'none' : 'lax',
          path: '/'
        })
        res.cookie('accessToken', accessToken, {
          httpOnly: true,
          secure: environment === 'production',
          sameSite: environment === 'production' ? 'none' : 'lax',
          path: '/'
        })

I am using NextJs pages and separate express backend. In local development, the cookies are available inside ‘getServerSideProps” and can access it. And I can see accessToken from it to my backend through axios.

But the deployed site on vercel has empty or undefined cookie “req.headers.cookie” while trying to access inside getServerSideProps in production. But yeah, with client side fetching even in vercel deployed site, I can see access token being available to backend. So, no problem of cookie not being set on deployed frontend domain. Just that there is cookies are undefined only inside getServerSideProps in vercel deployment.

What might be the issue? Am I missing something? Has anyone encountered this issue? I tried all methods of setting path to “/” and all others but still no luck

In local development, cookies are being populated in getServerSideProps as seen in the picture
enter image description here

Empty or undefined cookie just in vercel deployed domain(production) that’s why second else statement ran

enter image description here

jQuery filter results with checkboxes

I have the below code for a simple checkbox filter. It works well if all conditions are met with the checkboxes, i.e. Monday or Tuesday are checked. But checking both Monday and Tuesday gives no results. I would like it to show results that have a Monday or a Tuesday but can’t adapt what i have. Any help massively appreciated!

            <form id="filter">
                <h3>Filter</h3>
                <h4>Day</h4>
                <div class="checkDays"><input class="" type="checkbox" value="Monday" /> Monday</div>
                <div class="checkDays"><input class="" type="checkbox" value="Tuesday" /> Tuesday</div>
                <div class="checkDays"><input class="" type="checkbox" value="Wednesday" /> Wednesday</div>
                <div class="checkDays"><input class="" type="checkbox" value="Thursday" /> Thursday</div>
                <div class="checkDays"><input class="" type="checkbox" value="Friday" /> Friday</div>
                <div class="checkDays"><input class="" type="checkbox" value="Saturday" /> Saturday</div>
                <div class="checkDays"><input class="" type="checkbox" value="Sunday" /> Sunday</div>
                <h4>Time</h4>
                <div class="checkTime"><input class="" type="checkbox" value="AM" /> AM</div>
                <div class="checkTime"><input class="" type="checkbox" value="PM" /> PM</div>
                <div class="checkTime"><input class="" type="checkbox" value="ALL DAY" /> ALL DAY</div>
            </form>

            <div class="noresults"></div>
            <?php $loop = new WP_Query(array('post_type' => 'session', 'posts_per_page' => 50)); while ( $loop->have_posts() ) : $loop->the_post(); ?>
            <div class="card" data-combined="<?php the_field('AM/PM');?>,<?php $field = get_field_object('day'); $days = $field['value']; if($days): foreach( $days as $day ): echo ',' . $field['choices'][$day]; endforeach; endif; ?>">
            </div>

            <script>
            $('form#filter').on('change', function () {

                var filterList = [];

                $("form#filter .checkDays input:checked").each(function () {
                    var dataDays = $(this).val();
                    filterList.push(dataDays);
                });

                $("form#filter .checkTime input:checked").each(function () {
                    var dataTime = $(this).val();
                    filterList.push(dataTime);
                });

                if (filterList.length == 0) {
                    jQuery('.card').removeClass('is-hidden');
                    jQuery('.card').fadeIn();

                } else {

                    jQuery('.card').filter(function () {
                        const isVisible = ['data-combined'].some(attr => {
                            const attrValue = jQuery(this).attr(attr);
                            if (!attrValue) {
                                return;
                            }
                            const offerings = attrValue.split(',');
                            return filterList.every(offering => offerings.indexOf(offering) > -1);
                        });

                        if (isVisible) {
                            jQuery(this).fadeIn('slow');
                        } else {
                            jQuery(this).hide();
                        }
                    });
                }

            });
            </script>

Discord canvafy welcome / leave card

I don’t know where the recursion is happening. I don’t know how to stop it from sending multiple welcome attachments. After a while my bot crashes and sends the error: RequestAbortedError [AbortError]: Request aborted. I use sequelize as my schema / model.

my code:

const { WelcomeLeave } = require('canvafy');
const Guild = require('../model/guild');

function getRandomColor() {
    const letters = '0123456789ABCDEF';
    let color = '#';
    for (let i = 0; i < 6; i++) {
        color += letters[Math.floor(Math.random() * 16)];
    }
        return color;
}

module.exports = {
    name: 'guildMemberAdd',

    async execute(member) {
        const WelcomeGuild = await Guild.findOne({ where: {id: member.guild.id } });

        const randomBorderColor = getRandomColor();
        const randomAvatarBorderColor = getRandomColor();
           
            const welcome = await new WelcomeLeave()
                .setAvatar(member.user.displayAvatarURL({ forceStatic: true, extension: 'png' }))
                .setBackground('image', WelcomeGuild.welcomeBackground || '')
                .setTitle('Welcome!')
                .setDescription(`Glad you're here ${member.user.username}!`)
                .setBorder(randomBorderColor)
                .setAvatarBorder(randomAvatarBorderColor)
                .setOverlayOpacity(0.3)
                .build();

            if(WelcomeGuild.welcomeChannelId) {
                const welcomeChannel = await member.guild.channels.fetch(WelcomeGuild.welcomeChannelId);
                welcomeChannel.send({ content: `Hello ${member}!`, files: [{ attachment: welcome, name: `welcome-${member.id}.png` }] });
            }

        if(WelcomeGuild.welcomeRoleId) {
            const welcomeRole = await member.guild.roles.fetch(WelcomeGuild.welcomeRoleId);
            await member.roles.add(welcomeRole);
        }
    }
}

I don’t know how to properly pass the value of the image string like these;

if(WelcomeGuild.welcomeChannelId) {
                const welcomeChannel = await member.guild.channels.fetch(WelcomeGuild.welcomeChannelId);

if(WelcomeGuild.welcomeRoleId) {
            const welcomeRole = await member.guild.roles.fetch(WelcomeGuild.welcomeRoleId);

and implement it to the background

if(WelcomeGuild.welcomeBackground) {
            const welcomeBackground = WelcomeGuild.welcomeBackground;

^this doesn’t work

Exception has occurred: SyntaxError: Unexpected token ‘d’, “dropdown” is not valid JSON

I started using bootstrap v5.3.3 and when i press on the dropdown button, i get this exception: “Exception has occurred: SyntaxError: Unexpected token ‘d’, “dropdown” is not valid JSON”.
Exception message

The program i am using: Visual Stuido Code

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Test title</title>

    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
  </head>
  
  <body>
    <div class="dropdown">
        <a class="btn btn-secondary dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
          Dropdown link
        </a>
      
        <ul class="dropdown-menu">
          <li><a class="dropdown-item" href="#">Action</a></li>
          <li><a class="dropdown-item" href="#">Another action</a></li>
          <li><a class="dropdown-item" href="#">Something else here</a></li>
        </ul>
      </div>

      
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>
  • The dropdown button works when i uncheck the Caught Exceptions.
  • I tried installing bootstrap via npm, but i got the same exception.
  • Is there a way to fix this Exception?

Error while trying to run moxios test – Cannot read properties of undefined (reading ‘url’)

I have a class where I am making an axios instance in the constructor. This class also has service methods (omitted in the snippet):-

export class CartCreationService extends SuperClass {
  public static axiosInstance: AxiosInstance;
  constructor(serviceName: string) {
    super(serviceName);
    CartCreationService.axiosInstance = axios.create({
      baseURL: Configuration.NEW_CART_API,
      headers: {
        [Constants.CONTENT_TYPE]: Constants.APPLICATION_JSON,
        [Constants.X_API_KEY]: Configuration.CLIENT_SIDE_API_KEY,
        [Constants.CORRELATIONID]: Configuration.CORRELATIONID,
        [Constants.ADD_EFFECTIVE_PRICE]: true
      }
    });
    CartCreationService.axiosInstance = Utils.setAxiosLogInterceptor(CartCreationService.axiosInstance);
  }
}

In my Mocha test file, this is what I have. I’m importing the same axios instance from my class and using it to call a service method:-

describe("Test", () => {
  let cartCreationService;

  before(() => {
    cartCreationService = CartCreationService.Instance();
  });
  beforeEach(() => {
    moxios.install(CartCreationService.Instance().axiosInstance);
  });
  afterEach(() => {
    moxios.uninstall(CartCreationService.Instance().axiosInstance);
  });
  let requestJSON = {
    "data": {}
  };
  const cartId = "036336e2ca5519f840dc";
  const mainItemId = "";
  it.only("should return", async() => {
    let requrl = "url";
    moxios.stubRequest(requrl, {
      status: 200,
      responseText: JSON.parse(JSON.stringify(cart))
    });
    try {
      const result = await cartCreationService.addAccessoryToCart(requestJSON, cartId, mainItemId);
      expect(result.type).to.equal("Cart");
      requrl = "";
    } catch (error) {
      console.log("error ->", error);
    }
  });
});

I’m always getting an error Cannot read properties of undefined (reading 'url') in the catch block. Where am I going wrong?

Tabulator update columns definition on data filtering

I would like to know if there is the possibility to update the column definition on data filtering.

Here is a code pen that fully show my situation.

let tableData = [
  {
    name: "Donna Summer",
    gender: "female"
  },
  {
    name: "Oli Bob",
    gender: "male",
    filed_male: "1"
  },
  {
    name: "Mary May",
    gender: "female",
    filed_female: "2"
  },
  {
    name: "Christine Lobowski",
    gender: "female",
    filed_female: "2"
  },
  {
    name: "Brendon Philips",
    gender: "male",
    filed_male: "1"
  }

I have table data with different fields, in that case rows with gender: “female” have a non common field “filed_female” and rows with gender: “male” have a non common field “filed_male”.

I would like to update columns definition on filtering rows with gender female/male to show also the column filed_female/filed_male.

I’ve already try a solution, updating table data with only filtered rows, but than I can’t remove the filter to show again all the rows.

Is there any other solution? Many thanks!

How can I decode the encoded MediaCodec bytes using Node.js or JavaScript?

I am a new Java learner who created a screen recording application in Java. The application was working fine, but I converted the stream to bytes using mediacodec and sent it via socket connection through Node.js.

tried code:-

/MainActivity.java/

package com.hivemdm.remoteviewer;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.display.DisplayManager;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import org.apache.cordova.*;

import java.io.IOException;
import java.nio.ByteBuffer;

public class MainActivity extends CordovaActivity {

    private static final int REQUEST_CODE_SCREEN_CAPTURE = 1001;
    private static final int REQUEST_CODE_PERMISSIONS = 1002;

    private MediaProjectionManager mediaProjectionManager;
    private MediaProjection mediaProjection;
    private MediaCodec mediaCodec;
    private Surface surface;
    private boolean isRecording = false;
    private socketClient socketClient;
    private EncoderThread encoderThread;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Initialize socket client
        socketClient = new socketClient();

        // Request screen recording permission
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
                    != PackageManager.PERMISSION_GRANTED ||
                    ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                            != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        REQUEST_CODE_PERMISSIONS);
            } else {
                startScreenRecording();
            }
        } else {
            // Lower API versions do not support screen recording
            Log.e("MainActivity", "Screen recording not supported on this device.");
        }

        // Set by <content src="index.html" /> in config.xml
        loadUrl(launchUrl);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED
                    && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                startScreenRecording();
            } else {
                Log.e("MainActivity", "Permissions denied. Cannot start screen recording.");
            }
        }
    }

    private void startScreenRecording() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_CODE_SCREEN_CAPTURE);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_SCREEN_CAPTURE && resultCode == RESULT_OK) {
            mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
            if (mediaProjection != null) {
                // Configure MediaCodec
                try {
                    configureMediaCodec();
                } catch (IOException e) {
                    e.printStackTrace();
                    return;
                }

                // Start recording
                startRecording();
            }
        }
    }

    private void startRecording() {
        mediaProjection.createVirtualDisplay("MainActivity",
                1280, 720, getResources().getDisplayMetrics().densityDpi,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                surface, null, null);
        isRecording = true;

        // Start the encoder thread
        encoderThread = new EncoderThread();
        encoderThread.start();
    }

    private void configureMediaCodec() throws IOException {
        MediaFormat format = MediaFormat.createVideoFormat("video/avc", 1280, 720);
        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
        format.setInteger(MediaFormat.KEY_BIT_RATE, 4000000);
        format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
        format.setInteger(MediaFormat.KEY_CAPTURE_RATE, 30);
        format.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 1000000 / 30);

        try {
            mediaCodec = MediaCodec.createEncoderByType("video/avc");

            MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 1280, 720);
            mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
            mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 4000000);
            mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
            mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2); // 2 seconds between I-frames

            mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            surface = mediaCodec.createInputSurface();
            mediaCodec.start();
        } catch (IOException e) {
            e.printStackTrace();
            Log.e("MainActivity", "Error configuring MediaCodec: " + e.getMessage());
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            Log.e("MainActivity", "Invalid argument for MediaCodec: " + e.getMessage());
        } catch (IllegalStateException e) {
            e.printStackTrace();
            Log.e("MainActivity", "Illegal state exception for MediaCodec: " + e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("MainActivity", "Unknown error occurred: " + e.getMessage());
        }
    }

    private void stopScreenRecording() {
        if (isRecording) {
            isRecording = false;
            mediaProjection.stop();

            if (mediaCodec != null) {
                mediaCodec.stop();
                mediaCodec.release();
                mediaCodec = null;
            }

            Log.d("MainActivity", "Screen recording stopped.");
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopScreenRecording();
        socketClient.disconnect(); // Disconnect the socket when activity is destroyed
    }

    private class EncoderThread extends Thread {
        @Override
        public void run() {
            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
            while (isRecording) {
                int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 10000);
                if (outputBufferIndex >= 0) {
                    ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferIndex);
                    if (outputBuffer != null) {
                        byte[] outData = new byte[bufferInfo.size];
                        outputBuffer.get(outData);
                        outputBuffer.clear();

                        // Send the encoded data over the socket
                        socketClient.sendData(outData);
                    }
                    mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
                }
            }
        }
    }
}

I finally received the data at the node server socket, as shown below.

Buffer 00 00 00 01 41 9a aa c0 af 2f 57 fa bf cf 4e ba 03 ff 5e be af f5 ea 1a a6 c7 fa ff ea ff 5f fd 5f ea ff 57 ae af f5 7f ab fd 5f eb ff ab fd 7f f5 7f … 2731 more bytes>

Can someone please confirm if the code above is correct? Also, could someone assist me with decoding MediaCodec bytes using Node.js or JavaScript?

Test function for array elements values check, not removing

I’m trying to wave out all the bad situations with the elements of my array. But unfortunately my JavaScript code doesn’t work as one piece: it works correctly with a separate “IF” selectors but not all together. Could anybody explain me whats the issue? Thanks a lot in advance!
Here is the code:

/** Check the elements of the array on:
* The array is empty
* Array element/s is/are not a numbers
* Among elements there is not an integers
* Among elements there is a negative number/s
* Among elements there is a too large numbers
*/
const parbaude = (mas) => {
    var response = [true, "... No problem found!"];
    if (mas.length == 0) {
        response = [false, "... Your array is empty!"];
    } else if (mas.filter(item => typeof item !== 'number')) {
        response = [false, "... Only numbers are allowed!"];
    } else if (mas.filter(item => !Number.isInteger(item))) {
        response = [false, "... Enter integer only!"];
    } else if (Math.min(...mas) <= 0) {
        response = [false, "... Only positive numbers are allowed!"];
    } else if (Math.max(...mas) > 1000) {
        response = [false, "... The number is too large: n < 1000!"];
    } else {
        // Return the test result
        return response;
    }
};
//  !!! Try each of these options !!!
//const mas = [];
//const mas = [3, 'd', 7, 9];
//const mas = [3, 4.6, 7, 9];
const mas = [3, -4, 7, 9];
//const mas = [3, 4000, 7, 9];
//const mas = [3, 4, 7, 9];
document.getElementById("izvade").innerHTML = parbaude(mas);

Unable to remove input box border in React

I’ve been trying to remove the black box that appears when you click the input box, but it doesn not go away

  const renderSearch = () => {
    return (
      <View style={styles.searchSection}>
        <FaSearch style={styles.searchIcon} />
        <TextInput
          value={searchValue}
          onChangeText={(text) => onSearch(text)}
          placeholder="Search for a restaurant"
          style={styles.input}
        />
      </View>
    )
  }

  input: {
    flex: 1,
    height: '100%',
    width: '100%',
    color: '#424242',
    backgroundColor: 'transparent',
    borderWidth: 0, // Eliminar el borde
    padding: 0, // Eliminar el relleno
    fontSize: 16 // Ajustar el tamaño de la fuente según sea necesario
  },

Remove the black box

Vue.js acess components values

I have a question:
I have two files. I want to dynamically access the value of assignmentData of the one file when it’s value changes. How do I do this? It’s changed when I mark a checkbox…
Component code:

<template>

    <form class="form-horizontal">

        <div class="form-group" >
            <label for="kursAusgewählt" class="col-sm-4 control-label"  ></label> 
           <template v-if="data_for_assignment.kurs.priority_system == 0">
                <div class="col-smfz-11" style="margin-top: -40px;" >
                    <label id="kursAusgewählt" class="checkbox-container" >
                        
                        <input  type="checkbox" :checked="assignmentData.selected" @change="update('selected', $event.target.checked)">
                        <span class="checkmark" style="margin-left: -40px; margin-top:33px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Auswählen</span> 
                        
                    </label>
                </div>
            </template>
        
            <template v-if="data_for_assignment.kurs.priority_system == 1" >
                <div class="col-smfz-6" >
                    <select v-model="assignmentData.selected_prio" class="form-control inline" data-width="85px" style="color:gray; ;width: 100px; margin-left:-40px;margin-top: -8px;">
                        <option v-for="prio in data_for_assignment.prios" :key="prio" :value="prio">
                            <template v-if="prio == 0">
                              Priorität &nbsp; wählen &nbsp;
                            </template>
                            <template v-else>
                                Priorität {{prio}}
                            </template>
                        </option>
                    </select>   
                </div>
            </template>
            
        </div>

    </form>
<script>

    import modal from "../../modal.vue"

    export default {
        name: 'anmeldenScheduleComponent',
        components: {
            modal
        },
        props: {
            assignmentData: [],
            data_for_assignment: {},
            
        },
        data: function() {
            return {
                value_default: {
                    selected: false,
                    selected_prio: 0,
                },
                showModal: false,
            }
        },
        updated (){
            this.setDefault();
        },
        mounted(){
            this.setDefault();
        },
        methods: {
        
            update(key, value) {
                this.assignmentData[key] = value;
                this.$emit('update:assignmentData', this.assignmentData);
                
            },

            setDefault() {
                if (this.assignmentData == [] || !this.assignmentData.assignedDefault){
                    for (const [key, value] of Object.entries(this.value_default)) {
                        this.assignmentData[key] ??= value;
                    }
                    
                    this.$emit('update:assignmentData', this.assignmentData);
                    this.assignmentData.assignedDefault = true;
                }
            },
            
        },
        computed: {
            
        }
    }
</script>

and here the code of the main file:

<template>


    <div class="home">
        
        <div class="body content rows scroll-y">
            <div class="page-heading animated fadeInDownBig">
                <h1>Kursanmeldung</h1>
            
                
            </div>
            <box_content>
                <h2><strong>Anmeldbare Kurses</strong>
               
                    <div class="" style="margin-top: 4px; margin-left: 150px; position: absolute; top: 16px; color: #909090">
                        <a class="additional-icon" id="dropdownErklaerung" data-toggle="dropdown" aria-expanded="false" style="color: #909090"><i class="fa fa-question-circle"></i></a>
        
                        <div class="fragezeichenErklaerung dropdown-menu pull-right" style="margin-right: -150px" aria-labelledby="dropdownErklaerung">
                            In diesem Menü können Sie die Kurse einsehen, für welche Sie sich anmelden können.
                        </div>
                    </div>

                
                    <template v-if="kurseAnmeldbar && kurseAnmeldbar.length > 0">
                        <div class="pull-right selectobenrechts" style="margin-top: -10px; max-width: 368px;">
                            <select v-model="selected_kurs_id" class="form-control inline" data-width="150px" style="z-index:0 !important; display: inline-block;;" @change="updateSelection">
                                <option v-for="kurs in kurseAnmeldbar" :key="kurs.id" :value="kurs.id">
                                    {{kurs.name}}
                                </option>
                            </select>       
                        </div>
                    </template>
     
                </h2>

                <template v-if="kurseAnmeldbar && kurseAnmeldbar.length > 0">
                    <div align="right" class="form-group">      
                        <div class="btn-toolbar">
                            <template v-if="!anmeldenAllowed">
                                <b>{{ anmeldenDisabledReason }}</b>
                            </template>   
                            <button type="button" class="btn btn-primary"   v-on:click="kursAnmelden"  :disabled="!anmeldenAllowed">Anmeldung absenden</button>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="textInput">Zusätzliche Bemerkung zur Anmeldung</label>
                        <input type="text" class="form-control" id="textInput" placeholder="Hier zusätzliche Bemerkungen eingeben...">
                    </div>

                    <div class="form-group" style="padding: 20px;">
                        <scheduler :assignments="termine" :allow_add_assignment="false" :allow_delete_assignment="false" :allow_drag_and_drop="false" :allow_resize="false" :slot_component_name="'anmeldenScheduleComponent'" v-bind:data_for_assignment="dataForAssignment" />
                    </div>

                </template>
                <template v-else>
                    <center> 
                        <h2>Es sind keine anmeldbaren Kurse vorhanden.</h2> 
                    </center>
                </template>
  

            </box_content>
            
        </div>
    </div>
 </template>
 <script>

    import {apiRequest} from "../../services/api.js"
    import box_content from "../../components/box_content.vue"
    import scheduler from "../../components/scheduler/scheduler.vue"
    import anmeldenScheduleComponent from "../../components/scheduler/slotComponents/anmeldenScheduleComponent.vue"

    import {timestringToDate} from "../../services/service_scheduler.js" 

    export default { 
      components: {
        scheduler, box_content, anmeldenScheduleComponent, 
      },
      
      
      data: function() {
          return {
            kurseAnmeldbar: [],
            selected_kurs_id: -1, 
            selected_kurs: {},
            assignmentData:{},
            
           
          }
        
      },
      
      methods: {
        
        
        async update ()  {
            try{
                this.kurseAnmeldbar = await apiRequest("get", "/kursverwaltung/kurse/anmeldbar");
            }catch{
                console.log("ERROR")
            }
            if (this.kurseAnmeldbar != null && this.kurseAnmeldbar.length > 0 && this.selected_kurs_id == -1){
                this.selected_kurs_id = this.kurseAnmeldbar[0].id;
                this.updateSelection();
            }
        },
        updateSelection(){
          for (const kurs of this.kurseAnmeldbar){
            if (kurs.id == this.selected_kurs_id){
                this.selected_kurs = kurs;
            }
          }
        },   
        async kursAnmelden() {
           let bemerkung= document.getElementById("textInput").value
            let belegungen = [];
            for (const termin of this.selected_kurs.termine){

                for (const real_termin of termin.reale_termine){
                    if (this.selected_kurs.priority_system == 0){ //&& real_termin.selected==true){
                        belegungen.push({
                            
                            "termin": 2,            //real_termin, //real_termin,//2,// termin.selected,//real_termin,
                            "mitglied":0,
                            "prio": null,
                            "bemerkung": bemerkung,
                            //"selected": true,
                        })
                     

                    }
                    else{
                        belegungen.push({
                           // "termin": real_termin,
                           "termin": 1,//termin.selected,//real_termin,
                            "mitglied":0,
                            "prio": real_termin.selected_prio,
                            "bemerkung": bemerkung,
                            //"prio": termin.selected_prio,
                        })
                    }
                }
            }
            try{      
                await apiRequest("post", "kursverwaltung/anmelden", 
                    {
                    "kurs":  this.selected_kurs.id,
                    "belegungen": belegungen,
                    }
                );
                this.requestResponse = "Belegung erfolgreich gespeichert"
            }catch(ex){
                this.requestResponse="Fehler"            }

            this.update();

        }
    },
      
    async mounted (){
          
        let dependency = document.createElement('script')
        dependency.setAttribute('src', '../../../../' + "js/script.js")
        document.head.appendChild(dependency)
        this.update();
        
      },
      computed: {
        
        termine(){
            let termine = []
            let counter = 0;
            for (let termin of this.selected_kurs.termine){
                termin.starttime = new Date(termin.starttime);
                termin.endtime = new Date(termin.endtime);
                termin.column_id = termin.wochentag;
                termin.title = "Termin " + (counter+1);
                //termin.selected = false;
                

                if (termin.selected_prio){
                    termin.selected_prio = String(termin.selected_prio)
                }

                termin.reale_termine = [] //Das brauchen wir für den Overlap. Also welche realen Termine der Termin abdeckt
                let overlap = false;
                let overlap_termin = null;
                for (let termin2 of termine){
                    if (termin.starttime.getTime() == termin2.starttime.getTime() && termin.endtime.getTime() == termin2.endtime.getTime() && termin.column_id == termin2.column_id){
                        overlap = true;
                        overlap_termin = termin2;
                    }
                }
                if (!overlap){
                    termin.reale_termine.push(termin.id);
                    termine.push(termin);                
                    counter++;
                } 
                else{
                    termin.hide = true;
                    overlap_termin.reale_termine.push(termin.id);
                }
                
            }
            return termine;
        },
        dataForAssignment(){
            let prios = Array.from(Array(this.selected_kurs.maximum_selections+1).keys())
            return {
                kurs: this.selected_kurs,
                prios: prios,
            }
        },
        anmeldenAllowed() {

            return this.anmeldenDisabledReason === ""; //Kann sein, dass hier der Render Bug entsteht

        },
        anmeldenDisabledReason () {
            const kurs = this.selected_kurs;
            let selectedTermineCount = 0;
            if (kurs.priority_system === 0) {
                selectedTermineCount = kurs.termine.filter(termine => termine.selected).length;
            }
            else if (kurs.priority_system === 1) {
                const selectedPriorities = [];
                for (const termin of kurs.termine) {
                    if (termin.selected_prio !== undefined && termin.selected_prio !== null && termin.selected_prio !== "" && termin.selected_prio !== "0" && termin.selected_prio !== 0) {
                        if (selectedPriorities.includes(termin.selected_prio)) {
                            return "  Die Prioritätsstufe " + termin.selected_prio + " ist doppelt belegt"
                        }
                        selectedPriorities.push(termin.selected_prio);
                    }
                }
                selectedTermineCount = selectedPriorities.length 
            }
            if (selectedTermineCount < kurs.minimial_selections){
                    return "Bitte wählen Sie mindestens " + kurs.minimial_selections + " Termin(e)"
                }
            else if (selectedTermineCount > kurs.maximum_selections){
                return "Bitte wählen Sie maximal " + kurs.maximum_selections + " Termin(e)"
            }
            else{
                return ""
            }    
        }
    }
}

</script>

<style>



</style>

I tried multiple times by v-mode, v-bind and so on but always got an error or that the value I try to access is “undefined”…
Thanks for your help!

Delay in reloading HTML page after sending data from Google Sheet

i integrate google sheet in my html page, when i send my data, everyhing good -> data apear in google table, but i had big delay in few second, after my page reloaded and clean old data, that was written in page before.

Code form

 <form action="https://script.google.com/macros/s/AKfycbyge9dyR6OtyfE2lir6f4cI32kX-7QSSRAqEgIILZeR4Z2M3JSQqoPdDheuImIkwpRg/exec" method ="post" id="add-form" name="contact-form">
                            <input type="text" name="Name"  class="form-control" placeholder="Ім'я" required="required">
                            <input type="email" name="Email"  class="form-control" placeholder="Почта" required="required">
                            <input type="text" name="Mobile"  class="form-control" placeholder="Мобільний" required="required">
                         
                            <textarea type="text" class="form-control" name="Message" placeholder="Побажання"
                                    required="required"></textarea>
                            <button type="submit" class="site-btn">Відправити</button>
                        </form>

My script app script, in Google sheet extentions

const sheetName = 'dataSite'
const scriptProp = PropertiesService.getScriptProperties()

function intialSetup () {
  const activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet()
  scriptProp.setProperty('key', activeSpreadsheet.getId())
}

function doPost (e) {
  const lock = LockService.getScriptLock()
  lock.tryLock(10000)

  try {
    const doc = SpreadsheetApp.openById(scriptProp.getProperty('key'))
    const sheet = doc.getSheetByName(sheetName)

    const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0]
    const nextRow = sheet.getLastRow() + 1

    const newRow = headers.map(function(header) {
      return header === 'Date' ? new Date() : e.parameter[header]
    })

    sheet.getRange(nextRow, 1, 1, newRow.length).setValues([newRow])

    return ContentService
      .createTextOutput(JSON.stringify({ 'result': 'success', 'row': nextRow }))
      .setMimeType(ContentService.MimeType.JSON)
  }

  catch (e) {
    return ContentService
      .createTextOutput(JSON.stringify({ 'result': 'error', 'error': e }))
      .setMimeType(ContentService.MimeType.JSON)
  }
}

My script in html page

$(document).ready(function() {
    $("#add-form, #add-form2").submit(function(event) {
        event.preventDefault(); // Prevent the default form submission behavior
        alert('Повідомлення Відправлено !');

        $.ajax({
            type: "POST",
            url: $(this).attr("action"),
            data: $(this).serialize(),

            error: function(xhr, status, error) {
                // Handle the error (if needed)
                console.error(xhr.responseText);
            },
            success: function(response) {
                // After successful form submission, reset the form
                $("#add-form, #add-from2")[0].reset();
                window.close();
            }
        }).then(function() {
            // Reload the page after successful AJAX request
            window.location.reload();
        });
    });
});

If sombody know, why my data, does not disappear instantly after sending, but continues to be visible on the page for several seconds, tnx

how to show realtime percenatage progress for form submit operation in laravel

I am developing a video project in Laravel, where a video can be uploaded and when video is being uploaded then after uploading video there are also few operations is performed. Like: cropping videos, encrypted videos using FFMPEG. And inserting records in some tables.

Below is my js code:

submitHandler: function(form) {
                var formData = new FormData(form);

                // Remove existing checkbox array
                $(form).find('input[type="checkbox"]').each(function() {
                    formData.delete($(this).attr('name'));
                });

                // Add new checkbox values to the formData
                $(form).find('.authorSection').each(function(index) {
                    var checkedValue = $(this).find('input[type="checkbox"]').prop('checked') ?
                        '1' : '0';
                    formData.append($(this).find('input[type="checkbox"]').attr('name'),
                        checkedValue);
                });

                // Handling the termscheckbox
                var termsCheckedValue = $('#terms_n_conditions').prop('checked') ? '1' : '0';
                formData.append('terms_n_conditions', termsCheckedValue);

                // Append CSRF token to formData
                formData.append('_token', $('meta[name="csrf-token"]').attr('content'));

                $('#videoSubmit').html('Please Wait...Do not reload page or click on any button.');
                $("#videoSubmit").attr("disabled", true);
                
                var ajax = new XMLHttpRequest();
                ajax.upload.addEventListener("progress", progressHandler, false);
                ajax.addEventListener("load", completeHandler, false);
                ajax.addEventListener("error", errorHandler, false);
                ajax.addEventListener("abort", abortHandler, false);

                ajax.open("POST", '{{ route('video.store') }}');
                ajax.send(formData);

                function progressHandler(event) {
                     console.log("Uploaded " + event.loaded + " bytes of " + event.total);
                    var percent = (event.loaded / event.total) * 100;
                    console.log('percentage==> '+Math.round(percent));
                    updateProgressBar(Math.round(percent));
                }

                function completeHandler(event) {
                    console.log('Response: ' + event.target.responseText);
                    $('#videoSubmit').html('Submit Your Video');
                    $("#videoSubmit").attr("disabled", false);
                    updateProgressBar(100);
                    // Handle additional operations or redirect here
                }

                function errorHandler(event) {
                    $('#videoSubmit').html('Submit Your Video');
                    $("#videoSubmit").attr("disabled", false);
                    $('.errorDisplayDiv').html('Upload Failed');
                }

                function abortHandler(event) {
                    $('#videoSubmit').html('Submit Your Video');
                    $("#videoSubmit").attr("disabled", false);
                    $('.errorDisplayDiv').html('Upload Aborted');
                }

                function updateProgressBar(percent) {
                    $('#progress').text('Progress: ' + percent + '%');
                    $('.progress .progress-bar').css('width', percent + '%');
                }
            }

here file uploading percentage is showing correct. But after uploading the video, other operations are executed. I want to also add the other operations percentage bar there. How can I do that?

Quill.js in error with webpack Encore integration

I’m encountering an issue while integrating Quill.js into my webpack setup. When trying to use Quill in my project, I’m getting the following error:

kotlin
Copy code
Uncaught Error: Module parse failed: Unexpected token (28:18)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|
| class Quill {

static DEFAULTS = {
| bounds: null,
| modules: {

It seems to be related to how webpack is handling Quill.js files, particularly with the static class field syntax used in Quill.
I use Webpack with Encore in my symfony project. (php 7.4 and symfony 5.4)

I’ve tried various configurations and searched for solutions online, but I’m still encountering this issue. Could someone please provide guidance on how to resolve this error and properly integrate Quill.js into my webpack setup?

Thanks in advance for your help!

I aim to integrate Quill.js seamlessly into my webpack setup so that I can use it to create rich text editors within my Symfony application. This integration should allow me to leverage Quill’s features without encountering any errors during the build process. Ultimately, I want to be able to include Quill.js in my project and use it to enhance the text editing experience for my users, all while maintaining a smooth development workflow with webpack.