Before & After
Reader
Video Player (default size / location)
Features
Theme settings
- Change the default size/location of video player.
- Make prev/next page buttons compact
- Custom font settings (clolor, paddings, space between lines, …)
- Custom highlightings (color, border, paddings) on words (lingqed, leared, new)
Addons
- Modified embedded player settings (caption on, auto play, disable controls)
- Add a video full screen toggle shortcut (x key)
- Change course sorting: Automatically changes the sorting option in a course page from ‘All lessons’ to other Option. You can change what would be defaulted by changing the number in
.dropdown-item:nth-child(3)
.
How to use?
It is a userscript can be used in Tampermonkey or other apps.
Install the extension and copy & paste my code.
Homepage:
Random tutorial I found on google:
Code
// ==UserScript==
// @name LingQ Addon
// @description Custom embedded player, and sort course automatically.
// @match https://www.lingq.com/*/learn/*/web/reader/*
// @match https://www.lingq.com/*/learn/*/web/library
// @version 1.3
// ==/UserScript==
(function () {
"use strict";
// Style settings
var style = document.createElement("style");
style.textContent = `
:root {
--width_small: 540px;
--height_small: 370px;
--height_big: 650px;
--width_big: 1100px;
--right_pos: 0.5%;
--bottom_pos: 5.5%;
--font_size: 1.1rem;
--font_color: #e0e0e0;
--line_height: 1.7;
--lingq_background: hsl(41 43% 30% / 0.7);
--lingq_border: hsl(43 99% 64% / 0.3);
--lingq_border_learned: hsl(43 99% 64% / 0.5);
--blue_border: hsl(213 99% 64% / 0.5);
}
.video-player .video-wrapper,
.sent-video-player .video-wrapper {
height: var(--height_big);
overflow: hidden;
}
.modal.video-player .modal-content {
max-width: var(--width_big);
margin-bottom: 0;
}
.video-player.is-minimized .video-wrapper,
.sent-video-player.is-minimized .video-wrapper {
height: var(--height_small);
width: var(--width_small);
}
.video-player.is-minimized .modal-content,
.sent-video-player.is-minimized .modal-content {
max-width: var(--width_small);
margin-bottom: 0;
}
.video-player.is-minimized,
.sent-video-player.is-minimized {
left: auto;
top: auto;
right: var(--right_pos);
bottom: var(--bottom_pos);
z-index: 99999999;
overflow: visible
}
// make prev/next page buttons compact
main {}
.reader-component {
grid-template-columns: 1.5rem 1fr 1.5rem !important;
}
.reader-component>div>a.button>span {
width: 1.5rem !important;
}
// font settings
article {}
.reader-container {
margin: 0 !important;
float: left !important;
line-height: var(--line_height) !important;
padding: 0 !important;
font-size: var(--font_size) !important;
}
.reader-container p {
margin-top: 0 !important;
}
.reader-container p span.sentence-item {
color: var(--font_color) !important;
}
.sentence.is-playing,
.sentence.is-playing span {
text-underline-offset: .2em !important;
}
// LingQ highlightings
.phrase-cluster {}
.phrase-item {
padding: 0 !important;
}
.phrase-item:not(.phrase-item-status--4, .phrase-item-status--4x2) {
background-color: var(--lingq_background) !important;
}
.phrase-item.phrase-item-status--4,
.phrase-item.phrase-item-status--4x2 {
background-color: rgba(0, 0, 0, 0) !important;
}
.phrase-cluster:not(:has(.phrase-item-status--4, .phrase-item-status--4x2)) {
border: 1px solid var(--lingq_border) !important;
border-radius: .25rem;
}
.phrase-cluster:has(.phrase-item-status--4, .phrase-item-status--4x2) {
border: 1px solid var(--lingq_border_learned) !important;
border-radius: .25rem;
}
.reader-container .sentence .lingq-word:not(.is-learned) {
border: 1px solid var(--lingq_border) !important;
background-color: var(--lingq_background) !important;
}
.reader-container .sentence .lingq-word.is-learned {
border: 1px solid var(--lingq_border_learned) !important;
}
.reader-container .sentence .blue-word {
border: 1px solid var(--blue_border) !important;
}
.phrase-cluster:hover,
.phrase-created:hover {
padding: 0 !important;
}
.phrase-cluster:hover .phrase-item,
.phrase-created .phrase-item {
padding: 0 !important;
}
.reader-container .sentence .selected-text {
padding: 0 !important;
}
`;
document.querySelector("head").appendChild(style);
// Add new shortcuts
document.addEventListener('keydown', function(event) {
const targetElement = event.target;
const isTextInput = (targetElement.type === 'text' || targetElement.type === 'textarea');
if (isTextInput) {
return;
}
// video full screen toggle (x key)
if (event.key === 'x' || event.key === 'X') {
const full_screen_btn = document.querySelector('.modal-section > div > button:nth-child(2)');
if (full_screen_btn) {
full_screen_btn.click();
}
}
});
// Custom embedded player
function replaceNoCookie() {
document.querySelectorAll('iframe').forEach(function(iframe) {
let src = iframe.getAttribute('src');
if (src && src.includes('autoplay=0')) {
src = src.replace('autoplay=0', 'autoplay=1'); // video will automatically start to play.
src = src.replace('disablekb=1', 'disablekb=0'); // keyboard controls are enabled.
src = src + '&cc_load_policy=1' // caption is shown by default.
src = src + '&controls=0' // player controls do not display in the player.
iframe.setAttribute('src', src);
console.log(src);
}
});
}
const iframeObserver = new MutationObserver(function(mutationsList, observer) {
for (const mutation of mutationsList) {
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach(node => {
if (node.nodeName === 'IFRAME') {
replaceNoCookie();
} else if (node.querySelectorAll) {
node.querySelectorAll('iframe').forEach(replaceNoCookie);
}
});
} else if (mutation.type === 'attributes' && mutation.attributeName === 'src' && mutation.target.nodeName === 'IFRAME') {
replaceNoCookie();
}
}
});
if (document.URL.includes("/reader/")) {
iframeObserver.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['src'] });
}
// Sort courses
function addClickListener() {
document.querySelectorAll("div.library-item-wrap").forEach((item) => {
if (!item.dataset.listenerAdded) {
item.addEventListener("click", function () {
setTimeout(() => {
/* Change the number in .dropdown-item:nth-child(3) by your preference
1: All lessons
2: Oldest to Newest
3: Newest to Oldest
4: Last Opened
5: New Words %
6: A-Z */
document.querySelector(
".library-item--menu-box .collection-section--controllers .dropdown-item:nth-child(5)"
).click();
}, 500);
});
item.dataset.listenerAdded = true;
}
});
}
const libraryObserver = new MutationObserver(addClickListener);
if (document.URL.includes("/library")) {
libraryObserver.observe(document.body, { childList: true, subtree: true });
addClickListener();
}
})();
You can customize settings by adjusting these values in the code:
:root {
--width_small: 540px;
--height_small: 370px;
--height_big: 650px;
--width_big: 1100px;
--right_pos: 0.5%;
--bottom_pos: 5.5%;
--font_size: 1.1rem;
--font_color: #e0e0e0;
--line_height: 1.7;
--lingq_background: hsl(41 43% 30% / 0.7);
--lingq_border: hsl(43 99% 64% / 0.3);
--lingq_border_learned: hsl(43 99% 64% / 0.5);
--blue_border: hsl(213 99% 64% / 0.5);
}