Skip to content

Instantly share code, notes, and snippets.

@Doliman100
Last active August 19, 2021 11:22
Show Gist options
  • Select an option

  • Save Doliman100/0b7868cdc870f7ad70b9f871488049f6 to your computer and use it in GitHub Desktop.

Select an option

Save Doliman100/0b7868cdc870f7ad70b9f871488049f6 to your computer and use it in GitHub Desktop.
Adds a volume control option to the duolingo.com settings page.
// ==UserScript==
// @version 1.3
// @name Duolingo Volume Control
// @namespace https://gist.github.com/Doliman100
// ==/UserScript==
// ==UserScript==
// @name Duolingo Volume Control
// @namespace https://gist.github.com/Doliman100
// @version 1.3
// @description Adds a volume control option to the settings page.
// @author Doliman100
// @icon https://d35aaqx5ub95lt.cloudfront.net/favicon.ico
// @updateURL https://gist.githubusercontent.com/raw/0b7868cdc870f7ad70b9f871488049f6/script.meta.js
// @downloadURL https://gist.githubusercontent.com/raw/0b7868cdc870f7ad70b9f871488049f6/script.user.js
// @match https://www.duolingo.com/*
// @grant none
// ==/UserScript==
"use strict";
let first = true;
let layer = true;
let style = true;
let volume = localStorage.getItem("volume") || 1;
Howler.volume(volume);
window.addEventListener("storage", function(e)
{
if (e.key === "volume")
{
volume = e.newValue;
Howler.volume(volume);
}
});
function inject()
{
if (first)
{
this.disconnect();
this.observe(document.querySelector("._1Xlh1"), { childList: true });
first = false;
}
if (location.pathname.substring(0, 9) !== "/settings")
{
layer = true;
}
else
{
if (layer)
{
this.observe(document.querySelector("._2PVaI"), { childList: true });
layer = false;
}
if (location.pathname === "/settings/account")
{
if (style)
{
document.head.insertAdjacentHTML("beforeend",
`<style>
#volume {
display: flex;
height: 24px;
margin-top: 10px;
}
#volume input {
-webkit-appearance: none;
border-radius: 8px;
background-color: #e5e5e5;
width: 196px;
height: 16px;
margin-top: 4px;
overflow: hidden;
}
#volume input::-webkit-slider-thumb {
-webkit-appearance: none;
box-shadow: -95px 0 0 87px #1cb0f6;
box-sizing: content-box;
border-radius: 50%;
border: 2px solid #1cb0f6;
background-color: #fff;
width: 12px;
height: 12px;
}
#volume input::-moz-range-thumb {
box-shadow: -95px 0 0 87px #1cb0f6;
box-sizing: content-box;
border-radius: 50%;
border: 2px solid #1cb0f6;
background-color: #fff;
width: 12px;
height: 12px;
}
#volume div {
margin: 2px 0 0 12px;
}
</style>`
);
style = false;
}
const volume_pct = (volume * 100).toFixed();
document.querySelector('[name="enableSpeaker"]').closest("tr").insertAdjacentHTML("afterend",
`<tr>
<td class="_1CsoA _2cAA0">Volume</td>
<td class="_1n58L _2cAA0 _2k8ad">
<div id="volume">
<input type="range" min="0" max="100" value="${volume_pct}" />
<div>${volume_pct}</div>
</div>
</td>
</tr>`
);
const volume_input = document.querySelector("#volume input");
const volume_output = document.querySelector("#volume div");
volume_input.oninput = function()
{
volume_output.textContent = this.value;
}
volume_input.onchange = function()
{
volume = this.value / 100;
localStorage.setItem("volume", volume);
Howler.volume(volume);
}
}
}
}
new MutationObserver(inject).observe(document.getElementById("root"), { childList: true });
@Nudin
Copy link

Nudin commented Mar 11, 2021

Is this still alive? Because it seems not to work for me…
It fails with ReferenceError: Howler is not defined eventhough I can access Howler from the console.

@Doliman100
Copy link
Author

It's strange. It looks like the script runs before the Howler object is initialized. What browser and script manager are you using? I have now tested it in Chrome with Tampermonkey and it works fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment