-01 / Trader ++

// ==UserScript==
// @name         Trader ++
// @license MIT
// @namespace    https://www.jeuxvideo.com/forums/0-3011927-0-1-0-1-0-finance.htm
// @version      0.11
// @description  Script qui aide à se sentir TRADER
// @author       -01
// @match        https://www.jeuxvideo.com/forums/0-3011927*
// @match        https://www.jeuxvideo.com/forums/42-30*
// @require      https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @require      https://static.cryptowat.ch/assets/scripts/embed.bundle.js
// @require      https://files.coinmarketcap.com/static/widget/currency.js
// @run-at       document-end
// @updateURL    https://openuserjs.org/install/-01/Trader_++.user.js
// @downloadURL  https://openuserjs.org/install/-01/Trader_++.user.js
// @grant        none
// ==/UserScript==

/* -----------------Changes Logs----------------

v 0.2
- Fix css
- Ajout de nouvelles cryptos
- Chart thème sombre

v 0.11
- Support https

v 0.10.2
- Ajouts de nouvelles cryptos
- Mise à jour des images buggés
- Suprresion de shitcoins qui apparaisaient dans un titre involontairement ("sur", "des", "bon", "coin" etc)

v 0.10.1
- Correction de fautes d'orthographe
- Possibilités de ne plus afficher les logos dans les titres
v 0.10.0
- Ajout d'une fenêtre de réglages pour personnaliser le script
- Ajout de nouvelles cryptos
- (bug) Ne supprime plus forcément tous les [ ] d'un titre

v 0.9.5
- Ajout du WTC (TO THE MOOON <3)

v 0.9.4
- Possibilité de ne plus afficher les logos
- Meilleur détection du nom des cryptos dans les titres

v 0.9.3
- Détection des topic cryptos plus large (plus forcément en majuscule et entre crochet)
- Ajout du logo de la crypto
- Optimisation


v 0.9.2
-Fix du bug sur le topic de l'IOTA
-Fix d'une potentielle faille

    */

(function () {
  if (document.querySelector('html').className === 'theme-light') {
    cccTheme = {}
  }
  else {
    // css chart dark theme
    cccTheme = {
      "General": {
        "background": "#333",
        "borderColor": "#545454",
        "borderRadius": "4px 4px 0 0"
      },
      "Header": {
        "background": "#000",
        "color": "#FFF"
      },
      "Followers": {
        "background": "#333",
        "color": "#FFF",
        "borderColor": "#e0bd93",
        "counterBorderColor": "#333",
        "counterColor": "#f5d7b2"
      },
      "Data": {
        "priceColor": "#FFF",
        "infoLabelColor": "#CCC",
        "infoValueColor": "#CCC"
      },
      "Chart": {
        "fillColor": "rgba(86,202,158,0.5)",
        "borderColor": "#56ca9e"
      },
      "Conversion": {
        "background": "#000",
        "color": "#999"
      }
    };
  }

  var cryptoMap = new Map()

  if (localStorage.getItem('cryptos-trader++') === null) {
    // cache crypto data from cryptocompare
    console.log("TRADER++ loading crypto from cryptocompare...: ")
    fetch('https://min-api.cryptocompare.com/data/all/coinlist').then((data) => data.json()).then(r => {
      Object.keys(r.Data).map((ticker) => {
        if (r.Data[ticker].IsTrading) { // filter
          cryptoMap.set(ticker, {
            ticker: r.Data[ticker].Name,
            img: r.Data[ticker].ImageUrl
          })
        }
      })
      localStorage.setItem('cryptos-trader++', JSON.stringify([...cryptoMap]))
      console.log("TRADER++ crypto cached: " + cryptoMap.size)

    })
  }
  else {
    cryptoMap = new Map(JSON.parse(localStorage.getItem(('cryptos-trader++'))));
    console.log("TRADER++ crypto cached: " + cryptoMap.size)

  }
  setTimeout(charge_selectizejs, 1000);
  setTimeout(settings_selectize, 2500);

  function charge_selectizejs() {
    var script = document.createElement("script");
    script.src = "https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.9.1/js/standalone/selectize.js";
    document.getElementsByTagName("head")[0].appendChild(script);

    var script = document.createElement("link");
    script.rel = "stylesheet";
    script.type = "text/css";
    script.href = "https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.4/css/selectize.default.css";
    document.getElementsByTagName("head")[0].appendChild(script);
    console.log("selectize chargé");
  }

  function settings_selectize() {
    // réglage de selecize
    $('#band_1').selectize({
      maxItems: 4
    });
    $('#band_2').selectize({
      maxItems: 4
    });
    $('#acceuil').selectize();
    $('#devise').selectize();
    $('#time_1').selectize();
    $('#time_2').selectize();
    $('#logo').selectize();
    $("#trader-settings").click(save_settings);

    if (localStorage.getItem("trader_first_install") === null) {
      // Le popup apparait à la première install
      localStorage.setItem("trader_first_install", "0")
      var modal = document.getElementById('modal-settings');
      modal.style.display = "block";
    }
  }

  function save_settings() {
    settings = {
      "band_1": $("#band_1").val(),
      "band_2": $("#band_2").val(),
      "acceuil": $("#acceuil").val(),
      "devise": $("#devise").val(),
      "time_1": $("#time_1").val(),
      "time_2": $("#time_2").val(),
      "logo": $("#logo").val()
    }

    localStorage.setItem("settings", JSON.stringify(settings));
    console.log("settings saved");
    location.reload();

  }

  if (localStorage.getItem("settings") === null) { // Valeurs par défaut

    var AFFICHER_LOGO = true; // remplacez true par false pour ne plus afficher les logos
    var CONVERTIR_EN = "BTC"; // Devises. Valeurs possibles : USD, EUR, BTC
    var PERIODE_1 = "1D"; // PERIODE1 -> range du graphique 1. Valeurs possibles : 1D, 2W, 1M, 3M, 6M, 1Y.
    var PERIODE_2 = "1W"; // PERIODE2 -> range du graphique 2. Valeurs possibles : 1D, 2W, 1M, 3M, 6M, 1Y.

    var CRYPTO_DEFAULT = "BTC"; // crytpo qui s'affiche sur les graphique de la liste des sujets.

    var CRYPTOS_BANDEAU_1 = "BTC,ETH,BCH,XRP"; // crypto qui s'affiche sur le bandeau 1 (en dessus de la liste des sujets). Mettre seulement le raccourci de la crypto.
    var CRYPTOS_BANDEAU_2 = "LTC,XEM,DASH,XMR"; // crypto qui s'affiche sur le bandeau 2

  }
  else { // Valeurs personalisées

    settings = JSON.parse(localStorage.getItem("settings"));
    if (settings.logo == "1") { // surement moyen d'utiliser directement des booléens
      var AFFICHER_LOGO = true;
    }
    else {
      var AFFICHER_LOGO = false;
    }
    var CONVERTIR_EN = settings.devise;
    var PERIODE_1 = settings.time_1;
    var PERIODE_2 = settings.time_2;

    var CRYPTO_DEFAULT = settings.acceuil;

    if (settings.band_1 !== null) {
      band_1 = settings.band_1.join();
    }
    else {
      band_1 = null;
    }
    var CRYPTOS_BANDEAU_1 = band_1;

    if (settings.band_2 !== null) {
      band_2 = settings.band_2.join();
    }
    else {
      band_2 = null;
    }
    var CRYPTOS_BANDEAU_2 = band_2;

  }

  validCoinsList = cryptoMap.keys()
  validCoinsList = [...validCoinsList]

  /* Modal settings */
  var modal = document.createElement("div");
  modal.id = "modal-settings";
  modal.className = "modal";
  modal.innerHTML = '<div class="modal-content"> <div class="modal-header"><span class="close"><img src="https://cdn4.iconfinder.com/data/icons/ionicons/512/icon-close-128.png" height="50px" alt="close"></span> <h2>Paramètres Trader++</h2></div><div class="modal-body">Bandeau 1 : <select id="band_1"> <option value=""></option> </select>Bandeau 2 : <select id="band_2"> <option value=""></option> </select>Graphe accueil : <select id="acceuil"> <option value="BTC">BTC</option> </select>Devise : <select id="devise"> <option value="BTC">BTC</option> <option value="USD">USD</option> <option value="EUR">EUR</option> </select>Intervalle graphe 1 : <select id="time_1"> <option value="1D">1 jour</option> <option value="1W">1 semaine</option> <option value="2W">2 semaines</option> <option value="1M">1 mois</option> <option value="3M">3 mois</option> <option value="6M">6 mois</option> <option value="1Y">1 an</option> </select>Intervalle graphe 2 : <select id="time_2"> <option value="1W">1 semaine</option> <option value="1D">1 jour</option> <option value="2W">2 semaines</option> <option value="1M">1 mois</option> <option value="3M">3 mois</option> <option value="6M">6 mois</option> <option value="1Y">1 an</option> </select> Afficher les logos dans les titres : <select id="logo"> <option value="1">Oui</option> <option value="0">Non</option> </select> <button type="button" id="trader-settings" class="btn btn-primary">Enregistrer</button> </div></div>';
  document.body.appendChild(modal);

  /* CSS du modal */
  function addcss(css) {
    var head = document.getElementsByTagName('head')[0];
    var s = document.createElement('style');
    s.setAttribute('type', 'text/css');
    if (s.styleSheet) { // IE
      s.styleSheet.cssText = css;
    }
    else { // the world
      s.appendChild(document.createTextNode(css));
    }
    head.appendChild(s);
  }

  addcss(".modal{display:none;position:fixed;z-index:1000;padding-top:100px;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:#000;background-color:rgba(0,0,0,.4)}.modal-content{position:relative;background-color:white;margin:auto;padding:0;border:1px solid #888;width:80%;box-shadow:0 4px 8px 0 rgba(0,0,0,.2),0 6px 20px 0 rgba(0,0,0,.19);-webkit-animation-name:animatetop;-webkit-animation-duration:.4s;animation-name:animatetop;animation-duration:.4s}.modal-body,.modal-header{padding:2px 16px}@-webkit-keyframes animatetop{from{opacity:0}to{opacity:1}}@keyframes animatetop{from{opacity:0}to{opacity:1}}.close{color:#fff;float:right;font-size:28px;font-weight:700}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer}.modal-header{background-color:#004466;color:#fff}");

  $(".paraTradePlus").css({
    "border-radius": "2px",
    "background-color": "#d5d5d5",
    "border": "solid rgba(42, 42, 42, 0.38) 1px",
  });

  btn = '<button class="paraTradePlus" style="background-color: rgb(195, 195, 195);margin-left: 10px;border: none;font-size: 0.75em;">Trader++</button>';
  $('.spreadContainer').first().append(btn);
  //$('.breadcrumb-icon').css("display", "flex");

  var modal = document.getElementById('modal-settings');
  var btn = document.getElementsByClassName("paraTradePlus")[0];
  var span = document.getElementsByClassName("close")[0];
  btn.onclick = function () {
    modal.style.display = "block";
  };
  span.onclick = function () {
    modal.style.display = "none";
  };
  window.onclick = function (event) {
    if (event.target == modal) {
      modal.style.display = "none";
    }
  };

  function add_options(select_id) {
    /* Ajoute toutes les cryptos dans le champ select */
    validCoinsList.forEach(function (coin) {
      var option = document.createElement("option");
      option.value = coin;
      option.innerText = coin;

      select = document.getElementById(select_id);
      select.appendChild(option);
    });

  }
  add_options("band_1");
  add_options("band_2");
  add_options("acceuil");
  /* Fonction widget cryptocompare.com */
  function widget(urlAPI, elmt) {
    baseUrl = "https://widgets.cryptocompare.com/";
    var s = document.createElement("script");
    s.type = "text/javascript";
    s.async = true;
    s.src = baseUrl + urlAPI;
    elmt.appendChild(s);
  }

  /* Fonction qui affiche le bandeau */
  function widgetHeader(coins) {
    $('.bloc-pagi-default')[0].outerHTML = "<div class='header-crypto' style='visibility: hidden; height:30px'></div>" + $('.bloc-pagi-default')[0].outerHTML;
    urlAPI = "serve/v3/coin/header?fsyms=" + coins + "&tsyms=" + CONVERTIR_EN;
    widget(urlAPI, $(".header-crypto")[0]);
    setTimeout(function () { // css des bandeaux
      $('.ccc-widget.ccc-header-v3').css({
        "background": "#d2d2d2",
        "padding": "5px",
        "border-radius": "2px",
        "margin-bottom": "5px"
      });

      $('.header-crypto').css("visibility", "visible");
    }, 500);
  }

  /* Fonction qui affiche les 2 graphiques */
  function widgetCharts(coin, period1, period2) {
    coin = coin.replace("MIOTA", "IOT");
    coin = coin.replace("IOTA", "IOT");
    console.log("chart du : " + coin);
    $('.card-jv-forum').after("<div id='chart-1'></div>");
    $('.card-jv-forum').after("<div id='chart-2'></div>");
    if (coin == "BTC" && CONVERTIR_EN == "BTC") { // Pour évitter de faire bugger le cours du BTC
      urlAPI1 = "serve/v2/coin/chart?fsym=" + coin + "&tsym=" + "USD" + "&period=" + period1;
      urlAPI2 = "serve/v2/coin/chart?fsym=" + coin + "&tsym=" + "USD" + "&period=" + period2;
    }
    else {
      urlAPI1 = "serve/v2/coin/chart?fsym=" + coin + "&tsym=" + CONVERTIR_EN + "&period=" + period1;
      urlAPI2 = "serve/v2/coin/chart?fsym=" + coin + "&tsym=" + CONVERTIR_EN + "&period=" + period2;
    }
    widget(urlAPI1, $("#chart-2")[0]);
    widget(urlAPI2, $("#chart-1")[0]);
  }

  /* Détecte les cryptos valides dans les titres et affiche leur graphiques */
  function widgetTopic(period1, period2) {
    var titreTopic = $('#bloc-title-forum').text();
    var coin = findCoin(titreTopic);

    if (coin)
      widgetCharts(coin, period1, period2);
  }

  function check(coin) {

    if (cryptoMap.has(coin)) {
      console.log("Coin valide détécté : " + coin);
      return coin;
    }
  }

  function findCoin(string) { //trouve une coin valide dans la string
    //cherche les coins potentiels
    var string
    var coinReg = new RegExp(/\b[A-Z]{3,6}\b/g);
    coin_arr = string.match(coinReg);
    if (coin_arr !== null) {
      var validCoin = coin_arr.find(check);
    }
    if (typeof validCoin !== "undefined") {
      return validCoin;
    }
    else {
      return false;
    }
  }

  function linkImage(coin) {

    baseURL = "https://www.cryptocompare.com";
    var imageLink = baseURL + cryptoMap.get(coin).img;
    return imageLink;
  }

  function imageSujetCoin() {
    $('.topic-title').each(function () {
      var titreTopic = $(this).text();
      console.log(titreTopic)
      var coin = findCoin(titreTopic);
      if (coin) {
        var tag = new RegExp(/^\[[A-Z]{3,6}\]/g);

        var newTitre = titreTopic.replace(tag, ""); // si le titre commence par [], delete le tag
        $(this).text(newTitre);

        var image = linkImage(coin);
        var elmt = document.createElement('img');
        elmt.alt = coin;
        elmt.src = image;
        elmt.height = 15;
        elmt.style = "border-radius: 2px; margin-right: 5px;";
        $(this).prepend(elmt);
        console.log("Lien de l'image : " + image);
      }
    });

  }
  /* Charge les widgets */
  var url_forum = "https://www.jeuxvideo.com/forums/0-3011927-0-1-0-";
  if (window.location.href.includes(url_forum)) { // graph liste sujet
    widgetCharts(CRYPTO_DEFAULT, PERIODE_1, PERIODE_2);
    if (AFFICHER_LOGO) {
      imageSujetCoin();
    }
  }
  else { // graph topic
    widgetTopic(PERIODE_1, PERIODE_2);
  }
  if (CRYPTOS_BANDEAU_1 !== null) {
    widgetHeader(CRYPTOS_BANDEAU_1);
  }
  if (CRYPTOS_BANDEAU_2 !== null) {
    widgetHeader(CRYPTOS_BANDEAU_2);
  }

  /* intégration des liens coinmarketplace et cryptowatch */
  function embeddedLink() {
    coinmarketplaceReg = new RegExp("https?:\/\/coinmarketcap\.com\/currencies\/[a-zA-Z0-9]+\/");
    cryptowatchReg = new RegExp("https:\/\/cryptowat\.ch\/[a-zA-Z]+\/[a-zA-Z0-9]+(\/[a-z0-9]+)?");
    id = 0;
    $('.bloc-contenu a,.message__content-text a').each(function () {
      id++;
      var lien = ($(this).attr('href'));
      var obj = $(this);
      if (coinmarketplaceReg.test(lien)) {
        var lienMarket = coinmarketplaceReg.exec(lien)[0];
        console.log(lienMarket);
        coin = lienMarket.replace(/https:\/\/coinmarketcap.com\/currencies\/|http:\/\/coinmarketcap.com\/currencies\/|\//g, ""); // isole le coin
        html = '<div class="coinmarketcap-currency-widget" style="max-width:300px; zoom: 0.8; background-color:white; border-radius:15px"></div>';
        obj.after(html);
        $(".coinmarketcap-currency-widget").attr({
          "data-currency": coin,
          "data-base": CONVERTIR_EN,
          "data-secondary": "BTC"
        });
      }
      if (cryptowatchReg.test(lien)) {
        lienCrypto = cryptowatchReg.exec(lien)[0];
        dataArr = lienCrypto.replace("https:\/\/cryptowat.ch\/", "").split("/"); // isole les 2 var
        console.log("Lien cryptowatch détécté : " + lienCrypto + " -> " + dataArr);
        exchange = dataArr[0];
        coin = dataArr[1];
        if (typeof dataArr[2] !== "undefined") {
          interval = dataArr[2];
          console.log("time précisé : " + interval);
        }
        else {
          interval = "1h";
        }
        html = '<div id="chart-cryptowatch' + id + '" style="height:500px;"></div>';
        obj.after(html);
        var chart = new cryptowatch.Embed(exchange, coin, {
          width: 650,
          timePeriod: interval,
          presetColorScheme: 'standard',
          customColorScheme: {
            bg: "000000",
            text: "b2b2b2",
            textStrong: "e5e5e5",
            textWeak: "7f7f7f",
            short: "FD4600",
            shortFill: "FF672C",
            long: "6290FF",
            longFill: "002782",
            cta: "363D52",
            ctaHighlight: "414A67",
            alert: "FFD506",
          }
        });
        chart.mount('#chart-cryptowatch' + id);
      }
    });
  }

  embeddedLink();

})();