Firebase database and app localization - localization

I am building a quiz game for both iOS & Android platforms and I want to be able to handle localization.
I am using Firebase's realtime database solution in order to pull all of the question the game is going to have.
I am hardcoding the questions into the Firebase's database and every question object has 2 parameters:
ID - Obviously
Text - The question text itself e.g. "Who was John Kennedy?"
I am having hard time thinking about how to localize the questions I am pulling from Firebase. Obviously if the app is localized as Spanish I want to get the questions text translated to Spanish.
How do I go about it?
Thank you very very much :)

Database like this...
{
"en": { "Q1": "Who was JFK?" },
"es": { "Q1": "¿Quién era JFK?" }
}
Accessed like this (JavaScript)...
var locale = fooLocale() || 'en'; // get locale, fallback to English
var firedb = firebase.database(); // init database
var content = firedb.ref(locale); // get reference to locale data
content.child('Q1').on('value', function (snapshot) { // request Q1
document.getElementById('Q1').innerHTML = snapshot.val(); // set UI text
});

Related

YouTube API - retrieve more than 5k items

I just want to fetch all my liked videos ~25k items. as far as my research goes this is not possible via the YouTube v3 API.
I have already found multiple issues (issue, issue) on the same problem, though some claim to have fixed it, but it only works for them as they don't have < 5000 items in their liked video list.
playlistItems list API endpoint with playlist id set to "liked videos" (LL) has a limit of 5000.
videos list API endpoint has a limit of 1000.
Unfortunately those endpoints don't provide me with parameters that I could use to paginate the requests myself (e.g. give me all the liked videos between date x and y), so I'm forced to take the provided order (which I can't get past 5k entries).
Is there any possibility I can fetch all my likes via the API?
more thoughts to the reply from #Yarin_007
if there are deleted videos in the timeline they appear as "Liked https://...url" , the script doesnt like that format and fails as the underlying elements dont have the same structure as existing videos
can be easily fixed with a try catch
function collector(all_cards) {
var liked_videos = {};
all_cards.forEach(card => {
try {
// ignore Dislikes
if (card.innerText.split("\n")[1].startsWith("Liked")) {
....
}
}
catch {
console.log("error, prolly deleted video")
}
})
return liked_videos;
}
to scroll down to the bottom of the page ive used this simple script, no need to spin up something big
var millisecondsToWait = 1000;
setInterval(function() {
window.scrollTo(0, document.body.scrollHeight);
console.log("scrolling")
}, millisecondsToWait);
when more ppl want to retrive this kind of data, one could think about building a proper script that is more convenient to use. If you check the network requests you can find the desired data in the response of requests called batchexecute. One could copy the authentification of one of them provide them to a script that queries those endpoints and prepares the data like the other script i currently manually inject.
Hmm. perhaps Google Takeout?
I have verified the youtube data contains a csv called "liked videos.csv". The header is Video Id,Time Added, and the rows are
dQw4w9WgXcQ,2022-12-18 23:42:19 UTC
prvXCuEA1lw,2022-12-24 13:22:13 UTC
for example.
So you would need to retrieve video metadata per video ID. Not too bad though.
Note: the export could take a while, especially with 25k videos. (select only YouTube data)
I also had an idea that involves scraping the actual liked videos page (which would save you 25k HTTP Requests). But I'm unsure if it breaks with more than 5000 songs. (also, emulating the POST requests on that page may prove quite difficult, albeit not impossible. (they fetch /browse?key=..., and have some kind of obfuscated / encrypted base64 strings in the request-body, among other parameters)
EDIT:
Look. There's probably a normal way to get a complete dump of all you google data. (i mean, other than takeout. Email them? idk.)
anyway, the following is the other idea...
Follow this deep link to your liked videos history.
Scroll to the bottom... maybe with selenium, maybe with autoit, maybe put something on the "end" key of your keyboard until you reach your first liked video.
Hit f12 and run this in the developer console
// https://www.youtube.com/watch?v=eZPXmCIQW5M
// https://myactivity.google.com/page?utm_source=my-activity&hl=en&page=youtube_likes
// go over all "cards" in the activity webpage. (after scrolling down to the absolute bottom of it)
// create a dictionary - the key is the Video ID, the value is a list of the video's properties
function collector(all_cards) {
var liked_videos = {};
all_cards.forEach(card => {
// ignore Dislikes
if (card.innerText.split("\n")[1].startsWith("Liked")) {
// horrible parsing. your mileage may vary. I Tried to avoid using any gibberish class names.
let a_links = card.querySelectorAll("a")
let details = a_links[0];
let url = details.href.split("?v=")[1]
let video_length = a_links[3].innerText;
let time = a_links[2].parentElement.innerText.split(" • ")[0];
let title = details.innerText;
let date = card.closest("[data-date]").getAttribute("data-date")
liked_videos[url] = [title,video_length, date, time];
// console.log(title, video_length, date, time, url);
}
})
return liked_videos;
}
// https://stackoverflow.com/questions/57709550/how-to-download-text-from-javascript-variable-on-all-browsers
function download(filename, text, type = "text/plain") {
// Create an invisible A element
const a = document.createElement("a");
a.style.display = "none";
document.body.appendChild(a);
// Set the HREF to a Blob representation of the data to be downloaded
a.href = window.URL.createObjectURL(
new Blob([text], { type })
);
// Use download attribute to set set desired file name
a.setAttribute("download", filename);
// Trigger the download by simulating click
a.click();
// Cleanup
window.URL.revokeObjectURL(a.href);
document.body.removeChild(a);
}
function main() {
// gather relevant elements
var all_cards = document.querySelectorAll("div[aria-label='Card showing an activity from YouTube']")
var liked_videos = collector(all_cards)
// download json
download("liked_videos.json", JSON.stringify(liked_videos))
}
main()
Basically it gathers all the liked videos' details and creates a key: video_ID - Value: [title,video_length, date, time] object for each liked video.
It then automatically downloads the json as a file.

data not being saved in firebase database

I am just starting out with Firebase and have managed to send data to a Firebase Realtime Database. The problem is that some times it works and sometimes not. I am struggling to understand why.
Here is a code snippet
var pq_data = jsPsych.data.get().values();
for (var ix= 0; ix < pq_data.length; ix++){
var object=pq_data[ix];
var pq_boo = pq_database.ref(subj_id +ix.toString()+'/').update(object)
}
As I say this works sometimes but not always and I understand that it may have something to do with the code completing before the write operations have(?)
I have read but do not clearly understand advice about onCompletion and I am still in the dark. I need to make sure each object is written to the database - is this possible and if so how?
Very much a beginner,
Philip.
// Import Admin SDK
var admin = require("firebase-admin");
// Get a database reference to our blog
var db = admin.database();
var ref = db.ref("server/saving-data/fireblog");
First, create a database reference to your user data. Then use set() / setValue() to save a user object to the database with the user's username, full name, and birthday. You can pass set a string, number, boolean, null, array or any JSON object. Passing null will remove the data at the specified location. In this case you'll pass it an object:
var usersRef = ref.child("users");
usersRef.set({
alanisawesome: {
date_of_birth: "June 23, 1912",
full_name: "Alan Turing"
},
gracehop: {
date_of_birth: "December 9, 1906",
full_name: "Grace Hopper"
}
});
Thanks for this Yes For brevity I didn't show all the code and so I have access to the database. The problem is with sending data to it. Sometimes it works and sometimes not.
I now realise this is related to my failure to deal with Promises. I have now some understanding of these but still need to make sure that the data gets captured in the database. SO even though the Promise may return an Error I still need to re-send the data so that it will get written to the database. Still not sure whether this is advisable or even possible.

Swift Firebase database overwriting

I am making a real-time messenger using Firebase. Currently, whenever I press a button I want a new message to be appended to the channel with the index of the message, but currently, whenever I press the button a new message is created that overwrites the old message. I know that setValue is usually the issue, but I really cannot tell what I'm doing wrong. What the database looks like before I add my new message. This is what it looks like after I add a new message here, and then the code I am using to add to the database.
#IBAction func sendMessageTapped(_ sender: Any) {
if messageTextField.text == "" {
print("blank")
return
} else {
// First we will update the amount of messages that the channel has.
ref.child("channels").child(channelName!).setValue(["numberOfMessages" : numberOfMessages+1 ])
numberOfMessages += 1
// after we have updated the amount of messages we will try to create a new message.
ref.child("channels").child(channelName!).child("messages").child(String(numberOfMessages)).child("message").child("content").setValue(messageTextField.text)
ref.child("channels").child(channelName!).child("messages").child(String(numberOfMessages)).child("message").child("name").setValue("Buddy")
}
}
ok, Firebase is not a traditional table based database, is a DOCUMENT based database. At the very top you have a thing called a "collection" which is just a list of "document" things. In your case, you'd have several collection things to serve as channels: "General", "TopicQ", "InterstingStuff" etc, and within them each message as a document. No need to have a document, to then list the messages within it.
Second, you don't need indexes as you're using them, make the message id an attribute of the message, because firebase support querying by field, and even then is questionable because if you make each message a document, they will have their own auto generated id's if you want.
Third, in your code you're rewriting the whole document each time, this is why you lose your previous messages, so if you keep it, you need to add a merge option:
// Update one field, creating the document if it does not exist.
db.collection("cities").document("BJ").setData([ "capital": true ], merge: true)
you probably want to do something like this. This is what I did for my app, hope this helps someone. This rootRef.childByAutoId() generates a new entry with unique id. You can use this as reference for your case.
let rootRef = Database.database().reference(withPath: "channels")
let childRef = rootRef.childByAutoId()
let values = ["Type": self.textField.text!, "message": self.textView.text!] as? [String : Any]
childRef.updateChildValues(values)

iPad Offline Web App with Multiple Entries

I've found a ton of information on LocalStorage with HTML5 but they all focus on persistent single entries being saved.
I need to be able to have a contact form (simple name/email/phone) that gets saved to the iPad and then allows another person to submit an entry to save to the iPad locally (no Wifi/Internet available).
Then I want to be able to go in later and grab all the entries that were made in whatever format available.
Any direction & help would be appreciated.
I searched on Stackoverflow & Google but still couldn't find multiple entry tutorials or examples.
Thanks!
localStorage is a good fit for what you're after. As localStorage only supports strings, you will need to do some conversions to/from JSON to serialize the entries.
Here is some general code to hopefully get you started:
// read out any previous contact forms (initialise if it is empty)
var jsonEntries = localStorage["contactFormEntries"];
var contactFormEntries = JSON.parse(jsonEntries ? jsonEntries : '[]');
// ...
// sometime later... create a contact form record
var contactForm = {
'name': 'Timmy',
'email': 'timmy#example.com'
};
// add it to the entries array
contactFormEntries.push(contactForm);
// serialize all the contact form entries into local storage
localStorage["contactFormEntries"] = JSON.stringify(contactFormEntries);
// ...
// then, when you want to send the entries, read them all out again
var contactFormEntries = JSON.parse(localStorage["contactFormEntries"]);

Tab Groups - Any API

Is there any way to use the high-level APIs to detect whether a tab is in the active Panorama group? It seems there's no mention of the tab group a tab belongs to in the tabs module, at least.
Currently there are no plans to provide a tab group api - the 'panorama' feature in Firefox has not proved to be very popular, so there may not be much benefit vs focusing on other features.
Actually there is a way.
I don't know how to get the XUL tab with the SDK, but I know it's possible as I recall people posting questions that did this. Maybe #canuckistani you can help us get the xul tab.
Anyways once you have the tab then you can access it's property _tabViewTabItem. And from here you can do whatever you want. Like figure out the group id of the tab by going tab._tabViewTabItem.parent.id Or change group id's.
Here is some code, the first two lines are non-sdk code.
var tab = gBrowser.tabContainer.childNodes[10]; //non sdk code
gBrowser.selectedTab = tab; //non sdk code
console.log(tab._tabViewTabItem.parent.id) //works both in sdk and non-sdk
Note: pinned tabs dont have the _tabViewTabItem property. So thats how you can tell if its pinned.
var tabs = gBrowser.tabContainer.childNodes;
for (var i=0; i<tabs.length; i++) {
try {
console.log(tabs[i]._tabViewTabItem.parent.id);
} catch(ex) {
console.warn('tab ' + i + ' ex:', ex);
console.log('its probably pinned')
}
}
The Tab Groups extension stores it's data using SessionStore.
var tabData = JSON.parse(SessionStore.getTabValue(tab,"tabview-tab"));
console.log(tabData.groupID); // 3
Data about the groups themselves is stored on the browser.xul object (ie. ownerGlobal). Data specific to each group is stored as "tabview-group" and other data is stored as "tabview-groups".
var groupsData = JSON.parse(SessionStore.getWindowValue(tab.ownerGlobal, 'tabview-groups'));
console.log(groupsData); // Object { nextID: 4,
activeGroupId: 3,
activeGroupName: "Third Group",
totalNumber: 2 }
var groupData = JSON.parse(SessionStore.getWindowValue(tab.ownerGlobal, 'tabview-group'));
console.log(tabData[3].title); // Third Group

Resources