[YouTube-Chat] Words Typing

Added word typing game in chat area.

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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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)

}