Any way to bypass fetch() character limit? [closed]

So, I was making a HTML loader that uses HTML from raw GitHub URLS. Smaller HTMLs loaded but when I tried to load larger HTMLS they were incomplete. Every time I loaded a large HTML they cut off at the same time. Is this a character limit? Or is this a problem with my code?

I don’t really know how to fix this which is why I’m asking. Code down below:

<html>
    <head>
        <title>f1re</title>
    </head>
    <body>
        <div class="topbar">
            <button class="bl small" onclick="reload()">
                ↻
            </button>
            <button class="small" onclick="info()">?</button>
            <input type="text" id="URL" placeholder="Enter GIT URL">
            <button class="br big" onclick="loadFunc()">
                Go to URL
            </button>
        </div>
        <iframe id="frame"></iframe>
    </body>
    <script>
        let proxy = "";
        let curr = 'about:blank';
        async function loadFunc(){
            let link = document.querySelector("#URL").value;
            let data = await fetch(proxy.toString()+link.toString());
            let doc = await data.text();
            curr = link;
            document.querySelector("#frame").src = "data:text/html;charset=utf-8,"+doc.toString();
        }
        async function reload(){
            let link = curr;
            let data = await fetch(proxy.toString()+link.toString());
            let doc = await data.text();
            curr = link;
            document.querySelector("#frame").src = "data:text/html;charset=utf-8,"+doc.toString();
        }
        function info(){
            alert('f1re only works for GIT URLS.');
            if(prompt('View GIT URL list? [Y]es / [N]o').toString() === 'Y'){
                alert('Viewing GIT URLS... Click OK to open next page.');
                alert('https://raw.githubusercontent.com/ThisAintComputin/GitSite/refs/heads/main/Main.html');
                alert('NOTE: You can make your own GIT sites. (it is very complicated for beginners though)');
            };
        }
    </script>
    <style>
        body{
            margin: 0px;
        }
        .topbar{
            display: flex;
            position: fixed;
            top: 0%;
            left: 0%;
            right: 0%;
        }
        #URL{
            width: 85%;
            text-align: center;
        }
        .big{
            width: 10%;
        }
        .small{
            width: 5%;
        }
        button{
            background-color: black;
            color: red;
        }
        input{
            background-color: black;
            color: red;
        }
        .bl{
            border-bottom-left-radius: 10px;
        }
        .br{
            border-bottom-right-radius: 10px;
        }
        #frame{
            width: 100%;
            height: 90%;
            position: fixed;
            top: 3%;
            border: none;
        }
    </style>
</html>

vscode format space inside curly braces

In VSCode, there are extra spaces after and before curly braces, I want to remove the extra spaces inside braces,

from

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';

to

import {StrictMode} from 'react';
import {createRoot} from 'react-dom/client';

I added the following in the settings.json file, but it works when I didn’t install prettier extensions when save file, but it doesn’t work after installing prettier extension.

"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false

Also, after this setting, when I write import {crete and press TAB key, the auto import function always inserts the spaces,

how can we remove the spaces when press TAB key and format the file?

React Image Upload Failed to process image

I am currently building a feature to upload a profile picture of the user, frontend is done and working however the backend keeps rejecting the image uploaded, even if it is a jpeg, jpg, png file type.

const storage = multer.memoryStorage(); 
const upload = multer({
    storage: storage,
    fileFilter: (req, file, cb) => {
        const filetypes = /jpeg|jpg|png/;
        const mimetype = filetypes.test(file.mimetype);
        const extname = filetypes.test(path.extname(file.originalname).toLowerCase());

        if (mimetype && extname) {
            return cb(null, true);
        }
        cb(new Error('Invalid file type. Only JPEG and PNG files are allowed.'));
    }
});

// Profile image upload endpoint
router.post('/upload-profile-image', upload.single('profile_img'), async (req, res) => {
    const { customer_id } = req.query;

   
    console.log('Upload request received for customer ID:', customer_id);

    if (!req.file) {
        console.log('No file uploaded.');
        return res.status(400).send({ error: 'No file uploaded.' });
    }

    // Log file details
    console.log('File received:', req.file.originalname, 'Size:', req.file.size);
    console.log('MIME type:', req.file.mimetype);

    try {
        
        if (!req.file.buffer || req.file.buffer.length === 0) {
            return res.status(400).send({ error: 'Uploaded file is empty.' });
        }

       
        console.log('Buffer length:', req.file.buffer.length);

       
        console.log('Processing image...');
        let processedImage;

        
        if (req.file.mimetype === 'image/png') {
            processedImage = await sharp(req.file.buffer)
                .resize(150, 150) 
                .png({ quality: 80 }) 
                .toBuffer();
        } else if (req.file.mimetype === 'image/jpeg' || req.file.mimetype === 'image/jpg') {
            processedImage = await sharp(req.file.buffer)
                .resize(150, 150) 
                .jpeg({ quality: 80 }) 
                .toBuffer();
        } else {
            return res.status(400).send({ error: 'Unsupported image format.' });
        }

        // Log successful image processing
        console.log('Image processing complete. Compressed image size:', processedImage.length);

      
        if (!Buffer.isBuffer(processedImage)) {
            throw new Error('Processed image is not a valid buffer.');
        }

        const sql = 'UPDATE users SET profile_img = ? WHERE customer_id = ?';

     
        console.log('Executing SQL query:', sql);

        db.query(sql, [processedImage, customer_id], (err, result) => {
            if (err) {
                console.error('Database update failed:', err);
                return res.status(500).send({ error: 'Database update failed.' });
            }

           
            console.log('Profile image updated successfully for customer ID:', customer_id);
            res.status(200).send({ message: 'Profile image updated successfully.' });
        });
    } catch (error) {
        console.error('Failed to process image:', error.message);
        
        if (error.message.includes('Input buffer contains unsupported image format')) {
            return res.status(400).send({ error: 'Input buffer contains unsupported image format.' });
        }

        res.status(500).send({ error: 'Failed to process image.' });
    }
});

This is what I normally get in my backend logs:

console log on my backend route

I need help fixing the error:


Upload request received for customer ID: 2
File received: profile-image.jpg Size: 63
MIME type: image/jpeg
Buffer length: 63
Processing image...
Failed to process image: Input buffer contains unsupported image format
Error: Input buffer contains unsupported image format
    at Sharp.toBuffer (C:UsersuserDocumentsPortfoliobackendnode_modulessharpliboutput.js:163:17)
    at C:UsersuserDocumentsPortfolioustpEccomSystembackendroutescustomerData.js:59:18
    at Layer.handle [as handle_request] (C:UsersuserDocumentsPortfoliobackendnode_modulesexpresslibrouterlayer.js:95:5)
    at next (C:UsersuserDocumentsPortfoliobackendnode_modulesexpresslibrouterroute.js:149:13)
    at done (C:UsersuserDocumentsPortfoliobackendnode_modulesmulterlibmake-middleware.js:45:7)
    at indicateDone (C:UsersuserDocumentsPortfolio\backendnode_modulesmulterlibmake-middleware.js:49:68)
    at Multipart.<anonymous> (C:UsersuserDocumentsPortfoliobackendnode_modulesmulterlibmake-middleware.js:166:7) 
    at Multipart.emit (node:events:514:28)    
    at emitCloseNT (node:internal/streams/destroy:132:10)
    at process.processTicksAndRejections (node:internal/process/task_queues:81:21)

Failed to process image: Input buffer contains unsupported image format

Canvas Tangent Line and Point Disappears at x = 2.5 Despite Correct Slope Calculation

I’m trying to visualize a curve and its tangent line using HTML5 canvas. The curve is ( y = x^2 ), and the tangent line should dynamically update as I drag a slider for ( x )-values between 0 and 2.5. The slope calculation works correctly, but as I drag the slider near ( x = 2.5 ), the tangent line and point disappear off the canvas.

Here’s the relevant part of my JavaScript code:

function drawTangentLine(x) {
    // Current slope and tangent line drawing logic
// Limit x to the range 0 to 2.5
    x = Math.min(Math.max(x, 0), 2.5);  // Ensure x stays between 0 and 2.5

    let y = x * x; // y = x^2 at x
    let slope = 2 * x; // Derivative of y = x^2 is 2x

    // Display the current slope
    slopeValue.textContent = slope.toFixed(2);

    // Calculate the tangent line
    let tangentStartX = x - 0.5; // Start of tangent line
    let tangentEndX = x + 0.5;   // End of tangent line

    // Ensure that the tangent line remains within canvas bounds (x range -2 to 2.5)
    tangentStartX = Math.max(tangentStartX, -2); // Limit to left side of curve
    tangentEndX = Math.min(tangentEndX, 2.5);    // Limit to right side of curve

    let tangentStartY = y - slope * (x - tangentStartX); // Adjust Y for slope
    let tangentEndY = y + slope * (tangentEndX - x);     // Adjust Y for slope

    // Convert graph coordinates to canvas coordinates
    let canvasTangentStartX = centerX + tangentStartX * scale;
    let canvasTangentStartY = centerY - tangentStartY * scale;
    let canvasTangentEndX = centerX + tangentEndX * scale;
    let canvasTangentEndY = centerY - tangentEndY * scale;

    // Draw the tangent line
    ctx.beginPath();
    ctx.moveTo(canvasTangentStartX, canvasTangentStartY);
    ctx.lineTo(canvasTangentEndX, canvasTangentEndY);
    ctx.strokeStyle = '#008080'; // Greenish color for tangent
    ctx.lineWidth = 3;
    ctx.stroke();

    // Draw the point of tangency
    let canvasX = centerX + x * scale;
    let canvasY = centerY - y * scale;
    ctx.beginPath();
    ctx.arc(canvasX, canvasY, 6, 0, 2 * Math.PI);
    ctx.fillStyle = '#0000FF'; // Blue dot
    ctx.fill();
}

Here’s the relevant part of my HTML code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Änderungsfaktor</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h2>Änderungsfaktor</h2>
        <div class="slopeDisplay">Die Steigung beträgt: <span id="slopeValue">0.00</span></div>
        <canvas id="curveCanvas" width="400" height="400"></canvas>
        <div class="slider-container">
            <input type="range" id="xSlider" min="0" max="2.5" step="0.01" value="0">

        </div>
        <div class="description">
            If you drag the tangent line along the curve from ( x = 0 ) to ( x = 2.5 ), the tangent line gets steeper. This also means that the value of the slope becomes greater.
        </div>
    </div>
    <script src="script.js"></script>
</body>
</html>

I’m using canvas scaling with a defined center and range, and the tangent line should remain visible within the canvas bounds. However, at higher ( x )-values, the tangent line seems to move outside the visible area.

What adjustments should I make to keep the tangent line and point of tangency within the canvas?

The slope value of 2.5 should be the max range for my slider

And this is the issue.

enter image description here

Stripe Error: “Livemode of key does not match mode of account (hint: legacy testmode keys are not supported. Please use a sandbox.)”

I’m trying to test metered billing via an AWS Lambda function written in NodeJS. I get the following error message from Stripe:

Error processing metered billing event: StripeAuthenticationError: Livemode of key does not match mode of account (hint: legacy testmode keys are not supported. Please use a sandbox.)

I’m absolutely baffled as to why I’m getting this error because I’m using my test mode key for this. I’ve also been testing stuff via Stripe all day and everything has been working fine.

I thought for sure it had to do with the livemode: BOOLEAN attribute that the Meter Event Object has, so I explicitly set that as false for testing purposes:

        // Create the metered billing event with the v2 API (Custom Event Billing)
        const meterEvent = await stripe.v2.billing.meterEvents.create({
            event_name: 'product_creation', // You can use your custom event name
            payload: {
                value: 1,  // Increment by 1 product creation
                stripe_customer_id: stripeCustomerID  // Stripe customer ID
            },
            livemode: false  // IMPORTANT!!! --> make sure to set this to TRUE in the live mode.
            // this parameter must overtly be specified for TEST vs LIVE mode, for the meter event object.
        });

Nope, still getting this error.

Any ideas as why this may be happening and what the fix could be?

Thanks!…

Move to next node on click

I’m editing a Tampermonkey script that takes elements from the DOM and makes a new element from those to add them to a different part of the page. The original element has an X button that changes the display value of the div (to style="display: none")

<div id="alertTable">
    <ul>
        <li>Element 0 index 0
        <img src="example.com/img0.jpg">
        <img class="x-close" src="example.com/x_icon.png">
        </li>
    </ul>
</div>
$(document).ready(function newDiv() {
var newElementText = document.querySelector('#alertTable li');
var newElementImg = document.querySelector('#alertTable li img');
var newElementClose = document.querySelector('.x-close');

var newElementCSS = `
<style>
#scriptDiv img {
    width: 500px;
}
#scriptDiv li {
    color: #f8f8f8;
} 
</style>
`;

const HTMLElement = `
<div id="scriptDiv">
${newElementText}
${newElementImg}
${newElementClose}
</div>
`;

$('.DOMheader').prepend(HTMLElement);
});

The issue with that code is that sometimes the <ul> element of the DOM contains more than one element, like so, and the original code only detects and interacts with the first instance of the elements it finds with querySelector (logically)

<div id="alertTable">
    <ul>
        <li>Element 0 index 0
        <img src="example.com/img0.jpg">
        <img class="x-close" src="example.com/x_icon.png">
        </li>
        <li>Element 1 index 1
        <img src="example.com/img1.jpg">
        <img class="x-close" src="example.com/x_icon.png">
        </li>
        <li>Element 2 index 2
        <img src="example.com/img2.jpg">
        <img class="x-close" src="example.com/x_icon.png">
        </li>
    </ul>
</div>

I’d like to modify the original code to listen for the click on the .x-close element, and display the next <li> element’s information on the newElement variables. How could this be achieved? The original code includes this to “close” the DOM’s div when clicking on the injected element’s close button

var DOMClose = document.querySelector('#alertTable.x-close');
var ScriptClose = document.querySelector('#scriptDiv.x-click');

ScriptClose.addEventListener('click', function () {
 DOMClose.click();
}

How to change Base Map/Map Type with custom control in Leaflet?

I created custom bar as image below:
see "Red Circle"

This my HTML code:


<div class="collapse map-custombar-collapse-left" id="listMapBaseControl">
    <ul class="ul-map-custombar-collapse-left">
        <li class="li-map-custombar-collapse-left">
            <div class="form-check">
            <input class="form-check-input" type="radio" name="radiomaptype" id="mapTypeToOSM" value="osm" checked>
            <label class="form-check-label" for="mapTypeToOSM">OSM Map</label>
            </div>
        </li>
        <li class="li-map-custombar-collapse-left">
            <div class="form-check">
            <input class="form-check-input" type="radio" name="radiomaptype" id="mapTypeToStreet" value="streetmap">
            <label class="form-check-label" for="mapTypeToStreet">Google Street</label>
            </div>
        </li>
        <li class="li-map-custombar-collapse-left">
            <div class="form-check">
            <input class="form-check-input" type="radio" name="radiomaptype" id="mapTypeToTraffic" value="trafficmap">
            <label class="form-check-label" for="mapTypeToTraffic">Google Traffic</label>
            </div>
        </li>
        <li class="li-map-custombar-collapse-left">
            <div class="form-check">
            <input class="form-check-input" type="radio" name="radiomaptype" id="mapTypeToSatellite" value="satellitemap">
            <label class="form-check-label" for="mapTypeToSatellite">Satellite Map</label>
            </div>
        </li>
        <li class="li-map-custombar-collapse-left">
            <div class="form-check">
            <input class="form-check-input" type="radio" name="radiomaptype" id="mapTypeToHybrid" value="hybridmap">
            <label class="form-check-label" for="mapTypeToHybrid">Hybrid Map</label>
            </div>
        </li>
    </ul>
</div>

<div id="map" style="height:100%;"></div>

and, this my JS Code:


var googleStreets = L.tileLayer('http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',{
        maxZoom: 20,
        subdomains:['mt0','mt1','mt2','mt3']
});

var googleHybrid = L.tileLayer('http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}',{
        maxZoom: 20,
        subdomains:['mt0','mt1','mt2','mt3']
});

var googleSat = L.tileLayer('http://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}',{
        maxZoom: 20,
        subdomains:['mt0','mt1','mt2','mt3']
});

var googleTraffic = L.tileLayer('https://{s}.google.com/vt/lyrs=m@221097413,traffic&x={x}&y={y}&z={z}', {
        maxZoom: 20,
        minZoom: 2,
        subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
});

var osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 20,
    attribution: '© OpenStreetMap'
});

var map = L.map('map', {
    center: [-5.368029,112.005921],
    zoom: 5,
    layers: [osm]
});

var baseMaps = {
    "OSM": osm,
    "Street": googleStreets,
    "Traffic": googleTraffic,
    "Satellite": googleSat,
    "Hybrid": googleHybrid
};

var overlays =  {//add any overlays here
};

//var layerControl = L.control.layers(baseMaps,overlays,{position:'bottomleft'}).addTo(map); Hidden default control

$('input[type=radio][name=radiomaptype]').on('change', function() {
  switch ($(this).val()) {
    case 'osm':
      baseMaps["OSM"].addTo(map);
      break;
    case 'streetmap':
      baseMaps["Street"].addTo(map);
      break;
    case 'trafficmap':
      baseMaps["Traffic"].addTo(map);
      break;
    case 'satellitemap':
      baseMaps["Satellite"].addTo(map);
      break;
    case 'hybridmap':
      baseMaps["Hybrid"].addTo(map);
      break;
    
    default:
      baseMaps["OSM"].addTo(map);
      break;
  }
});

I have 2 issues:

  1. Example, last selected position on radio “Satellite Map”, when I reload the page, the map type changes to default type which is “OSM”, but on the radio still selected/checked is “Satellite Map” although I set default checked is for “OSM” in the HTML code above.

  2. When page first loads, first try to change map type is success, but on the second try, changing map type is not working.

Example:

  1. Page open
  2. Select “Google Sat” radio. Map will change to “Google Sat” – successful
  3. Select “Google Hybrid radio, and map will change to “Google Hybrid” – successful
  4. Select “Google Sat” radio again, and map fail to change.

I’m still learning about Leaflet and need help

PS: If using default layer control from Leaflet, I didn’t encounter the issues.

See black circle

Javascript loop to wait for input from external source (Android tasker)

I am quite new to JavaScript.
I am having a hard time with wait loops in JavaScript to wait for content from an external source (tasker).
In particular I have an HTML document with JavaScript (shown in a WebView element inside a Tasker (Android app) scene on my Android phone) which should show results from the Google Places API (new version). I am using Tasker to retrieve the data from Google which works quite well. I can also read the retrieved data with JavaScript. But I can’t figure out how to build a wait loop with JS which checks if the data retrieval with Tasker has finished.

I’ve experimented with setInterval and setTimeout.

Below is one of my attempts. The wait for the value of the second control variable to equal the value of the first control variable works well, indicating that the data retrieval by Tasker has finished. The counter usually is around 6 at this point. However, then the content of the if (answer == random) condition is also executed 6 times (e.g. retrievedData is set 6 times) and the function this.fillHtmlElements() doesn’t seem to be executed.
Everything works fine if I only set one setTimeout to 3 or 4s; but that would not account for variable internet speed etc.

loadContent(){
          const myInterval = setInterval(dataRetrieve, 500);
          let random = Math.random().toFixed(5); // this generates a random number as a control variable
          setGlobal('CheckNumberIn', random); // This function sets the global Tasker variable 'CheckNumberIn' to the control variable. When the Tasker loading Task has finished, Tasker will set the value of its second global control variable ('CheckNumberOut') to the same value
          performTask('loadingGoogle', '15', this.locationType, Data.distance); // this initiates the tasker task 'loadingGoogle' to retrieve the data; '15' is the priority of the Tasker task, this.locationType is the searched location Type (e.g. sushi_restaurant), Data. distance the search radius
          let counter = 0;
          function dataRetrieve() {
            let answer = global('CheckNumberOut'); //retrieves the value of the second control variable 'CheckNumberOut'
            if (answer == random) { //checks if value of second control variable equals the value of the first control variable -> meaning that Tasker has loaded the data from Google
                let retrievedData = global ('RetrievedData'); //reads the retrieved data from the global Tasker variable 'RetrievedData'
                this.inputData = JSON.parse(this.retrievedData); //parses the received JSON-data
                this.fillHtmlElements(); //function to update HTML elements with new received data
                clearInterval(myInterval);
            } else if (counter < 30) {
              counter++;
            } else {
              clearInterval(myInterval);
            }

          }
        }

Thank you very much for your help.

Greetings from Germany,

Philipp

Code splitting javascript files in vue with webpack not working

Vue 3.5.11

I am using the pinia npm package to use stores in my vue app. I have been doing it the synchronous way:

<script setup>
 import { storeToRefs } from "pinia";
 import { usePhotoApi } from "@/composables/photos";
 const state = usePhotoApi();
 const { info, errored, loading } = storeToRefs(state);
  onMounted(()=>{
   Promise.all([state.getPhotos()]).then(() => {
    console.log("form fields are", info.value);
  });
})
</script>

My photos.js file is this:

  import { defineStore } from "pinia";

  export const usePhotoApi = defineStore("photos", {
    state: () => ({
      info: null,
      loading: true,
      errored: false
    }),
    actions: {
      async getPhotos() {
         //get my photos
    },
  });

This works fine, but it can be better optimized. I found this: https://vuejsdevelopers.com/2017/07/03/vue-js-code-splitting-webpack/ and I now have the following:

<script setup>
  import { storeToRefs } from "pinia";
  const usePhotoApi = () => import("@/composables/photos.js");
  const state = await usePhotoApi()
  const { info, errored, loading } = storeToRefs(state);
  onMounted(()=>{
   Promise.all([state.getPhotos()]).then(() => {
    console.log("form fields are", info.value);
   });
  })

 </script>

Now, I get an error:

 state.getPhotos is not a function 

There are no other errors, just the one above. What is the correct syntax (or way) to call methods from my javascript using code splitting like the article outlines? Thanks

Need to refresh current page manually to be able to run user-script

I tried various ways (changed @match directive, tried @run-at xxx many combination), but can’t figure out the way to prompt the login only at the good time. When I open the page, I need to refresh the page to be able to run the script. This is the bug I need to fix. The goal is to promt() when the virtual keyboard is loaded.

I’m pretty sure I’m missing something, but don’t know what.

This is my user-script:

// ==UserScript==
// @name         Boursorama
// @namespace    GillesQuenot
// @version      20241013
// @description  xxx
// @author       Gilles Quenot
// @match        https://clients.boursobank.com/connexion/saisie-mot-de-passe*

// ==/UserScript==

(function() {
    'use strict';

    function myFunction() {
        var targetElement = document.querySelector('ul.password-input li:nth-last-of-type(1) button.sasmap__key');

        if (!targetElement && !targetElement.complete) {
            // The element is not loaded yet, try again later
            setTimeout(myFunction, 500)
        } else {
            var login = window.prompt('login');
        }
    };

    window.addEventListener('load', function() {
        setTimeout(myFunction, 500)
    }, false);

})();

Also tried this way, but exactly the same bug:

// ==UserScript==
// @name         Boursorama
// @namespace    GillesQuenot
// @version      20241009
// @require      https://cdn.jsdelivr.net/gh/CoeJoder/[email protected]/waitForKeyElements.js
// @description  xxx
// @author       Gilles Quenot
// @match        https://clients.boursobank.com/connexion/saisie-mot-de-passe

// ==/UserScript==

(function() {
    'use strict';

    waitForKeyElements('ul.password-input li:nth-last-of-type(1) button.sasmap__key', (element) => {
        var login = window.prompt('login');
    });

})();

Any way to fix this?

Send text message from Unity Client to Javascript server using Unity Render Streaming and WebRTC

I am trying to setup a streaming app using Unity and currently Unity Render Streaming plugin is being used with the RTCPeerConnection to stream the video. I edited the bidirectional WebApp sample (sendvideo.js) to just send a video to the Unity app that is my client, where I am using the ReceiverSample.cs to visualize the video. I need to send back a text message could be “Hello world” for instance, from Unity to Javascript during the video streaming, but I wasn’t successful to do it.

I am currently using the following:

  • WebRTC Version: 2.3.3-preview
  • Unity Render Streaming Version: 3.0.1-preview
  • Unity Version: 2022.3.45f1

And here is what I’ve tried to get the Unity side to send message to javascript webapp:

sendvideo.js

import * as Logger from "../../module/logger.js";

export class SendVideo {
  constructor(localVideoElement, remoteVideoElement) {
    this.localVideo = localVideoElement;
    this.remoteVideo = remoteVideoElement;
    this.peerConnection = null;
    this.dataChannel = null; // Add DataChannel variable
  }

  async startLocalVideo() {
    try {
      const videoElement = document.createElement('video');
      videoElement.src = '/videos/video.mp4'; // Path to your video file
      videoElement.muted = true;
      await videoElement.play();

      const stream = videoElement.captureStream();
      this.localVideo.srcObject = stream;
      await this.localVideo.play();

      this.initializePeerConnection();

    } catch (err) {
      Logger.error(`Error starting local video: ${err}`);
    }
  }

  // Set up WebRTC connection and DataChannel
  initializePeerConnection() {
    this.peerConnection = new RTCPeerConnection();

    this.dataChannel = this.peerConnection.createDataChannel("myDataChannel");

    this.dataChannel.onopen = () => {
      console.log("DataChannel open: Connection established with Unity client");
    };

    this.dataChannel.onmessage = (event) => {
      console.log(`Received message from Unity: ${event.data}`); 
    };

    this.peerConnection.createOffer().then(offer => {
      return this.peerConnection.setLocalDescription(offer);
    }).then(() => {
      console.log("Offer created and sent to Unity client");
    }).catch(err => console.error(err));
  }
}

And here is the ReceiverSample.cs code:

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using Unity.WebRTC; 

public class ReceiverSample : MonoBehaviour
{
#pragma warning disable 0649
    [SerializeField] private Button startButton;
    [SerializeField] private Button stopButton;
    [SerializeField] private InputField connectionIdInput;
    [SerializeField] private RawImage remoteVideoImage;
    [SerializeField] private ReceiveVideoViewer receiveVideoViewer;
    [SerializeField] private SingleConnection connection;
#pragma warning restore 0649

    private RTCDataChannel dataChannel;
    private float messageInterval = 2.0f; // Send a message every 2 seconds

    void Awake()
    {
        startButton.onClick.AddListener(OnStart);
        stopButton.onClick.AddListener(OnStop);
        if (connectionIdInput != null)
            connectionIdInput.onValueChanged.AddListener(input => connectionId = input);
        receiveVideoViewer.OnUpdateReceiveTexture += texture => remoteVideoImage.texture = texture;
    }

    private void OnStart()
    {
        if (string.IsNullOrEmpty(connectionId))
        {
            connectionId = System.Guid.NewGuid().ToString("N");
            connectionIdInput.text = connectionId;
        }
        connectionIdInput.interactable = false;

        // Create the connection
        connection.CreateConnection(connectionId, true);

        // Subscribe to the DataChannel event (available from the connection object)
        connection.OnDataChannel += OnDataChannelReceived;

        startButton.gameObject.SetActive(false);
        stopButton.gameObject.SetActive(true);
    }

    private void OnDataChannelReceived(RTCDataChannel channel)
    {
        dataChannel = channel;

        dataChannel.OnOpen += () =>
        {
            Debug.Log("DataChannel opened. Starting to send messages.");
            StartCoroutine(SendHelloWorldMessage());
        };

        dataChannel.OnClose += () =>
        {
            Debug.Log("DataChannel closed.");
        };

        dataChannel.OnMessage += OnMessageReceived;
    }

    private void OnMessageReceived(byte[] message)
    {
        string receivedMessage = System.Text.Encoding.UTF8.GetString(message);
        Debug.Log($"Message received from WebApp: {receivedMessage}");
    }

    private IEnumerator SendHelloWorldMessage()
    {
        while (dataChannel.ReadyState == RTCDataChannelState.Open)
        {
            dataChannel.Send("Hello World");
            Debug.Log("Sent 'Hello World' to JavaScript client");
            yield return new WaitForSeconds(messageInterval);
        }
    }

    private void OnStop()
    {
        StopAllCoroutines(); 
        connection.DeleteConnection(connectionId);
        connectionId = String.Empty;
        connectionIdInput.text = String.Empty;
        connectionIdInput.interactable = true;
        startButton.gameObject.SetActive(true);
        stopButton.gameObject.SetActive(false);
    }
}

The ReceiverSample.cs outputs the following errors:

AssetsSamplesUnity Render Streaming3.0.1-previewExampleReceiverReceiverSample.cs(15,30): error CS0246: The type or namespace name ‘SingleConnection’ could not be found (are you missing a using directive or an assembly reference?)
AssetsSamplesUnity Render Streaming3.0.1-previewExampleReceiverReceiverSample.cs(15,30): error CS0246: The type or namespace name ‘SingleConnection’ could not be found (are you missing a using directive or an assembly reference?)

I’d like to know if this is the correct approach or is my code approach using RTCDataChannel will work for my usecase, and if so, how can I fix it to get it working the way I need it to work.

Adding multiple event listeners for same event in socket io/react

I have a global context which listens to a new-message event.

SocketContext.js (global)

 useEffect(() => {
         if (!socket) return

         socket.on("new_message", (data) => {
            // Dont run the code if we're on /chat (as that means there is another listener with same name attatched)
            if (pathname === "/chat") return              

            // Update chats latest message. This should only run if we aren't on /chat route
            dispatch(updateChat({ data: data.message}))
        })

        return () => socket.off("new_message")
}, [socket])

I have a Chat component where the local messages state should be updated when a new message is received

Chat.js (rendered when user visits /chat route)

const [messages, setMessages) = useState([])

useEffect(() => {
  if (!socket) return

  socket.on("new_message", (data) => {
      setMessages((prev) => [...prev, data.message])
  })

  return () => socket.off("new_message")
}, [socket])

Both components listen to the same event. But both do different things depending on whether the user is on the /chat route. The code inside the global event listener wont run if the route is /chat but the event is still fired and being listened to globally (even when we’re listening to the same event when on the /chat route).

Is this considered bad practise (adding two event listeners with the same name in different places)? One alternative is to add one event listener globally, however then I would have to store messages state globally in order to update it.

Identify disconnect between constatns and values in JavaScript

I have a webpage built by PHP that depends on a JavaSript script. Within the JS are extensive references to constants (rather than literals), to assist in simplified maintenance between the web page and the javascript. Hopefully the following images, taken from a Chrome debug session, will help explain my problem. I set a breakpoint in the code (line 295) that handles one of my buttons.

The following image shows the code stopped just before calling a function that will ask the server to update a table. Note that, at line 295 testValue shows that CONST_CB_CULL_VIEWER value is ‘viewerCull’ – which means that CONST_CB_CULL_VIEWER is also that same value. (This is confirmed to the right of that statement, where the values of the CONSTs are shown. Why the debugger does not show the value of the constant here [on the left], I do not know.)

calling the update function

I single step into that function, and the below image is what I see. Note that the value passed to updateChatTable is the NAME of the constant, rather than its value. I do not expect this; I expected the value of the constant to be placed into the ‘key’ of the name/value pair.

within the called function

What must I do in order to cause the constant at line 295 to behave as expected, creating NVP {‘viewerCull’: on/off} rather than {‘CONST_CB…’: on/off? Am I using the constant incorrectly? Is the colon after the const name giving me a problem? Or is it something else?

How to generate Full Height and Fixed Width Web Page PDF with puppeteer?

I would like to convert markdown to Single Page Full Height and Fixed A4 paper Width PDF with puppeteer.
I want to integrate it in vscode, so it is written as the extension.

The following exportPDF() is the code to do it,
But it has a problem that when it export PDF, There is a slight difference between the Height that calculate before print (calucatePageHeight()) and actually printed PDF.
This difference cause a problem that exported PDF has 2nd page.

I use fixed width div container in order to calculate Page height when render content in fixed width.
Probably It cause the problem but I have no idea how to fix it.

import * as vscode from "vscode";
import * as fs from "node:fs";
import * as puppeteer from "puppeteer-core";
import markdownit from "markdown-it";
import kt from "@vscode/markdown-it-katex";
import * as path from "node:path";
import os from "node:os";
import { Buffer } from "node:buffer";
import jschardet from "jschardet";


async function addStyle(page: puppeteer.Page): Promise<void> {
    const css_path = expanduser(vscode.workspace.getConfiguration("full-height-pdf")["styleSheet"]);
    if (css_path !== "" && fs.existsSync(css_path) && fs.lstatSync(css_path).isFile()) {
        await page.addStyleTag({ path: css_path });
    }
    let output_line_height = "";
    if (vscode.workspace.getConfiguration("full-height-pdf")["lineHeight"] !== "") {
        output_line_height = `p {
                    line-height: ${vscode.workspace.getConfiguration("full-height-pdf")["lineHeight"]};
        }`;
    }

    let output_general_font_family = "";
    if (vscode.workspace.getConfiguration("full-height-pdf")["generalFontFamily"] !== "") {
        output_general_font_family = `h1,h2,h3,h4,h5,h6,p,td {
                    font-family: ${vscode.workspace.getConfiguration("full-height-pdf")["generalFontFamily"]};
        }`;
    }
    let output_mono_font_family = "";
    if (vscode.workspace.getConfiguration("full-height-pdf")["monoFontFamily"] !== "") {
        output_mono_font_family = `pre,code {
                    font-family: ${vscode.workspace.getConfiguration("full-height-pdf")["monoFontFamily"]};
        }`;
    }
    await page.addStyleTag({
        content:
            `${output_line_height}
        ${output_general_font_family}
        ${output_mono_font_family}
        `
    });

}

async function openWithEncodingDetect(filepath: string, force_encoding?: string): Promise<string> {
    const filestat = await fs.promises.stat(filepath);
    const filesize = filestat.size;
    const f = await fs.promises.open(filepath, "rs");
    try {
        const read_buf = new Uint8Array(filesize);
        await f.read(read_buf);
        const guess_encoding = jschardet.detect(Buffer.from(read_buf));
        let encoding_name = guess_encoding.encoding;
        if (guess_encoding.encoding === "windows-1252") {
            encoding_name = "shift-jis";
        }
        if (force_encoding) {
            encoding_name = force_encoding;
        }
        const text_decoder = new TextDecoder(encoding_name, { fatal: false });
        return text_decoder.decode(read_buf);
    } finally {
        await f.close();
    }
}

function paperWidth(sizename: string): string {
    const s = sizename.toLocaleLowerCase();
    switch (s) {
        case "legal":
        case "letter":
            return "215.9mm";
            break;
        case "tabloid":
        case "ledger":
            return "279.4mm";
            break;
        case "a0":
            return "84.1cm";
            break;
        case "a1":
            return "59.4cm";
            break;
        case "a2":
            return "42.0cm";
            break;
        case "a3":
            return "29.7cm";
            break;
        case "a4":
            return "21.0cm";
            break;
        case "a5":
            return "14.8cm";
            break;
        case "a6":
            return "10.5cm";
            break;
        default:
            return "21.0cm";
    }

}


function expanduser(text: string): string {
    if (text.startsWith("~/")) {
        const j = path.join(os.homedir(), text.substring(2));
        return j;
    }
    return text;
}

async function calculatePageHeight(sizename: string, markdowntext: string): Promise<number> {
    const width = paperWidth(sizename);
    const mdtext = convertmd2htmltext(markdowntext);
    // Render all content in the container that has fixed width  

    const template = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Calculate Width</title></head><body><div id="container">${mdtext}</div></body></html>`;
    
    const text_encoder = new TextEncoder();
    const encoded_string = text_encoder.encode(template);
    const buffer = Buffer.from(encoded_string);
    const launch_option: puppeteer.PuppeteerLaunchOptions = {};
    const executablePath = vscode.workspace.getConfiguration("full-height-pdf")["executablePath"];
    if (executablePath !== "") {
        if (fs.existsSync(executablePath)) {
            launch_option.executablePath = executablePath;
        } else {
            await vscode.window.showWarningMessage("Chrome executable does not exists", { modal: true });
        }
    }
    launch_option.channel = "chrome";
    //launch_option.headless = false;
    const browser = await puppeteer.launch(launch_option);
    try {
        const page = await browser.newPage();
        page.setDefaultTimeout(0);
        await page.goto(`data:text/html;base64,${buffer.toString("base64")}`/*, { waitUntil: "domcontentloaded" }*/);
        await page.addStyleTag({
            content: `
                div#container {
                width: ${width};
                }`});
        await addStyle(page);
        const pageHeight = await page.evaluate(() => {
            const container = document.getElementById("container");
            return Math.max(container!!.clientHeight, container!!.scrollHeight); // get Tallest Height in the container Height
        });
        return pageHeight;
    } finally {
         await browser.close();
    }
}

function convertmd2htmltext(text: string): string {
    const md = markdownit().use(kt);
    return md.render(text);
}

async function exportPath(): Promise<string> {
    let output_path: string = expanduser(vscode.workspace.getConfiguration("full-height-pdf")["exportPath"]);
    try {
        await fs.promises.access(output_path, fs.constants.F_OK);
    } catch (e: any) {
        const selected_uri = await vscode.window.showSaveDialog({ filters: { "PDF": ["pdf"] } });
        if (selected_uri === undefined) {
            return "";
        }
        output_path = selected_uri!!.fsPath;
    }
    return output_path;
}

export async function exportPDF(fileUri?: any) {
    let md_text: string;
    if (fileUri === undefined) {
        const editor = vscode.window.activeTextEditor;
        if (!editor) {
            await vscode.window.showWarningMessage("No active editor");
            return;
        }
        /*
        const uri = editor.document.uri;
        const mdfilepath = uri.fsPath;
        if (!fs.existsSync(mdfilepath)) {
            if (editor.document.isUntitled) {
                await vscode.window.showWarningMessage("Please save the file");
                return;
            }
            await vscode.window.showWarningMessage("File does not exists");
            return;
        }
        */
        md_text = editor.document.getText();
    } else {
        try {
            md_text = await openWithEncodingDetect(fileUri.fsPath);
        } catch (e: any) {
            vscode.window.showErrorMessage("Error", { modal: true, detail: e.message });
            return;
        }
        if (!md_text) {
            return;
        }
    }
    const html_text = convertmd2htmltext(md_text);
    let pdf_title = vscode.workspace.getConfiguration("full-height-pdf")["PDFTitle"];
    if (pdf_title === "") {
        pdf_title = "PDF";
    }


    const output_html = `<!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>${pdf_title}</title>
        </head>
        <body>${html_text}</body>
    </html>`;
    const text_encoder = new TextEncoder();
    const encoded_string = text_encoder.encode(output_html);
    const buffer = Buffer.from(encoded_string);
    const size = vscode.workspace.getConfiguration("full-height-pdf")["widthFormat"].toLowerCase();
    const launch_option: puppeteer.PuppeteerLaunchOptions = {};
    const executablePath = vscode.workspace.getConfiguration("full-height-pdf")["executablePath"];
    if (executablePath !== "") {
        if (!fs.existsSync(executablePath)) {
            await vscode.window.showWarningMessage("Chrome executable does not exists", { modal: true });
            return;
        }
        launch_option.executablePath = executablePath;
        launch_option.args = ["--no-sandbox", "--disable-setuid-sandbox"];
    }
    launch_option.channel = "chrome";
    launch_option.headless = false;
    const export_path = await exportPath();
    if (export_path === "") {
        await vscode.window.showInformationMessage("output path is not specified");
        console.log("exported_path is blank string");
        return;
    }
    const browser = await puppeteer.launch(launch_option);
    try {
        const page = await browser.newPage();
        page.setDefaultTimeout(0);
        await page.goto(`data:text/html;base64,${buffer.toString("base64")}`);
        await addStyle(page);
        //const export_path = await exportPath();
        console.log(export_path);
        let width = paperWidth(size);
        let pageHeight;
        await vscode.window.withProgress({ title: "Exporting PDF...", location: vscode.ProgressLocation.Notification }, async (progress, token) => {
            if (vscode.workspace.getConfiguration("full-height-pdf")["useOriginalWidth"]) {
                pageHeight = await page.evaluate(() => {
                    return Math.max(document.documentElement.clientHeight, document.documentElement.scrollHeight, document.body.clientHeight, document.body.scrollHeight);
                });
                const width_value = await page.evaluate(() => {
                    return Math.max(document.documentElement.clientWidth, document.documentElement.scrollWidth, document.body.clientWidth, document.body.scrollWidth);
                });
                width = width_value.toString() + "px";

            } else {
                pageHeight = await calculatePageHeight(vscode.workspace.getConfiguration("full-height-pdf")["widthFormat"], md_text);
                // get page height
            }
            console.log("print widthxheight", width, pageHeight);
            const pdf_option: puppeteer.PDFOptions = { path: export_path, width: width, height: pageHeight.toString() + "px", margin: { bottom: "1px" }, printBackground: true };
            try {
                await page.pdf(pdf_option);
            } catch (e: any) {
                await vscode.window.showErrorMessage("Error", { modal: true, detail: e.message });
                return;
            }
        });
    } finally {
        //browser.close();
        console.log("Close");
    }

}

How to send photos to server in flask?

I am developing a website. I am getting user uploaded photo and sending it to flask back end to process. If everything goes through, the photos will be added to database, and redirect to a home page. Since user can upload photos multiple times, and may delete photos. I use an array to capture the updated photos.

project
|
|___app
|   |
|   |___templates
|   |   |
|   |   |__postAd.html
|   |   |___index.html
|   |
|   |__postAd.py
|   
|
|__main.py

postAd.html

<form
    method="POST"
    class="needs-validation"
    novalidate
    id="form"
    enctype="multipart/form-data"
    action="{{url_for('postAd.post_ad',category=category,subcategory=subcategory)}}"
  >
<input class="form-control" type="file" id="formFileMultiple" name="photo" accept=".jpg,.jpeg,.png" multiple="multiple"/>
      <div class="invalid-feedback">file support:jpg,jpeg,png</div>
      <output class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3"
        id="result">
      </output>
<button id="submit-button" class="btn btn-primary" type="submit">submit</button>
</form>
<script>
var submitButton = document.getElementById("submit-button");
form.addEventListener(
  "submit",
  function (event) {
    event.preventDefault();    
    if (!form.checkValidity()) {
      form.classList.add("was-validated");
    } 
    else {
      if (confirm("Are you sure you want to post the ad?")) {       
        sendPhotosToServer();
        form.submit();              
      }
    }
  },
  false
);
const imageInput = document.getElementById("formFileMultiple");
const output = document.querySelector("#result");
const uploadedPhotos = [];
imageInput.addEventListener("change", handleImageUpload);

function handleImageUpload(e) {
  const files = Array.from(e.target.files);
  const number_of_images = files.length;

  for (let i = 0; i < number_of_images; i++) {    
    uploadedPhotos.push(files[i]);
    const picReader = new FileReader();
    picReader.addEventListener("load", (event) => {
      const imgContainer = document.createElement("div");
      imgContainer.className = "col";
      imgContainer.innerHTML = `<div class="card">
                            <div class="image-container">
                                <img src="${event.target.result}" alt="${files[i].name}" class="card-img-top" style="height: 200px;
  object-fit: cover;">
                            </div>
                            <div class="card-body">
                                <button class="btn btn-danger btn-sm delete-btn">Delete</button>
                            </div>
                        </div>
                    `;
      const deleteBtn = imgContainer.querySelector(".delete-btn");
      deleteBtn.addEventListener("click", () => {
        imgContainer.remove();
        const index = uploadedPhotos.indexOf(files[i]);
        if (index > -1) {
          uploadedPhotos.splice(index, 1); // Remove the file from the array
        }
      });
      output.appendChild(imgContainer);      
    });
    picReader.readAsDataURL(files[i]);
  } 
}

async function sendPhotosToServer() {
  const formData = new FormData();

  // Append each photo from uploadedPhotos array to the form data
  uploadedPhotos.forEach((photo, index) => {
    formData.append(`photo_${index}`, photo);
  });
  try {
    const response = await fetch(`/post-ads/${category}/${subcategory}`, {
      method: "POST",
      body: formData,
    });

    if (response.ok) {
      const result = await response.json();
      console.log("Photos uploaded successfully!", result);
    } else {
      console.log("Failed to upload photos.", response.status);
    }
  } catch (error) {
    console.error("Error during photo upload:", error);
    console.log("An error occurred while uploading photos.");
  }
}
</script>

postAd.py

@postAd.route("/post-ads/<category>/<subcategory>", methods=['GET','POST'])
@login_required
def post_ad(category,subcategory):
response = render_template("postAd.html",category=category,subcategory=subcategory))
   if request.method == 'POST':
      photos = request.files.getlist('photo')
      ad = Ad(photos=photos)
      db.session.add(ad)
      db.session.commit()
      flash('post ad successfully!','success')
      return redirect(url_for('index.html'))
   return response

Each ad belongs to a category, subcategory. The photos are shown in browser, and each photo has a delete button. When I submit the form, the postAd never gets the photo in uploadedPhotos. It only gets the user last uploaded photos in browser. The console in development tool says Error during photo upload: TypeError: NetworkError when attempting to fetch resource.An error occurred while uploading photos. The network tab shows the fetch request is blocked with NS_binding aborted under transferred. It seems the error is related to network security. But I’m still in development, so everything uses http instead of https. Is there a way to get around this?