FZ Tracker

Track game versions you finished playing on F95Zone.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         FZ Tracker
// @namespace    https://f95zone.to/threads/186670/
// @version      1.2.0
// @author       feeling_blue
// @description  Track game versions you finished playing on F95Zone.
// @license      MIT
// @icon         https://external-content.duckduckgo.com/ip3/f95zone.to.ico
// @supportURL   https://f95zone.to/threads/186670/
// @match        https://f95zone.to/threads/*
// @match        https://f95zone.to/sam/latest_alpha/*
// @require      https://unpkg.com/[email protected]/dist/vue.global.prod.js
// @require      https://unpkg.com/@vueuse/[email protected]/index.iife.min.js
// @require      data:application/javascript,%3Bwindow.Vue%3DVue%3B
// @require      https://unpkg.com/@vueuse/[email protected]/index.iife.min.js
// @require      https://unpkg.com/[email protected]/dist/index.full.min.js
// @require      https://unpkg.com/@element-plus/[email protected]/dist/index.iife.min.js
// @resource     element-plus/dist/index.css  https://unpkg.com/[email protected]/dist/index.css
// @grant        GM_addStyle
// @grant        GM_getResourceText
// ==/UserScript==

(r=>{if(typeof GM_addStyle=="function"){GM_addStyle(r);return}const o=document.createElement("style");o.textContent=r,document.head.append(o)})(' html.dark{color-scheme:dark;--el-color-primary:#409eff;--el-color-primary-light-3:#3375b9;--el-color-primary-light-5:#2a598a;--el-color-primary-light-7:#213d5b;--el-color-primary-light-8:#1d3043;--el-color-primary-light-9:#18222c;--el-color-primary-dark-2:#66b1ff;--el-color-success:#67c23a;--el-color-success-light-3:#4e8e2f;--el-color-success-light-5:#3e6b27;--el-color-success-light-7:#2d481f;--el-color-success-light-8:#25371c;--el-color-success-light-9:#1c2518;--el-color-success-dark-2:#85ce61;--el-color-warning:#e6a23c;--el-color-warning-light-3:#a77730;--el-color-warning-light-5:#7d5b28;--el-color-warning-light-7:#533f20;--el-color-warning-light-8:#3e301c;--el-color-warning-light-9:#292218;--el-color-warning-dark-2:#ebb563;--el-color-danger:#f56c6c;--el-color-danger-light-3:#b25252;--el-color-danger-light-5:#854040;--el-color-danger-light-7:#582e2e;--el-color-danger-light-8:#412626;--el-color-danger-light-9:#2b1d1d;--el-color-danger-dark-2:#f78989;--el-color-error:#f56c6c;--el-color-error-light-3:#b25252;--el-color-error-light-5:#854040;--el-color-error-light-7:#582e2e;--el-color-error-light-8:#412626;--el-color-error-light-9:#2b1d1d;--el-color-error-dark-2:#f78989;--el-color-info:#909399;--el-color-info-light-3:#6b6d71;--el-color-info-light-5:#525457;--el-color-info-light-7:#393a3c;--el-color-info-light-8:#2d2d2f;--el-color-info-light-9:#202121;--el-color-info-dark-2:#a6a9ad;--el-box-shadow:0px 12px 32px 4px rgba(0, 0, 0, .36),0px 8px 20px rgba(0, 0, 0, .72);--el-box-shadow-light:0px 0px 12px rgba(0, 0, 0, .72);--el-box-shadow-lighter:0px 0px 6px rgba(0, 0, 0, .72);--el-box-shadow-dark:0px 16px 48px 16px rgba(0, 0, 0, .72),0px 12px 32px #000000,0px 8px 16px -8px #000000;--el-bg-color-page:#0a0a0a;--el-bg-color:#141414;--el-bg-color-overlay:#1d1e1f;--el-text-color-primary:#E5EAF3;--el-text-color-regular:#CFD3DC;--el-text-color-secondary:#A3A6AD;--el-text-color-placeholder:#8D9095;--el-text-color-disabled:#6C6E72;--el-border-color-darker:#636466;--el-border-color-dark:#58585B;--el-border-color:#4C4D4F;--el-border-color-light:#414243;--el-border-color-lighter:#363637;--el-border-color-extra-light:#2B2B2C;--el-fill-color-darker:#424243;--el-fill-color-dark:#39393A;--el-fill-color:#303030;--el-fill-color-light:#262727;--el-fill-color-lighter:#1D1D1D;--el-fill-color-extra-light:#191919;--el-fill-color-blank:transparent;--el-mask-color:rgba(0, 0, 0, .8);--el-mask-color-extra-light:rgba(0, 0, 0, .3)}html.dark .el-button{--el-button-disabled-text-color:rgba(255, 255, 255, .5)}html.dark .el-card{--el-card-bg-color:var(--el-bg-color-overlay)}html.dark .el-empty{--el-empty-fill-color-0:var(--el-color-black);--el-empty-fill-color-1:#4b4b52;--el-empty-fill-color-2:#36383d;--el-empty-fill-color-3:#1e1e20;--el-empty-fill-color-4:#262629;--el-empty-fill-color-5:#202124;--el-empty-fill-color-6:#212224;--el-empty-fill-color-7:#1b1c1f;--el-empty-fill-color-8:#1c1d1f;--el-empty-fill-color-9:#18181a}#--unocss--{layer:__ALL__}.el-form-item.button-group[data-v-9a23e112] .el-form-item__content{justify-content:flex-end}.fz-tracker .p-body-header{z-index:5}.fz-tracker .p-body{z-index:4}.fz-tracker .el-icon svg path{fill:currentColor}#--unocss-layer-start--__ALL__--{start:__ALL__}*,:before,:after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }::backdrop{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }.m-l-\\[10px\\]{margin-left:10px}.m-t-\\[5px\\]{margin-top:5px}.ml-4{margin-left:1rem}.inline-block{display:inline-block}[size~="20"]{width:5rem;height:5rem}[size~="35"]{width:8.75rem;height:8.75rem}.cursor-pointer{cursor:pointer}.border-rd-\\[3px\\]{border-radius:3px}.p-\\[5px\\]{padding:5px}.p-1{padding:.25rem}.p-l-\\[5px\\]{padding-left:5px}.v-middle{vertical-align:middle}.v-sub{vertical-align:sub}.text-\\[0\\.75em\\]{font-size:.75em}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\\[rgb\\(147\\,152\\,160\\)\\]{--un-text-opacity:1;color:rgb(147 152 160 / var(--un-text-opacity))}.text-\\#ec5555{--un-text-opacity:1;color:rgb(236 85 85 / var(--un-text-opacity))}.text-white{--un-text-opacity:1;color:rgb(255 255 255 / var(--un-text-opacity))}.opacity-70{opacity:.7}.hover\\:opacity-100:hover{opacity:1}.backdrop-blur-5{--un-backdrop-blur:blur(5px);-webkit-backdrop-filter:var(--un-backdrop-blur) var(--un-backdrop-brightness) var(--un-backdrop-contrast) var(--un-backdrop-grayscale) var(--un-backdrop-hue-rotate) var(--un-backdrop-invert) var(--un-backdrop-opacity) var(--un-backdrop-saturate) var(--un-backdrop-sepia);backdrop-filter:var(--un-backdrop-blur) var(--un-backdrop-brightness) var(--un-backdrop-contrast) var(--un-backdrop-grayscale) var(--un-backdrop-hue-rotate) var(--un-backdrop-invert) var(--un-backdrop-opacity) var(--un-backdrop-saturate) var(--un-backdrop-sepia)}.blur{--un-blur:blur(8px);filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia)}#--unocss-layer-end--__ALL__--{end:__ALL__} ');

(function (vue, ElementPlus, core, iconsVue) {
  'use strict';

  const cssLoader = (e) => {
    const t = GM_getResourceText(e);
    return GM_addStyle(t), t;
  };
  cssLoader("element-plus/dist/index.css");
  function gameStorageKey(gameID) {
    return `${gameID}-tracker`;
  }
  const _hoisted_1$1 = { class: "backdrop-blur-5 text-[0.75em] p-[5px] p-l-[5px] m-l-[10px] m-t-[5px] border-rd-[3px]" };
  const _sfc_main$2 = {
    __name: "LatestRecordTag",
    setup(__props) {
      const gameInfo = vue.inject("gameInfo");
      const gameData = JSON.parse(localStorage.getItem(gameStorageKey(gameInfo.ID)));
      const lastRecord = gameData.records[gameData.records.length - 1];
      const timeAgo = core.useTimeAgo(lastRecord ? lastRecord.time : null);
      let versionText = "";
      if (lastRecord && lastRecord.version !== gameInfo.version)
        versionText = `[${lastRecord.version}] `;
      return (_ctx, _cache) => {
        return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, vue.toDisplayString(vue.unref(versionText)) + vue.toDisplayString(vue.unref(lastRecord) ? vue.unref(timeAgo) : ""), 1);
      };
    }
  };
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
  function getDefaultExportFromCjs(x) {
    return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
  }
  var dayjs_min = { exports: {} };
  (function(module, exports) {
    !function(t, e) {
      module.exports = e();
    }(commonjsGlobal, function() {
      var t = 1e3, e = 6e4, n = 36e5, r = "millisecond", i = "second", s = "minute", u = "hour", a = "day", o = "week", c = "month", f = "quarter", h = "year", d = "date", l = "Invalid Date", $ = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/, y = /\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, M = { name: "en", weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), ordinal: function(t2) {
        var e2 = ["th", "st", "nd", "rd"], n2 = t2 % 100;
        return "[" + t2 + (e2[(n2 - 20) % 10] || e2[n2] || e2[0]) + "]";
      } }, m = function(t2, e2, n2) {
        var r2 = String(t2);
        return !r2 || r2.length >= e2 ? t2 : "" + Array(e2 + 1 - r2.length).join(n2) + t2;
      }, v = { s: m, z: function(t2) {
        var e2 = -t2.utcOffset(), n2 = Math.abs(e2), r2 = Math.floor(n2 / 60), i2 = n2 % 60;
        return (e2 <= 0 ? "+" : "-") + m(r2, 2, "0") + ":" + m(i2, 2, "0");
      }, m: function t2(e2, n2) {
        if (e2.date() < n2.date())
          return -t2(n2, e2);
        var r2 = 12 * (n2.year() - e2.year()) + (n2.month() - e2.month()), i2 = e2.clone().add(r2, c), s2 = n2 - i2 < 0, u2 = e2.clone().add(r2 + (s2 ? -1 : 1), c);
        return +(-(r2 + (n2 - i2) / (s2 ? i2 - u2 : u2 - i2)) || 0);
      }, a: function(t2) {
        return t2 < 0 ? Math.ceil(t2) || 0 : Math.floor(t2);
      }, p: function(t2) {
        return { M: c, y: h, w: o, d: a, D: d, h: u, m: s, s: i, ms: r, Q: f }[t2] || String(t2 || "").toLowerCase().replace(/s$/, "");
      }, u: function(t2) {
        return void 0 === t2;
      } }, g = "en", D = {};
      D[g] = M;
      var p = "$isDayjsObject", S = function(t2) {
        return t2 instanceof _ || !(!t2 || !t2[p]);
      }, w = function t2(e2, n2, r2) {
        var i2;
        if (!e2)
          return g;
        if ("string" == typeof e2) {
          var s2 = e2.toLowerCase();
          D[s2] && (i2 = s2), n2 && (D[s2] = n2, i2 = s2);
          var u2 = e2.split("-");
          if (!i2 && u2.length > 1)
            return t2(u2[0]);
        } else {
          var a2 = e2.name;
          D[a2] = e2, i2 = a2;
        }
        return !r2 && i2 && (g = i2), i2 || !r2 && g;
      }, O = function(t2, e2) {
        if (S(t2))
          return t2.clone();
        var n2 = "object" == typeof e2 ? e2 : {};
        return n2.date = t2, n2.args = arguments, new _(n2);
      }, b = v;
      b.l = w, b.i = S, b.w = function(t2, e2) {
        return O(t2, { locale: e2.$L, utc: e2.$u, x: e2.$x, $offset: e2.$offset });
      };
      var _ = function() {
        function M2(t2) {
          this.$L = w(t2.locale, null, true), this.parse(t2), this.$x = this.$x || t2.x || {}, this[p] = true;
        }
        var m2 = M2.prototype;
        return m2.parse = function(t2) {
          this.$d = function(t3) {
            var e2 = t3.date, n2 = t3.utc;
            if (null === e2)
              return /* @__PURE__ */ new Date(NaN);
            if (b.u(e2))
              return /* @__PURE__ */ new Date();
            if (e2 instanceof Date)
              return new Date(e2);
            if ("string" == typeof e2 && !/Z$/i.test(e2)) {
              var r2 = e2.match($);
              if (r2) {
                var i2 = r2[2] - 1 || 0, s2 = (r2[7] || "0").substring(0, 3);
                return n2 ? new Date(Date.UTC(r2[1], i2, r2[3] || 1, r2[4] || 0, r2[5] || 0, r2[6] || 0, s2)) : new Date(r2[1], i2, r2[3] || 1, r2[4] || 0, r2[5] || 0, r2[6] || 0, s2);
              }
            }
            return new Date(e2);
          }(t2), this.init();
        }, m2.init = function() {
          var t2 = this.$d;
          this.$y = t2.getFullYear(), this.$M = t2.getMonth(), this.$D = t2.getDate(), this.$W = t2.getDay(), this.$H = t2.getHours(), this.$m = t2.getMinutes(), this.$s = t2.getSeconds(), this.$ms = t2.getMilliseconds();
        }, m2.$utils = function() {
          return b;
        }, m2.isValid = function() {
          return !(this.$d.toString() === l);
        }, m2.isSame = function(t2, e2) {
          var n2 = O(t2);
          return this.startOf(e2) <= n2 && n2 <= this.endOf(e2);
        }, m2.isAfter = function(t2, e2) {
          return O(t2) < this.startOf(e2);
        }, m2.isBefore = function(t2, e2) {
          return this.endOf(e2) < O(t2);
        }, m2.$g = function(t2, e2, n2) {
          return b.u(t2) ? this[e2] : this.set(n2, t2);
        }, m2.unix = function() {
          return Math.floor(this.valueOf() / 1e3);
        }, m2.valueOf = function() {
          return this.$d.getTime();
        }, m2.startOf = function(t2, e2) {
          var n2 = this, r2 = !!b.u(e2) || e2, f2 = b.p(t2), l2 = function(t3, e3) {
            var i2 = b.w(n2.$u ? Date.UTC(n2.$y, e3, t3) : new Date(n2.$y, e3, t3), n2);
            return r2 ? i2 : i2.endOf(a);
          }, $2 = function(t3, e3) {
            return b.w(n2.toDate()[t3].apply(n2.toDate("s"), (r2 ? [0, 0, 0, 0] : [23, 59, 59, 999]).slice(e3)), n2);
          }, y2 = this.$W, M3 = this.$M, m3 = this.$D, v2 = "set" + (this.$u ? "UTC" : "");
          switch (f2) {
            case h:
              return r2 ? l2(1, 0) : l2(31, 11);
            case c:
              return r2 ? l2(1, M3) : l2(0, M3 + 1);
            case o:
              var g2 = this.$locale().weekStart || 0, D2 = (y2 < g2 ? y2 + 7 : y2) - g2;
              return l2(r2 ? m3 - D2 : m3 + (6 - D2), M3);
            case a:
            case d:
              return $2(v2 + "Hours", 0);
            case u:
              return $2(v2 + "Minutes", 1);
            case s:
              return $2(v2 + "Seconds", 2);
            case i:
              return $2(v2 + "Milliseconds", 3);
            default:
              return this.clone();
          }
        }, m2.endOf = function(t2) {
          return this.startOf(t2, false);
        }, m2.$set = function(t2, e2) {
          var n2, o2 = b.p(t2), f2 = "set" + (this.$u ? "UTC" : ""), l2 = (n2 = {}, n2[a] = f2 + "Date", n2[d] = f2 + "Date", n2[c] = f2 + "Month", n2[h] = f2 + "FullYear", n2[u] = f2 + "Hours", n2[s] = f2 + "Minutes", n2[i] = f2 + "Seconds", n2[r] = f2 + "Milliseconds", n2)[o2], $2 = o2 === a ? this.$D + (e2 - this.$W) : e2;
          if (o2 === c || o2 === h) {
            var y2 = this.clone().set(d, 1);
            y2.$d[l2]($2), y2.init(), this.$d = y2.set(d, Math.min(this.$D, y2.daysInMonth())).$d;
          } else
            l2 && this.$d[l2]($2);
          return this.init(), this;
        }, m2.set = function(t2, e2) {
          return this.clone().$set(t2, e2);
        }, m2.get = function(t2) {
          return this[b.p(t2)]();
        }, m2.add = function(r2, f2) {
          var d2, l2 = this;
          r2 = Number(r2);
          var $2 = b.p(f2), y2 = function(t2) {
            var e2 = O(l2);
            return b.w(e2.date(e2.date() + Math.round(t2 * r2)), l2);
          };
          if ($2 === c)
            return this.set(c, this.$M + r2);
          if ($2 === h)
            return this.set(h, this.$y + r2);
          if ($2 === a)
            return y2(1);
          if ($2 === o)
            return y2(7);
          var M3 = (d2 = {}, d2[s] = e, d2[u] = n, d2[i] = t, d2)[$2] || 1, m3 = this.$d.getTime() + r2 * M3;
          return b.w(m3, this);
        }, m2.subtract = function(t2, e2) {
          return this.add(-1 * t2, e2);
        }, m2.format = function(t2) {
          var e2 = this, n2 = this.$locale();
          if (!this.isValid())
            return n2.invalidDate || l;
          var r2 = t2 || "YYYY-MM-DDTHH:mm:ssZ", i2 = b.z(this), s2 = this.$H, u2 = this.$m, a2 = this.$M, o2 = n2.weekdays, c2 = n2.months, f2 = n2.meridiem, h2 = function(t3, n3, i3, s3) {
            return t3 && (t3[n3] || t3(e2, r2)) || i3[n3].slice(0, s3);
          }, d2 = function(t3) {
            return b.s(s2 % 12 || 12, t3, "0");
          }, $2 = f2 || function(t3, e3, n3) {
            var r3 = t3 < 12 ? "AM" : "PM";
            return n3 ? r3.toLowerCase() : r3;
          };
          return r2.replace(y, function(t3, r3) {
            return r3 || function(t4) {
              switch (t4) {
                case "YY":
                  return String(e2.$y).slice(-2);
                case "YYYY":
                  return b.s(e2.$y, 4, "0");
                case "M":
                  return a2 + 1;
                case "MM":
                  return b.s(a2 + 1, 2, "0");
                case "MMM":
                  return h2(n2.monthsShort, a2, c2, 3);
                case "MMMM":
                  return h2(c2, a2);
                case "D":
                  return e2.$D;
                case "DD":
                  return b.s(e2.$D, 2, "0");
                case "d":
                  return String(e2.$W);
                case "dd":
                  return h2(n2.weekdaysMin, e2.$W, o2, 2);
                case "ddd":
                  return h2(n2.weekdaysShort, e2.$W, o2, 3);
                case "dddd":
                  return o2[e2.$W];
                case "H":
                  return String(s2);
                case "HH":
                  return b.s(s2, 2, "0");
                case "h":
                  return d2(1);
                case "hh":
                  return d2(2);
                case "a":
                  return $2(s2, u2, true);
                case "A":
                  return $2(s2, u2, false);
                case "m":
                  return String(u2);
                case "mm":
                  return b.s(u2, 2, "0");
                case "s":
                  return String(e2.$s);
                case "ss":
                  return b.s(e2.$s, 2, "0");
                case "SSS":
                  return b.s(e2.$ms, 3, "0");
                case "Z":
                  return i2;
              }
              return null;
            }(t3) || i2.replace(":", "");
          });
        }, m2.utcOffset = function() {
          return 15 * -Math.round(this.$d.getTimezoneOffset() / 15);
        }, m2.diff = function(r2, d2, l2) {
          var $2, y2 = this, M3 = b.p(d2), m3 = O(r2), v2 = (m3.utcOffset() - this.utcOffset()) * e, g2 = this - m3, D2 = function() {
            return b.m(y2, m3);
          };
          switch (M3) {
            case h:
              $2 = D2() / 12;
              break;
            case c:
              $2 = D2();
              break;
            case f:
              $2 = D2() / 3;
              break;
            case o:
              $2 = (g2 - v2) / 6048e5;
              break;
            case a:
              $2 = (g2 - v2) / 864e5;
              break;
            case u:
              $2 = g2 / n;
              break;
            case s:
              $2 = g2 / e;
              break;
            case i:
              $2 = g2 / t;
              break;
            default:
              $2 = g2;
          }
          return l2 ? $2 : b.a($2);
        }, m2.daysInMonth = function() {
          return this.endOf(c).$D;
        }, m2.$locale = function() {
          return D[this.$L];
        }, m2.locale = function(t2, e2) {
          if (!t2)
            return this.$L;
          var n2 = this.clone(), r2 = w(t2, e2, true);
          return r2 && (n2.$L = r2), n2;
        }, m2.clone = function() {
          return b.w(this.$d, this);
        }, m2.toDate = function() {
          return new Date(this.valueOf());
        }, m2.toJSON = function() {
          return this.isValid() ? this.toISOString() : null;
        }, m2.toISOString = function() {
          return this.$d.toISOString();
        }, m2.toString = function() {
          return this.$d.toUTCString();
        }, M2;
      }(), k = _.prototype;
      return O.prototype = k, [["$ms", r], ["$s", i], ["$m", s], ["$H", u], ["$W", a], ["$M", c], ["$y", h], ["$D", d]].forEach(function(t2) {
        k[t2[1]] = function(e2) {
          return this.$g(e2, t2[0], t2[1]);
        };
      }), O.extend = function(t2, e2) {
        return t2.$i || (t2(e2, _, O), t2.$i = true), O;
      }, O.locale = w, O.isDayjs = S, O.unix = function(t2) {
        return O(1e3 * t2);
      }, O.en = D[g], O.Ls = D, O.p = {}, O;
    });
  })(dayjs_min);
  var dayjs_minExports = dayjs_min.exports;
  const dayjs = /* @__PURE__ */ getDefaultExportFromCjs(dayjs_minExports);
  const trackerVersion = "1.2.0";
  const _export_sfc = (sfc, props) => {
    const target = sfc.__vccOpts || sfc;
    for (const [key, val] of props) {
      target[key] = val;
    }
    return target;
  };
  const _hoisted_1 = {
    key: 0,
    class: "text-2xl"
  };
  const _sfc_main$1 = {
    __name: "VersionTracker",
    setup(__props) {
      const gameInfo = vue.inject("gameInfo");
      const gameData = core.useLocalStorage(
        gameStorageKey(gameInfo.ID),
        {
          name: gameInfo.name,
          author: gameInfo.author,
          records: [],
          trackerVersion
        },
        {
          deep: true,
          listenToStorageChanges: true
        }
      );
      for (const prop of ["name", "author", "scriptVersion"]) {
        if (gameData.value[prop] !== gameInfo[prop]) {
          gameData.value[prop] = gameInfo[prop];
        }
      }
      const checked = vue.computed({
        get() {
          return gameData.value.records.some((record) => record.version === gameInfo.version);
        },
        set(newVal) {
          if (newVal)
            addRecord(gameInfo);
          else
            removeRecord(gameInfo);
        }
      });
      const lastRecord = vue.computed(() => {
        const records = gameData.value.records;
        if (records.length > 0) {
          return records[records.length - 1];
        }
        return null;
      });
      const lastRecordTime = vue.computed(() => {
        if (lastRecord.value) {
          return lastRecord.value.time;
        }
        return null;
      });
      const timeAgo = core.useTimeAgo(lastRecordTime);
      const lastPlayedText = vue.computed(() => {
        if (!lastRecord.value)
          return "";
        const lastRecordVersion = lastRecord.value.version;
        if (lastRecordVersion === gameInfo.version) {
          return "Finished ";
        } else {
          return `Finished [${lastRecordVersion}] `;
        }
      });
      const removeFlagConfirmVisible = vue.ref(false);
      function handleFlagClick() {
        if (checked.value) {
          removeFlagConfirmVisible.value = true;
        } else {
          checked.value = true;
        }
      }
      const form = vue.reactive({
        version: "",
        date: ""
      });
      const rules = vue.reactive({
        version: [
          {
            required: true,
            message: "Please input version",
            trigger: "blur"
          },
          {
            min: 1,
            max: 30,
            message: "Length should be 1 to 30",
            trigger: "blur"
          },
          {
            validator: (rule, value, callback) => {
              if (gameData.value.records.some((record) => record.version === value)) {
                callback(new Error(`[${value}] already recorded`));
              } else {
                callback();
              }
            },
            trigger: "blur"
          }
        ],
        date: [
          {
            type: "date",
            required: true,
            message: "Please pick a date",
            trigger: "change"
          }
        ]
      });
      const formRef = vue.ref(null);
      const popoverVisible = vue.ref(false);
      const onSubmit = () => {
        formRef.value.validate().then(() => {
          addRecord({
            version: form.version,
            time: form.date.getTime()
          });
          popoverVisible.value = false;
          form.version = "";
          form.date = "";
        }).catch(() => {
        });
      };
      const popoverCommonProps = {
        effect: "light",
        teleported: false,
        placement: "bottom"
      };
      function addRecord({ version, time }) {
        time = time || Date.now();
        gameData.value.records.push({
          version,
          time
        });
        gameData.value.records.sort((a, b) => a.time - b.time);
      }
      function removeRecord({ version }) {
        gameData.value.records = gameData.value.records.filter((record) => record.version !== version);
      }
      function formatTime(time) {
        if (dayjs(time).hour() === 0 && dayjs(time).minute() === 0 && dayjs(time).second() === 0) {
          return dayjs(time).format("YYYY-MM-DD");
        } else {
          return dayjs(time).format("YYYY-MM-DD HH:mm:ss");
        }
      }
      return (_ctx, _cache) => {
        const _component_el_icon = vue.resolveComponent("el-icon");
        const _component_el_popconfirm = vue.resolveComponent("el-popconfirm");
        const _component_el_tooltip = vue.resolveComponent("el-tooltip");
        const _component_el_input = vue.resolveComponent("el-input");
        const _component_el_form_item = vue.resolveComponent("el-form-item");
        const _component_el_date_picker = vue.resolveComponent("el-date-picker");
        const _component_el_button = vue.resolveComponent("el-button");
        const _component_el_form = vue.resolveComponent("el-form");
        const _component_el_popover = vue.resolveComponent("el-popover");
        const _component_el_table_column = vue.resolveComponent("el-table-column");
        const _component_el_table = vue.resolveComponent("el-table");
        return vue.openBlock(), vue.createElementBlock("span", null, [
          vue.createVNode(_component_el_popconfirm, vue.mergeProps({ visible: vue.unref(removeFlagConfirmVisible) }, popoverCommonProps, {
            width: "350",
            "confirm-button-text": "OK",
            "cancel-button-text": "Cancel",
            title: "Remove flag and delete corresponding record?",
            onConfirm: _cache[0] || (_cache[0] = ($event) => removeFlagConfirmVisible.value = checked.value = false),
            onCancel: _cache[1] || (_cache[1] = ($event) => removeFlagConfirmVisible.value = false)
          }), {
            reference: vue.withCtx(() => [
              vue.createElementVNode("span", {
                class: vue.normalizeClass(["p-1 inline-block cursor-pointer v-sub", vue.unref(checked) ? "text-#ec5555" : "text-[rgb(147,152,160)]"])
              }, [
                vue.createVNode(_component_el_icon, {
                  size: 35,
                  onClick: handleFlagClick
                }, {
                  default: vue.withCtx(() => [
                    vue.createVNode(vue.unref(iconsVue.Flag))
                  ]),
                  _: 1
                })
              ], 2)
            ]),
            _: 1
          }, 16, ["visible"]),
          vue.unref(lastPlayedText) ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_1, [
            vue.createTextVNode(vue.toDisplayString(vue.unref(lastPlayedText)) + " ", 1),
            vue.createVNode(_component_el_tooltip, vue.mergeProps(popoverCommonProps, {
              content: formatTime(vue.unref(lastRecordTime))
            }), {
              default: vue.withCtx(() => [
                vue.createElementVNode("span", null, vue.toDisplayString(vue.unref(timeAgo)), 1)
              ]),
              _: 1
            }, 16, ["content"])
          ])) : vue.createCommentVNode("", true),
          vue.createVNode(_component_el_popover, vue.mergeProps(popoverCommonProps, {
            visible: vue.unref(popoverVisible),
            width: 350,
            trigger: "click"
          }), {
            reference: vue.withCtx(() => [
              vue.createVNode(_component_el_icon, {
                size: 20,
                class: "v-middle ml-4 cursor-pointer text-white opacity-70 hover:opacity-100"
              }, {
                default: vue.withCtx(() => [
                  vue.createVNode(vue.unref(iconsVue.CirclePlusFilled), {
                    onClick: _cache[2] || (_cache[2] = ($event) => popoverVisible.value = true)
                  })
                ]),
                _: 1
              })
            ]),
            default: vue.withCtx(() => [
              vue.createVNode(_component_el_form, {
                ref_key: "formRef",
                ref: formRef,
                "label-width": "130px",
                rules: vue.unref(rules),
                model: vue.unref(form)
              }, {
                default: vue.withCtx(() => [
                  vue.createVNode(_component_el_form_item, {
                    label: "Finished Version",
                    prop: "version"
                  }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_input, {
                        modelValue: vue.unref(form).version,
                        "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => vue.unref(form).version = $event)
                      }, null, 8, ["modelValue"])
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_form_item, {
                    label: "Finished Time",
                    prop: "date"
                  }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_date_picker, {
                        modelValue: vue.unref(form).date,
                        "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => vue.unref(form).date = $event),
                        teleported: false,
                        "data-popper-placement": "bottom",
                        type: "date",
                        placeholder: "Pick a date",
                        style: { "width": "100%" }
                      }, null, 8, ["modelValue"])
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_form_item, { class: "button-group" }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_button, {
                        size: "small",
                        onClick: _cache[5] || (_cache[5] = ($event) => popoverVisible.value = false)
                      }, {
                        default: vue.withCtx(() => [
                          vue.createTextVNode("Cancel")
                        ]),
                        _: 1
                      }),
                      vue.createVNode(_component_el_button, {
                        size: "small",
                        type: "primary",
                        onClick: onSubmit
                      }, {
                        default: vue.withCtx(() => [
                          vue.createTextVNode("Create")
                        ]),
                        _: 1
                      })
                    ]),
                    _: 1
                  })
                ]),
                _: 1
              }, 8, ["rules", "model"])
            ]),
            _: 1
          }, 16, ["visible"]),
          vue.createVNode(_component_el_popover, vue.mergeProps(popoverCommonProps, {
            width: 500,
            trigger: "click"
          }), {
            reference: vue.withCtx(() => [
              vue.createVNode(_component_el_icon, {
                size: 20,
                class: "v-middle ml-4 cursor-pointer text-white opacity-70 hover:opacity-100"
              }, {
                default: vue.withCtx(() => [
                  vue.createVNode(vue.unref(iconsVue.Document), {
                    onClick: ($event) => 1
                  })
                ]),
                _: 1
              })
            ]),
            default: vue.withCtx(() => [
              vue.createVNode(_component_el_table, {
                data: vue.unref(gameData).records,
                "default-sort": { prop: "time", order: "descending" }
              }, {
                default: vue.withCtx(() => [
                  vue.createVNode(_component_el_table_column, {
                    "min-width": "120",
                    property: "version",
                    label: "Version"
                  }),
                  vue.createVNode(_component_el_table_column, {
                    sortable: "",
                    "min-width": "150",
                    property: "time",
                    label: "Time"
                  }, {
                    default: vue.withCtx(({ row }) => [
                      vue.createTextVNode(vue.toDisplayString(formatTime(row.time)), 1)
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_table_column, {
                    "min-width": "100",
                    label: "Operations"
                  }, {
                    default: vue.withCtx(({ row }) => [
                      vue.createVNode(_component_el_button, {
                        size: "small",
                        type: "danger",
                        onClick: ($event) => removeRecord(row)
                      }, {
                        default: vue.withCtx(() => [
                          vue.createTextVNode(" Delete ")
                        ]),
                        _: 2
                      }, 1032, ["onClick"])
                    ]),
                    _: 1
                  })
                ]),
                _: 1
              }, 8, ["data"])
            ]),
            _: 1
          }, 16)
        ]);
      };
    }
  };
  const VersionTracker = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-9a23e112"]]);
  const _sfc_main = {
    __name: "App",
    setup(__props) {
      const titleElement2 = vue.inject("titleElement");
      document.documentElement.classList.add("fz-tracker");
      return (_ctx, _cache) => {
        return vue.openBlock(), vue.createBlock(vue.Teleport, { to: vue.unref(titleElement2) }, [
          vue.createVNode(VersionTracker)
        ], 8, ["to"]);
      };
    }
  };
  document.documentElement.classList.add("dark");
  const titleElement = document.querySelector(".p-title-value");
  const isGamePage = (() => {
    const breadcrumbUl = document.querySelector("ul.p-breadcrumbs");
    if (breadcrumbUl) {
      const breadcrumbs = [...breadcrumbUl.querySelectorAll(":scope > li")];
      return breadcrumbs.length === 3 && breadcrumbs[2].innerText.trim().toLowerCase().includes("games");
    }
    return false;
  })();
  const isLatestUpdatesPage = window.location.pathname.startsWith("/sam/latest_alpha");
  if (isGamePage) {
    const gameInfo = titleElement ? (() => {
      const titleText = [...titleElement.childNodes].find((node) => node.nodeType === Node.TEXT_NODE).textContent.trim();
      const matches = titleText.match(/^(.*?)\s*\[(.*?)\]\s*\[(.*?)\]$/);
      if (matches && matches.length === 4) {
        const ID = window.location.pathname.split("/")[2].split(".")[1];
        return {
          ID,
          name: matches[1],
          version: matches[2],
          author: matches[3]
        };
      }
    })() : null;
    if (gameInfo) {
      const appEl = document.createElement("div");
      document.body.append(appEl);
      vue.createApp(_sfc_main).use(ElementPlus).provide("gameInfo", gameInfo).provide("titleElement", titleElement).mount(appEl);
    }
  } else if (isLatestUpdatesPage) {
    const gameCardListEl = document.querySelector("#latest-page_items-wrap_inner");
    if (gameCardListEl) {
      gameCardListEl.querySelectorAll("[data-thread-id]").forEach(mountTag);
      core.useMutationObserver(
        gameCardListEl,
        (mutations) => {
          mutations.filter((mutation) => mutation.type === "childList" && mutation.addedNodes.length > 0).map((mutation) => [...mutation.addedNodes]).flat().forEach(mountTag);
        },
        { childList: true }
      );
    }
  }
  function mountTag(gameInfoEl) {
    const gameInfo = {
      ID: parseInt(gameInfoEl.getAttribute("data-thread-id"), 10),
      name: gameInfoEl.querySelector(".resource-tile_info-header_title").textContent.trim(),
      version: gameInfoEl.querySelector(".resource-tile_label-version").textContent.trim(),
      author: gameInfoEl.querySelector(".resource-tile_dev").textContent.trim()
    };
    if (localStorage.getItem(gameStorageKey(gameInfo.ID))) {
      const tageContainer = document.createElement("div");
      Object.assign(tageContainer.style, {
        position: "absolute",
        left: 0,
        top: 0
      });
      gameInfoEl.append(tageContainer);
      vue.createApp(_sfc_main$2).provide("gameInfo", gameInfo).mount(tageContainer);
    }
  }

})(Vue, ElementPlus, VueUse, ElementPlusIconsVue);