Guest User

NAI Card Data Shower

a guest
Aug 18th, 2021
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name        Card Data
  3. // @namespace   Violentmonkey Scripts
  4. // @match       *://*/*
  5. // @grant       none
  6. // @version     1.0
  7. // @author      me :)
  8. // @description 8/17/2021, 5:50:10 PM
  9. // @require https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js
  10. // @grant GM_xmlhttpRequest
  11. // ==/UserScript==
  12.  
  13. // Card Data Shower: This script shows a box of the json data for an NAI card
  14. // Hover over the card and press control to make the box appear
  15. // Hover over the box and press shift to make the box go away
  16. // Double click on the box to copy the json
  17.  
  18.  
  19. // things you might want to change
  20. const triggerKey = 17; // 17 is control
  21. const closeKey   = 16; // 16 is shift
  22. const boxWidth  = "800px";
  23. const boxHeight = "600px";
  24. const boxMargin = "-300px 0 0 -400px";
  25. const fontSize  = "0.7em";
  26.  
  27. // other constants
  28. const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10];
  29. const chunkSignature = [116, 69, 88, 116];
  30. const chunkStart = 33; // beginning of the NAI data chunk
  31. const typeStart = chunkStart + 4;
  32. const dataStart = chunkStart + 8;
  33.  
  34.  
  35. jQuery.noConflict();
  36. jQuery( document ).ready(function( $ ) {
  37.   var source; // identifying images by src
  38.  
  39.   // styles
  40.   $("head").append(`
  41.     <style>
  42.     #follow {
  43.       position: fixed;
  44.       z-index: 100;
  45.       top: 50%;
  46.       left: 50%;
  47.       margin: ${boxMargin};
  48.       width: ${boxWidth};  
  49.       height: ${boxHeight};
  50.       background-color: white;
  51.       overflow: auto;
  52.       border-style: solid;
  53.       border-width: 3px;  
  54.     }
  55.  
  56.     #jsonData {
  57.       font-size: ${fontSize};
  58.     }
  59.  
  60.     #copyIndicator {
  61.       opacity: 0;
  62.       color: red;
  63.     }
  64.     </style>
  65.   `);
  66.  
  67.  
  68.   // wait until new images appear
  69.   waitForKeyElements ("img[cardEvent!='set']", function() {
  70.    
  71.     $("img[cardEvent!='set']").on("mouseover",function() {
  72.       source = this.src;
  73.      
  74.       if (source[0] == '/') {
  75.         source = "https:" + source;
  76.       }  
  77.      
  78.       $(document).on("keydown",function(e) {
  79.         if (e.keyCode == triggerKey) {          
  80.           getImageData(source);
  81.         }
  82.       });  
  83.     }).on("mouseleave",function() {
  84.       $(document).off("keydown");
  85.     });
  86.  
  87.     $("img").attr("cardEvent","set"); // stops repeated event assignment(?)
  88.   });
  89.  
  90.   // Gets the data from the card and writes
  91.   function getImageData(image) {
  92.     return GM_xmlhttpRequest({
  93.       method: "GET",
  94.       url: image,
  95.       responseType: "arraybuffer",
  96.       onloadend: function(responseObject) {
  97.         const byteArray = new Uint8Array(responseObject.response);
  98.         if (arraysEqual(byteArray.slice(0,8), pngSignature) && arraysEqual(byteArray.slice(typeStart,typeStart+4), chunkSignature)) {
  99.           console.log("Good");
  100.           $("#follow").remove();
  101.           let dataLength = getLength(byteArray.slice(chunkStart,chunkStart + 4));
  102.           jsonData = atob(String.fromCharCode(...byteArray.slice(dataStart + 8, dataStart+dataLength)));
  103.           $("body").prepend("<div id='follow'></div>");
  104.           $("#follow").prepend(`<p id='jsonData'> ${jsonData} <p>`);
  105.           $("#follow").append(`<p id='copyIndicator'>Copied</p>`);
  106.          
  107.           followEvents();
  108.         }
  109.       }
  110.     });  
  111.   }
  112.  
  113.   // Reads the 4 bytes as given in decimal and returns proper value for data length
  114.   function getLength(lengthBytes) {
  115.     var total = 0;
  116.     for (let i = 0; i < lengthBytes.length; i++) {
  117.       total += lengthBytes[i] * (256**(lengthBytes.length - i - 1));
  118.     }
  119.     return total;
  120.   }
  121.  
  122.   // sets the event handlers for the infobox
  123.   function followEvents() {
  124.     $("#follow").on("mouseover", function() {
  125.      
  126.       $(document).on("keydown",function(e) {
  127.         if (e.keyCode == closeKey) {          
  128.           $("#follow").remove();
  129.         }
  130.       });
  131.    
  132.     }).on("mouseleave", function() {
  133.       $(document).off("keydown");
  134.    
  135.     }).on("dblclick", function() {
  136.       navigator.clipboard.writeText($("#jsonData").text());
  137.       $("#copyIndicator").css("opacity", 1);
  138.       $("#copyIndicator").fadeTo("slow", 0);
  139.     });
  140.   }
  141.  
  142.   // checks if two (ordered) arrays are equal
  143.   function arraysEqual(a, b) {
  144.     if (a === b) return true;
  145.     if (a == null || b == null) return false;
  146.     if (a.length !== b.length) return false;
  147.    
  148.     for (var i = 0; i < a.length; ++i) {
  149.       if (a[i] !== b[i]) return false;
  150.     }
  151.     return true;
  152.   }
  153.    
  154.   // Gotten from https://gist.github.com/BrockA/2625891 ; for handling ajax stuff
  155.   function waitForKeyElements (
  156.     selectorTxt,    /* Required: The jQuery selector string that
  157.                         specifies the desired element(s).
  158.                     */
  159.     actionFunction, /* Required: The code to run when elements are
  160.                         found. It is passed a jNode to the matched
  161.                         element.
  162.                     */
  163.     bWaitOnce,      /* Optional: If false, will continue to scan for
  164.                         new elements even after the first match is
  165.                         found.
  166.                     */
  167.     iframeSelector  /* Optional: If set, identifies the iframe to
  168.                         search.
  169.                     */
  170.   ) {
  171.     var targetNodes, btargetsFound;
  172.  
  173.     if (typeof iframeSelector == "undefined")
  174.         targetNodes     = $(selectorTxt);
  175.     else
  176.         targetNodes     = $(iframeSelector).contents ()
  177.                                            .find (selectorTxt);
  178.  
  179.     if (targetNodes  &&  targetNodes.length > 0) {
  180.         btargetsFound   = true;
  181.         /*--- Found target node(s).  Go through each and act if they
  182.             are new.
  183.         */
  184.         targetNodes.each ( function () {
  185.             var jThis        = $(this);
  186.             var alreadyFound = jThis.data ('alreadyFound')  ||  false;
  187.  
  188.             if (!alreadyFound) {
  189.                 //--- Call the payload function.
  190.                 var cancelFound     = actionFunction (jThis);
  191.                 if (cancelFound)
  192.                     btargetsFound   = false;
  193.                 else
  194.                     jThis.data ('alreadyFound', true);
  195.             }
  196.         } );
  197.     }
  198.     else {
  199.         btargetsFound   = false;
  200.     }
  201.  
  202.     //--- Get the timer-control variable for this selector.
  203.     var controlObj      = waitForKeyElements.controlObj  ||  {};
  204.     var controlKey      = selectorTxt.replace (/[^\w]/g, "_");
  205.     var timeControl     = controlObj [controlKey];
  206.  
  207.     //--- Now set or clear the timer as appropriate.
  208.     if (btargetsFound  &&  bWaitOnce  &&  timeControl) {
  209.         //--- The only condition where we need to clear the timer.
  210.         clearInterval (timeControl);
  211.         delete controlObj [controlKey]
  212.     }
  213.     else {
  214.         //--- Set a timer, if needed.
  215.         if ( ! timeControl) {
  216.             timeControl = setInterval ( function () {
  217.                     waitForKeyElements (    selectorTxt,
  218.                                             actionFunction,
  219.                                             bWaitOnce,
  220.                                             iframeSelector
  221.                                         );
  222.                 },
  223.                 300
  224.             );
  225.             controlObj [controlKey] = timeControl;
  226.         }
  227.     }
  228.     waitForKeyElements.controlObj   = controlObj;
  229. }
  230.  
  231. });
  232.  
Advertisement
Add Comment
Please, Sign In to add comment