DigDig.IO Server Selector

Server selector for digdig.io. Double click to copy, single click to download.

当前为 2021-07-21 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name DigDig.IO Server Selector
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2.8
  5. // @description Server selector for digdig.io. Double click to copy, single click to download.
  6. // @author Zertalious (Zert)
  7. // @match *://digdig.io/*
  8. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  9. // @grant unsafeWindow
  10. // @grant GM_addStyle
  11. // ==/UserScript==
  12.  
  13. GM_addStyle( `
  14.  
  15. body {
  16. margin: 0;
  17. overflow: hidden;
  18. font-family: 'Ubuntu';
  19. text-shadow: 1px 0 #000, -1px 0 #000, 0 1px #000, 0 -1px #000, 1px 1px #000, -1px -1px #000;
  20. color: #fff;
  21. width: 100vw;
  22. height: 100vh;
  23. }
  24.  
  25. .pointer-lock canvas {
  26. pointer-events: none;
  27. }
  28.  
  29. .pointer-lock:after {
  30. content: 'Pointer is locked. Press [X] to unlock.';
  31. position: absolute;
  32. left: 50%;
  33. top: 10px;
  34. transform: translate(-50%, 0);
  35. background: rgb(233 30 30 / 60%);
  36. padding: 2px 5px;
  37. text-shadow: none;
  38. z-index: 999;
  39. }
  40.  
  41. .group {
  42. position: absolute;
  43. right: 15px;
  44. bottom: 15px;
  45. display: flex;
  46. flex-direction: column;
  47. }
  48.  
  49. .group > * {
  50. margin-bottom: 8px;
  51. }
  52.  
  53. .group > *:last-child {
  54. margin-bottom: 0;
  55. }
  56.  
  57. .btn {
  58. background: #aeaeae;
  59. font-size: 2.25em;
  60. text-align: center;
  61. padding: 0.2em;
  62. cursor: pointer;
  63. box-shadow: inset 0 0 0 0.1em rgba(0, 0, 0, 0.25);
  64. border-radius: 0.1em;
  65. position: relative;
  66. user-select: none;
  67. }
  68.  
  69. .btn:before {
  70. content: ' ';
  71. position: absolute;
  72. top: 0.1em;
  73. left: 0.1em;
  74. width: calc(100% - 0.2em);
  75. height: calc(100% - 0.2em);
  76. background: transparent;
  77. }
  78.  
  79. .btn:hover:before {
  80. background: hsla(0, 0%, 100%, 0.25);
  81. }
  82.  
  83. .btn:active:before {
  84. background: rgba(0, 0, 0, 0.1);
  85. }
  86.  
  87. .btn i {
  88. text-shadow: none;
  89. }
  90.  
  91. [tooltip] {
  92. position: relative;
  93. }
  94.  
  95. [tooltip]:after {
  96. content: attr(tooltip);
  97. font-size: 0.9rem;
  98. position: absolute;
  99. right: 100%;
  100. top: 50%;
  101. transform: translate(-10px, -50%);
  102. white-space: nowrap;
  103. pointer-events: none;
  104. background: rgba(0, 0, 0, 0.5);
  105. padding: 0.25em 0.4em;
  106. border-radius: 0.2em;
  107. opacity: 0;
  108. transition: 0.2s;
  109. }
  110.  
  111. [tooltip]:not(.disabled):hover:after {
  112. opacity: 1;
  113. }
  114.  
  115. [tooltip]:is(.force-tooltip):after {
  116. opacity: 1 !important;
  117. }
  118.  
  119. .dialog {
  120. position: absolute;
  121. right: 85px;
  122. bottom: 15px;
  123. background: #aeaeae;
  124. padding: 0.75em;
  125. border-radius: 0.3em;
  126. box-shadow: inset 0 0 0 0.3em rgba(0, 0, 0, 0.25);
  127. width: 300px;
  128. transition: 0.2s;
  129. }
  130.  
  131. .dialog > * {
  132. margin-bottom: 5px;
  133. }
  134.  
  135. .dialog > *:last-child {
  136. margin-bottom: 0;
  137. }
  138.  
  139. .dialog.disabled {
  140. transform: translate(0, calc(100% + 15px));
  141. }
  142.  
  143. .dialog .btn {
  144. font-size: 1.25rem;
  145. background: #bb5555;
  146. }
  147.  
  148. .title {
  149. font-size: 1.5em;
  150. text-align: center;
  151. }
  152.  
  153. .spinner {
  154. margin: 10px auto;
  155. width: 60px;
  156. height: 60px;
  157. border: 10px solid transparent;
  158. border-top-color: rgba(0, 0, 0, 0.3);
  159. border-radius: 50%;
  160. animation: spin 0.5s infinite;
  161. }
  162.  
  163. .option {
  164. background: rgba(0, 0, 0, 0.1);
  165. padding: 0.5em 0.75em;
  166. border-radius: 0.25em;
  167. cursor: pointer;
  168. }
  169.  
  170. .option.active {
  171. box-shadow: inset 0 0 0 0.15em rgba(0, 0, 0, 0.2);
  172. }
  173.  
  174. @keyframes spin {
  175. from {
  176. transform: rotate(0);
  177. }
  178.  
  179. to {
  180. transform: rotate(360deg);
  181. }
  182. }
  183.  
  184. ` );
  185.  
  186. const temp = document.createElement( 'div' );
  187.  
  188. temp.innerHTML += `
  189.  
  190. <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"/>
  191. <div class="group">
  192. <div class="btn leaderboard-btn" tooltip="Capture leaderboard [G]">
  193. <i class="fa fa-trophy"></i>
  194. </div>
  195. <div class="btn screenshot-btn" tooltip="Take screenshot [F]">
  196. <i class="fa fa-camera"></i>
  197. </div>
  198. <div class="btn servers-btn" tooltip="Servers">
  199. <i class="fa fa-globe"></i>
  200. </div>
  201. </div>
  202. <div class="dialog disabled">
  203. <div class="title">Servers</div>
  204. <div class="spinner"></div>
  205. <div class="btn refresh-btn">refresh</div>
  206. <div class="btn close-btn">close</div>
  207. </div>
  208. </div>
  209.  
  210. `;
  211.  
  212. while ( temp.children.length > 0 ) {
  213.  
  214. document.body.appendChild( temp.children[ 0 ] );
  215.  
  216. }
  217.  
  218. temp.innerHTML = '';
  219.  
  220. const spinner = document.querySelector( '.spinner' );
  221.  
  222. let selectedServerId = new URLSearchParams( document.location.search.substring( 1 ) ).get( 'server' );
  223.  
  224. if ( selectedServerId ) {
  225.  
  226. const idFromUrl = selectedServerId;
  227.  
  228. const interval = setInterval( function () {
  229.  
  230. if ( idFromUrl !== selectedServerId ) {
  231.  
  232. clearInterval( interval );
  233.  
  234. }
  235.  
  236. try {
  237.  
  238. connect( idFromUrl );
  239.  
  240. clearInterval( interval );
  241.  
  242. } catch ( e ) { }
  243.  
  244. }, 50 );
  245.  
  246. }
  247.  
  248. ( async function () {
  249.  
  250. await fetchServers( 'ffa' );
  251. await fetchServers( 'teams' );
  252.  
  253. spinner.style.display = 'none';
  254.  
  255. } )();
  256.  
  257. const serverIds = {};
  258.  
  259. const refreshBtn = document.querySelector( '.refresh-btn' );
  260.  
  261. async function fetchServers( mode ) {
  262.  
  263. const response = await fetch( 'https://api.n.m28.io/endpoint/digdig-' + mode + '/findEach' );
  264. const json = await response.json();
  265.  
  266. for ( let key in json.servers ) {
  267.  
  268. const id = json.servers[ key ].id;
  269.  
  270. if ( ! serverIds[ id ] ) {
  271.  
  272. serverIds[ id ] = true;
  273.  
  274. const div = document.createElement( 'div' );
  275. div.classList.add( 'option' );
  276. div.innerHTML = mode + '_' + key.split( '-' )[ 1 ] + '_' + id;
  277. div.setAttribute( 'data-id', id );
  278.  
  279. dialog.insertBefore( div, refreshBtn );
  280.  
  281. div.onclick = function () {
  282.  
  283. connect( id );
  284.  
  285. }
  286.  
  287. if ( ! selectedServerId || selectedServerId === id ) {
  288.  
  289. div.click();
  290.  
  291. }
  292.  
  293. }
  294.  
  295. }
  296.  
  297. }
  298.  
  299. function connect( id ) {
  300.  
  301. selectedServerId = id;
  302.  
  303. cp6.forceServerID( selectedServerId );
  304.  
  305. onServerChange();
  306. }
  307.  
  308. unsafeWindow.console.log = new Proxy( unsafeWindow.console.log, {
  309. apply( target, thisArgs, [ text ] ) {
  310.  
  311. if ( typeof text === 'string' && text.startsWith( 'Connecting to ' ) ) {
  312.  
  313. const id = text.split('Connecting to ')[ 1 ].split( '.' )[ 0 ];
  314.  
  315. if ( id !== selectedServerId ) {
  316.  
  317. selectedServerId = id;
  318.  
  319. onServerChange();
  320.  
  321. }
  322.  
  323. }
  324.  
  325. return Reflect.apply( ...arguments );
  326.  
  327. }
  328. } );
  329.  
  330. function onServerChange() {
  331.  
  332. const url = new URL( window.location );
  333. url.searchParams.set( 'server', selectedServerId );
  334.  
  335. history.pushState( {}, document.title, url );
  336.  
  337. const active = document.querySelector( '.option.active' );
  338.  
  339. if ( active ) {
  340.  
  341. active.classList.remove( 'active' );
  342.  
  343. }
  344.  
  345. const option = document.querySelector( '[data-id="' + selectedServerId + '"]' );
  346.  
  347. if ( option ) {
  348.  
  349. option.classList.add( 'active' );
  350.  
  351. }
  352.  
  353. }
  354.  
  355. const dialog = document.querySelector( '.dialog' );
  356. const serversBtn = document.querySelector( '.servers-btn' );
  357.  
  358. serversBtn.onclick = function () {
  359.  
  360. if ( dialog.classList.contains( 'disabled' ) ) {
  361.  
  362. dialog.classList.remove( 'disabled' );
  363. this.classList.add( 'disabled' );
  364.  
  365. } else {
  366.  
  367. hideDialog();
  368.  
  369. }
  370.  
  371. }
  372.  
  373. document.body.onclick = function ( event ) {
  374.  
  375. if ( [ 'canvas', 'loading' ].indexOf( event.target.id ) > - 1 || event.target === this ) {
  376.  
  377. hideDialog();
  378.  
  379. }
  380.  
  381. }
  382.  
  383. document.querySelector( '.close-btn' ).onclick = hideDialog;
  384.  
  385. refreshBtn.onclick = async function () {
  386.  
  387. spinner.style.display = '';
  388.  
  389. await fetchServers( 'ffa' );
  390. await fetchServers( 'teams' );
  391.  
  392. spinner.style.display = 'none';
  393.  
  394. };
  395.  
  396. function hideDialog() {
  397.  
  398. dialog.classList.add( 'disabled' );
  399. serversBtn.classList.remove( 'disabled' );
  400.  
  401. }
  402.  
  403. function createClickListener( a, b ) {
  404.  
  405. let clicks = 0;
  406.  
  407. return function () {
  408.  
  409. clicks ++;
  410.  
  411. setTimeout( function () {
  412.  
  413. if ( clicks === 1 ) {
  414.  
  415. a();
  416.  
  417. }
  418.  
  419. clicks = 0;
  420.  
  421. }, 300 );
  422.  
  423. if ( clicks === 2 ) {
  424.  
  425. b();
  426.  
  427. }
  428.  
  429. }
  430.  
  431. }
  432.  
  433. const screenshotBtn = document.querySelector( '.screenshot-btn' );
  434. const leaderboardBtn = document.querySelector( '.leaderboard-btn' );
  435.  
  436. const displayCopiedScreenshot = createCopiedDisplayer( screenshotBtn );
  437. const displayCopiedLeaderboard = createCopiedDisplayer( leaderboardBtn );
  438.  
  439. screenshotBtn.onclick = createClickListener(
  440. function () {
  441.  
  442. downloadCanvas( document.querySelector( 'canvas' ), 'digdig' );
  443.  
  444. },
  445. copyScreenshot
  446. );
  447.  
  448. leaderboardBtn.onclick = createClickListener(
  449. function () {
  450.  
  451. if ( leaderboard ) {
  452.  
  453. downloadCanvas( getLeaderboardCanvas(), 'digdig_leaderboard' );
  454.  
  455. }
  456.  
  457. },
  458. copyLeaderboard
  459. );
  460.  
  461. function copyScreenshot() {
  462.  
  463. copyCanvasToClipboard( document.querySelector( 'canvas' ) );
  464.  
  465. displayCopiedScreenshot();
  466.  
  467. }
  468.  
  469. function copyLeaderboard() {
  470.  
  471. if ( leaderboard ) {
  472.  
  473. copyCanvasToClipboard( getLeaderboardCanvas() );
  474.  
  475. displayCopiedLeaderboard();
  476.  
  477. }
  478.  
  479. }
  480.  
  481. window.addEventListener( 'keyup', function ( event ) {
  482.  
  483. const key = String.fromCharCode( event.keyCode );
  484.  
  485. if ( key === 'F' ) {
  486.  
  487. copyScreenshot();
  488.  
  489. } else if ( key === 'G' ) {
  490.  
  491. copyLeaderboard();
  492.  
  493. } else if ( key === 'X' ) {
  494.  
  495. document.body.classList.toggle( 'pointer-lock' );
  496.  
  497. }
  498.  
  499. } );
  500.  
  501. function createCopiedDisplayer( element ) {
  502.  
  503. let old, timeout;
  504.  
  505. return function () {
  506.  
  507. if ( element.classList.contains( 'force-tooltip' ) ) {
  508.  
  509. clearTimeout( timeout );
  510.  
  511. } else {
  512.  
  513. old = element.getAttribute( 'tooltip' );
  514. element.setAttribute( 'tooltip', 'Copied!' );
  515. element.classList.add( 'force-tooltip' );
  516.  
  517. }
  518.  
  519. timeout = setTimeout( function () {
  520.  
  521. element.setAttribute( 'tooltip', old );
  522. element.classList.remove( 'force-tooltip' );
  523.  
  524. }, 1000 );
  525.  
  526. }
  527.  
  528. }
  529.  
  530.  
  531. function getLeaderboardCanvas() {
  532.  
  533. const offset = - 115 * 0.8 * 0;
  534.  
  535. const canvas = document.createElement( 'canvas' );
  536. canvas.width = leaderboard.width;
  537. canvas.height = leaderboard.height + offset;
  538.  
  539. canvas.getContext( '2d' ).drawImage( leaderboard, 0, offset );
  540.  
  541. return canvas;
  542.  
  543. }
  544.  
  545. function copyCanvasToClipboard( canvas ) {
  546.  
  547. canvas.toBlob( function ( blob ) {
  548.  
  549. navigator.clipboard.write( [ new ClipboardItem( { 'image/png': blob } ) ] );
  550.  
  551. } );
  552.  
  553. }
  554.  
  555. function downloadCanvas( canvas, filename ) {
  556.  
  557. const a = document.createElement( 'a' );
  558.  
  559. a.href = canvas.toDataURL();
  560. a.download = filename + '_' + Date.now() + '.png';
  561.  
  562. a.click();
  563.  
  564. }
  565.  
  566. let leaderboard;
  567. let leaderboardPartial;
  568.  
  569. const Canvas = unsafeWindow.OffscreenCanvas ? unsafeWindow.OffscreenCanvas.prototype : unsafeWindow.HTMLCanvasElement.prototype;
  570.  
  571. Canvas.getContext = new Proxy( Canvas.getContext, {
  572. apply() {
  573.  
  574. const ctx = Reflect.apply( ...arguments );
  575.  
  576. ctx.fillText = new Proxy( ctx.fillText, {
  577. apply( target, thisArgs, args ) {
  578.  
  579. if ( args[ 0 ].indexOf( 'Diggers' ) > - 1 ) {
  580.  
  581. leaderboardPartial = ctx.canvas;
  582.  
  583. }
  584.  
  585. return Reflect.apply( ...arguments );
  586.  
  587. }
  588. } );
  589.  
  590. ctx.drawImage = new Proxy( ctx.drawImage, {
  591. apply( target, thisArgs, args ) {
  592.  
  593. if ( args[ 0 ] === leaderboardPartial ) {
  594.  
  595. leaderboard = ctx.canvas;
  596.  
  597. }
  598.  
  599. return Reflect.apply( ...arguments );
  600.  
  601. }
  602. } );
  603.  
  604. return ctx;
  605.  
  606. }
  607. } )

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址