// ==UserScript== // @name DigDig.IO Server Selector // @namespace http://tampermonkey.net/ // @version 0.3.3 // @description Server selector for digdig.io. Double click to copy, single click to download. // @author Zertalious (Zert) // @match *://digdig.io/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant unsafeWindow // @grant GM_addStyle // @downloadURL https://update.greasyfork.cloud/scripts/428987/DigDigIO%20Server%20Selector.user.js // @updateURL https://update.greasyfork.cloud/scripts/428987/DigDigIO%20Server%20Selector.meta.js // ==/UserScript== unsafeWindow.Image = new Proxy( unsafeWindow.Image, { construct( target, thisArgs, args ) { const result = Reflect.construct( ...arguments ); result.crossOrigin = 'anonymous'; return result; } } ); GM_addStyle( ` body { margin: 0; overflow: hidden; font-family: 'Ubuntu'; text-shadow: 1px 0 #000, -1px 0 #000, 0 1px #000, 0 -1px #000, 1px 1px #000, -1px -1px #000; color: #fff; width: 100vw; height: 100vh; } .pointer-lock canvas { pointer-events: none; } .pointer-lock:after { content: 'Pointer is locked. Press [X] to unlock.'; position: absolute; left: 50%; top: 10px; transform: translate(-50%, 0); background: rgb(233 30 30 / 60%); padding: 2px 5px; text-shadow: none; z-index: 999; } .group { position: absolute; right: 15px; bottom: 15px; display: flex; flex-direction: column; } .group > * { margin-bottom: 8px; } .group > *:last-child { margin-bottom: 0; } .btn { background: #aeaeae; font-size: 2.25em; text-align: center; padding: 0.2em; cursor: pointer; box-shadow: inset 0 0 0 0.1em rgba(0, 0, 0, 0.25); border-radius: 0.1em; position: relative; user-select: none; } .btn:before { content: ' '; position: absolute; top: 0.1em; left: 0.1em; width: calc(100% - 0.2em); height: calc(100% - 0.2em); background: transparent; } .btn:hover:before { background: hsla(0, 0%, 100%, 0.25); } .btn:active:before { background: rgba(0, 0, 0, 0.1); } .btn i { text-shadow: none; } [tooltip] { position: relative; } [tooltip]:after { content: attr(tooltip); font-size: 0.9rem; position: absolute; right: 100%; top: 50%; transform: translate(-10px, -50%); white-space: nowrap; pointer-events: none; background: rgba(0, 0, 0, 0.5); padding: 0.25em 0.4em; border-radius: 0.2em; opacity: 0; transition: 0.2s; z-index: 999; } [tooltip]:not(.disabled):hover:after { opacity: 1; } [tooltip]:is(.force-tooltip):after { opacity: 1 !important; } .dialog { position: absolute; right: 85px; bottom: 15px; background: #aeaeae; padding: 0.75em; border-radius: 0.3em; box-shadow: inset 0 0 0 0.3em rgba(0, 0, 0, 0.25); width: 300px; transition: 0.2s; } .dialog > * { margin-bottom: 5px; } .dialog > *:last-child { margin-bottom: 0; } .dialog.disabled { transform: translate(0, calc(100% + 15px)); } .dialog .btn { font-size: 1.25rem; background: #bb5555; } .title { font-size: 1.5em; text-align: center; } .spinner { margin: 10px auto; width: 60px; height: 60px; border: 10px solid transparent; border-top-color: rgba(0, 0, 0, 0.3); border-radius: 50%; animation: spin 0.5s infinite; } .option { background: rgba(0, 0, 0, 0.1); padding: 0.5em 0.75em; border-radius: 0.25em; cursor: pointer; } .option.active { box-shadow: inset 0 0 0 0.15em rgba(0, 0, 0, 0.2); } @keyframes spin { from { transform: rotate(0); } to { transform: rotate(360deg); } } ` ); const temp = document.createElement( 'div' ); temp.innerHTML += `
Servers
refresh
close
`; while ( temp.children.length > 0 ) { document.body.appendChild( temp.children[ 0 ] ); } temp.innerHTML = ''; const spinner = document.querySelector( '.spinner' ); let selectedServerId = new URLSearchParams( document.location.search.substring( 1 ) ).get( 'server' ); if ( selectedServerId ) { const idFromUrl = selectedServerId; const interval = setInterval( function () { if ( idFromUrl !== selectedServerId ) { clearInterval( interval ); } try { connect( idFromUrl ); clearInterval( interval ); } catch ( e ) { } }, 50 ); } fetchAll(); async function fetchAll() { spinner.style.display = ''; await fetchServers( 'ffa' ); await fetchServers( 'teams' ); await fetchServers( 'tag' ); await fetchServers( 'br' ); await fetchServers( 'maze' ); spinner.style.display = 'none'; } const serverIds = {}; const refreshBtn = document.querySelector( '.refresh-btn' ); async function fetchServers( mode ) { const response = await fetch( 'https://api.n.m28.io/endpoint/digdig-' + mode + '/findEach' ); const json = await response.json(); for ( let key in json.servers ) { const id = json.servers[ key ].id; if ( ! serverIds[ id ] ) { serverIds[ id ] = true; const div = document.createElement( 'div' ); div.classList.add( 'option' ); div.innerHTML = mode + '_' + key.split( '-' )[ 1 ] + '_' + id; div.setAttribute( 'data-id', id ); dialog.insertBefore( div, refreshBtn ); div.onclick = function () { connect( id ); } if ( selectedServerId === id ) { div.click(); } } } } function connect( id ) { selectedServerId = id; cp6.forceServerID( selectedServerId ); onServerChange(); } unsafeWindow.console.log = new Proxy( unsafeWindow.console.log, { apply( target, thisArgs, [ text ] ) { if ( typeof text === 'string' && text.startsWith( 'Connecting to ' ) ) { const id = text.split('Connecting to ')[ 1 ].split( '.' )[ 0 ]; if ( id !== selectedServerId ) { selectedServerId = id; onServerChange(); } } return Reflect.apply( ...arguments ); } } ); function onServerChange() { const url = new URL( window.location ); url.searchParams.set( 'server', selectedServerId ); history.pushState( {}, document.title, url ); const active = document.querySelector( '.option.active' ); if ( active ) { active.classList.remove( 'active' ); } const option = document.querySelector( '[data-id="' + selectedServerId + '"]' ); if ( option ) { option.classList.add( 'active' ); } } const dialog = document.querySelector( '.dialog' ); const serversBtn = document.querySelector( '.servers-btn' ); serversBtn.onclick = function () { if ( dialog.classList.contains( 'disabled' ) ) { dialog.classList.remove( 'disabled' ); this.classList.add( 'disabled' ); } else { hideDialog(); } } document.body.onclick = function ( event ) { if ( [ 'canvas', 'loading' ].indexOf( event.target.id ) > - 1 || event.target === this ) { hideDialog(); } } document.querySelector( '.close-btn' ).onclick = hideDialog; refreshBtn.onclick = fetchAll; function hideDialog() { dialog.classList.add( 'disabled' ); serversBtn.classList.remove( 'disabled' ); } function createClickListener( a, b ) { let clicks = 0; return function () { clicks ++; setTimeout( function () { if ( clicks === 1 ) { a(); } clicks = 0; }, 300 ); if ( clicks === 2 ) { b(); } } } const screenshotBtn = document.querySelector( '.screenshot-btn' ); const leaderboardBtn = document.querySelector( '.leaderboard-btn' ); const displayCopiedScreenshot = createCopiedDisplayer( screenshotBtn ); const displayCopiedLeaderboard = createCopiedDisplayer( leaderboardBtn ); screenshotBtn.onclick = createClickListener( function () { downloadCanvas( document.querySelector( 'canvas' ), 'digdig' ); }, copyScreenshot ); leaderboardBtn.onclick = createClickListener( function () { if ( leaderboard ) { downloadCanvas( getLeaderboardCanvas(), 'digdig_leaderboard' ); } }, copyLeaderboard ); function copyScreenshot() { copyCanvasToClipboard( document.querySelector( 'canvas' ) ); displayCopiedScreenshot(); } function copyLeaderboard() { if ( leaderboard ) { copyCanvasToClipboard( getLeaderboardCanvas() ); displayCopiedLeaderboard(); } } window.addEventListener( 'keyup', function ( event ) { const key = String.fromCharCode( event.keyCode ); if ( key === 'F' ) { copyScreenshot(); } else if ( key === 'G' ) { copyLeaderboard(); } else if ( key === 'X' ) { document.body.classList.toggle( 'pointer-lock' ); } } ); function createCopiedDisplayer( element ) { let old, timeout; return function () { if ( element.classList.contains( 'force-tooltip' ) ) { clearTimeout( timeout ); } else { old = element.getAttribute( 'tooltip' ); element.setAttribute( 'tooltip', 'Copied!' ); element.classList.add( 'force-tooltip' ); } timeout = setTimeout( function () { element.setAttribute( 'tooltip', old ); element.classList.remove( 'force-tooltip' ); }, 1000 ); } } function getLeaderboardCanvas() { const offset = - 115 * 0.8 * 0; const canvas = document.createElement( 'canvas' ); canvas.width = leaderboard.width; canvas.height = leaderboard.height + offset; canvas.getContext( '2d' ).drawImage( leaderboard, 0, offset ); return canvas; } function copyCanvasToClipboard( canvas ) { canvas.toBlob( function ( blob ) { navigator.clipboard.write( [ new ClipboardItem( { 'image/png': blob } ) ] ); } ); } function downloadCanvas( canvas, filename ) { const a = document.createElement( 'a' ); a.href = canvas.toDataURL(); a.download = filename + '_' + Date.now() + '.png'; a.click(); } let leaderboard; let leaderboardPartial; const Canvas = unsafeWindow.OffscreenCanvas ? unsafeWindow.OffscreenCanvas.prototype : unsafeWindow.HTMLCanvasElement.prototype; Canvas.getContext = new Proxy( Canvas.getContext, { apply() { const ctx = Reflect.apply( ...arguments ); ctx.fillText = new Proxy( ctx.fillText, { apply( target, thisArgs, args ) { if ( args[ 0 ].indexOf( 'Diggers' ) > - 1 ) { leaderboardPartial = ctx.canvas; } return Reflect.apply( ...arguments ); } } ); ctx.drawImage = new Proxy( ctx.drawImage, { apply( target, thisArgs, args ) { if ( args[ 0 ] === leaderboardPartial ) { leaderboard = ctx.canvas; } return Reflect.apply( ...arguments ); } } ); return ctx; } } )