Greasy Fork

Greasy Fork is available in English.

超星 - 阅读任务显示已读时间

不要停下来啊!(指阅读)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        超星 - 阅读任务显示已读时间
// @description 不要停下来啊!(指阅读)
// @namespace   UnKnown
// @author      UnKnown
// @icon        https://imgsrc.baidu.com/forum/pic/item/6a63f6246b600c33c3d714d61c4c510fd9f9a106.jpg
// @version     1.1
// @match       https://*.chaoxing.com/course/*.html
// @grant       GM_getValue
// @grant       GM_setValue
// @inject-into page
// @run-at      document-start
// ==/UserScript==

const css = `
#top,
#readTime {
	opacity: .9;
	transition:
		opacity 150ms ease-in-out,
		filter   75ms ease-out;
}

#top:hover,
#readTime {
	opacity: 1;
}

#top:active {
	filter: brightness(1.5);
}

#readTime {
	display: flex;
	justify-content: center;
	align-items: center;
	position: fixed;
	right: 85px;
	bottom: 150px;
	width: 0;
	overflow: visible;
	white-space: nowrap;
}
#readTime > span {
	padding: 1ex 1ch;
	color: white;
	background-color: #212121;
	border-radius: 2px;
	box-shadow:
		0px 3px 1px -2px rgba(0, 0, 0, 0.2),
		0px 2px 2px 0px rgba(0, 0, 0, 0.14),
		0px 1px 5px 0px rgba(0, 0, 0, 0.12);
}
`.trim();

const sendLogs = function (para, url) {
/*
	var para = {
		courseid : courseid,
		chapterid : chapterid,
		height : document.getElementById("courseMainBox").clientHeight,
	}
	if (from != null && from != "") { p._from_ = from; }
	if (rtag != null && rtag != "") { p.rtag   = rtag; }
	var url = "/multimedia/readlog"
*/

	// 多功能随机取整函数
	/* 当 extra 存在时,范围为 base ~ base + extra
	    extra 不存在时,范围为 base ~ base * 2 */
	var roll = function (base, extra) {
		return Math.round(
			base + Math.random() * ( extra || base )
		);
	};

	// 发送频率
	var interval = 5000;
	var intervalInSecond = interval / 1000;

	// 发送概率
	var probability = 0.9;

	// 页面边距
	var pad = roll(200, 66);

	// 滚动参数,之后由 init 函数设置属性
	var scroll = {};

	var init = function () {
		para.h = 0;
		// para.height / ( 32 ~ 64 )
		scroll.base = para.height / roll(32);
		// para.height / ( 16 ~ 32 )
		scroll.extra = para.height / roll(16);
	};

	init();

	// 检测并处理参数对象的 chapterid 属性
	var setCourseid = function (paramObj) {
		if (
			// 传入的参数对象 paramObj 拥有 chapterid 属性
			paramObj.chapterid &&
			// window.courselist 对象存在,且为数组
			window.courselist &&
			Array.isArray(window.courselist)
		) {
			for( var i = 0; i < window.courselist.length; i++ ) {
				var course     = window.courselist[i];
				var coursenext = window.courselist[i + 1];
				if (
					// coursenext 不存在,
					coursenext == undefined || // (
					// 或者 coursenext 存在,但是当前滚动高度 paramObj.h
					// 的大小在 course.h 和 coursenext.h 之间
					course.h <= paramObj.h &&
					paramObj.h < coursenext.h // )
				) {
					// 按照 course.knowledgeid 是否存在,设置 chapterid
					paramObj.chapterid =
						course && course.knowledgeid || 0;
					break;
				}
			}
		}; // return paramObj;
	};

	var ajax = function (paramObj, baseUrl) {
		
		setCourseid(paramObj);
		
		var xhr = new XMLHttpRequest();
		xhr.open(
			"GET",
			baseUrl + "?" + new URLSearchParams(paramObj).toString(),
			true
		);
		xhr.send(null);

	};

	ajax(para, url);

	// 在右下角显示浏览器本地记录的本次已读时间
	// 后面的 time 和 duration 的单位都是秒
	var tick;
	var top = document.getElementById("top");

	if ( top ) {
		var toReadableTime = function (time) { // 传入总时长 duration

			if (time > 0) {
				var result = "";

				if (time >= 3600)
					result += Math.floor(time / 3600) + " 小时 ";
				if (time >= 60)
					result += Math.floor(time / 60 % 60) + " 分钟 ";
				// if (time >= 0)
					result += Math.floor(time % 60) + " 秒";

				return result;
			} else {
				return "0 秒";
			}

		};

		var div = document.createElement("div");
		var span = document.createElement("span");
		var style = document.createElement("style");

		// 总时长
		var duration = GM_getValue(para.courseid) || 0;

		div.id = "readTime";
		span.textContent =  toReadableTime(duration);
		style.textContent = css ||

"#readTime { display: flex; justify-content: center; align-items: center;" +
"position: fixed; right: 85px; bottom: 150px; width: 0; overflow: visible;" +
"white-space: nowrap; }" +
"#readTime > span { padding: 1ex 1ch; color: white; background-color: #212121; }";

		div.appendChild(span);
		div.appendChild(style);
		document.body.appendChild(div);

		tick = function (time) { // 传入每次增加的时长 intervalInSecond
			duration += time;
			span.textContent = toReadableTime(duration);
			para.courseid && GM_setValue(para.courseid, duration);
		};
	} else {
		tick = function () {};
	}

	setInterval(
		function () {
			if ( Math.random() <= probability ) {
				para.h += roll( scroll.base, scroll.extra );
				if ( para.h > ( para.height + pad ) ) {
					init();
				}
				ajax(para, url);
				tick(intervalInSecond);
			}
		}, interval
	);
}

Object.defineProperty(
	unsafeWindow, "sendLogs", {
		configurable: false,
		enumerable: true,
		writable: false,
		value: sendLogs
	}
);