I have this code where it gets a random post from r/memes and it get's the post's title with an image attached to it(if there is one), I got this with a lot of help and I just want it to be able to read the post's description. I want to be able to read the text if there is some in the post if I want to use this on like news subreddits or something.
if (msg.content == '-meme') {
function loadMemes() {
// Fetch JSON
return (
fetch('https://www.reddit.com/r/memes.json?limit=800&?sort=hot&t=all')
.then((res) => res.json())
// Return the actual posts
.then((json) => json.data.children)
);
}
function postRandomMeme(message) {
return loadMemes().then((posts) => {
// Get a random post's title and URL
const { title, url } = posts[Math.floor(Math.random() * posts.length)].data;
// Create the embed
const embed = new Discord.RichEmbed({
title,
image: { url },
footer: { text: 'Subreddit : r/memes' },
});
// Send the embed
return message.channel.send(embed);
});
}
// Usage:
postRandomMeme(msg);
// Log all errors
//.catch(console.error);
}
There is a github repository called reddit-bot which is open source and online. you can possibly get an idea from the code provided on there.
https://github.com/lowJ/reddit-bot/blob/master/index.js
I also found this npm package specifically made to get memes and also has an open source github repository.
https://www.npmjs.com/package/#blad3mak3r/reddit-memes
Related
So I'm using discord.js with this code here:
client.api.interactions(interaction.id, interaction.token).callback.post({
data: {
type: 4,
data: {
content: "Getting Data..."
}
}
})
I would like to be able to edit this message afterwards, but everything I have seen requireds a message id, and I seem to be unable to get the message id off of this code.
You can edit an interaction response with this patch request (See: Followup Messages):
PATCH /webhooks/<application_id>/<interaction_token>/messages/#original
Basic example using the axios library:
axios.patch(`https://discord.com/api/v8/webhooks/${appId}/${interaction.token}/messages/#original`, { content: 'New content' });
The answer to this request will also contain the message-id.
Here is an example function that will edit the original message either as plain text or an embed object and returns the discord message object for further usage (e.g. add reply emojis etc.):
const editInteraction = async (client, interaction, response) => {
// Set the data as embed if reponse is an embed object else as content
const data = typeof response === 'object' ? { embeds: [ response ] } : { content: response };
// Get the channel object by channel id:
const channel = await client.channels.resolve(interaction.channel_id);
// Edit the original interaction response:
return axios
.patch(`https://discord.com/api/v8/webhooks/${appId}/${interaction.token}/messages/#original`, data)
.then((answer) => {
// Return the message object:
return channel.messages.fetch(answer.data.id)
})
};
Also instead of sending an initial message like "getting data..." you also can send an empty response of type 5. This is the build-in method and displays a little loading animation too :) See here (One advantage is that this way no "edited" appears.)
client.api.interactions(interaction.id, interaction.token).callback.post({
data: {
type: 5,
},
})
I'm using Google Drive Picker UI to select a folder and create or update spreadsheet into that folder on a schedule
Sometimes it works as expected but recently it is showing a message called "In order to select an item, please sign in". On clicking "sign in" button it shows "The feature you requested is currently unavailable. Please try again later."
Previously, this used to occur when reauthorizing immediately after revoking access but now I'm requesting with extra params like whom the folder is shared with, created date, folder name to display in front-end. It worked fine for some days but now, the issue above mentioned is occurring frequently.
createPicker(oauthToken, authCode, authUser) {
const googleViewId = window.google.picker.ViewId.FOLDERS;
const docsView = new window.google.picker.DocsView(googleViewId)
.setIncludeFolders(true)
.setMimeTypes('application/vnd.google-apps.folder')
.setSelectFolderEnabled(true);
const picker = new window.google.picker.PickerBuilder()
.addView(docsView)
.setOAuthToken(oauthToken)
.setDeveloperKey(this.props.developerKey)
.setCallback(data => {
if (data.action === window.google.picker.Action.PICKED) {
this.fetchFolderDetails(data, authCode, authUser);
}
});
if (this.props.multiSelect) {
picker.enableFeature(window.google.picker.Feature.MULTISELECT_ENABLED);
}
picker.build().setVisible(true);
}
fetchFolderDetails(data, authCode, authUser) {
window.gapi.client
.init({
apiKey: this.props.developerKey
})
.then(() =>
window.gapi.client.request({
path: 'https://www.googleapis.com/drive/v2/files/' + data.docs[0].id,
params: {
fields: 'permissions, title, createdDate, shared'
}
})
)
.then(response => {
let googleDriveData = {
folderId: data.docs[0].id,
mimeType: data.docs[0].mimeType,
authCode,
authUser,
folderName: response.result.title,
permissions: response.result.permissions,
shared: response.result.shared,
createdTime: response.result.createdDate
};
this.props.onChange(googleDriveData);
});
}
I expect to see the list of folders after authorizing.
Update
Adding a google drive scope somewhat fixed the issue but still the immediate reauthorizing issue persists.
I have telegram bot using a telegraf.js library. I have some users that have been registered in bot, and I want to send a confirmation of something consent from one user to another. For realizing it, I need to add in sendMessage some consentId, but I don`t know how!
(this is pseudo-code, here I show my imagination of how that can be work)
bot.action('createContract', ctx => {
// we have some consent object from sequlize with right id
const consent = {
id : uuid4(),
status : 'PENDING',
initiatorId : uuid4(),
consonantId : uuid4()
};
sequelize.model.User.findByPk(consent.consonantId).then(user => {
// here i need add consentId to sendMessage but not show it to user
ctx.telegram.sendMessage(
user.chatId,
'Do you confirm ....',
Extra.HTML().markup((m) =>
m.inlineKeyboard([
m.callbackButton('sign', 'sign'),
m.callbackButton('decline', 'decline')
]))
);
});
});
bot.action('sign', ctx => {
// here we must a get consentId that we add in createContract action
sequelize.model.Consent.findByPk(ctx.consentId).then(consent => {
return consent.update({ status: 'SUCCESS' });
});
});
Problem: I am making an app with Firebase and React Native where users can post, and then other users can comment on posts. To do the comments, I need to grab the key of the content of a post. I tried using the child.getKey() function, but that gave me an error.
child.getKey is not a function. (In 'child.getKey()', 'child.getKey' is undefined)
I would really love some help getting the key. Thank you!
Code
getItems(){
var items = [];
var query = ref.orderByKey();
query.once ('value', (snap) => {
snap.forEach ( (child) => {
items.push({
content: child.val().content,
key: child.getKey()
});
});
items.reverse();
}).then(() => {
this.setState({firebaseItems: items});
});
}
Firebase layout
Posts:
-Kier498dma39md:
content: 'This is an example post. The numbers above me are an example of the random key I am trying to get.'
So, I did some research, and eventually found out all I needed to do was use key: child.key
I am working on my first Firebase project using AngularFire2. Below is the overall design of my learning project.
Users uploads photos and it's stored in the Firebase storage as images.
The uploaded photos are listed in the homepage sorted based on timestamp.
Below is the structure that I have now when I started. But I feel difficulty when doing joins. I should be able to get user details for each uploads and able to sort uploads by timestamp.
User:
- Name
- Email
- Avatar
Uploads:
- ImageURL
- User ID
- Time
I read few blogs de-normalising the data structure. For my given scenario, how best can i re-model my database structure?
Any example for creating some sample data in the new proposed solution will be great for my understanding.
Once the image upload is done, I am calling the below code to create an entry in the database.
addUpload(image: any): firebase.Promise<any> {
return firebase.database().ref('/userUploads').push({
user: firebase.auth().currentUser.uid,
image: image,
time: new Date().getTime()
});
}
I am trying to join 2 entities as below. i am not sure how can I do it efficiently and correctly.
getUploads(): any {
const rootDef = this.db.database.ref();
const uploads = rootDef.child('userUploads').orderByChild('time');
uploads.on('child_added',snap => {
let userRef =rootDef.child('userProfile/' + snap.child('user').val());
userRef.once('value').then(userSnap => {
???? HOW TO HANDLE HERE
});
});
return ?????;
}
I would like to get a final list having all upload details and its corresponding user data for each upload.
This type of join will always be tricky if you write it from scratch. But I'll try to walk you through it. I'm using this JSON for my answer:
{
uploads: {
Upload1: {
uid: "uid1",
url: "https://firebase.com"
},
Upload2: {
uid: "uid2",
url: "https://google.com"
}
},
users: {
uid1: {
name: "Purus"
},
uid2: {
name: "Frank"
}
}
}
We're taking a three-stepped approach here:
Load the data from uploads
Load the users for that data from users
Join the user data to the upload data
1. Load the data uploads
Your code is trying to return a value. Since the data is loaded from Firebase asynchronously, it won't be available yet when your return statement executes. That gives you two options:
Pass in a callback to getUploads() that you then call when the data has loaded.
Return a promise from getUploads() that resolves when the data has loaded.
I'm going to use promises here, since the code is already difficult enough.
function getUploads() {
return ref.child("uploads").once("value").then((snap) => {
return snap.val();
});
}
This should be fairly readable: we load all uploads and, once they are loaded, we return the value.
getUploads().then((uploads) => console.log(uploads));
Will print:
{
Upload1 {
uid: "uid1",
url: "https://firebase.com"
},
Upload2 {
uid: "uid2",
url: "https://google.com"
}
}
2. Load the users for that data from users
Now in the next step, we're going to be loading the user for each upload. For this step we're not returning the uploads anymore, just the user node for each upload:
function getUploads() {
return ref.child("uploads").once("value").then((snap) => {
var promises = [];
snap.forEach((uploadSnap) => {
promises.push(
ref.child("users").child(uploadSnap.val().uid).once("value")
);
});
return Promise.all(promises).then((userSnaps) => {
return userSnaps.map((userSnap) => userSnap.val());
});
});
}
You can see that we loop over the uploads and create a promise for loading the user for that upload. Then we return Promise.all(), which ensures its then() only gets called once all users are loaded.
Now calling
getUploads().then((uploads) => console.log(uploads));
Prints:
[{
name: "Purus"
}, {
name: "Frank"
}]
So we get an array of users, one for each upload. Note that if the same user had posted multiple uploads, you'd get that user multiple times in this array. In a real production app you'd want to de-duplicate the users. But this answer is already getting long enough, so I'm leaving that as an exercise for the reader...
3. Join the user data to the upload data
The final step is to take the data from the two previous steps and joining it together.
function getUploads() {
return ref.child("uploads").once("value").then((snap) => {
var promises = [];
snap.forEach((uploadSnap) => {
promises.push(
ref.child("users").child(uploadSnap.val().uid).once("value")
);
});
return Promise.all(promises).then((userSnaps) => {
var uploads = [];
var i=0;
snap.forEach((uploadSnap) => {
var upload = uploadSnap.val();
upload.username = userSnaps[i++].val().name;
uploads.push(upload);
});
return uploads;
});
});
}
You'll see we added a then() to the Promise.all() call, which gets invoked after all users have loaded. At that point we have both the users and their uploads, so we can join them together. And since we loaded the users in the same order as the uploads, we can just join them by their index (i). Once you de-duplicate the users this will be a bit trickier.
Now if you call the code with:
getUploads().then((uploads) => console.log(uploads));
It prints:
[{
uid: "uid1",
url: "https://firebase.com",
username: "Purus"
}, {
uid: "uid2",
url: "https://google.com",
username: "Frank"
}]
The array of uploads with the name of the user who created that upload.
The working code for each step is in https://jsbin.com/noyemof/edit?js,console
I did the following based on Franks answer and it works. I am not sure if this is the best way for dealing with large number of data.
getUploads() {
return new Promise((resolve, reject) => {
const rootDef = this.db.database.ref();
const uploadsRef = rootDef.child('userUploads').orderByChild('time');
const userRef = rootDef.child("userProfile");
var uploads = [];
uploadsRef.once("value").then((uploadSnaps) => {
uploadSnaps.forEach((uploadSnap) => {
var upload = uploadSnap.val();
userRef.child(uploadSnap.val().user).once("value").then((userSnap) => {
upload.displayName = userSnap.val().displayName;
upload.avatar = userSnap.val().avatar;
uploads.push(upload);
});
});
});
resolve(uploads);
});
}