mooket

银河奶牛历史价格 show history market data for milkywayidle

目前为 2025-03-20 提交的版本。查看 最新版本

// ==UserScript==
// @name         mooket
// @namespace    http://tampermonkey.net/
// @version      2025-03-20
// @description  银河奶牛历史价格 show history market data for milkywayidle
// @author       IOMisaka
// @match        https://www.milkywayidle.com/*
// @match        https://test.milkywayidle.com/*
// @connect      mooket.qi-e.top
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js
// @license MIT
// ==/UserScript==


(function () {
  'use strict';
  let initData_itemDetailMap = null;
  if (localStorage.getItem("initClientData")) {
    const obj = JSON.parse(localStorage.getItem("initClientData"));
    initData_itemDetailMap = obj.itemDetailMap;
  }
  function hookWS() {
    const dataProperty = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data");
    const oriGet = dataProperty.get;
    dataProperty.get = hookedGet;
    Object.defineProperty(MessageEvent.prototype, "data", dataProperty);

    function hookedGet() {
      const socket = this.currentTarget;
      if (!(socket instanceof WebSocket)) {
        return oriGet.call(this);
      }
      if (socket.url.indexOf("api.milkywayidle.com/ws") <= -1 && socket.url.indexOf("api-test.milkywayidle.com/ws") <= -1) {
        return oriGet.call(this);
      }
      const message = oriGet.call(this);
      Object.defineProperty(this, "data", { value: message }); // Anti-loop
      return handleMessage(message);
    }
  }
  function handleMessage(message) {
    let obj = JSON.parse(message);
    if (obj && obj.type === "market_item_order_books_updated") {
      requestMarket(obj.marketItemOrderBooks.itemHrid);
    }
    return message;
  }

  hookWS();

  let cur_day = 1;
  let cur_name = null;
  let w = "600px";
  let h = "330px";
  let configStr = localStorage.getItem("mooket_config");
  let config = configStr ? JSON.parse(configStr) : {"dayIndex":0,"visible":true,"filter":{"bid":true,"ask":true,"mean":true}};
  cur_day = config.day;//读取设置

  window.onresize = function () {
    checkSize();
  };
  function checkSize() {
    if (window.innerWidth < window.innerHeight) {
      w = "330px";
      h = "600px";
    } else {
      w = "600px";
      h = "330px";
    }
  }
  checkSize();
  // 创建容器元素并设置样式和位置
  const container = document.createElement('div');
  container.style.border = "1px solid #ccc"; //边框样式
  container.style.backgroundColor = "#fff";
  container.style.position = "fixed";
  container.style.zIndex = 10000;
  container.style.top = "50px"; //距离顶部位置
  container.style.left = "50px"; //距离左侧位置
  container.style.width = w; //容器宽度
  container.style.height = h; //容器高度
  container.style.cursor = "move";
  container.addEventListener("mousedown", function (e) {
    let disX = e.clientX - container.offsetLeft;
    let disY = e.clientY - container.offsetTop;
    document.onmousemove = function (e) {
      let x = e.clientX - disX;
      let y = e.clientY - disY;
      container.style.left = x + 'px';
      container.style.top = y + 'px';
    };
    document.onmouseup = function () {
      document.onmousemove = document.onmouseup = null;
    };
  });
  document.body.appendChild(container);

  const ctx = document.createElement('canvas');
  ctx.id = "myChart";
  container.appendChild(ctx);

  // 创建按钮组并设置样式和位置
  let wrapper = document.createElement('div');
  wrapper.style.display = 'inline-block';
  wrapper.style.backgroundColor="white"
  container.appendChild(wrapper);

  const days = [1, 3, 7, 30, 180]
  const dayTitle = ['1天', '3天', '7天', '30天', '半年']
  cur_day = days[config.dayIndex];

  for (let i = 0; i < 5; i++) {
    let btn = document.createElement('input');
    btn.id = 'chartType' + i;
    btn.type = 'radio';
    btn.name = 'chartType';
    btn.value = days[i];
    btn.style.cursor = 'pointer';
    btn.style.verticalAlign = "middle";
    btn.checked = i == config.dayIndex;
    btn.onclick = function () { 
      cur_day = this.value; 
      config.dayIndex = i;
      if(cur_name)requestMarket(cur_name, cur_day); 
      save_config();
    }

    let label = document.createElement('label');
    label.innerText = dayTitle[i];
    label.style.display = 'inline-block';
    label.style.verticalAlign = 'middle';
    label.style.textAlign = 'center';
    label.htmlFor = btn.id;
    label.style.margin = '1px';
    wrapper.appendChild(btn);
    wrapper.appendChild(label);
  }
  //添加一个btn隐藏canvas和wrapper
  let btn_close = document.createElement('input');
  btn_close.type = 'button';
  btn_close.value = '📈隐藏';
  btn_close.style.textAlign = 'center';
  btn_close.style.display = 'inline';
  btn_close.style.margin = 0;
  btn_close.style.top = '1px';
  btn_close.style.left = '1px';
  btn_close.style.cursor = 'pointer';
  btn_close.style.position = 'absolute';
  btn_close.onclick = toggle;
  function toggle() {
    setVisible(wrapper.style.display === 'none');
  };
  function setVisible(visible){
    if (visible) {
      wrapper.style.display = ctx.style.display = 'block';
      btn_close.value = '📈隐藏';
      container.style.width = w;
      container.style.height = h;
      config.visible = true;
      save_config();
    } else {
      wrapper.style.display = ctx.style.display = 'none';
      container.style.width = "63px";
      container.style.height = "25px";
      btn_close.value = '📈显示';
      config.visible = false;
      save_config();
    }
  }
  
  container.appendChild(btn_close);


  let chart = new Chart(ctx, {
    type: 'line',
    data: {
      labels: [],
      datasets: [{
        label: '市场',
        data: [],
        backgroundColor: 'rgba(255,99,132,0.2)',
        borderColor: 'rgba(255,99,132,1)',
        borderWidth: 1
      }]
    },
    options: {
      onClick:save_config,
      maintainAspectRatio: false,
      scales: {
        y: {
          beginAtZero: false
        }
      }
    }
  });

  function requestMarket(name, day = 1) {
    if (initData_itemDetailMap && initData_itemDetailMap[name]) {
      name = initData_itemDetailMap[name].name;
    }

    cur_name = name;
    cur_day = day;

    let time = day * 3600 * 24;
    fetch("https://mooket.qi-e.top/market", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        name: name,
        time: time
      })
    }).then(res => {
      res.json().then(data => updateChart(data, day));
    })
  }
  function formatTime(timestamp, day) {
    let date = new Date(timestamp * 1000);
    if (day <= 1) {
      return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
    }
    else if (day <= 3) {
      return date.toLocaleDateString([], { day: 'numeric', hour: '2-digit' });
    } else if (day <= 7) {
      return date.toLocaleDateString([], { day: 'numeric', hour: '2-digit' });
    } else if (day <= 30) {
      return date.toLocaleDateString([], { month: 'short', day: 'numeric' });
    } else
      return date.toLocaleDateString([], { year: 'numeric', month: 'short' });
  }

  //data={'bid':[{time:1,price:1}],'ask':[{time:1,price:1}]}
  function updateChart(data, day) {
    data.bid = data.bid.filter(o=>o.price>0);
    data.ask = data.ask.filter(o=>o.price>0);
    //timestamp转日期时间
    //根据day输出不同的时间表示,<3天显示时分,<=7天显示日时,<=30天显示月日,>30天显示年月

    let labels = data.bid.map(x => formatTime(x.time, day));

    chart.data.labels = labels;

    chart.data.datasets = [
      {
        label: '买入',
        data: data.bid.map(x => x.price),
        backgroundColor: '#ff3300',
        borderColor: '#990000',
        borderWidth: 1
      },
      {
        label: '卖出',
        data: data.ask.map(x => x.price),
        backgroundColor: '#00cc00',
        borderColor: '#006600',
        borderWidth: 1
      },
      {
        label: '均价',
        data: data.bid.map(({ price: bidPrice }, index) => {
          const { price: askPrice } = data.ask[index];
          return (bidPrice + askPrice) / 2;
        }),
        backgroundColor: '#ff9900',
        borderColor: '#996600',
        borderWidth: 1
      }
    ];
    chart.setDatasetVisibility(0, config.filter.ask);
    chart.setDatasetVisibility(1, config.filter.bid);
    chart.setDatasetVisibility(2, config.filter.mean);

    chart.update()
  }
  function save_config(){

    if(chart && chart.datasets && chart.datasets.length==3){
      config.filter.ask=chart.getDatasetMeta(0).visible;
      config.filter.bid=chart.getDatasetMeta(1).visible;
      config.filter.mean=chart.getDatasetMeta(2).visible;
    }
    localStorage.setItem("mooket_config", JSON.stringify(config));
  }
  //requestMarket('Apple', 1);
  setVisible(config.visible);

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址