优雅打印 | 显示难度
// ==UserScript==
// @name Luogu Helper
// @name:zh-CN 洛谷助手
// @description Print elegantly | Show difficulty
// @description:zh-CN 优雅打印 | 显示难度
// @namespace work.pythoner
// @match *://*.luogu.com.cn/*
// @require https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js
// @run-at document-end
// @grant GM_registerMenuCommand
// @grant GM_xmlhttpRequest
// @grant GM_listValues
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_log
// @version 1.0
// @author Hanson Hu
// @homepage https://blog.pythoner.work
// @icon https://blog.pythoner.work/favicon.ico
// @license MIT
// ==/UserScript==
$.noConflict();
jQuery(document).ready(function() {
function getToday() {
// local tz
let ret = new Date().toLocaleString('sv').slice(0, 10);
return ret;
}
function getTail(str) {
let index = str.lastIndexOf('\/');
return str.substring(index + 1, str.length);
}
function getCache(key) {
const value = GM_getValue(key);
if (value === undefined) return false;
const obj = JSON.parse(value);
const curr = Date.now();
if (curr - obj.time > CACHE_LIFESPAN) {
GM_deleteValue(key);
GM_log('Deleted key ' + key);
return false;
} else {
return obj.data;
}
}
function setCache(key, value) {
const curr = Date.now();
GM_setValue(key, JSON.stringify({data: value, time: curr}));
GM_log('Added key ' + key);
}
function getCFDifficulty() {
let ret = getCache(pnum);
if (ret) return ret;
const re = /CF(\d+)(\w+)/;
let t1 = re.exec(pnum)[1],
t2 = re.exec(pnum)[2];
GM_xmlhttpRequest({
method: 'GET',
url: 'https://codeforces.com/problemset/problem/' +
t1 + '/' + t2,
// synchronous is not supported
synchronous: true,
timeout: 10000,
onload: function(response) {
const re = /<span.+? title="Difficulty">\s*([*0-9]+)\s*<\/span>/,
html = response.responseText;
ret = re.exec(html)[1];
setCache(pnum, ret);
},
onerror: function(e) {
console.error('Access CodeForces error ', e);
},
ontimeout: function(e) {
console.error('Access CodeForces timeout ', e);
}
});
return ret;
}
function showDifficulty() {
let cfd = getCFDifficulty();
if (cfd && !flag) {
difficulty = cfd + '/' + difficulty;
flag = true;
jQuery('.side a[href^="/problem/list?difficulty="] span').text(difficulty);
}
}
function getDeferredValue() {
pnum = getTail(window.location.href);
title = jQuery('.header h1 span').prop('title').replace(pnum, '').trim();
problem = jQuery('.main .problem-card div').eq(1).html().trim();
difficulty = jQuery('.side a[href^="/problem/list?difficulty="] span').text().trim();
if (pnum.startsWith('CF')) showDifficulty();
}
function onClickPrint() {
jQuery('#app').remove();
let elem = '<h1 class="lfe-h1"><span title="' + title +
'">LG' + pnum + '. ' + title +
'</span></h1>';
jQuery('body').append(elem);
elem = '<div><p>' + difficulty + '</p></div>';
jQuery('body').append(elem);
elem = problem.replaceAll(/\sdata-v-\w+=""/g, '');
jQuery('body').append(elem);
elem = '<div style="position: absolute; top: 2px; right: 2px; ' +
'font-family: Bahnschrift, Trebuchet MS, sans-serif; ' +
'font-weight: lighter; font-stretch: condensed; ' +
'font-size: 20px;">' + getToday() + '</div>';
jQuery('body').append(elem);
jQuery('.lfe-h1').css({'font-size': '1.5em', 'font-weight': 'normal'});
jQuery('.lfe-h2').css('margin-bottom', '0');
jQuery('.lfe-h3').css('margin-bottom', '0');
jQuery('.sample .input').css({'border': '1px solid #eee', 'margin': '0.25em 0', 'padding': '0.25em'});
jQuery('.sample .output').css({'border': '1px solid #eee', 'margin': '0.25em 0', 'padding': '0.25em'});
jQuery('.sample .copy-btn').css('display', 'none');
jQuery('body').css({'zoom': '80%', 'padding': '2em 3em 2em 3em', 'font-size': '14px'});
}
function onClickPurgeCache() {
const curr = Date().now();
let arr = new Array();
for (const key of GM_listValues()) {
const obj = JSON.parse(GM_getValue(key));
if (curr - obj.time > CACHE_LIFESPAN) arr.push(key);
}
for (const key of arr) {
GM_deleteValue(key);
GM_log('Deleted key ' + key);
}
}
GM_registerMenuCommand('Prepare to print', onClickPrint);
GM_registerMenuCommand('Purge cache', onClickPurgeCache);
const CACHE_LIFESPAN = 30 * 86400 * 1000;
let pnum, title, problem, difficulty, flag = false;
// Luogu load content lazily
setTimeout(getDeferredValue, 1000);
// update asynchronous result
setTimeout(showDifficulty, 4000);
});