Zero_G

4chan External Sounds with support for yuki.la

Jan 30th, 2021
798
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name 4chan External Sounds
  3. // @namespace b4k
  4. // @description Plays audio associated with images on 4chan.
  5. // @author Bakugo
  6. // @version 1.7.0
  7. // @match *://boards.4chan.org/*
  8. // @match *://boards.4channel.org/*
  9. // @include     *://yuki.la/*
  10. // @run-at document-start
  11. // @grant       none
  12. // ==/UserScript==
  13.  
  14. (function() {
  15.     var doInit;
  16.     var doParseFile;
  17.     var doParseFiles;
  18.     var doPlayFile;
  19.     var doMakeKey;
  20.    
  21.     var allow;
  22.     var players;
  23.     var isChanX;
  24.    
  25.     allow = [
  26.         "4cdn.org",
  27.         "catbox.moe",
  28.         "dmca.gripe",
  29.         "lewd.se",
  30.         "pomf.cat",
  31.         "zz.ht"
  32.     ];
  33.    
  34.     document.addEventListener(
  35.         "DOMContentLoaded",
  36.         function (event) {
  37.             setTimeout(
  38.                 function () {
  39.                     if (
  40.                         document.body.classList.contains("ws") ||
  41.                         document.body.classList.contains("nws")
  42.                     ) {
  43.                         isChanX = false;
  44.                         doInit();
  45.                     }
  46.                 },
  47.                 (1)
  48.             );
  49.         }
  50.     );
  51.    
  52.     document.addEventListener(
  53.         "4chanXInitFinished",
  54.         function (event) {
  55.             if (
  56.                 document.documentElement.classList.contains("fourchan-x") &&
  57.                 document.documentElement.classList.contains("sw-yotsuba")
  58.             ) {
  59.                 isChanX = true;
  60.                 doInit();
  61.             }
  62.         }
  63.     );
  64.    
  65.     doInit = function () {
  66.         var observer;
  67.        
  68.         if (players) {
  69.             return;
  70.         }
  71.        
  72.         players = {};
  73.        
  74.         doParseFiles(document.body);
  75.        
  76.         observer =
  77.             new MutationObserver(
  78.                 function (mutations) {
  79.                     mutations.forEach(
  80.                         function (mutation) {
  81.                             if (mutation.type === "childList") {
  82.                                 mutation.addedNodes.forEach(
  83.                                     function (node) {
  84.                                         if (node.nodeType === Node.ELEMENT_NODE) {
  85.                                             doParseFiles(node);
  86.                                             doPlayFile(node);
  87.                                         }
  88.                                     }
  89.                                 );
  90.                             }
  91.                         }
  92.                     );
  93.                 }
  94.             );
  95.        
  96.         observer
  97.             .observe(
  98.                 document.body,
  99.                 {
  100.                     childList: true,
  101.                     subtree: true
  102.                 }
  103.             );
  104.     };
  105.    
  106.     doParseFile = function (file) {
  107.         var fileLink;
  108.         var fileName;
  109.         var key;
  110.         var match;
  111.         var player;
  112.         var link;
  113.        
  114.         if (!file.classList.contains("file")) {
  115.             return;
  116.         }
  117.        
  118.         if (isChanX) {
  119.             fileLink = file.querySelector(".fileText .file-info > a");
  120.         } else {
  121.             fileLink = file.querySelector(".fileText > a");
  122.         }
  123.        
  124.         if (!fileLink) {
  125.             return;
  126.         }
  127.        
  128.         if (!fileLink.href) {
  129.             return;
  130.         }
  131.        
  132.         fileName = null;
  133.        
  134.         if (isChanX) {
  135.             [
  136.                 file.querySelector(".fileText .file-info .fnfull"),
  137.                 file.querySelector(".fileText .file-info > a")
  138.             ].some(
  139.                 function (node) {
  140.                     if (node) {
  141.                         if (node.textContent) {
  142.                             fileName = node.textContent;
  143.                             return true;
  144.                         }
  145.                     }
  146.                    
  147.                     return false;
  148.                 }
  149.             );
  150.         } else {
  151.             [
  152.                 file.querySelector(".fileText"),
  153.                 file.querySelector(".fileText > a")
  154.             ].some(
  155.                 function (node) {
  156.                     if (node) {
  157.                         if (node.title) {
  158.                             fileName = node.title;
  159.                             return true;
  160.                         }
  161.                        
  162.                         if (
  163.                             node.tagName === "A" &&
  164.                             node.textContent
  165.                         ) {
  166.                             fileName = node.textContent;
  167.                             return true;
  168.                         }
  169.                     }
  170.                    
  171.                     return false;
  172.                 }
  173.             );
  174.         }
  175.        
  176.         if (!fileName) {
  177.             return;
  178.         }
  179.        
  180.         fileName = fileName.replace(/\-/, "/");
  181.        
  182.         key = doMakeKey(fileLink.href);
  183.        
  184.         if (!key) {
  185.             return;
  186.         }
  187.        
  188.         if (players[key]) {
  189.             return;
  190.         }
  191.        
  192.         match = fileName.match(/[\[\(\{](?:audio|sound)[ \=\:\|\$](.*?)[\]\)\}]/i);
  193.        
  194.         if (!match) {
  195.             return;
  196.         }
  197.        
  198.         link = match[1];
  199.        
  200.         if (link.includes("%")) {
  201.             try {
  202.                 link = decodeURIComponent(link);
  203.             } catch (error) {
  204.                 return;
  205.             }
  206.         }
  207.        
  208.        
  209.         if (link.match(/^(https?\:)?\/\//) === null) {
  210.             link = (location.protocol + "//" + link);
  211.         }
  212.        
  213.         try {
  214.             link = new URL(link);
  215.         } catch (error) {
  216.             return;
  217.         }
  218.        
  219.         if (
  220.             allow.some(
  221.                 function (item) {
  222.                     return (
  223.                         link.hostname.toLowerCase() === item ||
  224.                         link.hostname.toLowerCase().endsWith("." + item)
  225.                     );
  226.                 }
  227.             ) == false
  228.         ) {
  229.             return;
  230.         }
  231.        
  232.         player = new Audio();
  233.        
  234.         player.preload = "none";
  235.         player.volume = 0.80;
  236.         player.loop = true;
  237.        
  238.         player.src = link.href;
  239.        
  240.         players[key] = player;
  241.     };
  242.    
  243.     doParseFiles = function (target) {
  244.         target.querySelectorAll(".post")
  245.             .forEach(
  246.                 function (post) {
  247.                     if (post.parentElement.parentElement.id === "qp") {
  248.                         return;
  249.                     }
  250.                    
  251.                     if (post.parentElement.classList.contains("noFile")) {
  252.                         return;
  253.                     }
  254.                    
  255.                     post.querySelectorAll(".file")
  256.                         .forEach(
  257.                             function (file) {
  258.                                 doParseFile(file);
  259.                             }
  260.                         );
  261.                 }
  262.             );
  263.     };
  264.    
  265.     doPlayFile = function (target) {
  266.         var key;
  267.         var player;
  268.         var interval;
  269.        
  270.         if (isChanX) {
  271.             if (!(
  272.                 target.id === "ihover" ||
  273.                 target.className === "full-image"
  274.             )) {
  275.                 return;
  276.             }
  277.         } else {
  278.             if (!(
  279.                 target.id === "image-hover" ||
  280.                 target.className === "expanded-thumb" ||
  281.                 target.className === "expandedWebm"
  282.             )) {
  283.                 return;
  284.             }
  285.         }
  286.        
  287.         if (!target.src) {
  288.             return;
  289.         }
  290.        
  291.         key = doMakeKey(target.src);
  292.        
  293.         if (!key) {
  294.             return;
  295.         }
  296.        
  297.         player = players[key];
  298.        
  299.         if (!player) {
  300.             return;
  301.         }
  302.        
  303.         if (!player.paused) {
  304.             if (player.dataset.play == 1) {
  305.                 if (isChanX) {
  306.                     return;
  307.                 } else {
  308.                     player.dataset.again = 1;
  309.                 }
  310.             } else {
  311.                 player.pause();
  312.             }
  313.         }
  314.        
  315.         if (player.dataset.play != 1){
  316.             player.dataset.play = 1;
  317.             player.dataset.again = 0;
  318.             player.dataset.moveTime = 0;
  319.             player.dataset.moveLast = 0;
  320.         }
  321.        
  322.         switch (target.tagName) {
  323.             case "IMG":
  324.                 player.loop = true;
  325.                
  326.                 if (player.dataset.again != 1) {
  327.                     player.currentTime = 0;
  328.                     player.play();
  329.                 }
  330.                
  331.                 break;
  332.            
  333.             case "VIDEO":
  334.                 player.loop = false;
  335.                 player.currentTime = target.currentTime;
  336.                 player.play();
  337.                 break;
  338.            
  339.             default:
  340.                 return;
  341.         }
  342.        
  343.         if (player.paused) {
  344.             document.dispatchEvent(
  345.                 new CustomEvent(
  346.                     "CreateNotification",
  347.                     {
  348.                         bubbles: true,
  349.                         detail: {
  350.                             type: "warning",
  351.                             content: "Your browser blocked autoplay, click anywhere on the page to activate it and try again.",
  352.                             lifetime: 5
  353.                         }
  354.                     }
  355.                 )
  356.             );
  357.         }
  358.        
  359.         interval =
  360.             setInterval(
  361.                 function () {
  362.                     if (document.body.contains(target)) {
  363.                         if (target.tagName === "VIDEO") {
  364.                             if (target.currentTime != (+player.dataset.moveLast)) {
  365.                                 player.dataset.moveTime = Date.now();
  366.                                 player.dataset.moveLast = target.currentTime;
  367.                             }
  368.                            
  369.                             if (player.duration != NaN) {
  370.                                 if (
  371.                                     target.paused == true ||
  372.                                     target.duration == NaN ||
  373.                                     target.currentTime > player.duration ||
  374.                                     ((Date.now() - (+player.dataset.moveTime)) > 300)
  375.                                 ) {
  376.                                     if (!player.paused) {
  377.                                         player.pause();
  378.                                     }
  379.                                 } else {
  380.                                     if (
  381.                                         player.paused ||
  382.                                         Math.abs(target.currentTime - player.currentTime) > 0.100
  383.                                     ) {
  384.                                         player.currentTime = target.currentTime;
  385.                                     }
  386.                                    
  387.                                     if (player.paused) {
  388.                                         player.play();
  389.                                     }
  390.                                 }
  391.                             }
  392.                         }
  393.                     } else {
  394.                         clearInterval(interval);
  395.                        
  396.                         if (player.dataset.again == 1) {
  397.                             player.dataset.again = 0;
  398.                         } else {
  399.                             player.pause();
  400.                             player.dataset.play = 0;
  401.                         }
  402.                     }
  403.                 },
  404.                 (1000/30)
  405.             );
  406.     };
  407.    
  408.     doMakeKey = function (link) {
  409.         var match;
  410.        
  411.         if(link.includes('yuki')){
  412.             match = link.match(/\.(?:yuki)\.la\/(.+?)\/(.+?)\/(.+?)\.(.+?)$/);
  413.            
  414.             if (match) {
  415.                 return (match[3] + "." + match[4]);
  416.           }
  417.         }
  418.         else{
  419.             match = link.match(/\.(?:4cdn|4chan)\.org\/(.+?)\/(\d+?)\.(.+?)$/);
  420.            
  421.             if (match) {
  422.                 return (match[1] + "." + match[2]);
  423.           }
  424.         }
  425.        
  426.         return null;
  427.     };
  428. })();
  429.  
Add Comment
Please, Sign In to add comment