Nyako LIB

Common library for Tampermonkey/ViolentMonkey scripts

Tento skript by nemal byť nainštalovaný priamo. Je to knižnica pre ďalšie skripty, ktorú by mali používať cez meta príkaz // @require https://update.greasyfork.org/scripts/586977/1875787/Nyako%20LIB.js

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Advertisement:

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

Advertisement:

// ==UserScript==
// @name         Nyako LIB
// @version      0.5.0
// @description  Common library for Tampermonkey scripts
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @license     Apache License 2.0
// @author      https://t.me/Nyako_TW
// @compatible   tampermonkey
// @compatible   violentmonkey
// @incompatible greasemonkey
// ==/UserScript==

var NyakoLib = {};
 
 
// Вспомогательные утилиты
NyakoLib.getPlatform = function() {
  var ua = navigator.userAgent.toLowerCase();
  if (/android/.test(ua)) {
    return "android";
  }
  if (/iphone|ipad|ipod/.test(ua)) {
    return "ios";
  }
  if (/macintosh/.test(ua) && navigator.maxTouchPoints > 1) {
    return "ios";
  }
  if (/windows|linux|mac/.test(ua)) {
    return "pc";
  }
  return "unknown";
};
 
NyakoLib.safeRun = function(fn, name, platforms) {
  if (platforms == undefined) { platforms = []; }
  try {
    var platform = NyakoLib.getPlatform();
    if (platforms.length > 0 && !platforms.includes(platform)) {
      console.log("Пропущено " + name + ": недоступно для " + platform);
      return;
    }
    fn();
  } catch (e) {
    console.error("Ошибка в " + name + ":", e);
  }
};

NyakoLib.injectButton = function() {
  var btn = document.createElement("button");
  btn.setAttribute("id", "nya-config-button-script");
  btn.innerHTML = "⚙️ Настройки";
  
  var btn_style = "position: fixed; left: 25px; bottom: 25px; z-index: 2147483646; padding: 12px 18px; background: rgba(0,0,0,.65); color: #fff; border: 1px solid rgba(255,255,255,.15); border-radius: 14px; cursor: pointer; font-family: Arial, sans-serif; font-size: 14px; backdrop-filter: blur(15px); box-shadow: 0 10px 35px rgba(0,0,0,.6); transition: 0.3s;";
  btn.setAttribute("style", btn_style);
  
  btn.onmouseover = function() { btn.style.background = "rgba(0,0,0,.85)"; };
  btn.onmouseout = function() { btn.style.background = "rgba(0,0,0,.65)"; };
  
  document.body.appendChild(btn);
};


// Фунции уведомлений
NyakoLib.Notify = {};
 
NyakoLib.Notify.beep = function() {
  try {
    var ctx = new AudioContext();
    var osc = ctx.createOscillator();
    var gain = ctx.createGain();
 
    osc.type = "triangle";
    osc.connect(gain);
    gain.connect(ctx.destination);
 
    osc.frequency.setValueAtTime(1000, ctx.currentTime);
    osc.frequency.setValueAtTime(1400, ctx.currentTime + 0.15);
 
    gain.gain.setValueAtTime(0.2, ctx.currentTime);
    gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.3);
 
    osc.start(ctx.currentTime);
    osc.stop(ctx.currentTime + 0.3);
  } catch (e) {
    console.error("Ошибка в beep:", e);
  }
};
 
NyakoLib.Notify.getContainer = function() {
  var notify_container = document.getElementById("nyako-notify-container");
  if (!notify_container) {
    notify_container = document.createElement("div");
    notify_container.setAttribute("id", "nyako-notify-container");
    
    var container_style = "position: fixed; right: 25px; bottom: 25px; z-index: 2147483647; display: flex; flex-direction: column; justify-content: flex-end; gap: 15px; pointer-events: none;";
    notify_container.setAttribute("style", container_style);
    document.body.appendChild(notify_container);
  }
  return notify_container;
};
 
NyakoLib.Notify.show = function(message_text, duration_time, play_sound) {
  if (duration_time == undefined) { duration_time = 5000; }
  if (play_sound == undefined) { play_sound = true; }
 
  if (play_sound) {
    NyakoLib.Notify.beep();
  }
 
  var container = NyakoLib.Notify.getContainer();
  
  var current_notifs = container.getElementsByClassName("nyako-notify-box");
  while (current_notifs.length >= 3) {
    current_notifs[0].remove();
  }
 
  var box = document.createElement("div");
  box.setAttribute("class", "nyako-notify-box");
  
  var box_html = "<span>" + message_text + "</span>";
  box_html = box_html + "<button class=\"nyako-close\" style=\"width: 28px; height: 28px; border-radius: 50%; border: 1px solid rgba(255,255,255,.2); background: rgba(255,255,255,.08); color: #fff; cursor: pointer; font-size: 20px; display: flex; align-items: center; justify-content: center; padding: 0;\">×</button>";
  box.innerHTML = box_html;
 
  var box_style = "pointer-events: auto; min-width: 280px; max-width: 380px; padding: 16px 18px; display: flex; align-items: center; justify-content: space-between; gap: 15px; background: rgba(0,0,0,.65); backdrop-filter: blur(15px); border: 1px solid rgba(255,255,255,.15); border-radius: 14px; color: #fff; font-family: Arial, sans-serif; box-shadow: 0 10px 35px rgba(0,0,0,.6); opacity: 0; transform: translateX(30px); transition: 0.35s ease;";
  box.setAttribute("style", box_style);
 
  var close_btn = box.getElementsByClassName("nyako-close")[0];
 
  close_btn.onclick = function() {
    box.setAttribute("style", box_style + " opacity: 0; transform: translateX(30px);");
    setTimeout(function() { box.remove(); }, 350);
  };
 
  container.appendChild(box);
 
  setTimeout(function() {
    box.setAttribute("style", box_style + " opacity: 1; transform: translateX(0);");
  }, 10);
 
  if (duration_time > 0) {
    setTimeout(function() {
      if (box.parentNode) { close_btn.onclick(); }
    }, duration_time);
  }
 
  return box;
};
 
 
 
// Фунции настроек
NyakoLib.Config = {};
NyakoLib.Config.prefix = "nyako_";
NyakoLib.Config.items = {};
 
NyakoLib.Config.get = function(name, default_value) {
  return GM_getValue(NyakoLib.Config.prefix + name, default_value);
};
 
NyakoLib.Config.set = function(name, set_value) {
  GM_setValue(NyakoLib.Config.prefix + name, set_value);
};
 
NyakoLib.Config.setup = function(configs_list) {
  NyakoLib.Config.items = configs_list;
 
  GM_registerMenuCommand("⚙️ Настройки скрипта", function() {
    NyakoLib.Config.showWindow();
  });
 
  document.addEventListener("click", function(event_data) {
    var btn_element = event_data.target.closest("#nya-config-button-script");
    if (btn_element) {
      event_data.preventDefault();
      NyakoLib.Config.showWindow();
    }
  });
};
 
NyakoLib.Config.showWindow = function() {
  var old_window = document.getElementById("nyako-settings-window");
  if (old_window) {
    old_window.remove();
  }
 
  var win = document.createElement("div");
  win.setAttribute("id", "nyako-settings-window");
 
  var win_style = "position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 340px; background: rgba(0,0,0,.75); backdrop-filter: blur(15px); border: 1px solid rgba(255,255,255,.15); border-radius: 14px; color: #fff; font-family: Arial, sans-serif; box-shadow: 0 10px 40px rgba(0,0,0,.7); z-index: 2147483647; display: flex; flex-direction: column;";
  win.setAttribute("style", win_style);
 
  var header = document.createElement("div");
  header.setAttribute("style", "padding: 15px 18px; border-bottom: 1px solid rgba(255,255,255,.15); display: flex; justify-content: space-between; align-items: center; font-weight: bold; font-size: 16px;");
  
  var header_html = "<span>⚙️ Настройки</span>";
  header_html = header_html + "<button class=\"close-win\" style=\"width: 28px; height: 28px; border-radius: 50%; border: 1px solid rgba(255,255,255,.2); background: rgba(255,255,255,.08); color: #fff; cursor: pointer; font-size: 20px; display: flex; align-items: center; justify-content: center; padding: 0;\">×</button>";
  header.innerHTML = header_html;
  win.appendChild(header);
 
  var body_element = document.createElement("div");
  body_element.setAttribute("style", "padding: 15px 18px; display: flex; flex-direction: column; gap: 14px; max-height: 70vh; overflow-y: auto;");
 
  var needs_reload = false;
 
  // Локальная функция для создания одной настройки
  var createItemUI = function(key_name, opt_data) {
    let default_val = false;
    if (opt_data.defaultValue != undefined) { default_val = opt_data.defaultValue; }
    
    let opt_type = "checkbox";
    if (opt_data.type != undefined) { opt_type = opt_data.type; }
 
    let current_value = NyakoLib.Config.get(key_name, default_val);
 
    let label_element = document.createElement("label");
    label_element.setAttribute("style", "display: flex; justify-content: space-between; align-items: center; font-size: 14px; cursor: pointer;");
 
    let title_text = key_name;
    if (opt_data.title != undefined) { title_text = opt_data.title; }
 
    let label_html = "<span style=\"margin-right: 15px;\">" + title_text + "</span>";
    let input_html = "";
    
    let input_style = "padding: 4px 8px; border-radius: 6px; border: 1px solid rgba(255,255,255,.2); background: rgba(0,0,0,.5); color: #fff; outline: none; font-size: 14px; max-width: 140px;";
 
    if (opt_type == "checkbox") {
      let checked_attr = "";
      if (current_value) { checked_attr = "checked"; }
      input_html = "<input type=\"checkbox\" style=\"width: 18px; height: 18px; cursor: pointer;\" " + checked_attr + ">";
    } 
    else if (opt_type == "text" || opt_type == "number") {
      input_html = "<input type=\"" + opt_type + "\" value=\"" + current_value + "\" style=\"" + input_style + "\">";
      label_element.style.cursor = "default";
    }
    else if (opt_type == "select") {
      input_html = "<select style=\"" + input_style + "\">";
      if (opt_data.options != undefined) {
        for (let opt_name in opt_data.options) {
          let opt_val = opt_data.options[opt_name];
          let is_selected = (current_value == opt_val) ? "selected" : "";
          input_html = input_html + "<option value=\"" + opt_val + "\" " + is_selected + ">" + opt_name + "</option>";
        }
      }
      input_html = input_html + "</select>";
      label_element.style.cursor = "default";
    }
 
    label_element.innerHTML = label_html + input_html;
 
    let input_node = label_element.getElementsByTagName("input")[0];
    if (!input_node) { input_node = label_element.getElementsByTagName("select")[0]; }
    
    input_node.onchange = function() {
      let new_value = input_node.value;
      
      if (opt_type == "checkbox") {
        new_value = input_node.checked;
      } else if (opt_type == "number") {
        new_value = Number(new_value);
      }
      
      NyakoLib.Config.set(key_name, new_value);
      
      let msg_text = title_text + ": ";
      if (opt_type == "checkbox") {
        let on_text = "включено";
        let off_text = "выключено";
        if (opt_data.onText != undefined) { on_text = opt_data.onText; }
        if (opt_data.offText != undefined) { off_text = opt_data.offText; }
        
        if (new_value) { msg_text = msg_text + on_text; } else { msg_text = msg_text + off_text; }
      } else {
        msg_text = msg_text + new_value;
      }
      
      NyakoLib.Notify.show(msg_text, 5000, false);
 
      if (opt_data.reload !== false) {
        needs_reload = true;
      }
    };
 
    return label_element;
  };
 
  // Перебираем переданные настройки
  for (let top_key in NyakoLib.Config.items) {
    let top_val = NyakoLib.Config.items[top_key];
    
    // Проверяем: это настройка (старый формат) или категория (вложенный объект)
    if (top_val.title != undefined || top_val.defaultValue != undefined || top_val.type != undefined) {
      body_element.appendChild(createItemUI(top_key, top_val));
    } else {
      // Это категория
      let cat_header = document.createElement("div");
      var cat_style = "font-weight: bold; font-size: 15px; color: #e0e0e0; border-bottom: 1px solid rgba(255,255,255,.15); padding-bottom: 6px; margin-top: 5px; margin-bottom: -5px;";
      cat_header.setAttribute("style", cat_style);
      cat_header.innerText = top_key;
      body_element.appendChild(cat_header);
      
      for (let sub_key in top_val) {
        let sub_val = top_val[sub_key];
        body_element.appendChild(createItemUI(sub_key, sub_val));
      }
    }
  }
 
  win.appendChild(body_element);
 
  var win_close_btn = header.getElementsByClassName("close-win")[0];
  win_close_btn.onclick = function() {
    win.remove();
    if (needs_reload) {
      NyakoLib.Notify.show("Перезагрузка страницы для применения настроек...", 5000, false);
      setTimeout(function() { location.reload(); }, 1500);
    }
  };
 
  document.body.appendChild(win);
};
 
window.NyakoLib = NyakoLib;