Search for an image by pattern in NodeJS - node.js

I needed to use pictures of items from Minecraft for my project, but there are a lot of them for a long time to search and download, and I am very lazy. I got the idea to search Google for a picture using a template, for example: "minecraft: diamond_block" and the image must be on the domain: "https://static.wikia.nocookie.net/" and must have an aspect ratio of 1: 1, these are the requirements that are needed to find the image I want. How do I implement this in NodeJS

Used this
const GoogleImages = require('google-images');
const client = new GoogleImages('CSE KEY', 'API KEY');
const prefix = "minecraft "
let result = {}
client.search(prefix + 'ancient_debris', {})
.then(images => {
result = images.find((e) => {
if (e.url.match("https://static.wikia.nocookie.net/") === null) return false
if (e.url.match("latest") === null) return false
if (e.url.match("smart") !== null) return false
return e
})
console.log(result.url)
});

Related

Unable to trigger if block in wordle clone

I followed PedroTech's guide for a Wordle Clone to practice React, which I really enjoy. I've mostly had no issues and have made some additions myself but am having a hell of a time getting my gameOver condition to trigger on a win (guessing the correct word). It triggers correctly on a loss (6 guesses without the right word). The issue would seem at first blush to be a casing mismatch between the correct word from the word bank and the current word being concatted in the for loop, but upon logging each I am getting identical strings. I have tried everything in my toolbelt at this point and am at a loss.
Here is where the correct word and states are set. The correct word is set from a lowercase bank using use effect and is logged upon comp mount. I know it is correct because I am getting my letter colors to fill correctly upon guess. I will post an image to give a better idea of what I'm looking at.
`function App() {
const [board, setBoard] = useState(emptyBoard);
const [wordSet, setWordSet] = useState(new Set());
const [currentGuess, setCurrentGuess] = useState({ attempt: 0, letterPosition: 0 });
const [gamesWon, setGamesWon] = useState(0);
const [soupInfo, setSoupInfo] = useState([]);
const [soupPic, setSoupPic] = useState(null);
const [userPersist, setUserPersist] = useState(false);
const [validWord, setValidWord] = useState('');
const [disabledLetters, setDisabledLetters] = useState([]);
const [gameOver, setGameOver] = useState({ gameOver: false, guessedWord: false })
const [correctWord, setCorrectWord] = useState('');
const [playerPosition, setPlayerPosition] = useState(1);
// let [currentWord, setCurrentWord] = useState('');
let [soupIndex, setSoupIndex] = useState([]);
useEffect(() => {
genWordSet().then((words) => {
setWordSet(words.wordSet);
setCorrectWord(words.todaysWord);
});
}, []);`
Here is an image of the correct word being recognized letter by letter:
soup-seeker
Here is my onEnter() function that recognizes keydown input of a 5-letter word. This is where the gameOver state should change upon correctWord and currentWord being matched:
const onEnter = () => {
if (currentGuess.letterPosition !== 5) return;
let currentWord = '';
for (let i = 0; i < 5; i++) {
// setCurrentWord(board[currentGuess.attempt][i].toString())
currentWord += board[currentGuess.attempt][i].toLowerCase();
}
console.log(currentWord);
console.log(correctWord);
console.log(typeof currentWord);
console.log(typeof correctWord);
// + `\r`
//not sure why this \r is appearing in the word set but can just concatenate
if (wordSet.has(currentWord.toLowerCase() + `\r`)) {
setCurrentGuess({ attempt: currentGuess.attempt + 1, letterPosition: 0 });
console.log(currentWord)
console.log(correctWord);
} else {
setValidWord('Not null');
} if (currentWord === correctWord) {
setGameOver({ gameOver: true, guessedWord: true });
return;
};
if (currentGuess.attempt === 5) {
setGameOver({ gameOver: true, guessedWord: false })
return;
};
//increase the array index w attempt; reset position in array to start for next guess
};
I have a tried lower casing the current word in the if condition but it doesn't seem to do anything, and they are both registering as a lowercase strings anyways.
Could anyone help me out? I'm pretty new to this so my guess is I'm missing something really obvious. Usually I try to solve things myself but this one has me really stumped.
Thank you.

How to make a firebase function (using on create) return an error that I can catch from my react native app

I have created a Firebase function for my shopping app, where the function is triggered when an order is created and then it checks the quantity of each product in the order and update product quantity in the database. I need this to keep track of how many items is left of each product.
However, in case one of the products in the order has more quantity than what left (the quantity of the product in the database), I need a way for the function to return an error I can catch from my react native app so I can inform the user that the quantity he asked for is not available. I also need the function to stop the creating of the order doc in the database.
Here's the firebase function I wrote:
exports.countOrderProductChange = functions.firestore.document("/orders/{id}")
.onCreate((change, context) => {
const data = change.data();
const itemsList = data["itemsList"];
let error = "";
const newProductsSizes = {};
for (const item of itemsList) {
db.collection("products").doc(item.product.id).get().then((doc) => {
const product = doc.data();
let sizes = [];
if (item.product.id in newProductsSizes) {
sizes = newProductsSizes[item.product.id];
} else {
sizes = product.sizes;
}
const remaingSize = sizes.find((size) => (size.name == item.size));
const remaingSizeQty = remaingSize.qty;
if (remaingSizeQty < item.qty) {
if (remaingSizeQty == 0) {
error = "Sorry there's no more (" + item.size +
") size of the product: " + item.product.name;
} else {
error = "Sorry there's only "+ remaingSizeQty +
" of (" + item.size +
") size of the product: " + item.product.name;
}
functions.logger.log(error);
return error;
} else {
const sizeIndex = sizes.findIndex((obj) => (obj.name == item.size));
const newQty = remaingSizeQty - item.qty;
const newSizes = sizes;
newSizes[sizeIndex].qty = newQty;
newProductsSizes[item.product.id] = newSizes;
}
});
}
for (const productId in Object.keys(newProductsSizes)) {
if (Object.prototype.isPrototypeOf.call(newProductsSizes, productId)) {
db.collection("products").doc(productId).update({
sizes: newProductsSizes[productId],
});
}
}
});
As Doug Stevenson commented, your application is not able to directly run the onCreate function, as this type of function is a background function. As shown in the third point, these functions are called from the backend:
When the event provider generates an event that matches the function's conditions, the code is invoked.
You can check this related post for more reference, which also mentions listening to a document used to hold the status of the operation.
Another alternative would be to use a callable function. These functions allow you to handle errors on the client and are called directly within your app.

Forge viewer isLayerVisible is always false

For some reason I get always false on viewer.isLayerVisible(layerNode).
I followed this tutorial https://forge.autodesk.com/blog/toggle-sheet-layer-visibility
I have event handler on LAYER_VISIBILITY_CHANGED_EVENT, here is my code snippet in typescript:
viewer.addEventListener(Autodesk.Viewing.LAYER_VISIBILITY_CHANGED_EVENT, (e) => {
var root = viewer.model["myData"].layersRoot; //getLayersRoot() is not a function for some reason
var overlayLayer = viewer["getSelectedLayer"]();
if (viewer["layerRoot"] != undefined) {
var layerNode = root.children.filter((e) => { return e.name === overlayLayer })
var isLayerVisible = viewer.isLayerVisible(layerNode);
//show layer
if (isLayerVisible) {
viewer.impl.addOverlay("Edit2D", viewer["savedPoints"].overlayLayer)
}
//hide layer
else {
viewer.impl.removeOverlayScene("Edit2D")
}
}
});
After switching some layers from layer manager off, I also get viewer.areAllVisible() as true.
Forge viewer version is 7.*
Do you have any advice? Thanks!
I found out that you can access visible and visible layers from indexToLayer viewer property
var visibleLayers = Array.from(viewer.impl.layers.indexToLayer.filter(e => e != null && e.visible));

Index messed up if I upload more than one file at once

I've got the following firebase function to run once a file is uploaded to firebase storage.
It basically gets its URL and saves a reference to it in firestore. I need to save them in a way so that I can query them randomly from my client. Indexes seem to be to best fit this requirement.
for the firestore reference I need the following things:
doc ids must go from 0 to n (n beeing the index of the last
document)
have a --stats-- doc keeping track of n (gets
incremented every time a document is uploaded)
To achieve this I've written the following node.js script:
const incrementIndex = admin.firestore.FieldValue.increment(1);
export const image_from_storage_to_firestore = functions.storage
.object()
.onFinalize(async object => {
const bucket = gcs.bucket(object.bucket);
const filePath = object.name;
const splittedPath = filePath!.split("/");
// se siamo nelle immagini
// path = emotions/$emotion/photos/$photographer/file.jpeg
if (splittedPath[0] === "emotions" && splittedPath[2] === "photos") {
const emotion = splittedPath[1];
const photographer = splittedPath[3];
const file = bucket.file(filePath!);
const indexRef = admin.firestore().collection("images")
.doc("emotions").collection(emotion).doc("--stats--");
const index = await indexRef.get().then((doc) => {
if (!doc.exists) {
return 0;
} else {
return doc.data()!.index;
}
});
if (index === 0) {
await admin.firestore().collection("images")
.doc("emotions")
.collection(emotion)
.doc("--stats--")
.set({index: 0});
}
console.log("(GOT INDEX): " + index);
let imageURL;
await file
.getSignedUrl({
action: "read",
expires: "03-09-2491"
})
.then(signedUrls => {
imageURL = signedUrls[0];
});
console.log("(GOT URL): " + imageURL);
var docRef = admin.firestore()
.collection("images")
.doc("emotions")
.collection(emotion)
.doc(String(index));
console.log("uploading...");
await indexRef.update({index: incrementIndex});
await docRef.set({ imageURL: imageURL, photographer: photographer });
console.log("finished");
return true;
}
return false;
});
Getting to the problem:
It works perfectly if I upload the files one by one.
It messes up the index if I upload more than one file at once, because two concurrent uploads will read the same index value from --stats-- and one will overwrite the other.
How would you solve this problem? would you use another approach instead of the indexed one?
You should use a Transaction in which you:
read the value of the index (from "--stats--" document),
write the new index and
write the value of the imageURL in the "emotion" doc.
See also the reference docs about transactions.
This way, if the index value is changed in the "--stats--" document while the Transaction is being executed, the Cloud Function can catch the Transaction failure and generates an error which finishes it.
In parallel, you will need to enable retries for this background Cloud Function, in order it is retried if the Transaction failed in a previous run.
See this documentation item https://firebase.google.com/docs/functions/retries, including the video from Doug Stevenson which is embedded in the doc.

copy data from one node1 child to another node2 child with using firebase cloud functions

Below is my code of cloud functions I am trying to copy the data from users node to challenge node
exports.copyChallengeDate = functions.database.ref(`Users/{pushId}/DateChallengeAccept`).onCreate((snapshot, context)=>{
var DateChallengeAccept = snapshot.val();
console.log('Challenge', context.params.pushId, DateChallengeAccept);
var challenge = DateChallengeAccept;
return admin.database().ref('Challenge/' + context.params.pushId).child('DateChallengeAccept').set(challenge);
});
But the thing is when I am trying to copy the date from user table to challenge node it's only occur in QS5h99YxS0ZGpT42fpUFvzOdpTi1
D uid same as of Users node. I want to copy it in both uid's(QS5h99YxS0ZGpT42fpUFvzOdpTi1, 7aH9Ag8414VzM0n7P6ur4LvcepI2)
D present in challenge node. I was stuck in it from last two days please help me out
Update following you remark that DateChallengeAccept is not initialized when you create the record. You should use another method, like onUpdate() (or onWrite()) and not onCreate(), as you do in your question. Do as follows:
exports.copyChallengeDate = functions.database.ref(`Users/{pushId}`).onUpdate((change, context) =>
const DateChallengeAccept = change.after.val().DateChallengeAccept;
if ( DateChallengeAccept === undefined) {
return false;
}
const referredBy = change.after.val().referredBy;
console.log('Challenge', context.params.pushId, DateChallengeAccept);
const dateChallengeAcceptObj = {
"DateChallengeAccept": DateChallengeAccept
};
let updates = {};
updates['Challenge/' + context.params.pushId + '/DateChallengeAccept'] = dateChallengeAcceptObj;
updates['Challenge/' + referredBy + '/DateChallengeAccept'] = dateChallengeAcceptObj;
return admin.database().ref().update(updates);
});
You need to get the referredId value in your Function, because it is this data item that holds the ID of the other user (i.e. 7aH9Ag8414VzM0n7P6ur4LvcepI2). So you have to trigger the event on the parent node, not at the DateChallengeAccept node.
Then you have to use the update() method to write simultaneously to two nodes, see the doc here: https://firebase.google.com/docs/database/web/read-and-write#update_specific_fields
So you should do as follows:
exports.copyChallengeDate = functions.database.ref(`Users/{pushId}`).onCreate((snapshot, context)=>{
const DateChallengeAccept = snapshot.val().DateChallengeAccept;
if ( DateChallengeAccept === undefined) {
return false;
}
const referredBy = snapshot.val().referredBy;
console.log('Challenge', context.params.pushId, DateChallengeAccept);
const dateChallengeAcceptObj = {
"DateChallengeAccept": DateChallengeAccept
};
let updates = {};
updates['Challenge/' + context.params.pushId + '/DateChallengeAccept'] = dateChallengeAcceptObj;
updates['Challenge/' + referredBy + '/DateChallengeAccept'] = dateChallengeAcceptObj;
return admin.database().ref().update(updates);
});

Resources