Shift-H to set filter
// ==UserScript==
// @name GeoFilter(Fixed)
// @description Shift-H to set filter
// @namespace https://www.geoguessr.com/
// @version 1.1
// @author drparse, KaKa
// @match https://www.geoguessr.com/*
// @grant unsafeWindow
// @run-at document-start
// @copyright 2020, drparse
// @license GPL-3.0-or-later; http://www.gnu.org/licenses/gpl-3.0.txt
// @noframes
// ==/UserScript==
(function() {
'use strict';
function injected() {
const st = JSON.parse(window.localStorage.getItem('bintuluFilterState') || '{}');
const THEME = {
primary: '#3b82f6', // Blue
primaryDark: '#1e40af',
secondary: '#1f2937', // Dark gray
background: 'rgba(31, 41, 55, 0.92)',
border: 'rgba(59, 130, 246, 0.3)',
hover: 'rgba(59, 130, 246, 0.1)',
text: '#ffffff',
textSecondary: '#d1d5db',
};
const vertexOld = "const float f=3.1415926;varying vec3 a;uniform vec4 b;attribute vec3 c;attribute vec2 d;uniform mat4 e;void main(){vec4 g=vec4(c,1);gl_Position=e*g;a=vec3(d.xy*b.xy+b.zw,1);a*=length(c);}";
const fragOld = "precision highp float;const float h=3.1415926;varying vec3 a;uniform vec4 b;uniform float f;uniform sampler2D g;void main(){vec4 i=vec4(texture2DProj(g,a).rgb,f);gl_FragColor=i;}";
const vertexNew = `
const float f=3.1415926;
varying vec3 a;
varying vec3 potato;
uniform vec4 b;
attribute vec3 c;
attribute vec2 d;
uniform mat4 e;
void main(){
vec4 g=vec4(c,1);
gl_Position=e*g;
a = vec3(d.xy * b.xy + b.zw,1);
a *= length(c);
potato = vec3(d.xy, 1.0) * length(c);
}`;
const fragNew = `precision highp float;
const float h=3.1415926;
const float tau=6.2831853;
varying vec3 a;
varying vec3 potato;
uniform vec4 b;
uniform float f;
uniform sampler2D g;
vec3 RGBToHSL(vec3 color)
{
vec3 hsl;
float fmin = min(min(color.r, color.g), color.b);
float fmax = max(max(color.r, color.g), color.b);
float delta = fmax - fmin;
hsl.z = (fmax + fmin) / 2.0;
if (delta == 0.0) {
hsl.x = 0.0;
hsl.y = 0.0;
} else {
if (hsl.z < 0.5)
hsl.y = delta / (fmax + fmin);
else
hsl.y = delta / (2.0 - fmax - fmin);
float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;
float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;
float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;
if (color.r == fmax )
hsl.x = deltaB - deltaG;
else if (color.g == fmax)
hsl.x = (1.0 / 3.0) + deltaR - deltaB;
else if (color.b == fmax)
hsl.x = (2.0 / 3.0) + deltaG - deltaR;
if (hsl.x < 0.0)
hsl.x += 1.0;
else if (hsl.x > 1.0)
hsl.x -= 1.0;
}
return hsl;
}
float HueToRGB(float f1, float f2, float hue)
{
if (hue < 0.0) hue += 1.0;
else if (hue > 1.0) hue -= 1.0;
float res;
if ((6.0 * hue) < 1.0)
res = f1 + (f2 - f1) * 6.0 * hue;
else if ((2.0 * hue) < 1.0)
res = f2;
else if ((3.0 * hue) < 2.0)
res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;
else
res = f1;
return res;
}
vec3 HSLToRGB(vec3 hsl)
{
vec3 rgb;
if (hsl.y == 0.0)
rgb = vec3(hsl.z);
else {
float f2;
if (hsl.z < 0.5)
f2 = hsl.z * (1.0 + hsl.y);
else
f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);
float f1 = 2.0 * hsl.z - f2;
rgb.r = HueToRGB(f1, f2, hsl.x + (1.0/3.0));
rgb.g = HueToRGB(f1, f2, hsl.x);
rgb.b = HueToRGB(f1, f2, hsl.x - (1.0/3.0));
}
return rgb;
}
vec3 filter_nightTime(vec3 rgb) {
vec3 hsl = RGBToHSL(rgb);
hsl.z = 1.0 - hsl.z;
return HSLToRGB(hsl);
}
vec3 filter_hueShift(vec3 rgb, float degrees) {
vec3 hsl = RGBToHSL(rgb);
hsl.x = mod(hsl.x + degrees/360.0, 1.0);
return HSLToRGB(hsl);
}
vec3 filter_satShift(vec3 rgb, float amount) {
vec3 hsl = RGBToHSL(rgb);
hsl.y = clamp(hsl.y * amount, 0.0, 1.0);
return HSLToRGB(hsl);
}
vec3 filter_sepia(vec3 rgb, float hue, float amount) {
vec3 hsl = RGBToHSL(rgb);
hsl.x = hue;
hsl.y = 0.33;
return HSLToRGB(hsl);
}
vec3 filter_mauve(vec3 rgb) {
vec3 mauve = vec3(224.0/255.0, 176.0/255.0, 255.0/255.0);
return mix(vec3(1.0), mauve, clamp(distance(rgb, mauve)/(1.74*0.8), 0.0, 1.0));
}
vec3 filter_posterize(vec3 rgb, float amount) {
rgb = clamp(floor(rgb * amount + 0.5) / amount, 0.0, 1.0);
return rgb;
}
vec3 filter_gen69(vec3 rgb, float hue, float amount) {
vec3 hsl = RGBToHSL(rgb);
float prevSat = hsl.y;
hsl.y = 1.0;
hsl.x = prevSat < 0.1 ? mod(hsl.z * 2.0, 1.0) : hsl.x;
hsl.z = clamp(hsl.z, 0.2, 1.0);
return HSLToRGB(hsl);
}
vec3 filter_hueWheel(vec3 rgb, float angle) {
vec3 hsl = RGBToHSL(rgb);
hsl.x = mod(hsl.x + angle, 1.0);
return HSLToRGB(hsl);
}
vec3 filter_blur(sampler2D sampler, vec3 coord, float amount) {
float blurRadius = amount / 500.0 * a.z;
vec3 rgb = vec3(0.0);
float totalWeight = 0.0;
for(int i = -2; i <= 2; i++) {
for(int j = -2; j <= 2; j++) {
vec3 sampleCoord = coord + vec3(float(i) * blurRadius, float(j) * blurRadius, 0.0);
float weight = 1.0 - distance(vec2(float(i), float(j)), vec2(0.0)) * 0.2;
rgb += texture2DProj(sampler, sampleCoord).rgb * weight;
totalWeight += weight;
}
}
return rgb / totalWeight;
}
bool filter_colorInclude(vec3 rgb, float hueMin, float hueMax, float satMin) {
vec3 hsl = RGBToHSL(rgb);
float fudge = 0.1;
bool shouldInclude = (
hueMin < hsl.x && hsl.x < hueMax && satMin < hsl.y
) || (hueMin-fudge < hsl.x && hsl.x < hueMax+fudge && hsl.z < 0.2);
return shouldInclude;
}
void main(){
vec2 aD = potato.xy / a.z;
float thetaD = aD.y;
float thresholdD1 = 0.6;
float thresholdD2 = 0.7;
float x = aD.x;
float y = abs(4.0*x - 2.0);
float phiD = smoothstep(0.0, 1.0, y > 1.0 ? 2.0 - y : y);
vec3 coord = a;
`+(st.filterMinecraft?.on ? `
`+(st.filterSemiMinecraft?.on ? `
vec3 rgb0 = texture2DProj(g,a).rgb;
vec3 hsl0 = RGBToHSL(rgb0);
float q = (hsl0.y < 0.075 ? 1.0 : 5.0 * float(`+(st.filterMinecraft.value||20)+`))/1000.0 * a.z;
` : `
float q = float(`+(st.filterMinecraft.value||20)+`)/1000.0 * a.z;
`)+`
coord = normalize(floor(a/q)*q);
` : '')+`
`+(st.filterWaveDistortion?.on ? `
coord = normalize(a);
coord.y = coord.y + sin(y * tau * 10.0) * (float(`+(st.filterWaveDistortion.value||10)+`)/1000.0);
` : '')+`
vec3 rgb = texture2DProj(g,coord).rgb;
bool mask = true;
`+(st.filterVegetationOnly?.on ? `
mask = mask && filter_colorInclude(rgb, 0.10, 0.40, 0.1);
` : '')+`
`+(st.filterVegetationOff?.on ? `
mask = mask && !filter_colorInclude(rgb, 0.10, 0.40, 0.1);
` : '')+`
`+(st.filterCheckerboard?.on ? `
float checkerboard = mod(dot(floor(gl_FragCoord.xy / float(`+(st.filterCheckerboard?.value || 400)+`)), vec2(1.0)), 2.0);
mask = mask && checkerboard < 1.0;
` : '')+`
`+(st.filterNoCar?.on ? `
mask = mask && thetaD <= mix(thresholdD1, thresholdD2, phiD);
` : '')+`
rgb = mask ? rgb : vec3(0.5);
`+(st.filterNightTime?.on ? `
rgb = filter_nightTime(rgb);
` : '')+`
`+(st.filterGen5?.on ? `
rgb = filter_satShift(rgb, 2.0);
` : '')+`
`+(st.filterGen69?.on ? `
rgb = filter_gen69(rgb, 0.1, 0.5);
` : '')+`
`+(st.filterHueWheel?.on ? `
rgb = filter_hueWheel(rgb, x);
` : '')+`
`+(st.filterSepia?.on ? `
rgb = filter_sepia(rgb, 0.1, 0.5);
` : '')+`
`+(st.filterMauve?.on ? `
rgb = filter_mauve(rgb);
` : '')+`
`+(st.filterHueShift?.on ? `
rgb = filter_hueShift(rgb, float(`+(st.filterHueShift.value||180)+`));
` : '')+`
`+(st.filterPosterize?.on ? `
rgb = filter_posterize(rgb, float(`+(st.filterPosterize?.value || 5)+`));
` : '')+`
`+(st.filterGrayscale?.on ? `
rgb = vec3(dot(rgb, vec3( 0.2125, 0.7154, 0.0721 ) ));
` : '')+`
`+(st.filterInvert?.on ? `
rgb = vec3(1.0) - rgb;
` : '')+`
`+(st.filterPinhole?.on ? `
const float pinholeFactor = 1.65;
rgb = mix(vec3(0.0), rgb, clamp(
(2.0*abs(x-0.5) - 1.0/pinholeFactor)*(5.0*pinholeFactor),
0.0, 1.0) );
` : '')+`
`+(st.filterBlur?.on ? `
rgb = filter_blur(g, coord, float(`+(st.filterBlur.value||10)+`));
` : '')+`
vec4 i = vec4(rgb, f);
gl_FragColor=i;
}`;
const EXP_GL2 = false;
function installShaderSource(ctx) {
const g = ctx.shaderSource;
function shaderSource() {
if (typeof arguments[1] === 'string') {
let glsl = arguments[1];
if (glsl === vertexOld) {
glsl = vertexNew;
} else if (glsl === fragOld) {
glsl = fragNew;
}
return g.call(this, arguments[0], glsl);
}
return g.apply(this, arguments);
}
shaderSource.bestcity = 'bintulu';
ctx.shaderSource = shaderSource;
}
function installGetContext(el) {
const g = el.getContext;
el.getContext = function() {
if (arguments[0] === 'webgl' || arguments[0] === 'webgl2') {
if (EXP_GL2) arguments[0] = 'webgl2';
const ctx = g.apply(this, arguments);
if (ctx && ctx.shaderSource && ctx.shaderSource.bestcity !== 'bintulu') {
installShaderSource(ctx);
}
return ctx;
}
return g.apply(this, arguments);
};
}
const f = document.createElement;
document.createElement = function() {
if (arguments[0] === 'canvas' || arguments[0] === 'CANVAS') {
const el = f.apply(this, arguments);
installGetContext(el);
return el;
}
return f.apply(this, arguments);
};
function h(selector, ...args) {
let tag = selector.match(/^\w+/);
tag = tag ? tag[0] : 'div';
const classes = selector.matchAll(/\.(\w+)/g);
const id = selector.match(/#(\w+)/);
const $el = document.createElement(tag);
$el.classList.add(...([...classes].map(x => x[1])));
if (id) $el.id = id[1];
function addChild(child) {
if (typeof child === 'string') {
$el.appendChild(document.createTextNode(child));
} else if (child instanceof Node) {
$el.appendChild(child);
} else if (typeof child === 'object') {
return child;
}
}
for (const arg of args) {
if (Array.isArray(arg)) {
for (const sub of arg) addChild(sub);
} else {
const residual = addChild(arg);
if (residual) {
for (const key in residual) {
if (key.startsWith('on')) {
$el.addEventListener(key.slice(2).toLowerCase(), residual[key]);
} else if (key === 'style') {
Object.assign($el.style, residual[key]);
} else {
$el[key] = residual[key];
}
}
}
}
}
return $el;
}
function showGUI() {
let $el = document.getElementById('bintulu_filter_ui');
if ($el) {
$el.style.display = 'flex';
return $el;
}
$el = document.createElement('div');
$el.id = 'bintulu_filter_ui';
Object.assign($el.style, {
display: 'flex',
flexDirection: 'column',
position: 'fixed',
background: THEME.background,
backdropFilter: 'blur(10px)',
zIndex: '10000',
width: '340px',
top: '30px',
left: '150px',
padding: '20px',
borderRadius: '12px',
boxShadow: '0 20px 60px rgba(0, 0, 0, 0.4)',
border: `1px solid ${THEME.border}`,
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
color: THEME.text,
maxHeight: '80vh',
overflow: 'hidden',
});
function stateChanged() {
const j = JSON.stringify(st);
window.localStorage.setItem('bintuluFilterState', j);
}
function makeFilterWithOneParam(displayName, key, min, max, defaultV) {
const isEnabled = st[key]?.on || false;
return h('div.bntFilterItem', [
h('label.bntFilterHeader', { id: 'bnt_'+key, style: {
display: 'flex',
alignItems: 'center',
userSelect: 'none',
padding: '8px 0',
cursor: 'pointer',
transition: 'background-color 0.2s ease',
borderRadius: '6px',
paddingLeft: '8px',
}}, [
h('input', { type: 'checkbox', checked: isEnabled, onChange: (e) => {
st[key] = st[key] || { };
st[key].on = e.target.checked;
if (e.target.checked) {
if (key === 'filterMinecraft' && st.filterWaveDistortion) {
st.filterWaveDistortion.on = false;
const waveCheckbox = document.querySelector('#bnt_filterWaveDistortion input[type=checkbox]');
if (waveCheckbox) waveCheckbox.checked = false;
} else if (key === 'filterWaveDistortion' && st.filterMinecraft) {
st.filterMinecraft.on = false;
const minecraftCheckbox = document.querySelector('#bnt_filterMinecraft input[type=checkbox]');
if (minecraftCheckbox) minecraftCheckbox.checked = false;
}
}
const sliderContainer = document.getElementById('bntRange_'+key);
if (sliderContainer) {
sliderContainer.style.display = e.target.checked ? 'flex' : 'none';
}
stateChanged();
}, style: {
marginRight: '10px',
cursor: 'pointer',
width: '18px',
height: '18px',
accentColor: THEME.primary,
}}),
h('span', { style: {
flex: '1',
fontSize: '14px',
fontWeight: '500',
color: THEME.text,
}}, displayName),
]),
h('div.bntRangeInput', { id: 'bntRange_'+key, style: {
display: isEnabled ? 'flex' : 'none',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-start',
gap: '12px',
marginTop: '8px',
marginLeft: '28px',
paddingRight: '8px',
}}, [
h('input', {
type: 'range',
min,
max,
value: st[key]?.value || defaultV,
onInput: (e) => {
st[key] = st[key] || {};
const val = Number(e.target.value);
if (Number.isFinite(val)) {
st[key].value = val;
}
const percent = (val - min) / (max - min) * 100;
e.target.style.background = `linear-gradient(to right, ${THEME.primary} ${percent}%, #374151 ${percent}%)`;
const amountDisplay = document.getElementById('BntAmount_'+key);
if (amountDisplay) {
amountDisplay.innerText = String(val);
}
stateChanged();
},
onChange: (e) => {
// 可选:实时应用
// reapplyFilters();
},
style: {
flex: '1',
height: '6px',
borderRadius: '3px',
outline: 'none',
cursor: 'pointer',
}
}),
h('span.bntAmount', { id: 'BntAmount_'+key, style: {
minWidth: '40px',
fontSize: '12px',
color: THEME.textSecondary,
textAlign: 'right',
fontWeight: '600',
}}, String(st[key]?.value || defaultV)),
]),
]);
}
function makeFilterWithZeroParams(displayName, key) {
const isEnabled = st[key]?.on || false;
return h('div.bntFilterItem', [
h('label.bntFilterHeader', { id: 'bnt_'+key, style: {
display: 'flex',
alignItems: 'center',
userSelect: 'none',
padding: '8px 8px',
cursor: 'pointer',
transition: 'background-color 0.2s ease',
borderRadius: '6px',
}}, [
h('input', { type: 'checkbox', checked: isEnabled, onChange: (e) => {
st[key] = st[key] || { };
st[key].on = e.target.checked;
if (key === 'filterGen69' && st.filterGen69) {
st.filterHueWheel = st.filterHueWheel || { };
st.filterHueWheel.on = e.target.checked;
const hueWheelCheckbox = document.querySelector('#bnt_filterHueWheel input[type=checkbox]');
if (hueWheelCheckbox) hueWheelCheckbox.checked = e.target.checked;
} else if (key === 'filterMauve' && st.filterMauve) {
st.filterSepia = st.filterSepia || { };
st.filterSepia.on = false;
const sepiaCheckbox = document.querySelector('#bnt_filterSepia input[type=checkbox]');
if (sepiaCheckbox) sepiaCheckbox.checked = false;
} else if (key === 'filterSepia' && st.filterSepia) {
st.filterMauve = st.filterMauve || { };
st.filterMauve.on = false;
const mauveCheckbox = document.querySelector('#bnt_filterMauve input[type=checkbox]');
if (mauveCheckbox) mauveCheckbox.checked = false;
}
stateChanged();
}, style: {
marginRight: '10px',
cursor: 'pointer',
width: '18px',
height: '18px',
accentColor: THEME.primary,
}}),
h('span', { style: {
flex: '1',
fontSize: '14px',
fontWeight: '500',
color: THEME.text,
}}, displayName),
]),
]);
}
function spacer() {
return h('div', { style: {
height: '1px',
background: THEME.border,
margin: '12px 0',
}});
}
const header = h('div', { style: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: '16px',
paddingBottom: '12px',
borderBottom: `1px solid ${THEME.border}`,
}}, [
h('h2', { style: {
margin: '0',
fontSize: '16px',
fontWeight: '700',
color: THEME.text,
letterSpacing: '0.5px',
}}, '🎨 GeoFilter'),
h('div.headerButtons', { style: {
display: 'flex',
gap: '8px',
}}, [
h('button', {
id: 'bint_close_btn',
innerHTML: '✕',
style: {
background: THEME.hover,
border: `1px solid ${THEME.border}`,
borderRadius: '6px',
width: '32px',
height: '32px',
cursor: 'pointer',
color: THEME.text,
fontSize: '16px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: 'all 0.2s ease',
fontWeight: 'bold',
padding: '0',
},
onClick: () => { hideGUI(); },
onMouseEnter: function() {
this.style.background = '#ef4444';
this.style.borderColor = '#dc2626';
},
onMouseLeave: function() {
this.style.background = THEME.hover;
this.style.borderColor = THEME.border;
}
}),
]),
]);
const filterContainer = h('div.bntFilterOuter', { style: {
flex: '1',
overflow: 'auto',
paddingRight: '4px',
}}, [
makeFilterWithOneParam('Minecraft', 'filterMinecraft', '5', '50', 20),
makeFilterWithZeroParams('Semi Minecraft', 'filterSemiMinecraft'),
makeFilterWithOneParam('Cheer up beer', 'filterWaveDistortion', '1', '100', 10),
makeFilterWithOneParam('Hue Shift', 'filterHueShift', '10', '350', 180),
makeFilterWithZeroParams('Gen 5 camera', 'filterGen5'),
makeFilterWithZeroParams('Gen \'69 camera', 'filterGen69'),
makeFilterWithZeroParams('Hue wheel', 'filterHueWheel'),
makeFilterWithZeroParams('Sepia', 'filterSepia'),
makeFilterWithZeroParams('Mauve', 'filterMauve'),
makeFilterWithOneParam('Dog Vision', 'filterPosterize', '1', '10', 5),
makeFilterWithZeroParams('Grayscale', 'filterGrayscale'),
makeFilterWithZeroParams('Invert', 'filterInvert'),
makeFilterWithZeroParams('Night mode', 'filterNightTime'),
makeFilterWithZeroParams('Vegan mode', 'filterVegetationOnly'),
makeFilterWithZeroParams('Keto mode', 'filterVegetationOff'),
makeFilterWithZeroParams('No Car', 'filterNoCar'),
makeFilterWithZeroParams('Pinhole', 'filterPinhole'),
makeFilterWithOneParam('Checkerboard (nmpz)', 'filterCheckerboard', '2', '1000', 400),
makeFilterWithOneParam('Blur', 'filterBlur', '0', '100', 10),
]);
const footer = h('div.bntFooter', { style: {
display: 'flex',
gap: '8px',
marginTop: '16px',
paddingTop: '12px',
borderTop: `1px solid ${THEME.border}`,
}}, [
h('button', {
innerHTML: 'Apply',
style: {
flex: '1',
padding: '8px 12px',
background: '#10b981',
color: THEME.text,
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '13px',
fontWeight: '600',
},
onClick: () => {
stateChanged();
reapplyFilters();
}
}),
h('button', {
innerHTML: 'Reset',
style: {
flex: '1',
padding: '8px 12px',
background: `linear-gradient(135deg, ${THEME.primary}, ${THEME.primaryDark})`,
color: THEME.text,
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '13px',
fontWeight: '600',
},
onClick: () => {
for (const key in st) {
if (typeof st[key] === 'object' && st[key].on !== undefined) {
st[key].on = false;
}
}
document.querySelectorAll('#bintulu_filter_ui input[type=checkbox]').forEach(checkbox => {
checkbox.checked = false;
});
document.querySelectorAll('#bintulu_filter_ui .bntRangeInput').forEach(el => {
el.style.display = 'none';
});
stateChanged();
}
}),
]);
$el.appendChild(header);
$el.appendChild(filterContainer);
$el.appendChild(footer);
let ss = document.createElement('style');
ss.id = 'bintulu_filters';
ss.innerHTML = `
#bintulu_filter_ui {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
#bintulu_filter_ui input[type="range"] {
height: 6px;
border-radius: 3px;
background: linear-gradient(to right, #3b82f6 var(--p), #374151 var(--p));
}
#bintulu_filter_ui input[type="checkbox"] {
cursor: pointer;
}
.bntFilterHeader:hover {
background-color: ${THEME.hover};
}
.bntFilterOuter {
display: flex;
flex-direction: column;
gap: 4px;
}
.bntFilterItem {
display: flex;
flex-direction: column;
}
.bntRangeInput input[type="range"] {
flex: 1;
}
.bntRangeInput span {
min-width: 2em;
}
#bnt_filterHueWheel {
text-indent: 20px;
}
`;
document.head.appendChild(ss);
document.body.appendChild($el);
if (st.panelPinned) {
$el.setAttribute('data-pinned', 'true');
}
return $el;
}
function reapplyFilters() {
location.reload();
}
function hideGUI() {
const $el = document.getElementById('bintulu_filter_ui');
if ($el) $el.style.display = 'none';
}
function addCompassStyle() {
let style = document.createElement('style');
style.id = 'bintulu_nocompass';
style.innerHTML = '.compass { display: none }';
document.head.appendChild(style);
}
document.addEventListener('keydown', (evt) => {
if (!evt.repeat && evt.code === 'KeyK' && evt.shiftKey && !evt.altKey && !evt.ctrlKey && !evt.metaKey) {
let style = document.getElementById('bintulu_nocompass');
if (!style) {
addCompassStyle();
} else {
style.remove();
}
}
if (!evt.repeat && evt.code === 'KeyH' && evt.shiftKey && !evt.altKey && !evt.ctrlKey && !evt.metaKey) {
let $el = document.getElementById('bintulu_filter_ui');
if (!$el) {
showGUI();
} else {
if ($el.style.display === 'none') {
showGUI();
} else {
hideGUI();
}
}
}
});
const observer = new MutationObserver((mutationsList, observer) => {
const originalElements = document.querySelectorAll("[class*='styles_control__']");
if (originalElements.length > 0 && !document.getElementById('geo-filter')) {
const targetElement = originalElements[originalElements.length - 1];
const clonedElement = targetElement.cloneNode(true);
clonedElement.id = 'geo-filter';
const parent = targetElement.parentNode;
parent.insertBefore(clonedElement, targetElement);
const buttonElement = clonedElement.querySelector("button");
if (!buttonElement) return;
buttonElement.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="20"><!--! Font Awesome Pro 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M512 256c0 .9 0 1.8 0 2.7c-.4 36.5-33.6 61.3-70.1 61.3H344c-26.5 0-48 21.5-48 48c0 3.4 .4 6.7 1 9.9c2.1 10.2 6.5 20 10.8 29.9c6.1 13.8 12.1 27.5 12.1 42c0 31.8-21.6 60.7-53.4 62c-3.5 .1-7 .2-10.6 .2C114.6 512 0 397.4 0 256S114.6 0 256 0S512 114.6 512 256zM128 288c0-17.7-14.3-32-32-32s-32 14.3-32 32s14.3 32 32 32s32-14.3 32-32zm0-96c17.7 0 32-14.3 32-32s-14.3-32-32-32s-32 14.3-32 32s14.3 32 32 32zM288 96c0-17.7-14.3-32-32-32s-32 14.3-32 32s14.3 32 32 32s32-14.3 32-32zm96 96c17.7 0 32-14.3 32-32s-14.3-32-32-32s-32 14.3-32 32s14.3 32 32 32z" fill="#fff"></path></svg>`
const tooltip = document.createElement("div");
tooltip.textContent = "Show filter panel";
Object.assign(tooltip.style, {
position: "absolute",
bottom: "120%",
left: "50%",
transform: "translateX(-50%) scale(0.8)",
background: "#333",
color: "#fff",
padding: "4px 6px",
fontSize: "10px",
borderRadius: "4px",
whiteSpace: "nowrap",
opacity: "0",
pointerEvents: "none",
transition: "0.2s",
zIndex: 9999
});
clonedElement.style.position = "relative";
clonedElement.appendChild(tooltip);
clonedElement.addEventListener("mouseenter", () => {
tooltip.style.opacity = "1";
tooltip.style.transform = "translateX(-50%) scale(1)";
});
clonedElement.addEventListener("mouseleave", () => {
tooltip.style.opacity = "0";
tooltip.style.transform = "translateX(-50%) scale(0.8)";
});
clonedElement.addEventListener("click", () => {
let $el = document.getElementById('bintulu_filter_ui');
if (!$el) {
showGUI();
tooltip.textContent = "Close filter panel";
} else {
if ($el.style.display === 'none') {
showGUI();
tooltip.textContent = "Close filter panel";
} else {
hideGUI();
tooltip.textContent = "Show filter panel";
}
}
});
observer.disconnect()
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
unsafeWindow.eval(`(${injected.toString()})()`);
})();