// ==UserScript==
// @name ๐ธ Songsterr Ultimate (Premium Unlocked)
// @name:en ๐ธ Songsterr Ultimate (Premium Unlocked)
// @name:fr ๐ธ Songsterr Ultime (Premium Dรฉbloquรฉ)
// @name:es ๐ธ Songsterr Definitivo (Premium Desbloqueado)
// @name:de ๐ธ Songsterr Ultimativ (Premium Freigeschaltet)
// @name:it ๐ธ Songsterr Definitivo (Premium Sbloccato)
// @name:pt ๐ธ Songsterr Supremo (Premium Desbloqueado)
// @name:pt-BR ๐ธ Songsterr Supremo (Full Premium)
// @name:nl ๐ธ Songsterr Ultiem (Premium Ontgrendeld)
// @name:pl ๐ธ Songsterr Ostateczny (Premium Odblokowany)
// @name:ru ๐ธ Songsterr ะะฑัะพะปััะฝัะน (ะัะตะผะธัะผ ะ ะฐะทะฑะปะพะบะธัะพะฒะฐะฝ)
// @name:ja ๐ธ Songsterr ็ฉถๆฅต (ใใฌใใขใ ่งฃ้ค)
// @name:ko ๐ธ Songsterr ๊ถ๊ทน (ํ๋ฆฌ๋ฏธ์ ์ธ๋ฝ)
// @name:sv ๐ธ Songsterr Ultimat (Premium Upplรฅst)
// @name:da ๐ธ Songsterr Ultimativ (Premium Lรฅst Op)
// @namespace http://tampermonkey.net/
// @version 4.0.1
// @description Unlocks all Plus features (Speed, Loop, Solo, Mute, no pauses) + Native Export (.gp & .midi). (Tested on Zen Browser)
// @description:fr Dรฉbloque toutes les fonctionnalitรฉs Plus (Vitesse, Loop, Solo, Mute, sans pauses) + Tรฉlรฉchargement natif (.gp & .midi). (Testรฉ sur Zen Browser)
// @description:es Desbloquea todas las funciones Plus (Velocidad, Bucle, Solo, Mute, sin pausas) + Descarga nativa (.gp y .midi). (Probado en Zen Browser)
// @description:de Schaltet alle Plus-Features frei (Geschwindigkeit, Loop, Solo, Mute, ohne Pausen) + Nativer Download (.gp & .midi). (Getestet auf Zen Browser)
// @description:it Sblocca tutte le funzioni Plus (Velocitร , Loop, Solo, Mute, senza pause) + Download nativo (.gp e .midi). (Testato su Zen Browser)
// @description:pt Desbloqueia todos os recursos Plus (Velocidade, Loop, Solo, Mute, sem pausas) + Download nativo (.gp e .midi). (Testado no Zen Browser)
// @description:pt-BR Desbloqueia tudo do Plus (Velocidade, Loop, Solo, Mute, sem pausas) + Export nativo (.gp & .midi). (Testado no Zen Browser)
// @description:nl Ontgrendelt alle Plus-functies (Snelheid, Loop, Solo, Mute, geen pauzes) + Native download (.gp & .midi). (Getest op Zen Browser)
// @description:pl Odblokowuje wszystkie funkcje Plus (Prฤdkoลฤ, Pฤtla, Solo, Mute, bez przerw) + Natywny eksport (.gp i .midi). (Testowane na Zen Browser)
// @description:ru ะ ะฐะทะฑะปะพะบะธััะตั ะฒัะต ััะฝะบัะธะธ Plus (ะกะบะพัะพััั, ะะตัะปั, ะกะพะปะพ, Mute, ะฑะตะท ะฟะฐัะท) + ะะฐัะธะฒะฝัะน ัะบัะฟะพัั (.gp ะธ .midi). (ะัะพัะตััะธัะพะฒะฐะฝะพ ะฒ Zen Browser)
// @description:ja Plusใฎๅ
จๆฉ่ฝ๏ผ้ๅบฆใใซใผใใใฝใญใใใฅใผใใ็กๅๆญข๏ผใ่งฃ้ค + ใใคใใฃใใใฆใณใญใผใ๏ผ.gp & .midi๏ผใ(Zen Browserใงใในใๆธใฟ)
// @description:ko ๋ชจ๋ Plus ๊ธฐ๋ฅ ํด์ (์๋, ๋ฃจํ, ์๋ก, ๋ฎคํธ, ๋ฉ์ถค ์์) + ๋ค์ดํฐ๋ธ ๋ค์ด๋ก๋ (.gp & .midi). (Zen Browser์์ ํ
์คํธ๋จ)
// @description:sv Lรฅser upp alla Plus-funktioner (Hastighet, Loop, Solo, Mute, inga pauser) + Naturlig export (.gp & .midi). (Testat pรฅ Zen Browser)
// @description:da Lรฅser alle Plus-funktioner op (Hastighed, Loop, Solo, Mute, ingen pauser) + Naturlig download (.gp & .midi). (Testet pรฅ Zen Browser)
// @author Goulagman
// @match *://www.songsterr.com/*
// @require https://cdn.jsdelivr.net/npm/@coderline/alphatab@1.8.1/dist/alphaTab.min.js
// @connect dqsljvtekg760.cloudfront.net
// @connect d3d3l6a6rcgkaf.cloudfront.net
// @grant unsafeWindow
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @run-at document-start
// @license MIT
// @downloadURL none
// ==/UserScript==
(function () {
'use strict';
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// LOGGING SYSTEM with Toggle
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const LOG_KEY = 'songsterr_debug_logging';
let loggingEnabled = false;
try {
loggingEnabled = localStorage.getItem(LOG_KEY) === 'true';
} catch (e) {}
// Wrapper for console logging - supports different prefixes
function sgdLog(level, prefix, ...args) {
if (!loggingEnabled) return;
const fullPrefix = prefix ? `[${prefix}]` : '[SGD]';
if (level === 'error') console.error(fullPrefix, ...args);
else if (level === 'warn') console.warn(fullPrefix, ...args);
else console.log(fullPrefix, ...args);
}
// Toggle logging function
window.toggleSgdLogging = function() {
loggingEnabled = !loggingEnabled;
try {
localStorage.setItem(LOG_KEY, loggingEnabled);
} catch (e) {}
console.log(`๐ธ Songsterr Ultimate โ Logging ${loggingEnabled ? 'ENABLED' : 'DISABLED'}`);
updateLogToggleUI();
};
// Update toggle button UI
function updateLogToggleUI() {
const btn = document.getElementById('sgd-log-toggle');
if (btn) {
btn.innerHTML = `๐ Logging ${loggingEnabled ? 'ON' : 'OFF'}`;
btn.title = loggingEnabled ? 'Debug logging enabled (click to disable)' : 'Debug logging disabled (click to enable)';
btn.classList.toggle('active', loggingEnabled);
// Colors are handled by CSS classes (.active / :not(.active))
}
}
// Inject logging toggle into Gl5687 div
function injectLogToggle() {
const targetDiv = document.querySelector('.Gl5687');
if (!targetDiv || document.getElementById('sgd-log-toggle')) return;
// Style the target div to allow centering
targetDiv.style.cssText = `
display: flex !important;
align-items: center !important;
justify-content: center !important;
width: 100% !important;
height: 100% !important;
`;
const btn = document.createElement('button');
btn.id = 'sgd-log-toggle';
btn.className = 'sgd-log-toggle-btn';
btn.innerHTML = `๐ Logging ${loggingEnabled ? 'ON' : 'OFF'}`;
btn.title = loggingEnabled ? 'Debug logging enabled (click to disable)' : 'Debug logging disabled (click to enable)';
btn.addEventListener('click', window.toggleSgdLogging);
// Style the button - dark theme matching Songsterr
btn.style.cssText = `
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 8px 16px;
border: 1px solid ${loggingEnabled ? '#16a34a' : '#dc2626'};
border-radius: 6px;
background: ${loggingEnabled ? '#166534' : '#7f1d1d'};
color: #fff;
font-size: 14px;
font-weight: 500;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
cursor: pointer;
transition: all 0.15s ease;
min-width: 120px;
height: 36px;
`;
btn.addEventListener('mouseenter', () => {
btn.style.background = loggingEnabled ? '#15803d' : '#991b1b';
});
btn.addEventListener('mouseleave', () => {
btn.style.background = loggingEnabled ? '#166534' : '#7f1d1d';
});
targetDiv.appendChild(btn);
}
// Watch for Gl5687 div to appear
const logToggleObserver = new MutationObserver(() => {
injectLogToggle();
});
logToggleObserver.observe(document.documentElement, { childList: true, subtree: true });
// Initial log
console.log('๐ธ Songsterr Ultimate โ Active v4.0.0', loggingEnabled ? '(Debug logging ON)' : '');
// Replace all console.log throughout the script with sgdLog
// (This will be done via find/replace in subsequent edits)
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// YOUTUBE AUDIO-ONLY SYSTEM (contribution ใใใชใซ)
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
(function() {
'use strict';
// To avoid audio stopping issues (browser power-saving features, etc.),
// we don't use display: none for parent elements either. Instead we use
// size 0, transparency, and absolute positioning to completely
// remove them from visual view while keeping them functional.
const style = document.createElement('style');
style.id = 'paprika-yt-styles';
style.textContent = `
/* Hide iframe itself (exists in DOM, audio continues playing) */
.songsterr-yt-hidden-iframe {
opacity: 0 !important;
width: 0px !important;
height: 0px !important;
pointer-events: none !important;
position: absolute !important;
z-index: -9999 !important;
border: none !important;
}
/* Hide iframe parent wrapper/background frame elements */
.songsterr-yt-hidden-wrapper {
opacity: 0 !important;
width: 0px !important;
height: 0px !important;
min-width: 0px !important;
min-height: 0px !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
overflow: hidden !important;
background: transparent !important;
position: absolute !important;
pointer-events: none !important;
z-index: -9999 !important;
}
/* YouTube Audio-Only toggle button - dark theme */
#yt-toggle-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 6px;
border: 1px solid #3a3a3a;
background: #2a2a2a;
color: #a5a5a5;
cursor: pointer;
font-size: 16px;
transition: all 0.15s ease;
}
#yt-toggle-btn:hover { background: #3a3a3a; color: #e5e5e5; }
#yt-toggle-btn.audio-only { background: #16a34a; color: #fff; border-color: #22c55e; }
#yt-toggle-btn.audio-only:hover { background: #15803d; border-color: #16a34a; }
`;
if (document.head) {
document.head.appendChild(style);
} else {
document.addEventListener('DOMContentLoaded', () => document.head.appendChild(style));
}
// Audio-only mode state (persistent via localStorage)
const YT_AUDIO_KEY = 'songsterr_yt_audio_only';
let ytAudioOnlyMode = false;
try {
ytAudioOnlyMode = localStorage.getItem(YT_AUDIO_KEY) === 'true';
} catch (e) {}
/**
* Function to detect and hide YouTube iframes and multi-level frames (black backgrounds, etc.)
*/
function hideYouTubeIframes() {
if (!ytAudioOnlyMode) return; // Only hide if audio-only mode is activated
const iframes = document.querySelectorAll('iframe');
const keywords = /(player|video|youtube)/i;
iframes.forEach(iframe => {
const src = iframe.src || '';
if (src.includes('youtube.com') || src.includes('youtu.be')) {
if (!iframe.classList.contains('songsterr-yt-hidden-iframe')) {
// 1. Make iframe itself invisible
iframe.classList.add('songsterr-yt-hidden-iframe');
// 2. Process parent elements across multiple levels (up to 5 levels)
let currentParent = iframe.parentElement;
let level = 0;
while (currentParent && level < 5) {
// Stop when reaching body or html
if (currentParent.tagName === 'BODY' || currentParent.tagName === 'HTML') {
break;
}
const className = typeof currentParent.className === 'string' ? currentParent.className : '';
const idName = currentParent.id || '';
// Immediate wrappers (1-2 level parents) often have fixed size or black backgrounds, so hide unconditionally.
// For higher levels (3-5 levels), hide only if class name or ID contains player/video/youtube etc.
if (level < 2 || keywords.test(className) || keywords.test(idName)) {
currentParent.classList.add('songsterr-yt-hidden-wrapper');
}
currentParent = currentParent.parentElement;
level++;
}
}
}
});
}
// Function to show/hide iframes based on mode
function updateYtVisibility() {
if (ytAudioOnlyMode) {
hideYouTubeIframes();
} else {
// Video mode: remove hiding classes
document.querySelectorAll('.songsterr-yt-hidden-iframe').forEach(el => {
el.classList.remove('songsterr-yt-hidden-iframe');
});
document.querySelectorAll('.songsterr-yt-hidden-wrapper').forEach(el => {
el.classList.remove('songsterr-yt-hidden-wrapper');
});
}
// Update button
const btn = document.getElementById('yt-toggle-btn');
if (btn) {
btn.innerHTML = ytAudioOnlyMode ? '๐ต' : '๐ฌ';
btn.title = ytAudioOnlyMode ? 'Audio-only mode (click to show video)' : 'Video visible (click for audio-only)';
btn.classList.toggle('audio-only', ytAudioOnlyMode);
}
}
// Expose toggle function globally
window.toggleYtAudioOnly = function() {
ytAudioOnlyMode = !ytAudioOnlyMode;
try {
localStorage.setItem(YT_AUDIO_KEY, ytAudioOnlyMode);
} catch (e) {}
updateYtVisibility();
};
// Initialize state
hideYouTubeIframes();
// Setup MutationObserver to watch for DOM changes
const observer = new MutationObserver((mutations) => {
let shouldCheck = false;
for (const mutation of mutations) {
if (mutation.addedNodes.length > 0) {
shouldCheck = true;
break;
}
if (mutation.type === 'attributes' && mutation.target.tagName === 'IFRAME') {
shouldCheck = true;
break;
}
}
if (shouldCheck) {
hideYouTubeIframes();
}
});
function startObserving() {
if (!document.body) return;
hideYouTubeIframes();
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['src']
});
sgdLog('log', 'Songsterr YT Hider', 'Started monitoring (ใใใชใซ็ + toggle)');
}
if (document.body) {
startObserving();
} else {
document.addEventListener('DOMContentLoaded', startObserving);
}
})();
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// AUTOSCROLL FIX (contribution ใใใชใซ)
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
(function() {
'use strict';
sgdLog('log', 'Songsterr Native Restore', 'Initializing native auto-scroll recovery...');
// ==========================================
// 1. Disable CSS interference (restore scroll container)
// ==========================================
// SongsterrUltimate injects `body, html { overflow: auto !important; }` into