Skip to content

Instantly share code, notes, and snippets.

@lukaszmn
Last active January 10, 2020 22:51
Show Gist options
  • Save lukaszmn/41f267a69f5125fe0984038306553702 to your computer and use it in GitHub Desktop.
Save lukaszmn/41f267a69f5125fe0984038306553702 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Highbrow Labeler
// @namespace Violentmonkey Scripts
// @match https://gohighbrow.com/courses/
// @grant none
// @version 1.0
// @author Łukasz Nojek
// @description https://lukasznojek.com/blog/2020/01/course-movie-labeling-solution-using-firebase-and-violentmonkey/
// @require https://www.gstatic.com/firebasejs/7.6.1/firebase-app.js
// @require https://www.gstatic.com/firebasejs/7.6.1/firebase-auth.js
// @require https://www.gstatic.com/firebasejs/7.6.1/firebase-firestore.js
// ==/UserScript==
function database() {
let db;
const COLLECTION = 'links';
function init() {
const firebaseConfig = {
apiKey: "...........",
authDomain: "...........",
databaseURL: "...........",
projectId: "...........",
storageBucket: "...........",
messagingSenderId: "...........",
appId: "..........."
};
firebase.initializeApp(firebaseConfig);
db = firebase.firestore();
// Authenticate
const credentials = {
email: '...........',
password: '...........'
}
firebase.auth().signInWithEmailAndPassword(credentials.email, credentials.password);
}
function urlEncode(url) {
return url.replace('.', '<DOT>').replace('#', '<HASH>').replace('$', '<DOLLAR>').replace('/', '<SLASH>');
}
function urlDecode(url) {
return url.replace('<DOT>', '.').replace('<HASH>', '#').replace('<DOLLAR>', '$').replace('<SLASH>', '/');
}
function getKey(url) {
// get last non-empty URL's part between slahes
const pathPart = url.split('/').reverse().filter(x => x)[0];
return urlEncode(pathPart.toLowerCase());
}
function save(url, resolution) {
const key = getKey(url);
const data = { fullUrl: url, resolution };
db.collection(COLLECTION).doc(key).set(data);
return data;
}
function get(url, cb) {
const key = getKey(url);
db.collection(COLLECTION).doc(key).get().then(doc => {
doc.exists ? cb(doc.data()) : cb(null);
});
}
function getAll(cb) {
db.collection(COLLECTION).get()
.then(row => {
const res = row.docs.map(r => Object.assign({ key: urlDecode(r.id)}, r.data() ));
cb(res);
});
}
init();
return { save, get, getAll };
}
const db = database();
// db.save(window.location, 'TODO');
function ui(db) {
const CLICKABLE_SELECTOR = 'li.item p';
const GET_URL_FROM_CLICKABLE = p => {
const li = p.parentElement.parentElement;
return li.querySelector('a').href;
}
const GET_LABEL_PARENT_FROM_URL = link => {
const el = document.querySelector(`.box a[href="${link}"]`);
if (el) return el.parentElement;
}
const LABEL_CLASS = 'labeller';
const EXTRA_LABEL_STYLES = '';
function showLabel(row) {
let color, text;
switch (row.resolution) {
case 'TODO': color = 'orange'; text = 'TODO'; break;
case 'DONE': color = 'green'; text = 'DONE'; break;
case 'NOT': color = 'red'; text = 'NOT'; break;
}
colorize(row.fullUrl, color, text);
}
function showLabels() {
db.getAll(rows => rows.forEach(row => showLabel(row)));
}
function rotateLabel(ev) {
const url = GET_URL_FROM_CLICKABLE(ev.target);
db.get(url, row => {
let status;
switch ((row || {}).resolution || '') {
case '': status = 'DONE'; break;
case 'DONE': status = 'TODO'; break;
case 'TODO': status = 'NOT'; break;
case 'NOT': status = ''; break;
}
const data = db.save(url, status);
showLabel(data);
})
}
function handleClick() {
const style = document.createElement('style');
style.innerHTML = `${CLICKABLE_SELECTOR} { cursor: cell; }`;
document.head.appendChild(style);
for (const p of document.querySelectorAll(CLICKABLE_SELECTOR))
p.addEventListener('click', rotateLabel);
}
function colorize(link, color, text) {
const parent = GET_LABEL_PARENT_FROM_URL(link);
if (!parent) {
console.log(`Not found ${color}: ${link}`);
return;
}
console.log(`Found ${color}: ${link}`);
let mark = parent.querySelector(`div.${LABEL_CLASS}`);
if (mark)
mark.remove();
if (text) {
mark = document.createElement('div');
parent.appendChild(mark);
mark.outerHTML = `<div class="${LABEL_CLASS}" style="background: ${color}; color: white; padding: 5px 20px; text-align: center; ${EXTRA_LABEL_STYLES}">${text}</div>`;
}
}
showLabels();
handleClick();
}
ui(db);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment