Last active
January 22, 2022 21:22
-
-
Save atnbueno/f8bc6376bcdb1d8dace2c490f9ac0770 to your computer and use it in GitHub Desktop.
Greasemonkey: import/export Wordle's game state to migrate playing it from one device to another
This file contains hidden or 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 Wordle import/export | |
// @version 1.3 | |
// @author Antonio Bueno | |
// @namespace userscripts.atnbueno.com | |
// @match https://www.powerlanguage.co.uk/wordle/ | |
// @match https://wordle.danielfrg.com/ | |
// @require https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js | |
// @require https://cdn.jsdelivr.net/npm/toastify-js | |
// @resource toastifyCSS https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css | |
// @grant GM.getResourceUrl | |
// @grant GM.setClipboard | |
// ==/UserScript== | |
(function () { | |
"use strict"; | |
// DOM manipulations courtesy of jQuery | |
const strings = JSON.parse(`{ | |
"en": { | |
"label": "Import/export", | |
"prompt": "Paste to import, leave empty to export", | |
"importOK": "Updated data", | |
"importKO": "Data could not be updated", | |
"exportOK": "Game state copied to the clipboard", | |
"exportKO": "Game state could not be copied" | |
}, | |
"es": { | |
"label": "Importar/exportar", | |
"prompt": "Pega para importar, deja en blanco para exportar", | |
"importOK": "Datos actualizados", | |
"importKO": "Los datos no se han podido actualizar", | |
"exportOK": "Estado del juego copiado al portapapeles", | |
"exportKO": "El estado del juego no se ha podido copiar" | |
}}`); | |
const lang = location.href.includes("danielfrg") ? "es" : "en"; | |
// Modificacions are applied once the DOM has been build (images may be still loading) | |
$(document).ready(function () { | |
$("body").append('<button id="import-export">' + strings[lang].label); | |
$("#import-export").on("click", function () { | |
let pasted = prompt(strings[lang].prompt); | |
if (pasted != "") { | |
try { | |
let data = JSON.parse(atob(pasted)); | |
Object.keys(data).forEach(key => { window.localStorage.setItem(key, data[key]) }); | |
notification(strings[lang].importOK + ":\n" + Object.keys(data).join(", ")); | |
} catch (error) { | |
notification(strings[lang].importKO + ":\n" + error.message, "error"); | |
} | |
} else { | |
let data = {}; | |
try { | |
Object.keys(window.localStorage).forEach(key => { data[key] = localStorage.getItem(key); }); | |
GM.setClipboard(btoa(JSON.stringify(data))); | |
notification(strings[lang].exportOK + ":\n" + Object.keys(data).join(", ")); | |
} catch (error) { | |
notification(strings[lang].exportKO + ":\n" + error.message, "error"); | |
} | |
} | |
}); | |
}); | |
// External CSS files | |
(async function () { | |
// Toastify CSS | |
var externalFileURL = await GM.getResourceUrl("toastifyCSS"); | |
stylesheet = document.createElement("link"); | |
stylesheet.setAttribute("rel", "stylesheet"); | |
stylesheet.setAttribute("href", externalFileURL); | |
document.documentElement.appendChild(stylesheet); | |
})(); | |
// Inline CSS | |
var stylesheet = document.createElement("style"); | |
stylesheet.textContent = ` | |
div.toastify { margin: inherit; padding-bottom: 20px; } | |
div.toastify, #import-export { font-family: -apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif; } | |
#import-export { background-color: #E8E8F0; border-radius: 4px; border: 1px solid #888890; color: black; padding: 2px 6px; font-size: 13px; z-index: 50; position: fixed; bottom: 8px; right: 8px; } | |
#import-export:hover { background-color: #C8C8D0; border: 1px solid #686870; } | |
`; | |
document.documentElement.appendChild(stylesheet); | |
// Notifications courtesy of Toastify JS (see https://apvarun.github.io/toastify-js/) | |
function notification(message, type = "info", timeout = 5) { | |
// The "type" parameter accepts four values: "info", "warning", "error" and "hello" | |
// The "timeout" parameter is expressed in seconds although Toastify uses milliseconds | |
var color, icon; | |
switch (type) { | |
case "warning": | |
color = "rgba(201, 201, 0, 0.8)"; | |
icon = "โ "; | |
break; | |
case "error": | |
color = "rgba(201, 51, 51, 0.8)"; | |
icon = "๐"; | |
break; | |
case "hello": | |
color = "rgba(51, 153, 51, 0.8)"; | |
icon = "๐๐ผ"; | |
break; | |
default: | |
color = "rgba(51, 51, 153, 0.8)"; | |
icon = "โน"; | |
} | |
Toastify({ | |
text: icon + " " + message, | |
duration: timeout * 1000, | |
gravity: "bottom", | |
style: { | |
background: color, | |
} | |
}).showToast(); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment