Nyako LIB

Common library for Tampermonkey/ViolentMonkey scripts

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.org/scripts/586977/1875787/Nyako%20LIB.js

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

Advertisement:

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

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;