首页 > 其他分享 >【脚本】GutcOJ Helper 发布页 - FReQuenter 的博客园

【脚本】GutcOJ Helper 发布页 - FReQuenter 的博客园

时间:2023-05-01 20:13:25浏览次数:51  
标签:arr const Helper 发布页 博客园 innerHTML let allContestants

地址:https://www.cnblogs.com/FReQuenter5156/p/GutcOJ-Helper.html/

GutcOJ Helper 基于油猴,不知道什么是油猴请自行百度

适配 GuctOJ3.0 和 2.0 版本。

经由 NFLSOJ Helper 改编而来。

NFLSOJ Helper 发布页:http://www.nfls.com.cn:20035/article/1197

更新日志:https://www.luogu.com.cn/paste/vlwxsykx

待完成:

  • 根据 Rating 设置名字颜色

  • 修改背景

历史版本:

地址:https://www.cnblogs.com/FReQuenter5156/p/GutcOJ-Helper/

v0.3.1

  • 【更新】修复一个图标 bug

功能:

  • Predict Rating

  • 查找用户

  • 延长登录时间

源码

// ==UserScript==
// @name         GutcOJ Helper
// @namespace    https://github.com/NFLSCode/nflsoj-helper
// @version      0.3.1
// @description  Use GutcOJ More Easily
// @author       FReQuenter(NFLSOJ Helper by lexiyvv & ppip & GlaceonVGC & ACrazySteve)
// @match        *://oj.oimaster.cf/*
// @match        *://yun.oimaster.ml/*
// @require      http://oj.oimaster.cf/cdnjs/jquery/3.3.1/jquery.min.js
// @require      http://oj.oimaster.cf/cdnjs/blueimp-md5/2.10.0/js/md5.min.js
// @grant        GM_setClipboard
// @grant        GM_info
// ==/UserScript==
/* eslint-disable no-undef */
/* eslint-disable curly */

const domain = window.location.pathname, repo = "NFLSCode/nflsoj-helper";
try {
    let username = $(".dropdown.item")[1].children[0].innerText.slice(0, -1);
    /******************** contest module ********************/
    if (document.body.innerHTML.includes("我的比赛")) $(".menu")[1].innerHTML += `<a class="item" href="/summary/?username=${username}"><i class="tasks icon"></i>总结</a>`;
    if (/contest\/\d+(?!\d|\/[a-z])/.test(domain)) document.body.innerHTML = document.body.innerHTML.replaceAll("<!--", "").replaceAll("-->", "");
} catch {
    console.info('iframe');
}
async function getDOM(href) {
    return new DOMParser().parseFromString(await $.get(href), "text/html");
}

/******************** rightcol module ********************/
function genSearchBox(use, id, holder, api) {
    return [`
    <h4 class="ui top attached block header"><i class="search icon"></i>${use}</h4>
    <div class="ui bottom attached segment">
      <div class="ui search focus" id="${id}" style="width: 100%; ">
        <div class="ui left icon input" style="width: 100%; ">
          <input class="prompt" style="width: 100%;" type="text" placeholder="${holder}">
          <i class="search icon"></i>
        </div>
        <div class="results" style="width: 100%; "></div>
    </div></div>`, `
    $(function () {
      $('#${id}').search({
        debug: true,
        apiSettings: {url: '/api/v2/search/${api}/{query}', cache: false},
        fields: {title: 'name'}
      });
    });
    `];
}
if (domain == "/") {
    document.body.innerHTML = document.body.innerHTML.replaceAll("<!--", "").replaceAll("-->", "");
    let mian = $(".right.floated.five.wide.column")[0];
    let search1 = genSearchBox("查找用户", "user", "ID / 用户名 …", "users");
    mian.children[0].remove();mian.children[0].remove();
    mian.innerHTML = search1[0] + mian.innerHTML;
    let script = document.createElement("script");
    script.innerHTML = search1[1];
    mian.appendChild(script);
}
/******************** rating module ********************/
function getEloWinProbability(ra, rb) {
    return 1.0 / (1 + Math.pow(10, (rb - ra) / 400.0));
}
function getContestantSeed(contestantIndex, allContestants) {
    let seed = 1;
    let rating = allContestants[contestantIndex].currentRating;
    for (let i = 0; i < allContestants.length; i++) if (contestantIndex != i) seed += getEloWinProbability(allContestants[i].currentRating, rating);
    return seed;
}
function sum(arr) {
    let s = 0;
    for (let ind in arr) s += arr[ind];
    return s;
}
function getRatingSeed(rating, allContestants) {
    return 1 + sum(allContestants.map(c => getEloWinProbability(c.currentRating, rating)));
}
function getAverageRank(contestant, allContestants) {
    const realRank = allContestants[contestant].rank;
    const expectedRank = getContestantSeed(contestant, allContestants);
    const average = Math.sqrt(realRank * expectedRank);
    return average;
}
function getRatingToRank(contestantIndex, allContestants) {
    let averageRank = getAverageRank(contestantIndex, allContestants);
    let left = 1;// contestant.getPrevRating() - 2 * minDelta;
    let right = 8000;// contestant.getPrevRating() + 2 * maxDelta;
    while (right - left > 1) {
        const mid = (left + right) / 2;
        const seed = getRatingSeed(mid, allContestants);
        if (seed < averageRank) right = mid;
        else left = mid;
    }
    return left;
}
function calcRating(allContestants) {
    let deltas = [];
    const numberOfContestants = allContestants.length;
    for (let i = 0; i < allContestants.length; i++) {
        const expR = getRatingToRank(i, allContestants);
        deltas[i] = ((expR - allContestants[i].currentRating) / 2);
    }
    const deltaSum = sum(deltas);
    const inc = -deltaSum / numberOfContestants - 1;
    deltas = deltas.map(d => d + inc);
    const zeroSumCount = Math.min(Math.trunc(4 * Math.round(Math.sqrt(numberOfContestants))), numberOfContestants);
    const deltaSum2 = sum(deltas.slice(0, zeroSumCount));
    const inc2 = Math.min(Math.max(-deltaSum2 / zeroSumCount, -10), 0);
    deltas = deltas.map(d => d + inc2);
    return allContestants.map((contestant, i) => {
        let n = Math.round(deltas[i]);
        return `<td>${Math.round(contestant.currentRating + n)}<span class="rating_${n >= 0 ? "up" : "down"}">(${(n < 0 ? "" : "+") + n})</span></td>`;
    });
}
async function Rating() {
    if (document.getElementsByTagName("thead")[0].rows[0].innerHTML.includes("<th>Rating(Δ)</th>")) return ;
    const hisRating = $(".center.aligned.header")[0].innerText.replaceAll("(", "\\(").replaceAll(")", "\\)") + `<\\/td>[\\s\\S]*?(<td>\\d{3,4}[^/]*?<\\/td>)`,
          curRating = /<i class="star icon"><\/i>积分 (\d+)/;
    let arr = document.getElementsByTagName("tbody")[0].rows, c = Array.from({length: arr.length}, (v, i) => i);
    c = (await $.get(arr[0].innerHTML.match(/\/user\/\d+/)[0])).match(hisRating) != null
        ? await Promise.all(c.map(async i => (await $.get(arr[i].innerHTML.match(/\/user\/\d+/)[0])).match(hisRating)[1]))
        : calcRating(await Promise.all(c.map(async i => ({
            rank: arr[i].children[0].innerText,
            currentRating: parseInt((await $.get(arr[i].innerHTML.match(/\/user\/\d+/)[0])).match(curRating)[1])
        }))));
    document.getElementsByTagName("thead")[0].rows[0].innerHTML += "<th>Rating(Δ)</th>";
    for (let i = 0; i < arr.length; ++i) arr[i].innerHTML += c[i];
}
/******************** rank module ********************/
if (/\d+\/(ranklist|repeat)/.test(domain)) {
    let head = document.getElementsByTagName("tr")[0], pos = /ranklist/.test(domain) ? head.innerHTML.indexOf("</th>") + 5 : 0;
    if (head.innerHTML.indexOf("用户名") == -1) {
        let arr = document.getElementsByTagName("tbody")[0].rows;
        head.innerHTML = head.innerHTML.slice(0, pos) + "<th>用户名</th>" + head.innerHTML.slice(pos);
        for (let i = 0; i < arr.length; ++i) {
            let pos = /ranklist/.test(domain) ? arr[i].innerHTML.indexOf("</td>") : 0;
            arr[i].innerHTML = arr[i].innerHTML.slice(0, pos) + name[i] + arr[i].innerHTML.slice(pos);
        }
    }
    if (/ranklist/.test(domain)) {
        $(".padding")[0].innerHTML =
              `<span class="ui mini right floated labeled blue icon button" id="rating" style="top:6px;"><i class="calculator icon" id=calc></i>Predict Rating</span>`
            + $(".padding")[0].innerHTML;
        rating.addEventListener("click", async () => {
            rating.childNodes[1].data = "Please Wait...";
            await Rating();
            rating.childNodes[1].data = "Done!";
        });
    }
}
/******************** dashboard ********************/
if (domain == "/") {
    let col = $(".eleven.wide.column")[0], ind = col.innerHTML.search(/<h4 class="ui top attached block header"><i class="ui signal/);
    col.innerHTML = col.innerHTML.slice(0, ind) + `
    <h4 class="ui top attached block header">
      <style="width:20px;height:20px;position:relative;top:-3px;">GutcOJ Helper 控制面板
    </h4>
    <div class="ui bottom attached segment">
      <table class="ui very basic table" style="table-layout: fixed;">
        <tr><td>
          <h4 style="display:inline;">基础版(NFLSOJ Helper)链接</h4>
          <a class="ui red button" style="position:relative;left:20px;" href="https://github.com/${repo}/">
            <i class="ui linkify icon"></i>NFLSOJ Helper 主页
          </a><a class="ui orange button" id="l2" style="position:relative;left:20px;">
            <i class="repeat icon"></i>NFLSOJ Helper 最新版
          </a>
        </td></tr>
        <tr><td>
          <h4 style="display:inline;">主要功能</h4>
          <a class="ui yellow button" id="f1" style="position:relative;left:20px;">
            <i class="code icon"></i>延长登录时间
          </a>
          <a class="ui green button" id="f2" style="position:relative;left:20px;">
            <i class="code icon"></i>查找用户
          </a>
          <a class="ui blue button" id="f3" style="position:relative;left:20px;">
            <i class="code icon"></i>Predict Rating
          </a>
          <a class="ui purple button" id="f4" style="position:relative;left:20px;">
            <i class="code icon"></i>显示隐藏的用户名
          </a>
        </td></tr>
        <tr><td>
          <h4 style="display:inline;">发布页链接</h4>
          <a class="ui button" id="g1" style="position:relative;left:20px;" href="http://www.nfls.com.cn:20035/article/1197">
            <i class="linkify icon"></i>NFLSOJ: NFLSOJ Helper 发布页
          </a>
          <a class="ui black button" id="g2" style="position:relative;left:20px;" href="https://www.luogu.com.cn/blog/frequenter5156/GutcOJ-Helper">
            <i class="linkify icon"></i>洛谷博客:GutcOJ Helper 发布页
          </a>
        </td></tr>
      </table>
    </div>` + col.innerHTML.slice(ind);
    l2.addEventListener("click", async () => {
        window.location.href = `https://github.com/${repo}/releases/download/${(await $.get(`https://api.github.com/repos/${repo}/releases/latest`)).tag_name}/nflsoj-helper.min.user.js`;
    });
    f1.addEventListener("click", () => {
        document.cookie = `${document.cookie.match(/(^| )(login=[^;]*)(;|$)/)[2]};expires=Wed, 04 Aug 2077 01:00:00 GMT`;
        alert("登录时间延长至 Wed, 04 Aug 2077 01:00:00 GMT。\n在别处登录或登出后无效!");
    });
    f2.addEventListener("click", () => {
        alert("请到首页顶端查看!");
    });
    f3.addEventListener("click", () => {
        alert("请到比赛“排行榜”界面点击“Predict Rating”查看!");
    });
    f4.addEventListener("click", () => {
        alert("请到比赛“排行榜”界面查看,仅在该界面生效。\n虽然但是,截止目前,oimaster并没有这样做过。");
    });
}

v0.3

  • 【更新】大改控制面板。

  • 【更新】发布页

功能:

  • Predict Rating

  • 查找用户

  • 延长登录时间

v0.2

  • 【更新】删除了一些多余的东西。

  • 【移除】名字颜色修改

  • 【移除】修改背景

功能:

  • Predict Rating

  • 查找用户

  • 延长登录时间

v0.1

  • 【更新】第一版。除了 url 啥都没改。

功能:

  • Predict Rating

  • 查找用户

  • 延长登录时间

  • 名字颜色修改(是 NFLSOJ 上的啦)

  • 修改背景

标签:arr,const,Helper,发布页,博客园,innerHTML,let,allContestants
From: https://www.cnblogs.com/FReQuenter5156/p/GutcOJ-Helper.html

相关文章

  • 【配置】Simple Memory - 博客园 cnblogs 个性化博客配置
    前言地址:https://www.cnblogs.com/FReQuenter5156/setblog如题,使用的是SimpleMemory主题。Github连接:https://github.com/BNDong/Cnblogs-Theme-SimpleMemory。想个性化自己的博客只需要改代码就行了。不难改,注释很充分(也就是换一些url啥的。反正我是这么改的。搭建教......
  • 使用ViewDragHelper实现的DragLayout开门效果
    先看一下图,有个直观的了解,向下拖动handle就“开门了”:此DragLayout继承自LinearLayout,这样使得布局变的简单。我把最顶部的View叫做HeadView,中间的叫“把手”HandleView,底部的叫ContentView,姑且这样叫着。只有把手可以拖动,下面的ContentView不可以!只要给Dr......
  • 没有想到博客园还活着
    刚开始真的记不起来之前有发表过文章的网站是哪个了,注册了一部分网站都发现不是,后面搜索了半天才记起来是博客园。一晃都7年过去了,然而本人并没有什么长进,哈哈哈哈哈哈哈,只是从前后端不分离的PHP开发逐渐转前后端分离的Go开发了。好多年了,要重新开始看面试题了哈哈哈哈哈,准备把......
  • 搭配vscode的博客园
    在完成上篇文章:上传本地笔记到博客园的配置后新建工作区,文件夹名称为Cnblogs(自定义)点击右侧导航栏的CnblogsConsole点击扩展设置,可以设置存放博文的文件夹为上方新建的文件夹在本地文件夹新建文件后,可以选择右键保存到博客园,然后选择关联已有的博客或者新建博客,如果新......
  • 博客园图片缩放调整
    上传图片后把![image](https://img2023.cnblogs.com/blog/2421910/202304/2421910-20230429223423752-834545576.png)改为<imgsrc="https://img2023.cnblogs.com/blog/2421910/202304/2421910-20230429223423752-834545576.png"style="zoom:50%"alt=&qu......
  • 测试博客园的Markdown编辑器的支持语法和解析结果
    @目录欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学......
  • 博客园中如何使用HTML所见即可得编辑器TinyMCE
    大纲基本内容:文本、段落规范结构:标题、大纲大量数据:表格、列表内外跳转:链接、锚点视觉媒体:图像、视频、音乐用户交流:表单、交互文本字体、大小、前景色、背景色、加粗、倾斜、下划线、中划线、清楚格式段落段落行间距、段落字间距、段落居中对其、段落居左对齐、......
  • 博客园的使用体验,吐槽那些不好用的功能
    首先给我的感觉是首页没有查找博主的功能,比如说我想看大佬杨中科的博客,那么我在首页搜索”杨中科“会出现什么?如下图 结果却是这样的。。。。。这是什么啊 而我想要的是杨中科的首页  或者说你给我一个列表页,列表内展示的所有名字里面包含“杨中科”是三个字的所有博......
  • 博客园自定义皮肤设置2
    博客园自定义皮肤设置-21.选择皮肤LessIsMore2.博客侧边栏公告<style>#back-top{position:fixed;bottom:10px;right:5px;z-index:99;}#back-topspan{width:50px;height:64px;display:block;background:url(htt......
  • 博客园自定义皮肤设置
    目录博客园自定义皮肤设置1.选择皮肤darkgreentrip2.博客侧边栏公告3.页面定制css代码4.页首HTML代码博客园自定义皮肤设置1.选择皮肤darkgreentrip2.博客侧边栏公告<style>#back-top{position:fixed;bottom:10px;right:5px;z-index:99;}#ba......