[YouTube-Chat] Words Typing

Added word typing game in chat area.

目前為 2022-11-23 提交的版本,檢視 最新版本

// ==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)

}