UMU 增强

增强 UMU 的体验,可根据参与人数进行搜索,可模糊搜索,支持在新窗口打开页面从而不丢失当前浏览状态。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         UMU 增强
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  增强 UMU 的体验,可根据参与人数进行搜索,可模糊搜索,支持在新窗口打开页面从而不丢失当前浏览状态。
// @author       LinHQ
// @match        https://m.umu.cn/course/*
// @icon         https://m.umu.cn/favicon.ico
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @connect https://m.umu.cn/uapi/*
// @require https://greasyfork.org/scripts/429203-async-xmlhttprequest/code/Async%20xmlhttprequest.js?version=949226
// ==/UserScript==
'use strict'

// 搜索关键字 ask
let TYPES = new Map();
TYPES.set(1,"survey");
TYPES.set(2, "ask");
TYPES.set(3, "discussion");
TYPES.set(4, "photo");
TYPES.set(5, "GAME");
TYPES.set(6, "attendance");
TYPES.set(7, "mini_course");
TYPES.set(8, "raffle_drawing");
TYPES.set(9, "registration");
TYPES.set(10, "quiz");
TYPES.set(11, "video");
TYPES.set(12, "live");
TYPES.set(13, "article");
TYPES.set(14, "document");
TYPES.set(16, "exercise/?surl=");

let GROUPID = new URL(window.location.href).searchParams.get('groupId');

// 获取第{cid}目录下的内容
async function getChapters(cid, sessionCount) {
  let resp = await req({
    method: "POST",
    headers: {"Content-type": "application/x-www-form-urlencoded"},
    url: "https://m.umu.cn/uapi/v2/element/chapter-session",
    data: `t=${new Date().getTime()}&parent_id=${GROUPID}&chapter_id=${cid}&page=1&size=${sessionCount}&get_draft=0`
  });
  // 解析返回数据
  let li = JSON.parse(resp.responseText).data.list;
  li = li.map(l => {
    return {
      title: l.index + '.' + l.title,
      href: l.share_card_view.replace("element/share", `session/${TYPES.get(l.type)}`),
      people: parseInt(l.stat.finish_num),
      learned: l.extend.learn_status !== 0
    }
  });
  console.log(li);
  return li;
}

// 获取第{id}页
async function getPage(index) {
  let resp = await req({
    method: "POST",
    headers: {"Content-type": "application/x-www-form-urlencoded"},
    url: "https://m.umu.cn/uapi/v2/element/list",
    data: `t=${new Date().getTime()}&parent_id=${GROUPID}&page=${index}&size=15&get_draft=0`
  });
  return JSON.parse(resp.responseText).data;
}

// 获取所有列表
async function getIds() {
  let ids = [];
  let meta = await getPage(1);
  const pages = meta.page_info.total_page_num;
  for (let p = 1; p <= pages; p++) {
    let currentPage = await getPage(p);
    for (let dir of currentPage.list){
      let chapterIds = await getChapters(dir.id, parseInt(dir.session_count));
      ids = ids.concat(chapterIds);
    }
  }
  return ids;
}

// 根据人数进行过滤
function doFilter(filter, data) {
  console.log(data)
  // 【模式,值】
  let [mode, v] = filter.split(":");
  switch (mode) {
    case 's':
      return data.filter(e => e.title !== undefined && e.title.includes(v));
    case 'gt':
      return data.filter(e => e.people >= parseInt(v));
    case 'lt':
      return data.filter(e => e.people <= parseInt(v));
    case 'd':
      return data.filter(e => e.learned);
    case '!d':
      return data.filter(e => !e.learned);
    default:
      return [];
  }
}

(function () {
  GM_addStyle(`#gm_box{
  position: fixed;
  z-index: 9999;
  top: 0vh;
  left: 0;
  border: 1px solid #a0c5fd;
  border-radius: 5px;
  height: 95vh;
  width: 3.4rem;
  display: flex;
  flex-flow: column;
  }

  #gm_box input {
  margin: 10px;
  }

  #gm_box .show{
  height: 90vh;
  width: 3.4rem;
  margin: 3px auto;
  overflow: auto;
  padding: 5px;
  }

  #gm_box li {
  margin: 5px;
  border-left: 3px solid #fa541c;
  background: #e6e6e6;
  border-radius: 3px;
  padding: 3px;
  color: #114979;
  cursor: pointer;
  line-height: 1.2em;
  }

  #gm_box li.learned {
  border-left: 3px solid #52c41a;
  }

  #gm_box li.clicked {
  border-left: 3px solid #73289b;
  }

  #gm_box .state {
  text-align: center;
  align-self: center;
  font-size: 0.7em;
  }

  #gm_box .state span {
  color: #ff7875;
  }
  `);
  let container = document.createElement("div");
  container.id = "gm_box";
  container.innerHTML = `
  <input type="text" value="s:"/>
  <div class="state">Enter以开始搜索</div>
  <div class="show">
  <ol>
  </ol>
  </div>
  `;
  document.body.appendChild(container);

  let reader = document.querySelector("#gm_box input");
  let li = [];
  reader.onkeypress = async (e) => {
    let ol = document.querySelector(".show>ol");
    let state = document.querySelector("div.state");

    if (e.code === "Enter") {
      // 清除之前内容
      ol.innerHTML = "";

      // 检查缓存
      if (li.length === 0) {
        state.textContent = "正在加载中,请稍后...";
        li = await getIds();
      }

      let res = doFilter(e.target.value, li);
      // 展示结果
      state.textContent = `${res.length} 条结果`;
      for (let l of res) {
        let li = document.createElement("li");
        li.textContent = `${l.title}`;
        ol.appendChild(li);
        if (l.learned) li.classList.add("learned");

        li.onclick = () => {
          // 点击变色
          li.classList.add("clicked");
          window.open(l.href)
        };
      }
    }
  };

})();