Javascript code runs fine on Codesandbox but not on localy or on a webserver - javascript

I tried to read read QR code thanks to javascript code found in this tutorial
The code provided by this tutorial works inside the codesandbox linked in the tutorial, however it doesn't work when I tired the same exact code on my laptop or on my remote webserver. I've litteraly copy and paste the code with the same file configuration, filenames ect... but I'm getting the following JS error on my browser :
SyntaxError: Identifier 'qrcode' has already been declared (at qrCodeScanner.js:1:1)
Since I run the exact same code I d'ont understand what is going on there. Is there something needed on the server side in order to make the code works that is not mentioned in the tutorial ?
If you want to see the code used and see it in action, you can teste the codesandbox instance there.
EDIT
Here's the code I use :
(HMTL)
<!DOCTYPE html>
<html>
<head>
<title>QR Code Scanner</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width; initial-scale=1.0, maximum-scale=1.0; user-scalable=0;" />
<link rel="stylesheet" href="./src/style.css" />
<script src="https://rawgit.com/sitepoint-editors/jsqrcode/master/src/qr_packed.js"></script>
</head>
<body>
<div id="container">
<h1>QR Code Scanner</h1>
<a id="btn-scan-qr">
<img src="https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/07/1499401426qr_icon.svg">
<a/>
<canvas hidden="" id="qr-canvas"></canvas>
<div id="qr-result" hidden="">
<b>Data:</b> <span id="outputData"></span>
</div>
</div>
<script src="./src/qrCodeScanner.js"></script>
</body>
</html>
(Javascript)
const qrcode = window.qrcode;
const video = document.createElement("video");
const canvasElement = document.getElementById("qr-canvas");
const canvas = canvasElement.getContext("2d");
const qrResult = document.getElementById("qr-result");
const outputData = document.getElementById("outputData");
const btnScanQR = document.getElementById("btn-scan-qr");
let scanning = false;
qrcode.callback = res => {
if (res) {
outputData.innerText = res;
scanning = false;
video.srcObject.getTracks().forEach(track => {
track.stop();
});
qrResult.hidden = false;
canvasElement.hidden = true;
btnScanQR.hidden = false;
}
};
btnScanQR.onclick = () => {
navigator.mediaDevices
.getUserMedia({ video: { facingMode: "environment" } })
.then(function(stream) {
scanning = true;
qrResult.hidden = true;
btnScanQR.hidden = true;
canvasElement.hidden = false;
video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen
video.srcObject = stream;
video.play();
tick();
scan();
});
};
function tick() {
canvasElement.height = video.videoHeight;
canvasElement.width = video.videoWidth;
canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);
scanning && requestAnimationFrame(tick);
}
function scan() {
try {
qrcode.decode();
} catch (e) {
setTimeout(scan, 300);
}
}

Problem
The problem is that you are probably using a live server or just opening the html file, but in the sandbox parcel-bundler is used. var qrcode from the library collides with your const qrcode.
Solutions
Type module
Replace
<script src="./src/qrCodeScanner.js"></script>
with
<script type="module" src="./src/qrCodeScanner.js"></script>
Rename
Change your variable to something else like const myQrcode
Use a bundler
You can use parcel-bundler as in the sandbox or any other that will resolve variable collision for you

Related

How can I upload a file to a github repo in Javascript?

I have an audio file which is generated by a JS script integrated to my streamlit web-app with components.html, like this:
components.html(
"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- Set up your HTML here -->
<center>
<p><button id="record">Record</button></p>
<div id="sound-clip"></div>
</center>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script>
// Set up the AudioContext.
const audioCtx = new AudioContext();
// Top-level variable keeps track of whether we are recording or not.
let recording = false;
// Ask user for access to the microphone.
if (navigator.mediaDevices) {
navigator.mediaDevices.getUserMedia({ "audio": true }).then((stream) => {
// Instantiate the media recorder.
const mediaRecorder = new MediaRecorder(stream);
// Create a buffer to store the incoming data.
let chunks = [];
mediaRecorder.ondataavailable = (event) => {
chunks.push(event.data);
}
// When you stop the recorder, create a empty audio clip.
mediaRecorder.onstop = (event) => {
const audio = new Audio();
audio.setAttribute("controls", "");
$("#sound-clip").append(audio);
$("#sound-clip").append("<br />");
// Combine the audio chunks into a blob, then point the empty audio clip to that blob.
const blob = new Blob(chunks, { "type": "audio/wav; codecs=0" });
audio.src = window.URL.createObjectURL(blob);
// Clear the `chunks` buffer so that you can record again.
chunks = [];
};
mediaRecorder.start();
recording = true;
$("#record").html("Stop");
// Set up event handler for the "Record" button.
$("#record").on("click", () => {
if (recording) {
mediaRecorder.stop();
recording = false;
$("#record").html("Record");
} else {
$("#record").html("Stop");
}
});
}).catch((err) => {
// Throw alert when the browser is unable to access the microphone.
alert("Oh no! Your browser cannot access your computer's microphone.");
});
} else {
// Throw alert when the browser cannot access any media devices.
alert("Oh no! Your browser cannot access your computer's microphone. Please update your browser.");
}
</script>
</body>
</html>
"""
)
Since I'm using Streamlit I need to upload the generated file to a bucket (I was thinking to use a simple github repo for now), but I have problems understanding how to do it given the fact that the script is wrapped inside components.html. Is it possible to upload the file and later retrive it to use it inside my python script for some calculations?

Play loaded audio file with Tone.js web audio framework

Hi I'm creating a simple upload page where user load their local files and play it. For hour, i'm not uploading to the server, just want to create a file input and then play the audio file with Tone.js if it's possibel.
I'm using to this test P5.js library and Tone.js audio framework, the code below:
let inputFile, bttPlayFile;
let files;
window.AudioContext = window.AudioContext || window.webkitAudioContext;
let context = new Tone.Context();
let source;
function setup() {
inputFile = createFileInput(uploadTrack);
bttPlayFile = createButton('play');
bttPlayFile.mousePressed(tooglePlay);
}
function playSound(arraybuffer) {
context.decodeAudioData(arraybuffer, function(buf) {
source = new Tone.BufferSource();
source.connect(context).toDestinattion();
source.Tone.Buffer = buf;
source.start(0);
});
}
function selectedFile(evt) {
files = evt.target.files;
playFile(files[0]);
}
function playFile(file) {
let reader = new FileReader();
reader.onload = function(e) {
console.log(e.target.result);
playSound(e.target.result);
}
reader.readAsArrayBuffer(file);
}
function uploadTrack() {
inputFile.changed(selectedFile, false);
}
function tooglePlay() {
Tone.Transport.start();
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.32/Tone.js" integrity="sha512-USKCQh+O8BX/a2K06xPNTwduhmQvN/m9FhkR7PRysCRlPoqIItl7Qz3xVTZC/oIHe6g5XvnLHDUgGpRMZZTmFQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
At the moment, nothing happens and I want to understand why and how to proceed with this. Thanks!
If you open the console of your browser you should see a warning.
The AudioContext is "suspended". Invoke Tone.start() from a user
action to start the audio.
I think it will work if you call Tone.start() in the click handler of your "play" button before you load and decode the selected audio file.
It's unrelated to your question but it should be safe to remove window.AudioContext = window.AudioContext || window.webkitAudioContext from your code. Tone.js uses standardized-audio-context internally which should handle this for you.

p5js AudioIn function not working on instance mode

I was converting my p5js code to instance mode to run 2 canvases in the same DOM but my p5.AudioIn() function is not working. The error I get is referencing Failed to construct 'AudioWorkletNode'. I have uploaded a screenshot of the error below because it has more information about it. Why isn't AudioIn not working when converted to instance mode but works on global mode.
let s2 = function(sketch) {
sketch.quinnListenMic;
sketch.setup = function() {
let cnv = sketch.createCanvas(300, 300);
cnv.mousePressed(sketch.userStartAudio);
sketch.quinnListenMic = new p5.AudioIn(); //ERROR HERE
sketch.quinnListenMic.start();
}
sketch.draw = function() {
sketch.background(100)
sketch.micLevel = quinnListenMic.getLevel();
console.log(micLevel)
}
}
var myp5_2 = new p5(s2);
<html>
<head>
<script defer src=https://cdn.JsDelivr.net/npm/p5></script>
<script defer src=https://cdn.JsDelivr.net/npm/p5/lib/addons/p5.dom.min.js></script>
<script defer src=https://cdn.JsDelivr.net/npm/p5/lib/addons/p5.sound.min.js></script>
<script src="https://cdn.jsdelivr.net/npm/p5#1.4.0/lib/p5.js"></script>
</head>
<body>
</body>
</html>
There were a couple of issues, fixed below with comments:
let s2 = function(sketch) {
// sketch.quinnListenMic; doesn't make sense. 1) You don't want to store your variables on the p5 instance, and 2) that statement doesn't actually do anything
// This is how you declare a local variable for use in setup/draw functions:
let quinnListenMic;
sketch.setup = function() {
let cnv = sketch.createCanvas(300, 300);
cnv.mousePressed(sketch.userStartAudio);
quinnListenMic = new p5.AudioIn(); //ERROR HERE
quinnListenMic.start();
}
sketch.draw = function() {
// Fixed local variable declaration again
// Note: there is a bug with AudioIn.getLevel not working in all browsers
let micLevel = quinnListenMic.getLevel();
// Let's not spam the console log
// console.log(micLevel)
sketch.background(sketch.map(micLevel, 0, 1, 0, 255));
}
}
var myp5_2 = new p5(s2);
<html>
<head>
<!-- Your script tags were not valid -->
<script src="https://cdn.jsdelivr.net/npm/p5#1.4.0/lib/p5.js"></script>
<!-- For some reason p5.sound does not work with the defer attribute -->
<script src="https://cdn.jsdelivr.net/npm/p5#1.4.0/lib/addons/p5.sound.min.js"></script>
</head>
<body>
</body>
</html>

Using HtmlMediaElement.captureStream() to get the audio from a video

I'm trying to capture the audio track from a video and play it separately. I wrote the test page shown below. I'm able to capture the stream and I get a valid audio track with readyState == "live", but I hear nothing. What am I doing wrong?
The video I'm using comes from here: http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4. I'm serving the HTML and the video locally to avoid CORS issues.
<head>
<script>
function captureAudio() {
const videoEl = document.getElementById("video")
videoEl.volume = 0.0
const videoStream = videoEl.captureStream()
const audioTrack = videoStream.getAudioTracks()[0]
const audioStream = new MediaStream()
audioStream.addTrack(audioTrack)
const audioEl = document.createElement("audio")
audioEl.srcObject = audioStream
audioEl.autostart = true
audioEl.volume = 1.0
audioEl.muted = false
}
</script>
<body>
<video id="video" src="http://localhost:3000/BigBuckBunny.mp4" controls onplay="captureAudio()" />
</body>
</html>
It works if you set a volume different than 0 (for example, 0.5). I have modified your code and hosted it on Glitch. When you pause the audio (that I have attached to the DOM so you can interact with it), you can clearly hear the different sources of sound, one from the video and one from the audio.
<html>
<head>
<script>
function captureAudio() {
const videoEl = document.getElementById("video");
videoEl.volume = 0.5;
const videoStream = videoEl.captureStream();
const audioTrack = videoStream.getAudioTracks()[0];
const audioStream = new MediaStream();
audioStream.addTrack(audioTrack);
const audioEl = document.createElement("audio");
audioEl.controls = true;
document.body.append(audioEl);
audioEl.srcObject = audioStream;
audioEl.play();
audioEl.volume = 1.0;
audioEl.muted = false;
}
</script>
</head>
<body>
<video
id="video"
crossorigin
src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
controls
onplay="captureAudio()"
/>
</body>
</html>

How can I get a list of video cameras attached in my computer using JavaScript?

I want to display a list of video cameras attached to the user's computer, and when they select one, display streaming video from that camera in an HTML5 <video> tag.
How can I get a list of the video cameras attached to the user's computer?
Only works in chrome and edge
<script>
navigator.mediaDevices.enumerateDevices().then(function (devices) {
for(var i = 0; i < devices.length; i ++){
var device = devices[i];
if (device.kind === 'videoinput') {
var option = document.createElement('option');
option.value = device.deviceId;
option.text = device.label || 'camera ' + (i + 1);
document.querySelector('select#videoSource').appendChild(option);
}
};
});
</script>
<select id="videoSource"></select>
Perhaps Navigator.getUserMedia() (uses WebRTC under the hood) is what you're looking for, though I don't see anything that will directly tell you what devices are available (the list of devices isn't exposed to your codeā€”it's presented to the user when asking for permission to access available hardware).
Also note the browser support: Chrome 21+, Firefox 20+, Opera 12+, no support for IE and possibly Safari.
try out this...
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="author" content="Victor Stan">
<meta name="description" content="Get multiple video streams on one page. Adapted from code by Muaz Khan">
<title>Video Camera</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js" ></script>
<style type="text/css" media="screen">
video {
border:1px solid gray;
}
</style>
</head>
<body>
<script>
if (!MediaStreamTrack) document.body.innerHTML = '<h1>Incompatible Browser Detected. Try <strong style="color:red;">Chrome Canary</strong> instead.</h1>';
var videoSources = [];
MediaStreamTrack.getSources(function(media_sources) {
console.log(media_sources);
alert('media_sources : '+media_sources);
media_sources.forEach(function(media_source){
if (media_source.kind === 'video') {
videoSources.push(media_source);
}
});
getMediaSource(videoSources);
});
var get_and_show_media = function(id) {
var constraints = {};
constraints.video = {
optional: [{ sourceId: id}]
};
navigator.webkitGetUserMedia(constraints, function(stream) {
console.log('webkitGetUserMedia');
console.log(constraints);
console.log(stream);
var mediaElement = document.createElement('video');
mediaElement.src = window.URL.createObjectURL(stream);
document.body.appendChild(mediaElement);
mediaElement.controls = true;
mediaElement.play();
}, function (e)
{
alert('Hii');
document.body.appendChild(document.createElement('hr'));
var strong = document.createElement('strong');
strong.innerHTML = JSON.stringify(e);
alert('strong.innerHTML : '+strong.innerHTML);
document.body.appendChild(strong);
});
};
var getMediaSource = function(media) {
console.log(media);
media.forEach(function(media_source) {
if (!media_source) return;
if (media_source.kind === 'video')
{
// add buttons for each media item
var button = $('<input/>', {id: media_source.id, value:media_source.id, type:'submit'});
$("body").append(button);
// show video on click
$(document).on("click", "#"+media_source.id, function(e){
console.log(e);
console.log(media_source.id);
get_and_show_media(media_source.id);
});
}
});
}
</script>
</body>
</html>
JavaScript cannot access your cameras to return a list. You will need to use a Flash SWF to get the camera information and pass it back to your page's JavaScript.
EDIT:
to those who downvoted. These methods will not give him a dropdown list of available cameras. If it does, please post a link or code. At the current date, the only way to get a list of cameras (which is what his questions was) is to use Flash (or possibly silverlight, but Flash has much broader install coverage). I've edited my question to be a little more specific in terms of getting the list versus accessing a camera.

Categories