Last active
January 10, 2020 22:51
-
-
Save lukaszmn/41f267a69f5125fe0984038306553702 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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