[YouTube-Chat] Words Typing

Added word typing game in chat area.

当前为 2022-11-23 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         [YouTube-Chat] Words Typing
// @namespace    http://tampermonkey.net/
// @version      0.1beta
// @description  Added word typing game in chat area.
// @author       You
// @include        https://www.youtube.com/live_chat*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @require https://greasyfork.org/scripts/455302-youtube-auto-add-text-in-chatbox/code/%5BYouTube%5D%20Auto%20add%20Text%20in%20ChatBox.js?version=1120375
// @grant        none
// @license MIT
// ==/UserScript==

let words
let chatTextBox
let wordArea
let setWords = ['test','sample','word','arc', 'air', 'arm', 'ace', 'act', 'ash', 'asp','arc', 'air', 'arm', 'ace', 'act', 'ash', 'asp']
let inputEvent
let separator = " "
let searchTime = new Date().getTime()
let roundTypeCounter = 0
let typeCounter = 0

/**
 *@Description 単語集をロードする。
*/
fetch(`https://dl.dropboxusercontent.com/s/tw2j3ifk8mv2ten/jpWordsSample.txt?dl=0`).then(function(response) {

	return response.text()

}).then(function(text) {

	//textを取得した
	words = text.split("\r\n")

	htmlSetUp()
});





function htmlSetUp(){

	const shortcutKeys = `
Esc: Word skip
Tab: Switch Text Box
`

	document.getElementById("top").insertAdjacentHTML("afterend",`
<div id="minimum-dictionary">
  <div id="word-table">#<span id="wordarea">${setWords.join(separator)}</span></div>
  <div id="word-tools">
    <input id="word-search-box" maxlength="6" autocomplete="off" value="????" placeholder="[?] Search">
    <span><span id="word-match">0</span> word</span>
    <span id="shortcut-keys" title="${shortcutKeys}">⌨</span>
    <span><span id="typing-count">0</span> types</span>
    <span><span id="typing-speed">0.0</span> k/s</span>
  </div>
</div>
<style>
  #minimum-dictionary{
      margin-left: 48px;
      white-space: nowrap;
  }
  #word-search-box{
  background: rgb(0 0 0 / 10%);
      border: #000000 thin;
      border-top: none;
      outline: solid thin #ffffffa6;
      color: rgb(255 255 255 / 87%);
      width: 8rem;
  }
  #minimum-dictionary > div {
    margin-bottom: 1rem;
  }
  #word-tools > *{
    margin-right: 0.9rem;
  }
  #shortcut-keys:hover{
    text-decoration: underline;
    cursor: help;
  }

</style>`)


	chatTextBox = document.querySelector("#input > #input")
	wordArea = document.getElementById("wordarea")
    inputEvent = new typingCheck()

	chatTextBox.addEventListener("input", inputEvent.typeCheck.bind(inputEvent))
	chatTextBox.addEventListener("keydown", inputEvent.enterSubmitWord.bind(inputEvent))
	document.getElementById("word-search-box").addEventListener("keydown",wordSearch)
	setInterval(updateTypingSpeed,1000)
}



class typingCheck {

	constructor() {
		this.typelog = "";
	}


    /**
     *@Description inputイベントで入力ワードを比較する。
    */
	typeCheck(event){

		const c = new RegExp(`^${chatTextBox.textContent.slice(1)}`,"i")
		const match = setWords[0] ? setWords[0].match(c) : ""
		const matchLength = (match ? match[0].length : 0)

		if(event.data && /insertCompositionText|insertText/.test(event.inputType) && this.typelog.length < event.target.textContent.length){
			document.getElementById("typing-count").textContent = ++typeCounter;
			updateTypingSpeed()
		}

		this.typelog = event.target.textContent || "";

		if(match){
			wordArea.textContent = setWords[0].slice(matchLength) + separator + setWords.slice(1).join(separator)
        }else if(!chatTextBox.textContent){
            wordArea.textContent = setWords.join(separator)
        }

	}



    /**
     *@Description チャットテキストボックスのkeydownイベント。

     *@note
     *Enterで送信時、入力したワードを評価。
     *Escでワードスキップ
	 *Tabでテキストボックスフォーカス切り替え
    */
	enterSubmitWord(event){

        if(event.key == "Enter"){

            if(setWords[0] == chatTextBox.textContent.slice(1)){
                setWords = setWords.slice(1)
            }

			if(chatTextBox.textContent != "#" && chatTextBox.textContent){
				document.getElementById("typing-count").textContent = ++typeCounter;
				updateTypingSpeed()
			}

            wordArea.textContent = setWords.join(separator)

        }else if(event.key == "Escape"){

            setWords = setWords.slice(1)
            wordArea.textContent = setWords.join(separator)

        }else if(event.key == "Tab"){

			document.getElementById("word-search-box").focus()
			event.preventDefault()

		}
	}

}




/**
 *@Description ?でワードを検索する。
*/
function wordSearch(event){

	//検索ボックスにフォーカスしている状態でEnterを押した
	if(event.key == "Enter"){
		//Enterを押した検索ボックスの要素
		const searchBox = event.target
		//文字列で正規表現を作成
		const RegText = `^${searchBox.value.replace(/[?]/g, "\\D").replace(/[?]/g, "\\d")}$`
		//文字列を正規表現に変換
		const Reg = new RegExp(RegText ,"i")

		//正規表現にマッチする単語のみを絞り込む
		setWords = words.filter(word => Reg.test(word)).slice(0,500);

		//日本語検索時は全角スペースで区切る。英単語は半角スペースで区切る。
		separator = (/?/.test(searchBox.value) ? " " : " ")

		//結果を出力
		wordArea.textContent = setWords.join(separator)
		//結果件数を表示
		document.getElementById("word-match").textContent = setWords.length
		//検索ボックスを初期化
		searchBox.value = ""
		//打鍵速度計測用時間・測定用打鍵数を設定
		searchTime = new Date().getTime()
		roundTypeCounter = new Number(typeCounter)
		document.getElementById("typing-speed").textContent = (0).toFixed(1)

	}else if(event.key == "Tab"){

		chatTextBox.focus()

		event.preventDefault()

	}

}




/**
 *@Description 打鍵速度を更新する
*/
function updateTypingSpeed(){

	document.getElementById("typing-speed").textContent = ((typeCounter - roundTypeCounter) / ((new Date().getTime()-searchTime)/1000)).toFixed(1)

}