Last active
March 28, 2025 08:03
-
-
Save Lordmau5/f9fbf60651c765fc61a50a27ebcf7d4a to your computer and use it in GitHub Desktop.
Keygenmusic.tk Improvements
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 Keygenmusic.tk Improvements | |
// @namespace http://tampermonkey.net/ | |
// @version 1.3.1 | |
// @description Various extra functionality and fixes for the amazing site Keygenmusic.tk (Volume slider, Seekbar, Loop toggle, List fixes) | |
// @author Lordmau5 | |
// @match https://keygenmusic.tk/ | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=keygenmusic.tk | |
// @grant none | |
// @require https://unpkg.com/[email protected]/dist/hyperlist.js | |
// ==/UserScript== | |
/* | |
TODO: | |
- add download button | |
- show current seekbar second when holding down and dragging, so you know where you "drop" | |
- try to make audio not lag when scrolling (async-ify onaudioprocess?) | |
^ seems to mostly be fixed? | |
*/ | |
(function() { | |
'use strict'; | |
let repeatCount = 0; | |
let sliderValue = 0.5; | |
let currentSong = ''; | |
let seeking = false; | |
function toggleLoop() { | |
if (!window.watcher) return; | |
repeatCount = this.checked ? -1 : 0; | |
window.player.config.repeatCount = repeatCount; | |
window.player.reloadConfig(window.player.config, window.player.currentPlayingNode); | |
} | |
function onSliderInput() { | |
sliderValue = this.value / 100; | |
const slider_text = document.querySelector('#volume_slider_text'); | |
slider_text.innerText = `VOLUME ${this.value}%`; | |
localStorage.setItem('slider_volume', sliderValue); | |
} | |
function updateGainElement() { | |
if (!window.player) return; | |
if (window.player.config) { | |
window.player.config.repeatCount = repeatCount; | |
} | |
if (window.player.gainNode) { | |
window.player.gainNode.gain.value = sliderValue; | |
} | |
} | |
function buildLoopButton() { | |
const div = document.createElement('div'); | |
div.id = 'loop_control'; | |
div.classList.add('center'); | |
div.style = 'margin-top: 15px;'; | |
const strong = document.createElement('strong'); | |
strong.style = 'font-size: 19px; color: #a9b7c6;'; | |
strong.appendChild(document.createTextNode('LOOP')); | |
const switchDiv = document.createElement('div'); | |
switchDiv.classList.add('switch'); | |
const checkbox = document.createElement('input'); | |
checkbox.type = 'checkbox'; | |
checkbox.id = 'loop'; | |
checkbox.classList.add('switch-check'); | |
checkbox.onclick = toggleLoop; | |
const label = document.createElement('label'); | |
label.htmlFor = 'loop'; | |
label.classList.add('switch-label'); | |
label.appendChild(document.createTextNode('Check')); | |
label.appendChild(document.createElement('span')); | |
switchDiv.appendChild(checkbox); | |
switchDiv.appendChild(label); | |
div.appendChild(strong); | |
div.appendChild(switchDiv); | |
return div; | |
} | |
function buildVolumeSlider() { | |
/* Get LocalStorage Slider Value */ | |
const _raw_slider_volume = localStorage.getItem('slider_volume'); | |
if (!!_raw_slider_volume) { | |
sliderValue = Math.max(0, parseFloat(_raw_slider_volume)); | |
} | |
const div = document.createElement('div'); | |
div.id = 'volume_control'; | |
div.classList.add('center'); | |
div.style = 'margin-top: 15px;'; | |
const strong = document.createElement('strong'); | |
strong.style = 'font-size: 19px; color: #a9b7c6;'; | |
strong.id = 'volume_slider_text'; | |
strong.appendChild(document.createTextNode('VOLUME 50%')); | |
const innerDiv = document.createElement('div'); | |
const input = document.createElement('input'); | |
input.style = 'width: 30%;'; | |
input.type = 'range'; | |
input.min = '0'; | |
input.max = '100'; | |
input.value = sliderValue * 100; | |
input.oninput = onSliderInput; | |
input.classList.add('volume_slider_input'); | |
innerDiv.appendChild(input); | |
strong.innerText = `VOLUME ${input.value}%`; | |
div.appendChild(strong); | |
div.appendChild(innerDiv); | |
return div; | |
} | |
function onSeekbarInput() { | |
seeking = true; | |
} | |
function onSeekbarChange() { | |
seeking = false; | |
if (!window.player || !window.player.currentPlayingNode || !window.player.currentPlayingNode.modulePtr) return; | |
const seconds = document.querySelector('.seekbar_input').value; | |
window._openmpt_module_set_position_seconds(window.player.currentPlayingNode.modulePtr, seconds); | |
} | |
function onSeekbarMouseUp() { | |
seeking = false; | |
} | |
function buildSeekbar() { | |
const div = document.createElement('div'); | |
div.id = 'seekbar'; | |
div.classList.add('center'); | |
div.style = 'margin-top: 15px;'; | |
const strong = document.createElement('strong'); | |
strong.style = 'font-size: 19px; color: #a9b7c6;'; | |
strong.id = 'seekbar_text'; | |
strong.appendChild(document.createTextNode('00:00 / 00:00')); | |
const innerDiv = document.createElement('div'); | |
const input = document.createElement('input'); | |
input.style = 'width: 30%;'; | |
input.type = 'range'; | |
input.min = '0'; | |
input.max = '0'; | |
input.value = 0; | |
input.oninput = onSeekbarInput; | |
input.onchange = onSeekbarChange; | |
input.mouseup = onSeekbarMouseUp; | |
input.classList.add('seekbar_input'); | |
innerDiv.appendChild(input); | |
div.appendChild(strong); | |
div.appendChild(innerDiv); | |
return div; | |
} | |
function secondsToMinutes(seconds) { | |
seconds = Math.floor(seconds); | |
const minutes = Math.floor(seconds / 60); | |
const remaining_seconds = seconds % 60; | |
return `${minutes.toString().padStart(2, '0')}:${remaining_seconds.toString().padStart(2, '0')}`; | |
} | |
let times_played = 0; | |
function loopObserver() { | |
if (!window.player.currentPlayingNode || !window.player.currentPlayingNode.modulePtr) { | |
times_played = 0; | |
setTimeout(loopObserver, 100); | |
return; | |
} | |
// eslint-disable-next-line | |
const song_length = _openmpt_module_get_duration_seconds(window.player.currentPlayingNode.modulePtr); | |
// eslint-disable-next-line | |
const song_position = _openmpt_module_get_position_seconds(window.player.currentPlayingNode.modulePtr); | |
if (!seeking) { | |
document.querySelector('.seekbar_input').value = Math.floor(song_position % song_length); | |
} | |
const seekbar_text = document.querySelector('#seekbar_text'); | |
seekbar_text.innerText = `${secondsToMinutes(song_position % song_length)} / ${secondsToMinutes(song_length)}`; | |
const played = Math.floor(song_position / song_length); | |
if (played > times_played && repeatCount === -1) { | |
times_played = played; | |
window.user.getTracksPlayed(function (num) { | |
const new_count = parseInt(num, 10) + 1; | |
window.model.write('tracks_played', new_count); | |
window.UI.renderTracksPlayed(new_count); | |
window.watcher.handleTotalPlayed(); | |
}); | |
} | |
setTimeout(loopObserver, 100); | |
} | |
function hookSearch() { | |
if(!window.watcher || !window.watcher.search || !window.search_input) { | |
setTimeout(hookSearch, 100); | |
return; | |
} | |
const old_search = window.watcher.search; | |
const hook_search = function(val) { | |
window.UI.renderPlaylist(window.playList.setSelected(val), val); | |
window.playList.setCurrentPlayList(window.UI.getShuffleBtnStatus()); | |
}; | |
window.watcher.search = hook_search; | |
window.search_input.oninput = function() { | |
hook_search(window.search_input.value); | |
}; | |
console.log('[Hooked] window.watcher.search'); | |
} | |
let playlistObject = false; | |
let playlistConfig = {}; | |
let playlistSongs = []; | |
function hookPlaylist() { | |
if (!window.UI || !window.UI.renderPlaylist || !window.playList.song_lib || !window.playList.song_lib.length) { | |
setTimeout(hookPlaylist, 1); | |
return; | |
} | |
const hookVirtualList = function(playlist) { | |
playlistSongs = playlist; | |
if (window.__hookedVirtualList) { | |
playlistConfig.total = playlistSongs.length; | |
playlistObject.refresh(document.querySelector('#playlist table tbody'), playlistConfig); | |
return; | |
} | |
document.head.insertAdjacentHTML('beforeend', `<style> | |
#playlist .track { | |
max-width: 420px; | |
overflow: hidden; | |
white-space: nowrap; | |
text-overflow: clip; | |
} | |
#playlist .track_number { | |
min-width: 34px; | |
} | |
#playlist .heart { | |
position: absolute; | |
top: 18px; | |
right: 0px; | |
} | |
#playlist td.heart span { | |
color: #9daaaf; | |
} | |
</style>`); | |
const table = document.querySelector('#playlist table'); | |
const table_body = document.createElement('tbody'); | |
playlistConfig = { | |
itemHeight: 60, | |
total: playlistSongs.length, | |
useFragment: true, | |
overrideScrollPosition() { | |
return document.querySelector('.scroller').scrollTop; | |
}, | |
generate(index) { | |
const song = playlistSongs[index]; | |
// Outer track element | |
const track_element = document.createElement('tr'); | |
track_element.classList.add('playlist_track'); | |
track_element.setAttribute('data-path', song.path); | |
track_element.style.width = '100%'; | |
if (currentSong === song.path) { | |
track_element.classList.add('now_playing'); | |
} | |
/* Track Number */ | |
const track_number = document.createElement('td'); | |
track_number.classList.add('track_number'); | |
track_number.innerText = song.n; | |
/* ------------ */ | |
/* Track */ | |
const track = document.createElement('td'); | |
track.classList.add('track'); | |
const author = document.createElement('span'); | |
author.classList.add('rg'); | |
author.innerText = song.rg; | |
const name = document.createElement('span'); | |
name.classList.add('soft'); | |
name.innerText = song.sn; | |
const metadata = document.createElement('span'); | |
metadata.classList.add('mdt'); | |
metadata.classList.add('time'); | |
metadata.innerHTML = song.mdt || '​'; | |
track.appendChild(author); | |
track.appendChild(document.createElement('br')); | |
track.appendChild(name); | |
track.appendChild(document.createElement('br')); | |
track.appendChild(metadata); | |
/* ----- */ | |
/* Favorite */ | |
const favorite = document.createElement('td'); | |
favorite.setAttribute('title', 'Favorite'); | |
favorite.classList.add('heart'); | |
if (window.playList.isFavoriteSong(song.path)) { | |
favorite.classList.add('favorite'); | |
} | |
const heart_span = document.createElement('span'); | |
heart_span.innerHTML = '❤'; | |
favorite.appendChild(heart_span); | |
/* -------- */ | |
track_element.appendChild(track_number); | |
track_element.appendChild(track); | |
track_element.appendChild(favorite); | |
return track_element; | |
} | |
}; | |
playlistObject = window.HyperList.create(table_body, playlistConfig); | |
table.appendChild(table_body); | |
window.__hookedVirtualList = true; | |
}; | |
const old_renderPlaylist = window.UI.renderPlaylist; | |
const hook_renderPlaylist = function(playlist, listName) { | |
hookVirtualList(playlist); | |
console.log(`Loaded playlist "${listName}" with ${playlist.length} songs.`); | |
}; | |
window.UI.renderPlaylist = hook_renderPlaylist; | |
const table = document.querySelector('#playlist table'); | |
if (table.firstChild) { | |
while(table.firstChild) { | |
table.firstChild.remove(); | |
} | |
} | |
window.UI.renderPlaylist(window.playList.song_lib, ''); | |
window.playList.setSelected(''); | |
const old_scrollToSongInPlaylist = window.UI.scrollToSongInPlaylist; | |
const hook_scrollToSongInPlaylist = function(song) { | |
let id = -1; | |
for (let i = 0; i < window.playList.selected.length; i++) { | |
const _s = window.playList.selected[i]; | |
if (song === _s.path) { | |
id = i; | |
break; | |
} | |
} | |
if (id === -1) return; | |
window.$scroller.scrollTop(id * 60); | |
}; | |
window.UI.scrollToSongInPlaylist = hook_scrollToSongInPlaylist; | |
const old_updateSongInfo = window.watcher.updateSongInfo; | |
const hook_updateSongInfo = function(song) { | |
old_updateSongInfo(song); | |
currentSong = song; | |
document.querySelector('.seekbar_input').value = 0; | |
}; | |
window.watcher.updateSongInfo = hook_updateSongInfo; | |
const observer = new MutationObserver(function(mutationsList, observer) { | |
for(const mutation of mutationsList) { | |
if (mutation.type === 'childList') { | |
for (const tr of mutation.addedNodes) { | |
if(!tr.hasAttribute('data-path')) continue; | |
if(tr.getAttribute('data-path') === currentSong) { | |
tr.classList.add('now_playing'); | |
} | |
else { | |
tr.classList.remove('now_playing'); | |
} | |
} | |
} | |
} | |
}); | |
observer.observe(document.querySelector('#playlist table tbody'), { | |
attributes: false, | |
childList: true, | |
subtree: false | |
}); | |
} | |
function hookShuffle() { | |
if (!window.shuffle || !window.playList || !window.UI) { | |
setTimeout(hookShuffle, 1); | |
return; | |
} | |
window.shuffle.addEventListener('change', () => { | |
localStorage.setItem('shuffle', window.shuffle.checked); | |
}); | |
/* Get LocalStorage Shuffle Value */ | |
const _shuffle_status = localStorage.getItem('shuffle'); | |
if (!!_shuffle_status) { | |
window.shuffle.checked = _shuffle_status === 'true'; | |
window.playList.setCurrentPlayList(window.UI.getShuffleBtnStatus()); | |
} | |
} | |
function inject() { | |
const player_container = document.querySelector('#player .container'); | |
if (!player_container || !window.ChiptuneJsPlayer) { | |
setTimeout(inject, 100); | |
return; | |
} | |
// Add new method to this bad boy | |
window.ChiptuneJsPlayer.prototype.reloadConfig = function(config, processNode) { | |
if (!processNode || !processNode.modulePtr) return; | |
// eslint-disable-next-line | |
_openmpt_module_set_repeat_count(processNode.modulePtr, config.repeatCount); | |
// eslint-disable-next-line | |
_openmpt_module_set_render_param(processNode.modulePtr, OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT, config.stereoSeparation); | |
// eslint-disable-next-line | |
_openmpt_module_set_render_param(processNode.modulePtr, OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH, config.interpolationFilter); | |
}; | |
const old_ChiptuneJsPlayer_play = window.ChiptuneJsPlayer.prototype.play; | |
window.ChiptuneJsPlayer.prototype.play = function(buffer) { | |
old_ChiptuneJsPlayer_play.call(this, buffer); | |
document.querySelector('.seekbar_input').max = Math.floor(window._openmpt_module_get_duration_seconds(window.player.currentPlayingNode.modulePtr)); | |
}; | |
// Hook search | |
hookSearch(); | |
// Hook playlist | |
hookPlaylist(); | |
// Observe loops | |
loopObserver(); | |
// Hook shuffle button | |
hookShuffle(); | |
// Add Loop Button | |
player_container.appendChild(buildLoopButton()); | |
// Add Volume Slider | |
player_container.appendChild(buildVolumeSlider()); | |
// Add Seekbar | |
player_container.appendChild(buildSeekbar()); | |
setInterval(updateGainElement, 10); | |
} | |
setTimeout(inject, 100); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment