動畫瘋 OP管理工具

標記OP時間點 投票 跳過 自動跳過

目前为 2025-01-26 提交的版本。查看 最新版本

// ==UserScript==
// @name         動畫瘋 OP管理工具
// @version      1.0.1
// @description  標記OP時間點 投票 跳過 自動跳過
// @namespace    thomas2013
// @author       thomas2013 
// @homepage     https://home.gamer.com.tw/homeindex.php?owner=thomas2013
// @match        *://ani.gamer.com.tw/animeVideo.php?sn=*
// @icon         https://i2.bahamut.com.tw/anime/logo.svg
// @grant GM.xmlHttpRequest
// @license MIT
// ==/UserScript==


(async function () {
    const TESTING = false;
    let serverUrl = ''
    if (TESTING) {
        serverUrl = 'http://localhost:3000'
    } else {
        serverUrl = 'http://ec2-16-163-84-57.ap-east-1.compute.amazonaws.com:3000'
    }
    'use strict';

    const styles = document.createElement('style');
    styles.textContent = `
    .skTime-input {
        padding: 1px;
        border: 3px solid rgb(96, 98, 102);
        border-radius: 3px;
        font-size: 17px;
        width: 34px;
        transition: all 0.3s ease;
        outline: none;
        background-color: rgb(96, 98, 102);
        color: #2c2828;
    }

    .sk-input:hover {
        border-color: #9e9e9e;
    }

    .skTime-input::placeholder {
        color: #9e9e9e;
        opacity: 0.7;
    }

    .skPass-input {
        padding: 1px;
        border: 3px solid rgb(96, 98, 102);
        border-radius: 3px;
        font-size: 17px;
        width: 60px;
        transition: all 0.3s ease;
        outline: none;
        background-color: rgb(96, 98, 102);
        color: #2c2828;
    }

    .skPass-input:hover {
        border-color: #9e9e9e;
    }
        
    .status-container {
        position: absolute;
        top: 60px;
        right: 20px;
        width: auto;
        max-width: 300px;
        pointer-events: none;
    }

    .status-container-top {
        position: absolute;
        top: 100px;
        right: 26%;
        width: auto;
        z-index: 999;
        max-width: 300px;
        pointer-events: none;
    }

    .status-popover {
        position: relative;
        background: rgba(33, 33, 33, 0.9);
        color: white;
        padding: 12px 20px;
        border-radius: 8px;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
        margin-bottom: 10px;
        transition: all 0.3s ease;
        display: flex;
        align-items: center;
        gap: 10px;
        pointer-events: auto;
        opacity: 0;
        transform: translateX(20px);
    }

    .status-popover.show {
        opacity: 1;
        transform: translateX(0);
    }

    .status-popover.success {
        background: rgba(46, 125, 50, 0.9);
    }

    .status-popover.error {
        background: rgba(198, 40, 40, 0.9);
    }

    .status-popover.warning {
        background: rgba(255, 152, 0, 0.9);
    }

    .status-icon {
        font-size: 20px;
        flex-shrink: 0;
    }

    .status-message {
        font-size: 16px;
        flex-grow: 1;
        white-space: nowrap;
        text-overflow: ellipsis;
    }

    .status-close {
        margin-left: 10px;
        cursor: pointer;
        opacity: 0.7;
        transition: opacity 0.2s;
        flex-shrink: 0;
    }

    .status-close:hover {
        opacity: 1;
    }

    .opening-control-button {
        margin: 10px 0;
        display: flex;
        gap: 8px;
        justify-content: center;
    }

    .opening-control-button button {
        padding: 8px 15px;
        border-radius: 4px;
        border: none;
        background-color:rgb(96, 98, 102);
        color: white;
        box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        font-size: 14px;
        cursor: pointer;
        transition: all 0.2s ease;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
    }

    .opening-control-button button:hover {
        background-color: #404244;
        transform: translateY(-1px);
        box-shadow: 0 3px 5px rgba(0,0,0,0.15);
    }

    .opening-control-button button:active {
        transform: translateY(1px);
        box-shadow: 0 1px 2px rgba(0,0,0,0.1);
    }

        .opening-report-button {
        margin: 10px 0;
        display: flex;
        gap: 8px;
        justify-content: center;
    }

    .opening-report-button button {
        padding: 8px 15px;
        border-radius: 4px;
        border: none;
        background-color:rgb(96, 98, 102);
        color: white;
        box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        font-size: 14px;
        cursor: pointer;
        transition: all 0.2s ease;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
    }

    .opening-report-button button:hover {
        background-color: #404244;
        transform: translateY(-1px);
        box-shadow: 0 3px 5px rgba(0,0,0,0.15);
    }

    .opening-report-button button:active {
        transform: translateY(1px);
        box-shadow: 0 1px 2px rgba(0,0,0,0.1);
    }

    .inter-text {
        text-align: center;
        font-size: 10px;
        font-family: monospace;
        padding: 10px;
        background-color: #2e2f31;
        color: white;
        border-radius: 4px;
        margin: 10px 0;    
    }

    #videoTimer {
        text-align: center;
        font-size: 20px;
        font-family: monospace;
        padding: 10px;
        background-color: #2e2f31;
        color: white;
        border-radius: 4px;
        margin: 10px 0;
    }

    .inter-text {
        margin: 0;
        padding: 0;
        margin-bottom: 20px;
    }

    .parent-container {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        gap: 10px;
        align-items: flex-start;
    }

    .your-uploaded-time {
        background:rgb(62, 126, 222); 
    }
        
    .rank1-time {
        position: absolute;
        top: 0;
        left: 0;
        width: 100px;
        height: 100px;
        background-color: #3498db;
        z-index: 1;

        background:rgb(89, 169, 83);
        }
        
    .sk-container {
        background:rgb(23, 23, 23);
        border-radius: 10px;
        padding: 10px;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
        max-width: 400px;
        margin: 10px auto;
        flex: 0 0 auto;
    }

    .sk-time-wrapper {
        display: flex;
        flex-direction: column;
        gap: 6px;
    }

    .sk-time-list {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 12px;
        border-radius: 6px;
        font-size: 16px;
        color: #fff;
    }

    .sk-time {
        font-family: 'Roboto Mono', monospace;
        font-weight: 500;
    }

    .sk-votes {
        color: #9e9e9e;
        font-size: 14px;
    }

    .sk-vote-controls {
        align-items: center;
        display: flex;
        gap: 4px;
    }

    .sk-vote {
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 4px;
        padding: 8px 18px;
        border: none;
        border-radius: 6px;
        font-size: 14px;
        font-weight: 500;
        cursor: pointer;
        transition: all 0.2s ease;
        color: #fff;
        background: #424242;
    }

    .sk-vote--up:hover {
        background: #2e7d32;
    }
        
    .sk-vote--down:hover {
        background: #c62828;
    }
            
    .sk-vote-VOTEDP {
        background: #2e7d32;
    }
            
    .sk-vote-VOTEDN {
        background: #c62828;
        }
        
    .sk-vote-has-been-chosen {
        background:rgb(71, 60, 225);
    }

    .sk-vote:active {
        transform: scale(0.98);
    }

    .sk-icon {
        font-size: 12px;
    }

    .sk-vote-count {
        background: rgba(255, 255, 255, 0.1);
        padding: 2px 6px;
        border-radius: 4px;
        font-size: 12px;
    }

    .sk-vote--disabled {
        opacity: 0.5;
        cursor: not-allowed;
    }

    .ani-tab-content__item button.upload_vote {
        position: absolute;
        top: 300px;
        right: 25px;
        width: 44px;
        height: 34px;
        float: none;
        margin: 0;
        padding: 0;
        font-size: 18px;
        border-radius: 5px;
        border: 1px solid var(--anime-primary-color);
        background: var(--anime-primary-color);
        color: rgba(var(--anime-white-rgb), 1);
        box-shadow: 0 3px 6px -2px rgba(0, 0, 0, 0.2);
        z-index: 1;
        cursor: pointer;
        outline: none;
    }

    .sk-vote-material-icons {
        font-family: 'Material Icons';
        font-weight: normal;
        font-style: normal;
        font-size: 16px;
        line-height: 1;
        letter-spacing: normal;
        text-transform: none;
        display: inline-block;
        white-space: nowrap;
        word-wrap: normal;
        direction: ltr;
        -webkit-font-smoothing: antialiased;
    }

    .sk-sky-container {
        position: relative;
        display: flex;
        justify-content: center;
    }

    .skInfo {
        position: absolute;
        top: 8px;
        right: 85px;
        width: 25px;
        height: 25px;
        float: none;
        margin: 0;
        padding: 0px;
        font-size: 18px;
        border-radius: 17px;
        border: 1px solid #707070;
        background: #9baeb1;
        color: #f0f0f0f0;
        box-shadow: 0 3px 6px -2px rgba(0, 0, 0, 0.2);
        z-index: 1;
        cursor: pointer;
        outline: none;    
    }

    .info-container {
        position: relative;
        display: flex;
        justify-content: center;
    }

    .info-trigger {
        align-items: center;
    }

    .sk-introduction {
        z-index: 10000;
        font-size: 16px;
        visibility: hidden;
        position: absolute;
        right: -70px;
        top: 140px;
        transform: translateX(-50%);
        background-color: rgb(175 175 175 / 90%);
        padding: 12px;
        border-radius: 9px;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
        width: max-content;
        opacity: 1;
        translate: revert;
        transition: opacity 0.3s, visibility 0.3s;
    }

    .sk-introduction::after {
        position: absolute;
        top: 100%;
        left: 50%;
        margin-left: -5px;
        border-width: 5px;
        border-style: solid;
        border-color: #e5e5e5 transparent transparent transparent;
    }

    .sk-introduction div {
        padding: 3px;
    }

    .sk-introduction-title {
        font-size: 16px;
        font-weight: bold;
    }

    .sk-info-show {
        visibility: visible;
        opacity: 1;
    }

    .sk-info-hidden {
        visibility: hidden;
        opacity: 0;
    }

    .sk-sky-button-container {
        justify-content: center;
        z-index: 10000;    
        font-size: 16px;
        position: fixed;
        right: 212px;
        top: 3px;
        transform: translateX(-50%);
        background-color: rgb(55 57 60);
        padding: 9px;
        border-radius: 9px;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
        width: max-content;
        translate: revert;
        display: flex;
    }

    .sk-skip-button1 button {
        padding: 5px 12px;
        margin: 0 8px;
        border: none;
        border-radius: 4px;
        background-color: #30a9c2;
        color: white;
        font-weight: 500;
        cursor: pointer;
        transition: background-color 0.2s ease;
    }

    .sk-skip-button2 button {
        padding: 6px 4px;
        border: none;
        border-radius: 4px;
        background-color: #007bff;
        color: white;
        font-weight: 500;
        cursor: pointer;
        transition: background-color 0.2s ease;
    }

    .sk-sky-button-container button:hover {
        background-color: #0056b3;
    }

    .sk-skip-checkbox {
        position: relative;
    }

    .sk-skip-checkbox::after {
        content: "自動跳過一次";
        position: absolute;
        background-color: #333;
        color: white;
        padding: 5px 10px;
        border-radius: 4px;
        font-size: 14px;
        top: 100%;
        left: 100%;
        transform: translateX(-50%);
        white-space: nowrap;
        opacity: 0;
        visibility: hidden;
        transition: opacity 0.3s ease, visibility 0.3s ease;
        box-shadow: 0 2px 4px rgba(0,0,0,0.2);
    }

    .sk-skip-button2::after {
        content: "撤銷跳過";
        position: absolute;
        background-color: #333;
        color: white;
        padding: 5px 10px;
        border-radius: 4px;
        font-size: 14px;
        top: 100%;
        left: 100%;
        transform: translateX(-50%);
        white-space: nowrap;
        opacity: 0;
        visibility: hidden;
        transition: opacity 0.3s ease, visibility 0.3s ease;
        box-shadow: 0 2px 4px rgba(0,0,0,0.2);
    }

    .sk-skip-checkbox:hover::after {
        opacity: 1;
        visibility: visible;
    }

    `;
    document.head.appendChild(styles);
    function skMainTab() {
        let html = '<div>';
        html += '<div class="ani-setting-section is-seperate">';
        html += '<h4 class="ani-setting-title ">動畫瘋 OP工具</h4>';
        html += '<button id="aniSkRefresh" class="refresh">'
        html += '<i class="material-icons">refresh</i>'
        html += '</button>'
        html += '<div id="skInfo" class="skInfo"></div>'
        html += '<div id="mainControls" class="opening-control-button">';
        html += '<button id="toSkipOpening">跳過85秒</button>';
        html += '</div>';

        html += '<div id="mainControls" class="opening-report-button">';
        html += '<button id="inTime">回報起點</button>';
        html += '<button id="outTime">回報終點</button>';
        html += '</div>';

        html += '<div id="mainControls" class="inter-text">';
        html += '<div class="inter-text">(任選)</div>';
        html += '</div>';

        html += '<div id="subControls" class="opening-control-button">';
        html += '<button id="goBackMany"> -1 </button>';
        html += '<button id="goBack"> <<< </button>';
        html += '<button id="goBackSmall"> < </button>';
        html += '<button id="goForwardSmall"> > </button>';
        html += '<button id="goForward"> >>> </button>';
        html += '<button id="goForwardMany"> +1 </button>';
        html += '</div>';

        html += '<div>';
        html += '<span> </span>';
        html += '</div>';

        html += '<div>';
        html += '<div id="videoTimer"></div>';
        html += '</div>';
        html += '</div>';


        html += '<div class="ani-setting-section is-seperate">';
            html += '<h4 class="ani-setting-title ">時間點</h4>';
            html += '<div style:"margin-right: auto;" class="ani-setting-item ani-flex">';
                html += '<div id="skVoteFrame" class="aniSkList parent-container">';
                html += '</div>';
            html += '</div>';
            html += '<button id="aniSkUpload" class="upload_vote">'
            html += '<i class="sk-vote-material-icons"><div">提交</div></i>'
            html += '</button>'
        html += '</div>';


        html += '<div class="ani-setting-section is-seperate">';
            html += '<h4 class="ani-setting-title ">設定</h4>';
            html += '<div class="ani-setting-item ani-flex">';
                html += '<div class="ani-setting-label">';
                html += '<span class="ani-setting-label">自動跳過</span>';
                html += '</div>';
                html += '<div class="ani-setting-value ani-set-flex-right">';
                    html += '<div class="ani-checkbox">';
                    html += '<label class="ani-checkbox__label">';
                    html += `<input id="skSetting-${adder()}" type="checkbox" name="ani-checkbox" checked="">`;
                    html += '<div class="ani-checkbox__button"></div>';
                    html += '</label>';
                    html += '</div>';
                html += '</div>';
            html += '</div>';

            html += '<div class="ani-setting-item ani-flex">';
                html += '<div class="ani-setting-label">';
                html += '<span class="ani-setting-label">顯示手動按鈕</span>';
                html += '</div>';
                html += '<div class="ani-setting-value ani-set-flex-right">';
                    html += '<div class="ani-checkbox">';
                    html += '<label class="ani-checkbox__label">';
                    html += `<input id="skSetting-${adder()}" type="checkbox" name="ani-checkbox" checked="">`;
                    html += '<div class="ani-checkbox__button"></div>';
                    html += '</label>';
                    html += '</div>';
                html += '</div>';
            html += '</div>';

            html += '<div class="ani-setting-item ani-flex">';
                html += '<div class="ani-setting-label">';
                html += '<span class="ani-setting-label">只跳過一次</span>';
                html += '</div>';
                html += '<div class="ani-setting-value ani-set-flex-right">';
                    html += '<div class="ani-checkbox">';
                    html += '<label class="ani-checkbox__label">';
                    html += `<input id="skSetting-${adder()}" type="checkbox" name="ani-checkbox" checked="">`;
                    html += '<div class="ani-checkbox__button"></div>';
                    html += '</label>';
                    html += '</div>';
                html += '</div>';
            html += '</div>';

            html += '<div class="ani-setting-item ani-flex">';
                html += '<div class="ani-setting-label">';
                html += '<span class="ani-setting-label">優先使用自己的贊成票</span>';
                html += '</div>';
                html += '<div class="ani-setting-value ani-set-flex-right">';
                    html += '<div class="ani-checkbox">';
                    html += '<label class="ani-checkbox__label">';
                    html += `<input id="skSetting-${adder()}" type="checkbox" name="ani-checkbox" checked="">`;
                    html += '<div class="ani-checkbox__button"></div>';
                    html += '</label>';
                    html += '</div>';
                html += '</div>';
            html += '</div>';

            html += '<div class="ani-setting-item ani-flex">';
                html += '<div class="ani-setting-label">';
                html += '<span class="ani-setting-label">優先使用自己的時間點</span>';
                html += '</div>';
                html += '<div class="ani-setting-value ani-set-flex-right">';
                    html += '<div class="ani-checkbox">';
                    html += '<label class="ani-checkbox__label">';
                    html += `<input id="skSetting-${adder()}" type="checkbox" name="ani-checkbox" checked="">`;
                    html += '<div class="ani-checkbox__button"></div>';
                    html += '</label>';
                    html += '</div>';
                html += '</div>';
            html += '</div>';

            html += '<div class="ani-setting-item ani-flex">';
                html += '<div class="ani-setting-label">';
                html += '<span class="ani-setting-label">微調時間</span>';
                html += '</div>';
                html += '<div class="ani-setting-value ani-set-flex-right">';
                    html += '<div class="ani-checkbox">';
                    html += '<label class="ani-checkbox__label">';
                    html += '<div class="ani-setting-label">入點</div>';
                    html += '<input id="skInTime" class="skTime-input" type="text" name="ani-textbox" value="0">';
                    html += '<div class="ani-setting-label">出點</div>';
                    html += '<input id="skOutTime" class="skTime-input" type="text" name="ani-textbox" value="90">';
                    html += '</label>';
                    html += '</div>';
                html += '</div>';
            html += '</div>';

            html += '<div class="ani-setting-item ani-flex">';
                html += '<div class="ani-setting-label">';
                html += '<span class="ani-setting-label">密碼</span>';
                html += '</div>';
                html += '<div class="ani-setting-value ani-set-flex-right">';
                    html += '<div class="ani-checkbox">';
                    html += '<label class="ani-checkbox__label">';
                    html += '<div class="ani-setting-label"></div>';
                    html += '<input id="skPasswd" class="skPass-input" type="text" name="ani-textbox" value="">';
                    html += '</label>';
                    html += '</div>';
                html += '</div>';
            html += '</div>';
            
            html += '<div class="ani-setting-item ani-flex">';
                html += '<div class="ani-setting-label">';
                html += '<span class="ani-setting-label">離線版本(開發中)</span>';
                html += '</div>';
                html += '<div class="ani-setting-value ani-set-flex-right">';
                    html += '<div class="ani-checkbox">';
                    html += '<label class="ani-checkbox__label">';
                    html += `<input id="skSetting-${adder()}" type="checkbox" name="ani-checkbox" checked="">`;
                    html += '<div class="ani-checkbox__button"></div>';
                    html += '</label>';
                    html += '</div>';
                html += '</div>';
            html += '</div>';

        html += '</div>';

        html += '<div class="ani-setting-item ani-flex">';
            html += '<div class="ani-setting-label">';
            html += '<span class="ani-setting-label">刪除快取</span>';
            html += '</div>';
            html += '<div class="ani-setting-value ani-set-flex-right">';
                html += '<div>';
                html += '<button id="delete-cache" style="font-size: 12px;">刪除</button>';
                html += '</div>';
            html += '</div>';
        html += '</div>';

        html += '</div>';
        html += '</div>';
        html += '</div>';
        html += '</div>';
        return html;
    }

    function skInfo() {
        let html = '';
        html = `
        <div class="sk-sky-container">
            <div class="sk-introduction">
                <div class="sk-introduction-title">控制面板:\n</div>
                <div>回報終點 & 回報終點</div>
                <div></div>
                <div>只需選擇其中一個 資料一律以起點儲存\n</div>
                <div>每個使用者只能回報一個 可以回報新的來修改\n</div>
                <div>在一段時間後被鎖定\n</div>
                <div></div>
                <div>六個控制按鈕分別是 [-1秒 -6幀 -1幀 +1幀 +6幀 +1秒]\n</div>
                <div></div>
                <div class="sk-introduction-title">時間點:\n</div>
                <div>票數最高的會被優先使用\n</div>
                <div>使用者在一集動畫只能投下 '正' '負' 各一張票\n</div>
                <div></div>
                <div class="sk-introduction-title">上方手動按鈕:\n</div>
                <div>跳過OP: 在OP範圍內按下就會跳過OP</div>
                <div><按鈕: 返回到跳過OP之前的時間\n</div>
                <div></div>
                <div class="sk-introduction-title">設定:\n</div>
                <div>自動跳過: 在到達OP範圍時跳過OP\n</div>
                <div></div>
                <div>顯示手動按鈕: 顯示一組手動跳過OP用的按鈕\n</div>
                <div>跳過一次: 跳過之後回到OP範圍內不會被跳過\n</div>
                <div></div>
                <div>優先贊成票:\n</div>
                <div>總是使用自己投過贊成的時間點\n</div>
                <div></div>
                <div>優先時間點:\n</div>
                <div>總是使用自己回報的時間點\n</div>
                <div></div>
                <div>微調時間: 可以調整跳過OP的判定範圍\n</div>
                <div>密碼: 在這裡按下ctrl+a全選 ctrl+v貼上密碼\n</div>
                <div>離線版本: 不使用伺服器的資料 需要自己標記\n</div>
            </div>
        </div>
        `
        return html;
    }

    function skInfoTrigger() {
        let html = ''
        html = `
        <div id="info-trigger" class="info-container">
        <span class="info-trigger">?</span>
        </div>
        `
        return html;
    }

    function skSwitchButton() {
        let html = ''
        html = `
        <div class="ani-tabs__item">
            <div id="skipOpening" class="ani-tabs-link ani-tabs-link-opening">OP工具
            </div>
        </div>
        `
        return html;
    }
    
    function skSwitchTab() {
        let html = ''
        html = `
        <div id="opening-tab-content" class="ani-tab-content__item" style="display: none;">
        </div>
        `
        return html;
    }

    function skSkyMessage() {
        let html = ''
        html = `
        <div id="sky-message" class="status-container-top">
        </div>
        `
        return html;
    }

    function skSkipButton() {
        let html = ''
        html = `
        <div id="skSkipButContainer" class="sk-sky-button-container">
            <div class="sk-skip-checkbox">
                <div class="ani-checkbox" style="margin: 3px 0 0 5px;">
                    <label class="ani-checkbox__label">
                    <input id="skSetting-${adder()}" type="checkbox" name="ani-checkbox" checked="">
                    <div class="ani-checkbox__button"></div>
                    </label>
                </div>
            </div>
            <div class="sk-skip-button1">
                <button id="skSkipButton" class="sk-sky-button__item">跳過OP</button>
            </div>
            <div class="sk-skip-button2">
                <button id="redoSkipButton" class="skip-button2"> < </button>
            </div>
        </div>
        `
        return html;
    }

    function getSN() {
        const urlObj = document.URL;
        const sn = urlObj.match(/sn=(\d+)/)[1];
        return sn;
    }

    function GM_setValue(key, value) {
        localStorage.setItem(key, value);
    }

    function GM_delValue(key) {
        localStorage.removeItem(key);
    }

    function GM_getValue(key) {
        return localStorage.getItem(key);
    }

    // function snFormat(sn, user, vote, time, voted) {
    //     const cache = {
    //         sn: sn,
    //         data: [{
    //             time: time,
    //             user: user,
    //             vote: vote,
    //             voted: voted
    //         }]
    //     }
    //     return cache;
    // }

    // function dataFormat(time, vote, voted) {
    //     const cache = {
    //         time: time,
    //         vote: vote,
    //         voted: voted
    //     }
    //     return cache;
    // }

    function GM_loadCache(sn) {
        try {
            const cache = {};
            cache[sn] = JSON.parse(GM_getValue(sn));
            if (cache[sn] === null) {
                cache[sn] = { sn: sn, data: [] };
                GM_setValue([sn], JSON.stringify(cache[sn]));
            }
            return cache;
        } catch (error) {
            console.log(error);
        }
    }

    function GM_saveCache() {
        GM_setValue([sn], JSON.stringify(SkCache[sn]))
    }

    // async function addCache(content, data) {
    //     content[sn].data.push(data);
    //     return content;
    // }

    // async function removeCache(index) {
    //     SkCache[sn].data.splice(index, 1);
    //     return SkCache;
    // }

    // async function saveToCache(content) {
    //     GM_setValue([sn], JSON.stringify(content[sn]));
    // }

    // async function LocalToCloudData() {
    //     CloudTimes = [];
    //     SkCache[sn].data.forEach((item, index) => {
    //         const voteCache = {
    //             time: item.time,
    //             vote: item.vote,
    //         }
    //         CloudTimes.push(voteCache);
    //     })
    // }

    async function CloudToLocalData() {
        if (stringBool(skipSetting.offlineMode)) {
            return;
        }
        while (!CloudTimes.length) {
            await new Promise(resolve => setTimeout(resolve, 100));
        }
        const temp = SkCache[sn].data;
        SkCache[sn].data = [];
        CloudTimes.forEach((item, index) => {
            try {
                const dataCache = {
                    time: item.time,
                    vote: item.vote,
                    voted: false,
                    uploader: item.uploader
                }
                temp.forEach((item2, index2) => {
                    if (item2.time === item.time) {
                        dataCache.voted = item2.voted;
                    }
                })
                SkCache[sn].data.push(dataCache);
            } catch (error) {
                return;
            }
        })
    }

    function getLocalTime() {
        const cache = [];
        SkCache[sn].data.forEach((item, index) => {
            const voteCache = {
                time: item.time,
                vote: item.vote,
                voted: item.voted,
                uploader: item.uploader
            }
            cache.push(voteCache);
        });
        return cache;
    }

    function getOfflineData() {
        const cache = [];
        SkCache[sn].offlineData.forEach((item, index) => {
            const voteCache = {
                time: item.time,
                vote: item.vote,
                voted: item.voted,
                uploader: item.uploader
            }
            cache.push(voteCache);
        });
        return cache;
    }
    function stringBool(value) {
        if (value === "false" || value === false) {
            return false;
        } else {
            return true;
        }
    }

    function adder(reset) {
        const temp = pageTemp.adderCounter;
        if (reset === 1) {
            pageTemp.adderCounter = 0;
        } else {
            pageTemp.adderCounter += 1;
        }
        return temp;
    }

    //SkCache是這個sn的快取
    //getLocal可以取得快取內的物件
    //LocalTimes是拿來存getLocal拿到的資料
    //CloudTimes 伺服器回傳的值
    //voteData是投票資料
    let SkCache = {};
    let VideoTimer;
    let CloudTimes = [];
    let LocalTimes = [];
    let voteData = [];
    let sn = getSN();
    let skipSetting = {
        autoSkip: false,
        skipButton: false,
        skipOnce: false,
        pickMyVote: false,
        pickMyTime: false,
        offlineMode: false,
        skManualOnce: true,
        inTime: 0,
        outTime: 90,
        password: ""
    };

    let pageTemp = {
        sn : sn,
        messageCounter : 0,
        holdSk : false,
        runSk : skipSetting.autoSkip,
        runOnce: false,
        holdCounter : 0,
        adderCounter : 0,
        whenSk: 0
    };

    let skSettingMap = [];

    Object.entries(skipSetting).forEach(([key, value],index) => {
        if (typeof value === 'boolean') {
            skSettingMap.push([`skSetting-${index}`,key]);
        }
        if (GM_getValue(key) != undefined) {
            skipSetting[key] = GM_getValue(key);
        } else {
            GM_setValue(key, value);
        }
    })

    let userID = "";
    try {
        let cookie = document.cookie.split("; ").filter(cookie => cookie.startsWith("BAHAID")).shift();
        userID = cookie ? cookie.split("=").pop() : undefined;
    } catch (error) {
        console.error(error);
    }

    // html
    $('.ani-tabs').append(skSwitchButton());
    $('.ani-tab-content').append(skSwitchTab());
    $("#opening-tab-content").append(skMainTab());
    $("#skInfo").append(skInfoTrigger());
    $(".top_sky").append(skInfo());
    $(".sk-sky-container").append(skSkyMessage());
    $(".sk-sky-container").append(skSkipButton());

    // 為所有按鈕加上切換功能
    const aniTabsLinks = document.querySelectorAll('.ani-tabs-link');
    aniTabsLinks.forEach(link => {
        link.addEventListener('click', () => {
            let element = document.getElementById('opening-tab-content');
            element.style.display = 'none';
            element = document.getElementById('skipOpening');
            element.classList.add('is-disabled');
            element.classList.remove('is-active');
        });
    });

    // 為頁面加上切換功能
    const aniTabsLinksOpening = document.getElementById('skipOpening');
    aniTabsLinksOpening.addEventListener('click', () => {
        const otherTabs = Array.from(document.getElementsByClassName("ani-tab-content__item"));
        otherTabs.forEach(tab => {
            if (tab.id !== 'opening-tab-content') {
                tab.style.display = 'none';
            } else {
                tab.style.display = 'block';
            }
        });
        let element = document.getElementById('opening-tab-content');
        element.style.display = 'block';

        const otherButtons = Array.from(document.getElementsByClassName("ani-tabs-link"));
        otherButtons.forEach(element => {
            if (element.id !== 'skipOpening') {
                element.classList.add('is-disabled');
                element.classList.remove('is-active');
            } else {
                element.classList.remove('is-disabled');
                element.classList.add('is-active');
            }
        });
    });

    const ControlButton = function() {
        const controlButtons = ['goBackMany','goBackSmall', 'goBack', 'goForward', 'goForwardSmall', 'goForwardMany'];
        const controlButtonsSpeed = ['-1','-0.04166', '-0.25', '0.25', '0.04166', '+1'];
        const toSkipButton = document.getElementById('toSkipOpening');
        toSkipButton.addEventListener('click', () => {
            document.querySelectorAll("video")[0].currentTime += 85;
        });

        controlButtons.forEach((element, index) => {
            const button = document.getElementById(element);
            button.addEventListener('click', () => {
                document.querySelectorAll("video")[0].pause();
                document.querySelectorAll("video")[0].currentTime += Number(controlButtonsSpeed[index]);
                pageTemp.holdSk = false;
                pageTemp.holdCounter = 0;
            });
        });
    }

    // 主內容
    window.onload = async function () {
        //進度追蹤器
        async function updateTimer() {
            VideoTimer = document.querySelectorAll("video")[0].currentTime;
            const minute = Math.floor(VideoTimer / 60);
            const second = Math.floor(VideoTimer % 60);
            const microSecond = Math.floor((VideoTimer % 1) * 100);
            if (microSecond < 10) {
                document.getElementById("videoTimer").textContent = `目前 ${minute}分 ${second}.0${microSecond}秒`;
            } else {
                document.getElementById("videoTimer").textContent = `目前 ${minute}分 ${second}.${microSecond}秒`;
            }
            sn = getSN();
            if (pageTemp.sn !== sn) {
                await doingRefresh();
                pageTemp.sn = sn;
            }
        }
        setInterval(updateTimer, 200)
        ControlButton();
        const refreshButton = document.getElementById('aniSkRefresh');
        const uploadButton = document.getElementById('aniSkUpload');
        const outTimeButton = document.getElementById('outTime');
        const inTimeButton = document.getElementById('inTime');
        const toDeleteButton = document.getElementById('delete-cache');

        function saveSetting(checkbox, settingName) {
            skipSetting[settingName] = checkbox.checked;
            GM_setValue(settingName, checkbox.checked);
            console.log(skipSetting);
        }

        function applySettingButton() {
            try {
                skSettingMap.forEach((element, index) => {
                    const button = document.getElementById(element[0]);
                    const key = element[1];
                    button.addEventListener('change', (event) => saveSetting(event.target, key));
                    $(`#${element[0]}`).prop('checked', stringBool(skipSetting[key]));
                })
            } catch (error) {
                console.log(error);
            }

            try {
                const microTimeBox = [];
                microTimeBox.push(document.getElementById('skInTime'))
                microTimeBox.push(document.getElementById('skOutTime'))
                microTimeBox.forEach((element, index) => {
                    element.addEventListener('keydown', (event) => {
                        if (event.key === 'Enter') {
                            const Value = element.value;
                            if (index === 0) {
                                if (Value < 0 || Value >90) {
                                    element.value = 0
                                }
                                skipSetting.inTime = Value;
                                GM_setValue('inTime', Value);
                            } else {
                                if (Value < 0 || Value >100) {
                                    element.value = 90
                                }
                                skipSetting.outTime = Value;
                                GM_setValue('outTime', Value);
                            }
                        }
                    });
                });
                
                microTimeBox.forEach((element, index) => {
                    element.value = skipSetting[index === 0 ? 'inTime' : 'outTime'];
                });                
            } catch (error) {
                console.log(error);
            }
            
            try {
                const skPasswordInput = document.getElementById('skPasswd');
                skPasswordInput.addEventListener('keydown', (event) => {
                    if (event.key === 'Enter') {
                        const Value = skPasswordInput.value;
                        skipSetting.password = Value;
                        GM_setValue('password', Value);
                    }
                });
                skPasswordInput.value = skipSetting.password;                
            } catch (error) {
                console.log(error);
            }
            
            const skSkipButton = document.getElementById('skSkipButton');
            const redoSkipButton = document.getElementById('redoSkipButton');
            skSkipButton.addEventListener('click', () => {
                const startPoint = Number(LocalTimes[0].time) + Number(skipSetting.inTime);
                const endPoint = Number(LocalTimes[0].time) + Number(skipSetting.outTime);
                if (VideoTimer > startPoint && VideoTimer < endPoint) {
                    document.querySelectorAll("video")[0].currentTime = endPoint + 0.1;
                    showMessage("跳過", 1, 1500, 1);
                }
            });
            redoSkipButton.addEventListener('click', () => {
                if (pageTemp.whenSk !== 0) {
                    const time = pageTemp.whenSk;
                    pageTemp.runSk = false;
                    skipSetting.skipOnce = true;
                    document.querySelectorAll("video")[0].currentTime = time;
                    showMessage("回退", 1, 1500, 1);
                }
            });

            if (stringBool(skipSetting.skipButton)) {
                const manualButtonContainer = document.getElementById('skSkipButContainer');
                manualButtonContainer.classList.add('sk-info-show')
            }

            const skSkipOnce = document.getElementById('skSetting-6');
            skSkipOnce.addEventListener('change', (event) => {
                pageTemp.runSk = skipSetting.skManualOnce;
                pageTemp.runOnce = skipSetting.skManualOnce;
            });
        }    

        async function messageManger (text, status, onTop = 0) {
            let msgContainer = '';
            if (onTop === 1) {
                msgContainer = 'status-container-top'
            } else {
                msgContainer = 'status-container'
            }
            let container = document.getElementsByClassName(msgContainer)
            const tabContent = document.getElementById('opening-tab-content');
            if (!tabContent) {
                return;
            }
            if (getComputedStyle(tabContent).position === 'static') {
                tabContent.style.position = 'relative';
            }
            if (container.length === 0) {
                container = document.createElement('div');
                container.className = msgContainer;
                tabContent.appendChild(container);
            }
            let icon = '';
            let type = '';
            switch(status) {
                case 0:
                    icon = '✕';
                    type = 'error';
                    break;
                case 1:
                    icon = '✓';
                    type = 'success';
                    break;
                case 2:
                    icon = '⚠';
                    type = 'warning';
                    break;
                case 3:
                    icon = 'i';
                    type = 'info';
                    break;
            }
            pageTemp.messageCounter += 1;
            const counter = pageTemp.messageCounter;
            const messageHtml = `
                <div id="popover-${counter}" class="status-popover ${type}">
                    <span class="status-icon">${icon}</span>
                    <span class="status-message">${text}</span>
                    <span class="status-close">×</span>
                </div>
                `;
            $(`.${msgContainer}`).append(messageHtml)
            const element = document.getElementById(`popover-${counter}`);
            requestAnimationFrame(() => {
                element.classList.add('show');
            })
            element.addEventListener('click', () => {
                element.classList.remove('show');
                setTimeout(() => element.remove(), 300);
            });
            return counter;
        }
        
        async function showMessage(text, status, time = 1500, mode) {
            messageManger(text, status, mode)
            .then((counter) => {
                setTimeout(() => {
                    try {
                        const element = document.getElementById(`popover-${counter}`);
                        element.classList.remove('show');
                        setTimeout(() => element.remove(), 300);
                    } catch (error) {
                        return;
                    }
                }, time);
            })
        }

        async function SkRunningTime() {
            if (!pageTemp.runSk) {
                return;
            }
            if (pageTemp.holdSk) {
                pageTemp.holdCounter += 1;
                if (pageTemp.holdCounter > 100) {
                    pageTemp.holdSk = false;
                }
                return;
            }
            if (VideoTimer > 0) {
                const startPoint = Number(LocalTimes[0].time) + Number(skipSetting.inTime);
                const endPoint = Number(LocalTimes[0].time) + Number(skipSetting.outTime);
                if (VideoTimer > startPoint && VideoTimer < endPoint) {
                    pageTemp.whenSk = VideoTimer;
                    document.querySelectorAll("video")[0].currentTime = endPoint + 0.1;
                    showMessage("跳過", 1, 1500, 1);
                    if (skipSetting.skipOnce || pageTemp.runOnce) {
                        pageTemp.runSk = false;
                        $(`#skSetting-6`).prop('checked', false);
                    }
                }
            }
        }

        function SkControl(status) {
            clearInterval(SkRunningTime);
            if (status === true) {
                setInterval(SkRunningTime,200);
            }
        }

        function doingRefresh() {
            pageTemp.runSk = skipSetting.autoSkip;
            sn = getSN();
            SkCache = {};
            const content = GM_loadCache(sn);
            SkCache = content;
            getTimeData();
            SkControl(skipSetting.autoSkip);
        }

        async function sendVote() {
            let votes = [];
            let count = 0;
            console.log(voteData);
            for (const element of voteData) {
                if (element.voted !== false) {
                    votes.push({time: element.time, vote: element.voted});
                    count++;
                }
                if (count >= 2) {
                    break;
                };
            }
            const content = {
                'user': userID,
                'sn': sn,
                'votes': votes,
                'password': skipSetting.password
            };
            console.log(content);
            const snJson = JSON.stringify(content);
            const response = await aniSkVote(snJson);
            LocalTimes.forEach((element, index) => {
                const item = voteData[index];
                if (element.voted !== false && element.voted !== item.voted) {
                    element.vote += element.voted * -1;
                }
                if (item.voted !== false) {
                    element.vote += item.voted;
                }
                element.voted = item.voted;
            });
            SkCache[sn].data = LocalTimes;
            GM_saveCache()
            newHtml();

        }

        async function getTimeData() {
            if(stringBool(skipSetting.offlineMode)) {
                showMessage("離線模式",3);
                LocalTimes = getOfflineData();
                return;
            }
            const status = await getAniCloudTime();
            if (status.error) {
                LocalTimes = getLocalTime();
                showMessage("取得失敗 使用本地資料", 0, 3000);
            } else {
                if (status.found) {
                    CloudToLocalData();
                    LocalTimes = getLocalTime();
                    showMessage("更新成功", 1);
                } else {
                    LocalTimes = [];
                    showMessage("無資料 請標記", 2, 5000);
                }
            }

            for (let i = 0; i > LocalTimes.length; i++) {
                if (LocalTimes[i].time >= 36000) {
                    LocalTimes.splice(i, 1);
                    i--;
                }
            }
    
            // if (LocalTimes.length === 0) {
            //     LocalTimes.push({
            //         time: 59940,
            //         vote: -9999,
            //         voted: false
            //     });
            // }
    
            // for (const element of LocalTimes) {
            //     if (element.time >= 36000) {
            //         showMessage("找不到本地資料 :(", 0, 4500);
            //         break;
            //     }
            // }
            
            newHtml();
        }
        
        
        function newHtml() {
            let mode = 0;
            if (stringBool(skipSetting.pickMyTime)) {
                mode = 1
            }
            if (stringBool(skipSetting.pickMyVote)) {
                mode = 2
            }

            switch (mode) {
                case 1:
                    const index1 = LocalTimes.findIndex(item => item.uploader === true);
                    if (index1 !== -1) {
                      const [removed] = LocalTimes.splice(index1, 1);
                      LocalTimes.unshift(removed);
                    }
                    break;
                case 2:
                    const index2 = LocalTimes.findIndex(item => item.voted === 1);
                    if (index2 !== -1) {
                      const [removed] = LocalTimes.splice(index2, 1);
                      LocalTimes.unshift(removed);
                    }
                    break;
                default:
                    LocalTimes.sort((a, b) => b.vote - a.vote);
            }

            voteData = LocalTimes;
            SkCache[sn].data = LocalTimes;
            renderVoteHtml();
            updateVoteStatus();
        }

        function renderVoteHtml() {
            $("#skVoteFrame").empty();
            createVoteHtml().forEach((element, index) => {
                $("#skVoteFrame").append(element)
            });
            createVoteButton();
        }

        function createVoteHtml() {
            const arr = [];
            LocalTimes.forEach((element, index) => {
                const time = element.time;
                const vote = element.vote;
                const minute = Math.floor(time / 60);
                const second = Math.floor(time % 60);
                const microSecond = Math.floor((time % 1) * 100);
                const timeString = `${minute}分 ${second}.${microSecond}秒`;
                const voteString = `(${vote})`;
                const voteElement = `
                <div id="voteContainer-${time}" class="sk-container">
                    <div id="rank-${time}"></div>
                    <div class="sk-time-wrapper">
                        <div class="sk-time-list">
                            <span class="sk-time">${timeString}</span>
                            <span id="skVote-${time}" class="sk-votes">${voteString}</span>
                        </div>
                        <div id="vote-${time}" class="sk-vote-controls">
                            <button id="skVoteUp-${time}" class="sk-vote sk-vote--up">
                                <i class="sk-icon">▲</i>
                            </button>
                            <button id="skVoteDown-${time}" class="sk-vote sk-vote--down">
                                <i class="sk-icon">▼</i>
                            </button>
                        </div>
                    </div>
                </div>
                `;

                arr.push(voteElement);
            });
            return arr;
        }

        async function updateVoteStatus() {
            LocalTimes.forEach((element, index) => {
                const time = element.time;
                const vote = element.vote;
                const item = voteData[index];
                let voteString = "";
                if (element.voted !== item.voted) {
                    if (item.voted === 1) {
                        voteString = ` (${vote}) +${item.voted}`;
                    } else if (item.voted === -1) {
                        voteString = ` (${vote}) ${item.voted}`;
                    } else {
                        if (element.voted !== false) {
                            if (element.voted === 1) {
                                voteString = ` (${vote}) -1`;
                            } else if (element.voted === -1) {
                                voteString = ` (${vote}) +1`;
                            }
                        } else {
                            voteString = ` (${vote})`;
                        }
                    }
                } else {
                    voteString = ` (${vote})`;
                }
                const voteElement = document.getElementById(`skVote-${time}`);
                voteElement.textContent = voteString;

                if (index === 0) {
                    const voteContainer = document.getElementById(`rank-${time}`);
                    if (getComputedStyle(voteContainer).position === 'static') {
                        voteContainer.style.position = 'relative';
                    }            
                    $(`#rank-${time}`).append(`<div></div>`)
                }

                if (element.uploader === true) {
                    const voteContainer = document.getElementById(`rank-${time}`);
                    voteContainer.classList.add('your-uploaded-time');
                }
    
                const voteUp = document.getElementById(`skVoteUp-${time}`);
                const voteDown = document.getElementById(`skVoteDown-${time}`);
                voteDown.classList.remove('sk-vote-VOTEDN');
                voteDown.classList.remove('sk-vote-has-been-chosen');
                voteUp.classList.remove('sk-vote-VOTEDP');
                voteUp.classList.remove('sk-vote-has-been-chosen');
                if (!item.voted === false) {
                    if (item.vote === 1) {
                        voteUp.classList.add('sk-vote-VOTEDP');
                        voteDown.classList.remove('sk-vote-VOTEDN');
                    } else if (item.vote ===-1){
                        voteUp.classList.remove('sk-vote-VOTEDP');
                        voteDown.classList.add('sk-vote-VOTEDN');
                    }
                }

                if (element.voted !== false) {
                    if (element.voted === 1) {
                        voteUp.classList.add('sk-vote-has-been-chosen');
                        voteDown.classList.remove('sk-vote-has-been-chosen');
                    } else {
                        voteUp.classList.remove('sk-vote-has-been-chosen');
                        voteDown.classList.add('sk-vote-has-been-chosen');
                    }
                }
            });
        }

        function createVoteButton() {
            LocalTimes.forEach((item, index) => {
                const time = item.time;
                const voteButtonP = document.getElementById(`skVoteUp-${time}`);
                const voteButtonN = document.getElementById(`skVoteDown-${time}`);
                voteButtonP.addEventListener('click', () => handleVote(voteButtonP, 1, time, index));
                voteButtonN.addEventListener('click', () => handleVote(voteButtonN, -1, time, index));
            })
        }

        async function getAniCloudTime() {
            CloudTimes = [];
            const content = {
                'user': userID,
                'sn': sn
            };
            const snJson = JSON.stringify(content);
            const response = await aniSkGetTime(snJson);
            if (response === 'error') {
                return {
                    found : false,
                    error : true
                };
            }
            if (response.aniFound === 'notfound') {
                return {
                    found : false,
                    error : false
                };
            }
            try {
                response.aniFound.forEach(async aniFound => {
                    CloudTimes.push({ time: aniFound.time, vote: aniFound.vote, uploader: aniFound.uploader });
                })
                return {
                    found : true,
                    error : false
                };
            } catch (error) {
                return {
                    found : false,
                    error : true
                };
            }
        }

        async function uploadTime(type) {
            let time = 0;
            if (type === 'start') {
                time = VideoTimer
            } else {
                time = VideoTimer - 90
            }
            if (type === 'end' && VideoTimer <=89.99) {
                return;
            } 
            if (stringBool(skipSetting.offlineMode)) {
                SkCache[sn].offlineData = [];
                SkCache[sn].offlineData.push(
                    {
                        time: VideoTimer,
                        vote: 0,
                        voted: false,
                        uploader: true
                    }
                )
                GM_saveCache();
                GM_loadCache();
                return;
            }

            const content = {
                time: time,
                user: userID,
                sn: sn,
                password: skipSetting.password
            };
            const data = JSON.stringify(content);
            const response = await aniSkUploader(data);
            showMessage(response.message, 1);
        }

        function handleVoteCounter(vote, buttonIndex, time) {
            let holdVote = {voted: null, index: -1, lastVote: []};
            voteData.forEach((element, index) => {
                if (element.voted !== false && element.voted !== vote) {
                    holdVote.voted = element.voted;
                    holdVote.index = index;
                }
                holdVote.lastVote.push(element.vote);
            })

            voteData = [];
            LocalTimes.forEach((element, index) => {
                voteData.push({ time: element.time, vote: 0, voted: false, uploader: element.uploader });
                if (element.time === time && holdVote.lastVote[index] !== vote) {
                    voteData[index].vote = vote;
                    voteData[index].voted = vote;
                }
                if (index === holdVote.index && index !== buttonIndex) {
                    voteData[index].vote = holdVote.voted;
                    voteData[index].voted = holdVote.voted;
                }
            });
            console.log(voteData);
        }

        async function handleVote(button, vote, time, buttonIndex) {
            handleVoteCounter(vote, buttonIndex, time);
            updateVoteStatus();
        }

        function toggleInfo() {
            const infoButton = document.getElementsByClassName('sk-introduction');
            infoButton[0].classList.toggle('sk-info-show');
        }

        function toggleSkipButton() {
            const element = document.getElementById('skSkipButContainer');
            if (skipSetting.skipButton) {
                element.classList.add('sk-info-hidden');
                element.classList.remove('sk-info-show');
            } else {
                element.classList.remove('sk-info-hidden');
                element.classList.add('sk-info-show');
            }
        }

        async function aniSkVote(content) {
            return new Promise((resolve, reject) => {
                GM.xmlHttpRequest({
                    method: "POST",
                    url: `${serverUrl}/api/vote`,
                    data: content,
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    onload: function (response) {
                        if (response.status === 200) {
                            resolve(JSON.parse(response.responseText));
                            showMessage(JSON.parse(response.responseText).message, 1);
                        } else {
                            showMessage(JSON.parse(response.responseText).message, 0);
                            console.error('Error sending data:', response.status, response.statusText);
                        }
                    },
                    onerror: function (error) {
                        showMessage("網路錯誤",0)
                        console.error('Network Error:', error);
                        reject(error);
                    }
                });
            });
        }
    
        async function aniSkUploader(content) {
            return new Promise((resolve, reject) => {
                GM.xmlHttpRequest({
                    method: "POST",
                    url: `${serverUrl}/api/upload`,
                    data: content,
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    onload: function (response) {
                        if (response.status === 200) {
                            resolve(JSON.parse(response.responseText));
                        } else {
                            showMessage(JSON.parse(response.responseText).message, 0);
                            console.error('Error sending data:', response.status, response.statusText);
                        }
                    },
                    onerror: function (error) {
                        showMessage("網路錯誤",0)
                        console.error('Network Error:', error);
                        reject(error);
                    }
                });
            });
        }
    
        async function aniSkGetTime(content) {
            return new Promise((resolve, reject) => {
                GM.xmlHttpRequest({
                    method: "POST",
                    url: `${serverUrl}/api/getTime`,
                    data: content,
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    onload: function (response) {
                        if (response.status === 200) {
                            resolve(JSON.parse(response.responseText));
                        } else {
                            showMessage("取得資料失敗", 0)
                            console.error('Error sending data:', response.status, response.statusText);
                            reject(new Error(`HTTP Error ${response.status}: ${response.statusText}`));
                        }
                    },
                    onerror: function (error) {
                        showMessage("網路錯誤",0)
                        console.error('Network Error:', error);
                        resolve('error');
                    }
                });
            });
        }

        getTimeData();
        const skButton1 = document.getElementById('skSetting-1');
        const infoButton = document.getElementById('info-trigger'); 
        infoButton.addEventListener('click', () => toggleInfo());
        skButton1.addEventListener('click', () => toggleSkipButton());
        refreshButton.addEventListener('click', () => doingRefresh());
        toDeleteButton.addEventListener('click', () => GM_delValue(sn));
        uploadButton.addEventListener('click', () => sendVote());
        inTimeButton.addEventListener('click', () => uploadTime('start'));
        outTimeButton.addEventListener('click', () => uploadTime('end'));
        
        SkCache = GM_loadCache(sn);
        pageTemp.runSk = skipSetting.autoSkip;
        setInterval(SkRunningTime,200);
        applySettingButton();

    }
})();