- // ==UserScript==
- // @name DigDig.IO Server Selector
- // @namespace http://tampermonkey.net/
- // @version 0.2.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
- // ==/UserScript==
-
- const gameSockets = [];
-
- let lastServerGameTriedConnectingTo;
-
- unsafeWindow.console.log = new Proxy( unsafeWindow.console.log, {
- apply( target, thisArgs, args ) {
-
- const x = args[ 0 ];
-
- if ( ! lastServerGameTriedConnectingTo && typeof x === 'string' && x.startsWith( 'Connecting to ' ) ) {
-
- lastServerGameTriedConnectingTo = x.slice( 0, x.indexOf( '.' ) ).split( ' ' )[ 2 ];
-
- }
-
- return Reflect.apply( ...arguments );
-
- }
- } );
-
- unsafeWindow.WebSocket = new Proxy( unsafeWindow.WebSocket, {
- construct( target, args ) {
-
- const isGameSocket = args[ 0 ].endsWith( ':443' );
-
- if ( isGameSocket && selectedServerId ) {
-
- const url = new URL( args[ 0 ] );
-
- const items = url.hostname.split( '.' );
-
- if ( items[ 0 ] !== selectedServerId ) {
-
- if ( lastServerGameTriedConnectingTo === items[ 0 ] ) {
-
- console.log( '[SERVER SELECTOR] Overriding...', { from: items[ 0 ], to: selectedServerId } );
-
- items[ 0 ] = selectedServerId;
-
- url.hostname = items.join( '.' );
-
- args[ 0 ] = url.toString();
-
- } else {
-
- console.log( '[SERVER SELETOR] Internal server switch! Updating selected server...', { from: selectedServerId, to: items[ 0 ] } );
-
- lastServerGameTriedConnectingTo = items[ 0 ];
-
- setSelectedServerId( items[ 0 ] );
-
- }
-
- }
-
- }
-
- const socket = Reflect.construct( ...arguments );
-
- if ( isGameSocket ) {
-
- gameSockets.push( socket );
-
- }
-
- return socket;
-
- }
- } );
-
- function reconnect() {
-
- while ( gameSockets.length > 0 ) {
-
- try {
-
- gameSockets.shift().close();
-
- } catch ( err ) {}
-
- }
-
- }
-
- GM_addStyle( `
-
- body {
- margin: 0;
- overflow: hidden;
- background: #744100;
- font-family: 'Ubuntu';
- text-shadow: 1px 0 #000, -1px 0 #000, 0 1px #000, 0 -1px #000, 1px 1px #000, -1px -1px #000;
- }
-
- .group {
- position: absolute;
- right: 15px;
- bottom: 15px;
- display: flex;
- flex-direction: column;
- }
-
- .group > * {
- margin-bottom: 8px;
- }
-
- .group > *:last-child {
- margin-bottom: 0;
- }
-
- .btn {
- color: #fff;
- 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;
- }
-
- [tooltip]:not(.disabled):hover:after {
- opacity: 1;
- }
-
- [tooltip]:is(.force-tooltip):after {
- opacity: 1 !important;
- }
-
- .dialog {
- position: absolute;
- right: 85px;
- bottom: 15px;
- color: #fff;
- 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 += `
-
- <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"/>
- <div class="group">
- <div class="btn leaderboard-btn" tooltip="Capture leaderboard [G]">
- <i class="fa fa-trophy"></i>
- </div>
- <div class="btn screenshot-btn" tooltip="Take screenshot [F]">
- <i class="fa fa-camera"></i>
- </div>
- <div class="btn servers-btn" tooltip="Servers">
- <i class="fa fa-globe"></i>
- </div>
- </div>
- <div class="dialog disabled">
- <div class="title">Servers</div>
- <div class="spinner"></div>
- <div class="btn close-btn">close</div>
- <div class="btn refresh-btn">refresh</div>
- </div>
- </div>
-
- `;
-
- while ( temp.children.length > 0 ) {
-
- document.body.appendChild( temp.children[ 0 ] );
-
- }
-
- temp.innerHTML = '';
-
- const spinner = document.querySelector( '.spinner' );
-
- ( async function () {
-
- await fetchServers( 'ffa' );
- await fetchServers( 'teams' );
-
- spinner.style.display = 'none';
-
- } )();
-
- const serverIds = {};
-
- let selectedServerId = new URLSearchParams( document.location.search.substring( 1 ) ).get( 'server' );
-
- if ( selectedServerId ) {
-
- reconnect();
-
- }
-
- 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 ] = mode;
-
- const div = document.createElement( 'div' );
- div.classList.add( 'option' );
- div.innerHTML = mode + '_' + key.split( '-' )[ 1 ] + '_' + id;
- div.setAttribute( 'data-id', id );
-
- dialog.appendChild( div );
-
- div.onclick = function () {
-
- setSelectedServerId( id );
-
- reconnect();
-
- }
-
- if ( ! selectedServerId ) {
-
- div.click();
-
- } else if ( selectedServerId === id ) {
-
- div.click();
-
- }
-
- }
-
- }
-
- }
-
- function setSelectedServerId( id ) {
-
- selectedServerId = id;
-
- 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="' + id + '"]' );
-
- 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.getElementById( 'canvas' ).onclick = hideDialog;
- document.querySelector( '.close-btn' ).onclick = hideDialog;
-
- document.querySelector( '.refresh-btn' ).onclick = async function () {
-
- spinner.style.display = '';
-
- await fetchServers( 'ffa' );
- await fetchServers( 'teams' );
-
- spinner.style.display = 'none';
-
- };
-
- 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();
-
- }
-
- } );
-
- 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;
-
- 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;
-
- }
- } )