The error message displayed is as follows. ※The detailed error text could not be posted because the site was flagged as spam.
It seems that there is an error especially here
・loader.js
document.body.insertBefore(script, document.body.firstChild)
Refused to load the script 'https://meet.google.com/tf-core.js' because it violates the Content Security Policy directive
Refused to execute inline script because it violates the Content Security Policy directive
Uncaught (in promise) Event Context https://meet.google.com/ Stack trace loader.js:36 (Unnamed function)
extension.sh is the code to download the js files in the code. This shell was used to download the files.
Folder structure
extension
-face-kandmarks-detection.js
-ImMarkIMG.js
-extensions.sh
-main.js
-loader.js
-manifest.json
-tf-backend-webgl.js
-tf-converter.js
-tf-core.js
#!/usr/bin/env bash
#NOTE: if you are on macOS, update to bash v4 i.e brew install bash
rm -rf extension extension.zip
cp -r public extension
cd extension
declare -A scripts0=(
[file]='tf-core.js'
[url]='https://unpkg.com/@tensorflow/tfjs-core@2.4.0/dist/tf-core.js'
)
declare -A scripts1=(
[file]='tf-converter.js'
[url]='https://unpkg.com/@tensorflow/tfjs-converter@2.4.0/dist/tf-converter.js'
)
declare -A scripts2=(
[file]='tf-backend-webgl.js'
[url]='https://unpkg.com/@tensorflow/tfjs-backend-webgl@2.4.0/dist/tf-backend-webgl.js'
)
declare -A scripts3=(
[file]='face-landmarks-detection.js'
[url]='https://unpkg.com/@tensorflow-models/face-landmarks-detection@0.0.1/dist/face-landmarks-detection.js'
)
declare -n scripts
for scripts in ${!scripts@}; do
curl ${scripts[url]} -o ${scripts[file]}
sed -i"" -e "s|${scripts[url]}|${scripts[file]}|g" main.js
done
zip -r extension.zip *
mv extension.zip ../
{
"manifest_version": 3,
"name": "Meet Face Hack Extension",
"version": "0.0.1",
"description": "Meet hack",
"host_permissions": [
"https://meet.google.com/"
],
"content_scripts": [
{
"js": ["lmMarkImg.js","tf-core.js","tf-converter.js","tf- backend-webgl.js","face-landmarks-detection.js","loader.js","main.js"],
"matches": ["https://meet.google.com/*"],
"run_at": "document_start"
}
]
}
function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = src
script.onload = () => {
console.log(`loaded: ${src}`)
resolve()
}
script.onerror = (e) => reject(e)
document.body.insertBefore(script, document.body.firstChild)
})
}
async function loadLocalScript(path) {
const res = await fetch(chrome.runtime.getURL(path), {method: 'GET'})
const text = await res.text()
const script = document.createElement('script')
script.textContent = text
document.body.insertBefore(script, document.body.firstChild)
}
async function load() {
loadLocalScript("lmMarkImg.js")
await loadScript("tf-core.js")
await loadScript("tf-converter.js")
await loadScript("tf-backend-webgl.js")
await loadScript("face-landmarks-detection.js")
loadLocalScript("main.js")
}
window.addEventListener('load', async (evt) => {
await load()
})
const video = document.createElement('video')
const canvas = document.createElement('canvas')
const canvasCtx = canvas.getContext('2d')
let model = null
let keepAnimation = false
let imageIndex = 0
function getImage() {
const image = lmMarkImages[imageIndex]
imageIndex += 1
if (imageIndex == lmMarkImages.length) {
imageIndex = 0
}
return image
}
function drawImage(prediction) {
let imageIndex = 0
const boundingBox = prediction.boundingBox
const x = boundingBox.topLeft[0]
const y = boundingBox.topLeft[1]
const w = boundingBox.bottomRight[0] - x
const h = boundingBox.bottomRight[1] - y
// draw Rectangle for debug
// canvasCtx.strokeStyle = "rgb(255, 0, 0)";
// canvasCtx.strokeRect(x, y, w, h)
const image = getImage()
canvasCtx.drawImage(image, x, y, w, h)
}
async function updateCanvas() {
if (!keepAnimation) return
if (model) {
canvasCtx.drawImage(video, 0, 0, canvas.width, canvas.height)
const predictions = await model.estimateFaces({ input: video })
for (const prediction of predictions) {
drawImage(prediction)
}
}
requestAnimationFrame(updateCanvas)
}
function isScreenSharing(constraints) {
return !constraints.video.deviceId
}
function replaceStopFunction(stream, videoTrack) {
if (!videoTrack) return
videoTrack._stop = videoTrack.stop
videoTrack.stop = function () {
keepAnimation = false
videoTrack._stop()
stream.getTracks().forEach((track) => {
track.stop()
})
}
}
const _getUserMedia = navigator.mediaDevices.getUserMedia.bind(
navigator.mediaDevices
)
navigator.mediaDevices.getUserMedia = async function (constraints) {
const srcStream = await _getUserMedia(constraints)
if (isScreenSharing(constraints)) {
return srcStream
}
video.srcObject = srcStream
video.onloadedmetadata = function (e) {
video.play()
video.volume = 0.0
video.width = video.videoWidth
video.height = video.videoHeight
canvas.width = video.width
canvas.height = video.height
keepAnimation = true
updateCanvas()
}
const outStream = canvas.captureStream(10)
const videoTrack = outStream.getVideoTracks()[0]
replaceStopFunction(srcStream, videoTrack)
return outStream
}
async function loadModel() {
model = await faceLandmarksDetection.load(
faceLandmarksDetection.SupportedPackages.mediapipeFacemesh
)
//console.log("model: loaded")
}
function main() {
loadModel()
}
main()
Because it was necessary to paste a minimal amount of code, main.js was not pasted. I will add it if necessary.
textContent
of a script
element. Use src
with chrome.runtime.getURL
.Here's the entire loader.js:
const scripts = [
'lmMarkImg.js',
'main.js',
];
(function loadSequentially() {
const el = document.createElement('script')
el.src = chrome.runtime.getURL(scripts.shift());
if (scripts[0]) el.onload = loadSequentially;
document.documentElement.appendChild(el);
el.remove();
})();