Buffer.from in client components works just fine but when I try it in the browser developer console, it throws
Uncaught ReferenceError: Buffer is not defined
Blancer.com Tutorials and projects
Freelance Projects, Design and Programming Tutorials
Category Added in a WPeMatico Campaign
Buffer.from in client components works just fine but when I try it in the browser developer console, it throws
Uncaught ReferenceError: Buffer is not defined
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">
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.
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?
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:
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)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.
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
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();
})
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.
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?
For a complex keyPath like [domain, field], how to reliably get [domain, *]?
The current solution I come up is objectStore.getAllKeys(IDBKeyRange.bound([domain], [domain + ' '], true, true)), but it seems not quiet elegant.
Is there a more canonical way to do this?
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 });
}`
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:
IntersectionObserver with Django’s templating system?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
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?
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.
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.
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');
});
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