HTML form visible or hidden based on checkbox condition

I want to hide/visible a form based on checkbox in google webapp. If the checkbox is in checked condition then the form will be in visible else it should in hidden. I want to try with below mentioned code block. But not happen.

if (document.getElementById("df1").checked) {
   document.getElementById("co").style.visibility = "hidden";
} else {
   document.getElementById("co").style.visibility = "visible";
}
<form id="co" style="visibility : hidden">
<br>
<label type="text">Name </label><input type="text">
<br>
<label type="text">Roll No. </label><input type="number" value="0" min="0">
<br><br>
<input type="submit" value="submit">

<input type="checkbox" id="df1">

How to use React-toastify in multiple web components

I have a main project, let’s say projectA which import couple of other react components for example a module federated react components projectB.
In the projectA I have installed and imported the react toastify container in the App.js.ProjectB is also imported to App.js. Let’s say the App.Js in projectA is like this

const App = () => {
 return(
    <div>
      <ToastifyContainer />
      <ProjectB />
      <OtherCompoentsFromProjectA />
    </div>
 )
}

So, in this case, the toastify container only works with the ProjectA. But,seems like the notification does’t work from the projectB. The way only it works if we also import the ToastifyContainer also in projectB. So,it means the more are the components the more imports need to be done for react toastify. Is it the best practices. Or are there any other ways that we can handle it so the toastify components needs to be added only once for example only in projectA.

Wai aria field required is not read from scream reader

I need to read (WAI aria) an input and the screen reader must read if the file is required or not. I try this:

<input .... required>

but when SC go on the input doesn’t read that field is required so I do this:

<input .... aria-required="true">

and there is the same problem. Anyone can help me?

Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource. firefox url fetching issue

I made a form to collect email from users and give alert when data is successfully. When I enter any value in input, it gives me two errors:

  1. Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3001/emailcoll. (Reason: CORS request did not succeed). Status code: (null)
  2. Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource.

How do I resolve it?

Below is code of function where the component is:

 const handleChange = (e) => {
    setFormData({
      ...formData,
      [e.target.name]: e.target.value,
    });
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    const response = await fetch('http://localhost:3001/emailcoll', {
      method: 'POST',
      mode:"no-cors",
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(formData),
    });
    if (response.ok) {
      alert("Data Saved Successfully!")
    }
  };

below is code of form:

<form onSubmit={handleSubmit} className={styles.subs}>
    <label  className={styles.substext}>Stay updated on our all upcoming events!</label>
    <input onChange={handleChange} value={formData.email} name="email" className={styles.subsinput} placeholder="[email protected]"/>
    <button  type="submit" className={styles.subsbut}>Subscribe</button>
</form>

below is server code:

app.post('/emailcoll', async (req, res) => {
    const { email } = req.body;
    const filePath = './emailcoll.xlsx';

    let workbook;
    let worksheet;

    workbook = new ExcelJS.Workbook();
    await workbook.xlsx.readFile(filePath);
    worksheet = workbook.getWorksheet('Sheet 1');

    worksheet.columns = { header: 'Email', key: 'email' }
  
    worksheet.addRow({email});

   
    await workbook.xlsx.writeFile(filePath);
    res.send(STATUS_CODES)
})
app.listen(3001)

I tried using extensions for unblocking Access Control Allow Origin. Still same problem.
I have also included mode:”no-cors” in function.

Node Server demands one extra response from data processing service every time connected with RabbitMQ

My issue is quite weird, let me first explain what I am trying to achieve here. My goal is to have two services, both built in node js. First service is a web server built with express js to work as an API with the client. The second service is a data processing service that receives the request from the web server and processes the data.

Both of the services are connected via RabbitMQ queues and channels. Now the problem is that when I send the first request after starting the server, it works as expected, the data processing service sends back the processed data and it is then sent to the client.

On the second request, the web server demands two responses from the data processing service to work. On third request, it demands three responses, each time it demands one extra response. I thought maybe the messages are not getting acknowledged that maybe causing this problem. I have tried out every single thing I could from the docs and StackoverFlow but I can’t seem to understand this.

I even tried to implement same solution in GoLang where I encountered the exact same issue. I am providing the Node JS code, please do let me know what’s wrong here and how can I fix it. Thanks you

Web Server:

const express = require("express")
const app = express();
const amqp = require("amqplib")
let channel;

const QUEUE_REQUEST = "data_request_queue"
const QUEUE_RESPONSE = "data_response_queue"

async function rabbitMQ() {
    const connection = await amqp.connect("amqp://guest:guest@localhost:5672/")
    const channel = await connection.createChannel();
    await channel.assertQueue(QUEUE_REQUEST, {durable:false})
    await channel.assertQueue(QUEUE_RESPONSE, {durable:false})
    return channel;
}

app.get("/", async (req, res) => {
    await channel.sendToQueue(QUEUE_REQUEST, Buffer.from("requesting data..."))
    const msg = await new Promise((resolve, reject) => {
        channel.consume(QUEUE_RESPONSE, msg => {
            if (msg !== null) {
                channel.ack(msg)
                resolve(msg.content.toString())
            } else {
                channel.ack(msg)
                reject("could not receive msg")
            }
        })

    }) 
    return res.json({message: msg})
})

app.get("/clean", async (req, res) => {
    await channel.purgeQueue(QUEUE_REQUEST)
    await channel.purgeQueue(QUEUE_RESPONSE)

    return res.json({ message: "cleaned queues"})
})

app.listen(3000, async () => {
    console.log("Listening on port: 3000")
    channel = await rabbitMQ();
})

Data Processing Service

const amqp = require("amqplib/callback_api")

const QUEUE_REQUEST = "data_request_queue"
const QUEUE_RESPONSE = "data_response_queue"

amqp.connect("amqp://guest:guest@localhost:5672/", function (error0, connection) {
    if (error0) {
        throw error0;
    }
    connection.createChannel(function (error1, channel) {
        if (error1) {
            throw error1
        }

        channel.assertQueue(QUEUE_REQUEST, {durable: false});
        channel.assertQueue(QUEUE_RESPONSE, {durable: false});

        channel.consume(QUEUE_REQUEST, async (msg) => {
            if (msg !== null) {
                channel.sendToQueue(QUEUE_RESPONSE, Buffer.from("data..."))
                channel.ack(msg)                
            } else {
                console.log("consumer cancelled")
            }
        })
    });
})

Side Note: I am first time trying to implement this multi-service architecture just to learn how it works.

Vue.js render time optimalization

I have a problem with optimalization in vue.js. I know my thinking is not perfect but i need to optimize part of application quick.

I have app looking like Pinterest. I have 1k cards to show, every card have profile data some of them have more some of them have less. Problem is when i try to filter them i have to wait a lot of time to have them filtered. All cards are fetch by ajax all at once.

What i found is Vue.js is rerendering them every time i filter them. They are static data witch wont change and it cant be changed.

Is there a way to prevent rerendering components when they are filtered?

How can I send both audio and text data simultaneously through a WebSocket connection in Python?

I’m working on a chatbot application where I need to convert text to speech (TTS) on the backend and send both the generated audio and the original text to the frontend through a WebSocket connection. The text is being used for displaying in the chat interface, and the audio is played for users as part of the chatbot’s response.

What would be the best approach to send both the text and audio data via WebSocket? Should I encode the audio file into a specific format (e.g., base64) and send it alongside the text? Or is there a more efficient method? Additionally, how should I handle receiving and separating the two types of data on the frontend?

Any suggestions or code examples would be greatly appreciated!

Thanks in advance!

Backend code:

@router.websocket("/ws/voice-chat/") async def websocket_audio_endpoint(websocket: WebSocket): await websocket.accept()
    try:
        while True:
            data = await websocket.receive_text()
            chabotbotmodel = ChatbotModel(**json.loads(data))
            usr_id = chabotbotmodel.usr_id or chabotbotmodel.guest_id
    
            stream_data = stream_ai_chatbot(chabotbotmodel.usr_query, usr_id)
    
            # Check for propertyData in stream_data
            if stream_data.get("propertyData"):
                write_conversation_data_into_database(
                    chatbot_model.get("usr_id"),
                    chatbot_model.get("guest_id"),
                    usr_query,
                    response_data={"propertyData": stream_data.get("propertyData")},
                )
                await websocket.send_json({
                    "type": "text",
                    "content": stream_data.get("propertyData")
                })
    
            # Check for real-time data in stream_data
            elif stream_data.get("realtime_data"):
                realtime_response_data = ""
    
                async for item in real_time_data(
                        usr_query, stream_data.get("last_user_message")
                ):
                    # Generate audio using gTTS and encode to base64
                    tts = gTTS(text=item, lang='en')
                    audio_fp = BytesIO()
                    tts.write_to_fp(audio_fp)
                    audio_fp.seek(0)
    
                    audio_base64 = base64.b64encode(audio_fp.read()).decode('utf-8')
    
                    # Send both the base64-encoded audio and text response in one message
                    await websocket.send_json({
                        "type": "voice",
                        "audio": audio_base64,  # Audio in base64 format
                        "text": item  # Corresponding text
                    })
                    realtime_response_data = item
    
                # Store conversation data in database
                write_conversation_data_into_database(
                    chatbot_model.get("usr_id"),
                    chatbot_model.get("guest_id"),
                    usr_query,
                    response_data={"realtimeData": realtime_response_data},
                )
                print("nRealtime response data:", realtime_response_data)
    
            # Handle generic data response
            else:
                generic_response_data = ""
                response_text = ""
                async for item in generate_generic_response(
                        {
                            "role": "user",
                            "content": chabotbotmodel.usr_query
                        },
                        stream_data.get("last_user_message")):
                    generic_response_data = item
                    response_text += item + " "
                    await websocket.send_text(item)
                print("response_text-----",response_text)
                # Generate audio using gTTS and encode to base64
                tts = gTTS(text=response_text, lang='en')
                audio_fp = BytesIO()
                tts.write_to_fp(audio_fp)
                audio_fp.seek(0)
    
                audio_base64 = base64.b64encode(audio_fp.read()).decode('utf-8')
    
                # Send both the base64-encoded audio and text response in one message
                await websocket.send_json({
                    "type": "voice",
                    "audio": audio_base64
                })
                write_conversation_data_into_database(
                    chabotbotmodel.usr_id,
                    chabotbotmodel.guest_id,
                    chabotbotmodel.usr_query,
                    response_data={"genericData": generic_response_data},
                )

except WebSocketDisconnect:
    print("Client disconnected")

Frontend code:

function initializeVoiceWebSocket() { const wsEndpoint = "ws://0.0.0.0:5001/ws/voice-chat/"; voiceSocket = new WebSocket(wsEndpoint);            
    voiceSocket.onopen = function () {
                console.log("Voice WebSocket connection established");
            };

            voiceSocket.onmessage = function (event) {
                const response = JSON.parse(event.data);
                // Check if the response contains text and display it
                if (response.text) {
                    chatMessages.append(genericBotMessage(response.text));  // Display the text response
                    chatMessages.scrollTop(chatMessages.prop("scrollHeight"));
                }

                // Check if the response contains audio and play it
                if (response.audio) {
                    playBase64Audio(response.audio);  // Play the audio response if available
                }
            };

            voiceSocket.onerror = function (error) {
                console.error('Voice WebSocket Error:', error);
            };

            voiceSocket.onclose = function () {
                console.log("Voice WebSocket connection closed");
            };
        }

        // Function to send a text message
        function sendTextMessage(prompt) {
            if (textSocket.readyState === WebSocket.OPEN) {
                const message = {
                    usr_query: prompt,
                    usr_id: "066463f4-4762-42f2-8c72-69e79b0c99c7",  // Static or dynamic user ID
                    is_voice: isVoiceQuery  // Flag indicating whether it's a voice message
                };
                textSocket.send(JSON.stringify(message));
            } else {
                console.error('Text WebSocket is not open.');
            }
        }

        // Function to send a voice message
        function sendVoiceMessage(prompt) {
            if (voiceSocket.readyState === WebSocket.OPEN) {
                const message = {
                    usr_query: prompt,
                    usr_id: "066463f4-4762-42f2-8c72-69e79b0c99c7",  // Static or dynamic user ID
                    is_voice: true  // This is a voice-based message
                };
                voiceSocket.send(JSON.stringify(message));
            } else {
                console.error('Voice WebSocket is not open.');
            }
        }

        // Handle Text WebSocket Message
        function handleTextMessage(data) {
            chatMessages.append(genericBotMessage(data));  // Display the bot response
        }

        // Play Base64 Audio
        function playBase64Audio(base64Audio) {
            const audioBlob = base64ToBlob(base64Audio, 'audio/mpeg');
            const audioUrl = URL.createObjectURL(audioBlob);
            const audio = new Audio(audioUrl);
            audio.play();
        }

        // Convert Base64 to Blob
        function base64ToBlob(base64, mimeType) {
            const byteCharacters = atob(base64);
            const byteArrays = [];
            for (let offset = 0; offset < byteCharacters.length; offset += 512) {
                const slice = byteCharacters.slice(offset, offset + 512);
                const byteNumbers = new Array(slice.length);
                for (let i = 0; i < slice.length; i++) {
                    byteNumbers[i] = slice.charCodeAt(i);
                }
                const byteArray = new Uint8Array(byteNumbers);
                byteArrays.push(byteArray);
            }
            return new Blob(byteArrays, { type: mimeType });
        }`

How to auto-play videos using IntersectionObserver in a Django project?

Problem Description:
I’m working on a Django project where I want to auto-play videos when they are at least 70% visible in the viewport and pause them when they fall below 70%. I’ve written the JavaScript using IntersectionObserver, and the logic works well on its own. However, I’m facing some issues when integrating it into my Django template.

What I Have Tried:
I have a Video model in Django where each video file is stored. In the template, I loop through the videos and apply the IntersectionObserver logic for auto-play and pause. The videos load and display correctly, but the auto-play behavior isn’t consistent.

Here’s my setup:

models.py:

class Video(models.Model):
    vidid=ShortUUIDField(length=10,max_length=100,prefix="video",alphabet="abcdefgh")
    title = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    video_file = models.FileField(upload_to='videos/')
    uploaded_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

views.py:

def shorts_view(request,vidid):
    shorts1 = Video.objects.filter(vidid=vidid)
    shorts2 = Video.objects.all()

    context = {
        "shorts1":shorts1,
        "shorts2":shorts2,
    }

    return render(request,"videoshareing/shorts.html")

shorts.html

{%load static%}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lazy Load Shorts</title>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
    <style>
        /* Global Styles */
        body, html {
            margin: 0;
            padding: 0;
            background-color: #181818;
            color: #fff;
            font-family: Arial, sans-serif;
            height: 100%;
            overflow-y: scroll;
        }

        .shorts-container {
            display: flex;
            flex-direction: column;
        }

        .video-container {
            position: relative;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        video {
            width: 500px;
            height: 100%;
            object-fit: cover;
        }

        .follow-button {
            position: absolute;
            top: 10px;
            left: 10px;
            padding: 8px 12px;
            background-color: #ff0000;
            color: white;
            border: none;
            border-radius: 20px;
            cursor: pointer;
            font-size: 14px;
        }

        .actions {
            position: absolute;
            right: 10px;
            top: 50%;
            transform: translateY(-50%);
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .action-button {
            margin: 10px 0;
            color: white;
            text-align: center;
            cursor: pointer;
            padding: 10px;
            background-color: rgba(0, 0, 0, 0.5);
            border-radius: 50%;
            width: 50px;
            height: 50px;
            opacity: 0.8;
        }

        .action-button span {
            display: block;
            font-size: 12px;
            margin-top: 4px;
        }

        .fa-heart, .fa-thumbs-down, .fa-comment, .fa-share {
            font-size: 20px;
        }
    </style>
</head>
<body>
    <div class="shorts-container">
        <!-- Video 1 -->
        <div class="video-container">
            {%for s in shorts2%}
            <video class="video-player" src="{% static './assets/videos/video-1.mp4' %}" muted></video>
            <button class="follow-button">Follow</button>
            <div class="actions">
                <div class="action-button like">
                    <span><i class="fa-regular fa-heart"></i></span>
                    <span>161K</span>
                </div>
                <div class="action-button dislike">
                    <span><i class="fa-regular fa-thumbs-down"></i></span>
                    <span>Dislike</span>
                </div>
                <div class="action-button comment">
                    <span><i class="fa-regular fa-comment"></i></span>
                    <span>378</span>
                </div>
                <div class="action-button share">
                    <span><i class="fa-solid fa-share"></i></span>
                    <span>Share</span>
                </div>
            </div>
            {%endfor%}
        </div>

        <!-- Video 2 -->
        <!-- <div class="video-container">
            <video class="video-player" src="{% static './assets/videos/video-2.mp4' %}" muted></video>
            <button class="follow-button">Follow</button>
            <div class="actions">
                <div class="action-button like">
                    <span><i class="fa-regular fa-heart"></i></span>
                    <span>200K</span>
                </div>
                <div class="action-button dislike">
                    <span><i class="fa-regular fa-thumbs-down"></i></span>
                    <span>Dislike</span>
                </div>
                <div class="action-button comment">
                    <span><i class="fa-regular fa-comment"></i></span>
                    <span>450</span>
                </div>
                <div class="action-button share">
                    <span><i class="fa-solid fa-share"></i></span>
                    <span>Share</span>
                </div>
            </div>
        </div> -->
    </div>
    
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const videos = document.querySelectorAll('.video-player');

            // Create an intersection observer
            const observer = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    const video = entry.target;

                    // If the video is in view
                    if (entry.isIntersecting) {
                        video.play(); // Play the video when it enters the viewport
                    } else {
                        video.pause(); // Pause the video when it leaves the viewport
                    }
                });
            }, {
                threshold: 0.7  // Play the video when 70% is visible
            });

            // Observe each video element
            videos.forEach(video => {
                observer.observe(video);
            });
        });
    </script>
</body>
</html>

The Problem:
Even though the videos load, the auto-play and pause functionality sometimes doesn’t work properly. It works fine when I test the plain HTML + JavaScript, but something seems off when I integrate it with Django.

What I Need Help With:

  1. Is my approach correct for integrating JavaScript with Django templates in this scenario?
  2. Are there any best practices I should follow when using IntersectionObserver with Django’s templating system?
  3. Any suggestions on how I can debug or fix the issue would be greatly appreciated.

How to get more data from RSS Feed?

I created an react native expo app which can fetch and show rss feed data
Suppose on this site https://www.drive.com.au/news/ there are almost 30 posts and show more option but when I fetch the rss feed using this link https://www.drive.com.au/feed/ I got only 10 items. Why I’m not getting all the posts and is there any way to get more posts ?

My function looks like this :

// Function to fetch RSS Feed
const fetchRSSFeed = async (
  url: string,
  setFeedData: React.Dispatch<React.SetStateAction<FeedItem[]>>,
  setLoading: React.Dispatch<React.SetStateAction<boolean>>
) => {
  setLoading(true);
  try {
    const response = await axios.get(url);
    const parser = new xml2js.Parser();

    parser.parseString(response.data, (err: any, result: any) => {
      if (err) {
        console.error("Error parsing XML:", err);
        setLoading(false);
        return;
      }

      const items: FeedItem[] = result?.rss?.channel[0]?.item || [];
      setFeedData((prevItems) => [...prevItems, ...items]); // Add new feed items to the list
      setLoading(false);
    });
  } catch (error) {
    console.error("Error fetching RSS feed:", error);
    setLoading(false);
  }
};

I tried to look for pagination information on the rss feed but no luck

Spread Operator causing ‘Uncaught Error: Module build failed: SyntaxError: Unexpected token’

I’m encountering (Uncaught Error: Module build failed: SyntaxError: Unexpected token) which appears to be caused by the usage of the spread operator (…prevMeme) in your JSX code, which is not being properly transpiled by Babel. I’m using React 17.0.2 and should have the latest version of Babel but somehow it still failed to build.

Here’s my use of the spread operator:
Meme.js

I have tried to install all the latest packages of Babel that should be compatible with my project. Here’s my package.json:
package.json

And here’s my webpack.config.js:
webpack.config.js:

When I try to access the application in the browser I get this error:

index.pack.js:517 Uncaught Error: Module build failed: SyntaxError: Unexpected token (34:12)

[0m [90m 32 | [39m        [36mconst[39m url [33m=[39m allMemes[randomNumber][33m.[39murl
 [90m 33 | [39m        setMeme(prevMeme [33m=>[39m ({
[31m[1m>[22m[39m[90m 34 | [39m            [33m...[39mprevMeme[33m,[39m
 [90m    | [39m            [31m[1m^[22m[39m
 [90m 35 | [39m            randomImage[33m:[39m url
 [90m 36 | [39m        }))
 [90m 37 | [39m    }[0m

    at Object.<anonymous> (index.pack.js:517:7)
    at __webpack_require__ (index.pack.js:20:30)
    at Object.<anonymous> (index.pack.js:406:13)
    at __webpack_require__ (index.pack.js:20:30)
    at Object.<anonymous> (index.pack.js:534:12)
    at __webpack_require__ (index.pack.js:20:30)
    at index.pack.js:66:18
    at index.pack.js:69:10

Can someone please help me solve this issue?

`isomorphic-dompurify` with Angular 18 SSR runtime error: Cannot convert undefined or null to object

I installed isomorphic-dompurify ^2.15.0 to my Angular 18 SSR application. It builds successfully with the standard DomPurify code, such as:

import DOMPurify from "isomorphic-dompurify";
DOMPurify.sanitize(dirtyHtml);

But at runtime, you will get the following error:

[vite] Error when evaluating SSR module /main.server.mjs:
|- TypeError: Cannot convert undefined or null to object
    at Function.getPrototypeOf (<anonymous>)
    at node_modules/whatwg-url/lib/utils.js (C:...angularcache18.2.1vitedeps_ssrisomorphic-dompurify.js:19369:41)     
    at __require2 (C:...angularcache18.2.1vitedeps_ssrchunk-2FDURXR6.js:51:50)
    at node_modules/whatwg-url/lib/URL.js (C:...angularcache18.2.1vitedeps_ssrisomorphic-dompurify.js:22241:17)       
    at __require2 (C:...angularcache18.2.1vitedeps_ssrchunk-2FDURXR6.js:51:50)
    at node_modules/whatwg-url/webidl2js-wrapper.js (C:...angularcache18.2.1vitedeps_ssrisomorphic-dompurify.js:22648:16)
    at __require2 (C:...angularcache18.2.1vitedeps_ssrchunk-2FDURXR6.js:51:50)
    at node_modules/whatwg-url/index.js (C:...angularcache18.2.1vitedeps_ssrisomorphic-dompurify.js:22662:9)
    at __require2 (C:...angularcache18.2.1vitedeps_ssrchunk-2FDURXR6.js:51:50)
    at node_modules/jsdom/lib/api.js (C:...angularcache18.2.1vitedeps_ssrisomorphic-dompurify.js:141933:21)

I found a similar, still open, issue here for Angular 15: Build error when using isomorphic-dompurify in angular 15 universal #203.

XHR Polling Error Socket.io Chrome extension

I’m trying to communicate with my local server from my chrome extension with scoket.io but I’m getting an XHR Polling Error.

I don’t get this error when I simulate a client, I only get it with the chrome extension.

I’ve also tried using my ip instead of localhost, defining a websocket protocol when creating the server or adding a cors but I always get the same error.

enter image description here

manifest.js

{
  "manifest_version": 3,
  "name": "DogadPrime Alerte",
  "version": "2.0",
  "description": "Ne manquez jamais un live de DogadPrime sur Twitch ainsi que les prochaines vidéos youtube grâce à des notifications instantanées !",
  "permissions": [
    "notifications",
    "alarms",
    "storage",
    "activeTab",
    "webRequest"
  ],
  "minimum_chrome_version": "116",
  "host_permissions": ["http://localhost:3000/*"],
  "background": {
    "service_worker": "background.js",
    "type": "module"
  },
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  }
}

background.js

import { io } from "https://cdn.jsdelivr.net/npm/[email protected]/+esm";


const socketUrl = "http://localhost:3000/";
const socket = io(socketUrl, {
    transport: ["websocket"],
});


console.log("Lancement de l'extension browser");

if (typeof browser === "undefined") {
    var browser = chrome;
}

function showNotificationTwitch(stream) {
    browser.notifications.create('twitch-streamer-alert', {
        type: 'basic',
        iconUrl: 'icons/icon48.png',
        title: `${stream.user_name} est en live !`,
        message: `Regardez maintenant sur Twitch : ${stream.title}`,
        priority: 2
    });
}

browser.notifications.onClicked.addListener(function (notificationId) {
    if (notificationId === 'twitch-streamer-alert') {
        const twitchChannelUrl = 'https://www.twitch.tv/dogadprime';
        console.log('Ouverture de l'URL Twitch:', twitchChannelUrl);
        browser.tabs.create({ url: twitchChannelUrl });
    }
});


// Événement lorsqu'une connexion est établie
socket.on('connection', () => {
    console.log('Connexion au serveur');
});

socket.on('platformNotification', (data) => {
    console.log(data);
    const { platform, status, streamData } = data;
    if (platform == 'twitch' && status == true) {
        console.log('Le streamer est en direct !');
        console.log('Détails du stream :', data.streamData);
        showNotificationTwitch(streamData);
    } else {
        console.log('Le streamer n'est pas en direct.');
    }

});

socket.on('connect_error', (error) => {
    console.log('Erreur de connexion :', error);
});

server app.js

const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const fetch = require('node-fetch');
require('dotenv').config();

const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
    cors: {
        origin: "*",
        methods: ["GET", "POST"],
    },
});

const clientId = process.env.TWITCH_CLIENT_ID;
const accessToken = process.env.TWITCH_ACCESS_TOKEN;
const streamerName = 'sc2skyblue';
const twitchApiUrl = `https://api.twitch.tv/helix/streams?user_login=${streamerName}`;

let isStreamerOnline = false;

async function checkStreamerLive() {
    try {
        const response = await fetch(twitchApiUrl, {
            headers: {
                'Client-ID': clientId,
                'Authorization': `Bearer ${accessToken}`
            }
        });

        const data = await response.json();
        const currentlyOnline = data.data && data.data.length > 0;

        if (currentlyOnline && !isStreamerOnline) {

            io.emit('platformNotification', {
                platform: 'twitch',
                status: true,
                streamData: data.data[0]
            });
            console.log("Le streamer est en direct. Notification envoyée.");
        } else if (!currentlyOnline && isStreamerOnline) {

            io.emit('platformNotification', {
                platform: 'twitch',
                status: false,
                streamData: null
            });
            console.log("Le streamer est hors ligne. Notification envoyée.");
        }


        isStreamerOnline = currentlyOnline;

    } catch (error) {
        console.error('Erreur lors de la vérification du statut du streamer :', error);
    }
}


const checkInterval = 1 * 60 * 1000; // 1 minute
setInterval(checkStreamerLive, checkInterval);

io.on('connection', (socket) => {
    console.log('Un client est connecté');

    socket.emit('welcome', { message: 'Bienvenue sur le serveur Socket.IO' });

    socket.on('disconnect', () => {
        console.log('Un client s'est déconnecté');
    });
});

server.listen(3000, () => {
    console.log('Serveur en écoute sur le port 3000');
});

html2canvas issues chrome extension

I am trying to use the html2canvas within a chrome extension I am building.

For my chrome extension I am directly injecting JS so that the user can toggle the extension so it does not go out of focus and closes when the user clicks on the current tab.


<body>
    <script src="popup.js"></script>
  </body>

I am choosing to dynamically load the html2canvas from a local file where I have copied the JS file.

I am loading it within my content.js file (this file also contains the UI where it is directly injecting into the current tab DOM.

Here is the function where I am calling the html2canvas to load:

  async function mouseUpHandler(e) {
      if (!isSelecting) return;
    
      isSelecting = false;
    
      // Remove event listeners and overlay
      const overlay = document.getElementById("selectionOverlay");
      overlay.removeEventListener("mousedown", mouseDownHandler);
      overlay.removeEventListener("mousemove", mouseMoveHandler);
      overlay.removeEventListener("mouseup", mouseUpHandler);
      document.body.removeChild(overlay);
    
      // Get the selected area coordinates
      const rect = selectionBox.getBoundingClientRect();
    
      // Remove the selection boxhtm
      selectionBox.remove();
    
      console.log("Selected area:", rect);
    
      try {
        // Wait for html2canvas to be loaded
        await loadHtml2Canvas();
    
        // Ensure window.html2canvas is loaded and then use it
        window.html2canvas(document.body, {
          x: rect.left + window.scrollX,
          y: rect.top + window.scrollY,
          width: rect.width,
          height: rect.height,
          windowWidth: document.documentElement.scrollWidth,
          windowHeight: document.documentElement.scrollHeight,
          scale: window.devicePixelRatio // Adjust for high-DPI screens
        })
        .then((canvas) => {
          const dataUrl = canvas.toDataURL("image/png");
          console.log("Captured image data URL:", dataUrl);
    
          // Store the captured image data URL
          capturedImageDataUrl = dataUrl;
    
          // Display the captured image in the sidebar
          displayCapturedImage(dataUrl);
        })
        .catch((error) => {
          console.error('html2canvas error:', error);
        });
      } catch (error) {
        console.error(error.message);
      }
    }
    

And here is the loadhtml2canvas:

  function loadHtml2Canvas() {
      return new Promise((resolve, reject) => {
        // Check if html2canvas is already loaded
        if (typeof window.html2canvas !== 'undefined') {
          console.log('html2canvas is already loaded.');
          resolve(); // Resolve immediately if already loaded
          return;
        }
    
        // Load html2canvas dynamically
        let script = document.createElement('script');
        const scriptUrl = chrome.runtime.getURL('html2canvas.min.js');
        console.log('Loading html2canvas from:', scriptUrl);
        
        script.src = scriptUrl;
    
        script.onload = function() {
          console.log('html2canvas loaded dynamically.');
          if (typeof window.html2canvas !== 'undefined') {
            resolve(); // Resolve the promise if window.html2canvas is defined
          } else {
            reject(new Error('window.html2canvas is still not defined after loading.'));
          }
        };
    
        script.onerror = function() {
          reject(new Error('Failed to load html2canvas.'));
        };
    
        // Append the script to the document head
        document.head.appendChild(script);
      });
    }

What is happening is it looks like it is correctly being loaded from the file but then it turns out to be undefined.

Here is the console.log statements:

Selected area: DOMRect {x: 0, y: 0, width: 0, height: 0, top: 0, …}

content.js:409 Loading html2canvas from: chrome-extension://geekmcfbhphgbnafmfmcmhjeaeoaikod/html2canvas.min.js

content.js:414 html2canvas loaded dynamically.

content.js:482 window.html2canvas is still not defined after loading.
mouseUpHandler @ content.js:482

Any help would be greatly appreciated.

I have tried to load this from the manifest.js like so:

"content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["html2canvas.min.js", "content.js"]
    }
  ],
  "web_accessible_resources": [
    {
      "resources": ["html2canvas.min.js"], 
      "matches": ["<all_urls>"]
    }
  ]

I get the same error

How to update google apps script to apply to specific cells and not all cells

I have the following script which is doing exactly what I want (changing the currency symbol within cells depending on what is selected), except that it’s being applied to all cells, and I’d like it applied only to cells C9, C12, C13. I’m probably missing something painfully obvious, but I’m just not quite sure where I would put that in the script. Thank you!

function udtsymbol () {
    const s = SpreadsheetApp.getActiveSheet();
  const r = s.getDataRange();
  const symb = {"$":"$", "€":"€", "£":"£"};
  r.setNumberFormat(symb[s.getRange("C8").getValue()]+"###,##0.00");

I’ve tried editing the code in a number of different ways, including adding the range within getDataRange() and also putting in an if statement, but I keep getting errors, as I’m not familiar with javascript. Have been googling for hours so finally asking for help.