read_log

read log

// ==UserScript==
// @name         read_log
// @include      *wikipedia*
// @supportURL   https://github.com/sxlgkxk/browser_script/issues
// @version      0.3
// @description  read log
// @namespace    http://sxlgkxk.github.io/
// @author       sxlgkxk
// @icon         http://sxlgkxk.github.io/im/avatar.jpg
// @license      MIT
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function () {

	let blockWidth = 10
	let blockPadding = 3
	// weeksCount=53
	let weeksCount = 30 // 393, 94
	let canvasWidth = (blockWidth + blockPadding) * weeksCount + blockPadding
	let canvasHeight = (blockWidth + blockPadding) * 7 + blockPadding

	//-------------------------------- common functions --------------------------------

	function addScript(src) {
		let scripts_dom = document.createElement('script');
		scripts_dom.src = src;
		scripts_dom.type = 'text/javascript';
		document.getElementsByTagName('head')[0].appendChild(scripts_dom);
	}
	addScript('https://unpkg.com/axios/dist/axios.min.js')

	function getScrollPercent() {
		let h = document.documentElement,
			b = document.body,
			st = 'scrollTop',
			sh = 'scrollHeight';
		return ((h[st] || b[st]) / ((h[sh] || b[sh])) * 100).toFixed(2);
	}

	function getGistToken() {
		let gist_token = localStorage.getItem('gist_token')
		if (gist_token != null && gist_token.length > 10) {
			gist_token = prompt('gist_token?')
			if (gist_token) {
				localStorage.setItem('gist_token', gist_token)
			}
		}
		return gist_token
	}

	async function gist_get_async(gist_id, filename) {
		// gist_get_async("cfa70a44bb181edbb2be19dacbcf6808", "read_log.json").then((content)=>{console.log(content)})
		let response = await axios.get("https://api.github.com/gists/" + gist_id)
		let data = response.data
		let content = data.files[filename].content
		return content
	}

	async function gist_set_async(gist_id, filename, content) {
		// gist_set_async("cfa70a44bb181edbb2be19dacbcf6808", "read_log.json", "[]").then((content)=>{console.log(content)})
		let files = {}
		files[filename] = { "content": content }
		let gist_token = getGistToken()
		return await axios.patch("https://api.github.com/gists/" + gist_id, { files: files }, { headers: { Authorization: "token " + gist_token } })
	}

	function addStyle(html) {
		let style = document.createElement("div")
		document.body.before(style)
		style.innerHTML = `<style>` + html + `</style>`
	}

	//-------------------------------- code snippets --------------------------------

	addStyle(`
		#wpmArea{
			position: absolute;
			right: 10px;
			left:10px;
			background-color: rgba(255, 255, 255, 0.2);
		}
		#heatmap{
			background-color: #0d1117;
			margin: 0 auto;
			display:block;
		}
		table#history_table {
			border-collapse: collapse;
			width: 100%;
		}
		#history_table th, #history_table td {
			text-align: left;
			padding: 8px;
		}
		button.pagiBtn{
			background-color: #333;
			color: #fff;
			margin: 4px;
			padding-left: 15px;
			padding-right: 15px;
			padding-top: 9px;
			padding-bottom: 9px;
		}
	`)

	for (let i = 1; i <= 31; i++) {
		addStyle(`td.historyDay` + i + `{background-color: rgba(` + Math.floor(Math.random() * 255) + `,` + Math.floor(Math.random() * 255) + `,` + Math.floor(Math.random() * 255) + `, 0.5);}`)
	}

	function getColor(count) {
		let colors = [
			"#161b22",
			"#cef1dd",
			"#9ee3bb",
			"#6dd499",
			"#3cc677",
			"#33a865",
			"#2a8b53",
			"#216d41"
		]
		let max_count = 60 * 8
		return colors[Math.ceil(Math.min(count / max_count, 1) * (colors.length - 1))]
	}

	function setBlock(x, y, count, ctx) {
		ctx.fillStyle = getColor(count);
		ctx.fillRect(x * (blockWidth + blockPadding) - blockWidth, y * (blockWidth + blockPadding) - blockWidth, blockWidth, blockWidth);
	}

	function getRegularWeekday(date) {
		let weekday = date.getDay()
		return weekday ? weekday : 7
	}

	function sum(array) {
		return array.reduce((partialSum, a) => partialSum + a, 0)
	}

	function refreshHeatmap() {
		let log = localStorage.getItem('readlog')
		log = log ? JSON.parse(log) : {}

		let now = new Date();
		let now1 = new Date(now - getRegularWeekday(now) * 3600 * 24 * 1000)

		let canvas = document.querySelector('canvas#heatmap')
		let ctx = canvas.getContext('2d');
		ctx.clearRect(0, 0, canvas.width, canvas.height);

		for (let i = 0; i < 365; i++) {
			let date = new Date(now - i * 3600 * 24 * 1000)
			let weekday = getRegularWeekday(date)
			let y = weekday

			let date1 = new Date(date - getRegularWeekday(date) * 3600 * 24 * 1000)
			let x = weeksCount - (now1 - date1) / 1000 / 3600 / 24 / 7

			let dateStr = getDateStr(date)
			let uuid = getUuid()
			let data = log[dateStr]
			let count = data ? sum(Object.values(data)) : 0

			setBlock(x, y, count, ctx)
		}
	}

	function getUuid() {
		let uuid = localStorage.getItem('uuid')
		if (!uuid) {
			uuid = String(Math.random()).substring(2, 4)
			localStorage.setItem('uuid', uuid)
		}
		return uuid
	}

	function getHistoryDateStr(date = null) {
		date = new Date(date)
		let month = String(date.getMonth() + 1)
		let day = String(date.getDate())
		return month + "." + day
	}

	function getDateStr(date = null) {
		date = date ? date : new Date()
		let year = String(date.getFullYear()).substring(2, 4)
		let month = String(date.getMonth() + 1).padStart(2, '0')
		let day = String(date.getDate()).padStart(2, '0')
		return year + month + day
	}

	function updateLocalLog(uuid, date) {
		let log = localStorage.getItem('readlog')
		log = log ? JSON.parse(log) : {}
		if (!log[date]) log[date] = {}
		if (!log[date][uuid]) log[date][uuid] = 0
		log[date][uuid] += 1
		localStorage.setItem('readlog', JSON.stringify(log))
	}

	function updateGist() {
		let gist_id = "cfa70a44bb181edbb2be19dacbcf6808"
		let filename = "read_log.json"

		let log = localStorage.getItem('readlog')
		log = log ? JSON.parse(log) : {}

		// pull
		gist_get_async(gist_id, filename).then((content) => {
			let remoteLog = JSON.parse(content)
			for (let [date, data] of Object.entries(remoteLog)) {
				if (!log[date]) {
					log[date] = data;
					continue
				}
				for (let [uuid, count] of Object.entries(data)) {
					if (uuid != getUuid()) {
						log[date][uuid] = count
					}
				}
			}

			// push
			gist_set_async(gist_id, filename, JSON.stringify(log)).then((response) => { alert("update success") })
			localStorage.setItem('readlog', JSON.stringify(log))

			refreshHeatmap()
		})
	}

	//-------------------------------- statistics --------------------------------

	// chapter_dom = document.querySelector("div.chapter-detail")
	// if (!chapter_dom) chapter_dom = document.body
	// heatmap_panel = document.createElement("div")
	// chapter_dom.before(heatmap_panel)
	// heatmap_panel.innerHTML = `<canvas id="heatmap" width="` + canvasWidth + `" height="` + canvasHeight + `"></canvas>`

	// canvas = document.querySelector("canvas#heatmap")
	// canvas.onclick = updateGist

	// refreshHeatmap()

	//-------------------------------- wpm --------------------------------

	// function log(){
	// 	addLine()

	// 	uuid=getUuid()
	// 	date=getDateStr()
	// 	updateLocalLog(uuid, date)

	// 	lastGistUpdateDate=localStorage.getItem('lastGistUpdateDate')
	// 	if (!lastGistUpdateDate || lastGistUpdateDate!=date){
	// 		updateGist()
	// 		localStorage.setItem('lastGistUpdateDate', date)
	// 	}

	// 	refreshHeatmap()
	// }
	// document.log=log

	// setInterval(()=>{document.log()},1000*60)
	// refreshHeatmap()

	addStyle(`
		canvas#wpmCanvas {
			background-color: #333;
			position: fixed;
			bottom: 0px;
			right: 100px;
			width: 50px;
			height: 50px;
			opacity: 0.8;
			z-index: 3000;
		}
	`)
	// wpm_dom = document.createElement('div')
	// document.body.before(wpm_dom)
	// wpm_dom.innerHTML = `<canvas id="wpmCanvas" width="50px" height="50px"></canvas>`
	// let wpmQueue=[0]

	function drawWpmCanvas(){
		// console.log('draw')
		let canvas = document.querySelector("canvas#wpmCanvas")
		let ctx = canvas.getContext('2d');
		ctx.clearRect(0, 0, canvas.width, canvas.height);

		// lines
		ctx.beginPath();
		ctx.moveTo(50,50-50*Math.min(wpmQueue[wpmQueue.length-1]/500, 1));
		for(let i=wpmQueue.length-1;i>=0;i--){
			let y=50*Math.min(wpmQueue[i]/500,1);
			let x=50-(wpmQueue.length-1-i)*5-5;
			ctx.lineTo(x, 50-y);
			// console.log(x, y)
		}
		ctx.strokeStyle = "white";
		ctx.stroke();

		// draw wpm number
		ctx.font = "16px Arial bold";
		ctx.fillStyle = "#9aa83a";
		ctx.fillText(wpmQueue[wpmQueue.length-1], 5, 21);

	}
	// drawWpmCanvas()

	// let wpmArea = document.createElement("div")
	// wpmArea.id="wpmArea"
	// wpmArea.classList.add("wpmArea")
	// wpmArea.style.top = "0px"
	// wpmArea.style.height = "0px"
	// document.body.before(wpmArea)
	let forceUpdateWpmArea=false;
	
	let lastStartTime=new Date().getTime()
	function updateWpmArea(){
		let _lineStart=parseInt(wpmArea.style.top.replace("px",""))
		let _lineEnd=_lineStart+parseInt(wpmArea.style.height.replace("px",""))

		let lineEnd=document.documentElement["scrollTop"]+window.innerHeight*0.2
		let lineStart=Math.min(_lineEnd, lineEnd)-1;

		// queue push
		if(new Date().getTime()-lastStartTime>1000*60 || forceUpdateWpmArea){
			forceUpdateWpmArea=false;
			lastStartTime=new Date().getTime()
			wpmArea.style.top=lineStart+"px"
			wpmQueue.push(wpmArea[wpmQueue.length-1])
		}
		wpmArea.style.height=(lineEnd-_lineStart)+"px"

		let words_cnt=countWords(_lineStart, lineEnd)
		// console.log(_lineStart, lineEnd, words_cnt)
		wpmQueue[wpmQueue.length-1]=Math.round(words_cnt/((new Date().getTime()-lastStartTime)/1000/60))
		// drawWpmCanvas()
	}
	// let wpmInterval=setInterval(updateWpmArea, 1000)

	// document.querySelector('canvas#wpmCanvas').onclick = function(){
	// 	forceUpdateWpmArea=true;
	// 	updateWpmArea()
	// 	updateWpmArea()
	// }

	function countWords(lineStart, lineEnd){
		let items=document.querySelector('div.chapterContent')
		if(!items) return 0;
		items=items.querySelectorAll('p')
		let words_cnt=0;
		for(let item of items){
			let top=item.offsetTop;
			let text=item.innerText;
			let height=item.offsetHeight;
			let _words_cnt=text.split(" ").length;
			let end=top+height;

			if(lineStart > end || lineEnd < top) continue;

			if(lineStart<top && lineEnd>end){
				words_cnt+=_words_cnt;
				// console.log("1: "+text)
			}else if(lineStart<top && lineEnd>top){
				words_cnt+=_words_cnt*(lineEnd-top)/height;
				// console.log("2: "+text)
			}else if(lineStart<end && lineEnd>end){
				words_cnt+=_words_cnt*(end-lineStart)/height;
				// console.log("3: "+text)
			}else if(lineStart>top && lineEnd<end){
				words_cnt+=_words_cnt*(lineEnd-lineStart)/height;
				// console.log("4: "+text)
			}
		}
		return Math.round(words_cnt)
	}
	let cnt=countWords(0, 100000)
	console.log(cnt)

	//-------------------------------- history --------------------------------

	let chapter_dom = document.querySelector("div.chapter-detail")
	if (!chapter_dom) chapter_dom = document.body
	let history_panel = document.createElement("div")
	chapter_dom.before(history_panel)
	history_panel.innerHTML = `<div>
	<table id="history_table">
	</table>
	<button id="history_prev" class="pagiBtn">\<</button>
	<button id="history_next" class="pagiBtn">\></button>
	<input id="history_input" type="text" value="1" size="3">
	<button id="history_go" class="pagiBtn">go</button>
</div>`

	let history_data = localStorage.getItem('history_data')
	history_data = history_data ? JSON.parse(history_data) : {}
	history_data[location.href] = { date: new Date().getTime(), title: document.title.replace(" - Wikipedia", ''), url: location.href }
	localStorage.setItem('history_data', JSON.stringify(history_data))
	let history_list = Object.values(history_data).sort((a, b) => { return b.date - a.date })

	function setHistoryTable(page) {
		page = page ? page : 1
		let history_pageSize = 10
		let history_table = document.querySelector("#history_table")
		history_table.innerHTML = ""

		let start = (page - 1) * history_pageSize
		let end = Math.min(start + history_pageSize, history_list.length)

		for (let i = start; i < end; i++) {
			let day = new Date(history_list[i].date).getDate()
			history_table.innerHTML += `<tr>
			<td class="historyDay`+ day + `">` + getHistoryDateStr(history_list[i].date) + `</td>
			<td><a href="`+ history_list[i].url + `">` + history_list[i].title + `</a></td>
		</tr>`
		}
	}
	setHistoryTable(1)

	document.querySelector('#history_prev').onclick = () => {
		let history_page = document.querySelector('#history_input').value;
		setHistoryTable(--history_page);
		document.querySelector('#history_input').value = history_page
	}
	document.querySelector('#history_next').onclick = () => {
		let history_page = document.querySelector('#history_input').value;
		setHistoryTable(++history_page);
		document.querySelector('#history_input').value = history_page
	}

	document.querySelector('#history_go').onclick = () => {
		let history_page = document.querySelector('#history_input').value;
		setHistoryTable(history_page);
	}

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址