komica發文自訂名稱跟類別(Komica name and category custom settings)

為快速回覆表單添加自訂名稱和類別功能,保持拖拽功能,支持點擊No.插入引用到快速回覆內文並更新標題,通過AJAX刷新最新回覆,保留無貼圖、連貼機能、SAGE等功能,修復連貼機能點擊跳頁問題,優化503錯誤處理,處理Cloudflare預加載警告和$.isMobile錯誤,排除線程列表頁(如mode=module&load=mod_threadlist)

目前為 2025-04-26 提交的版本,檢視 最新版本

// ==UserScript==
// @name         komica發文自訂名稱跟類別(Komica name and category custom settings)
// @namespace    http://tampermonkey.net/
// @version      2.1
// @description  為快速回覆表單添加自訂名稱和類別功能,保持拖拽功能,支持點擊No.插入引用到快速回覆內文並更新標題,通過AJAX刷新最新回覆,保留無貼圖、連貼機能、SAGE等功能,修復連貼機能點擊跳頁問題,優化503錯誤處理,處理Cloudflare預加載警告和$.isMobile錯誤,排除線程列表頁(如mode=module&load=mod_threadlist)
// @author       Grok
// @match        *://*.komica1.org/*
// @exclude      *://*.komica1.org/*/src/*
// @exclude      *://*.komica1.org/*/thumb/*
// @exclude      *://*.komica1.org/*/pixmicat.php?mode=module*
// @grant        none
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @require      https://code.jquery.com/ui/1.12.1/jquery-ui.min.js
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 檢查當前網址,排除線程列表頁
    if (/mode=module/.test(window.location.search) && /load=mod_threadlist/.test(window.location.search)) {
        console.log('檢測到線程列表頁(mode=module&load=mod_threadlist),腳本已退出');
        return;
    }

    // 修補$.isMobile以避免script.js錯誤
    $.isMobile = function() {
        return /Mobi|Android/i.test(navigator.userAgent);
    };

    // 等待DOM加載完成
    $(document).ready(function() {
        // 修復Cloudflare預加載警告
        $('link[href*="challenges.cloudflare.com"]').attr('as', 'fetch');

        // 檢查quickreply表單並啟用拖拽
        var $quickReply = $('#quickreply');
        if ($quickReply.length) {
            $quickReply.draggable({
                handle: '.quickreply-head',
                containment: 'window'
            });
        }

        // 修復快速回覆表單的連貼機能勾選框
        var $quickReplyUpSeries = $('#quickreply-form input[name="up_series"]');
        if ($quickReplyUpSeries.length) {
            $quickReplyUpSeries.attr('id', 'quickreply-up_series');
            var $upSeriesLabel = $quickReplyUpSeries.next('label[for="up_series"]');
            if ($upSeriesLabel.length) {
                $upSeriesLabel.attr('for', 'quickreply-up_series');
            } else {
                $quickReplyUpSeries.after('<label for="quickreply-up_series">[連貼機能]</label>');
            }
            $quickReplyUpSeries.add($upSeriesLabel).on('click', function(e) {
                e.preventDefault();
                console.log('點擊連貼機能:', e.target);
                $quickReplyUpSeries.prop('checked', !$quickReplyUpSeries.prop('checked'));
                $('#postform input[name="up_series"]').prop('checked', false);
            });
        }

        // 修復其他勾選框(noimg, ObHGyhdTR)
        var $quickReplyNoImg = $('#quickreply-form input[name="noimg"]');
        if ($quickReplyNoImg.length) {
            $quickReplyNoImg.attr('id', 'quickreply-noimg');
            var $noImgLabel = $quickReplyNoImg.next('label[for="noimg"]');
            if ($noImgLabel.length) {
                $noImgLabel.attr('for', 'quickreply-noimg');
            } else {
                $quickReplyNoImg.after('<label for="quickreply-noimg">[無貼圖]</label>');
            }
            $quickReplyNoImg.add($noImgLabel).on('click', function(e) {
                e.preventDefault();
                console.log('點擊無貼圖:', e.target);
                $quickReplyNoImg.prop('checked', !$quickReplyNoImg.prop('checked'));
                $('#postform input[name="noimg"]').prop('checked', false);
            });
        }

        var $quickReplySage = $('#quickreply-form input[name="ObHGyhdTR"]');
        if ($quickReplySage.length) {
            $quickReplySage.attr('id', 'quickreply-sage');
            var $sageLabel = $quickReplySage.next('label[for="ObHGyhdTR"]');
            if ($sageLabel.length) {
                $sageLabel.attr('for', 'quickreply-sage');
            } else {
                $quickReplySage.after('<label for="quickreply-sage">[SAGE]</label>');
            }
            $quickReplySage.add($sageLabel).on('click', function(e) {
                e.preventDefault();
                console.log('點擊SAGE:', e.target);
                $quickReplySage.prop('checked', !$quickReplySage.prop('checked'));
                $('#postform input[name="ObHGyhdTR"]').prop('checked', false);
            });
        }

        // 處理名稱輸入框
        var $nameInputFname = $('#fname');
        var $nameInputPlaceholder = $("input[placeholder='名稱']:not(.hide)");
        var $nameInputs = $().add($nameInputFname).add($nameInputPlaceholder);

        if ($nameInputs.length) {
            $nameInputs.each(function() {
                var $input = $(this);
                var $setNameBtn = $('<button type="button" style="font-family: Arial; margin-left: 5px;">設置名稱</button>');
                $input.after($setNameBtn);

                $setNameBtn.on('click', function() {
                    var customName = prompt('請輸入自訂名稱:', $input.val() || '');
                    if (customName !== null && customName.trim() !== '') {
                        if ($input.attr('id') === 'fname') {
                            customName = customName.substring(0, 100);
                        }
                        $input.val(customName);
                        localStorage.setItem('input-name-' + ($input.attr('id') || 'placeholder'), customName);
                    }
                });

                var savedName = localStorage.getItem('input-name-' + ($input.attr('id') || 'placeholder'));
                if (savedName) {
                    $input.val(savedName);
                }
            });
        }

        // 處理類別輸入框
        var $categoryInputs = $("input[name='category']");
        if ($categoryInputs.length) {
            $categoryInputs.each(function() {
                var $input = $(this);
                var $setCategoryBtn = $('<button type="button" style="font-family: Arial; margin-left: 5px;">設置類別</button>');
                $input.after($setCategoryBtn);

                $setCategoryBtn.on('click', function() {
                    var customCategory = prompt('請輸入類別標籤(以逗號分隔):', $input.val() || '');
                    if (customCategory !== null && customCategory.trim() !== '') {
                        var tags = customCategory.split(',').map(tag => tag.trim()).filter(tag => tag !== '');
                        if (tags.length > 0) {
                            var categoryValue = tags.join(', ');
                            $input.val(categoryValue);
                            localStorage.setItem('input-category-' + ($input.attr('name') || 'category'), categoryValue);
                        } else {
                            alert('請輸入至少一個有效的標籤!');
                        }
                    }
                });

                var savedCategory = localStorage.getItem('input-category-' + ($input.attr('name') || 'category'));
                if (savedCategory) {
                    $input.val(savedCategory);
                }
            });
        }

        // 處理點擊No.插入引用並更新標題
        $('.qlink').on('click', function(e) {
            e.preventDefault();
            var postNo = $(this).attr('data-no');
            var quoteText = `>>No.${postNo}\n`;

            var $quickReplyTextarea = $('#quickreply textarea[name="pOBvrtyJK"]');
            if ($quickReplyTextarea.length) {
                $quickReply.css('display', 'block');
                var currentText = $quickReplyTextarea.val();
                $quickReplyTextarea.val(quoteText + currentText);
                $quickReplyTextarea.focus();

                var $quickReplyTitle = $('.quickreply-title');
                if ($quickReplyTitle.length) {
                    $quickReplyTitle.text(`Quick Reply >>No.${postNo}`);
                }
            } else {
                console.warn('未找到快速回覆表單的textarea');
            }
        });

        // 處理快速回覆表單關閉按鈕
        $('.quickreply-close').on('click', function() {
            $quickReply.css('display', 'none');
        });

        // 處理快速回覆表單提交(帶重試機制)
        function submitReply(formData, $form, attempt = 1, maxAttempts = 3) {
            console.log(`提交表單(嘗試 ${attempt}/${maxAttempts}):`, Array.from(formData.entries()));

            $.ajax({
                url: $form.attr('action') || 'pixmicat.php',
                type: 'POST',
                data: formData,
                processData: false,
                contentType: false,
                success: function(response, status, xhr) {
                    console.log('提交成功,回應狀態:', xhr.status, '回應內容:', response);

                    // 重置表單
                    $form.find('textarea[name="pOBvrtyJK"]').val('');
                    $form.find('input[name="upfile"]').val('');
                    $form.find('input[name="noimg"]').prop('checked', false);
                    $form.find('input[name="up_series"]').prop('checked', false);
                    $form.find('input[name="ObHGyhdTR"]').prop('checked', false);
                    $form.find('input[name="category"]').val(localStorage.getItem('input-category-category') || '');
                    $form.find('input[name="bvUFbdrIC"]').val(localStorage.getItem('input-name-placeholder') || '');

                    // 刷新線程
                    refreshThread();
                },
                error: function(xhr, status, error) {
                    console.error(`提交失敗(嘗試 ${attempt}/${maxAttempts}):`, status, error, '回應狀態:', xhr.status, '回應內容:', xhr.responseText);

                    // 處理503錯誤或潛在成功
                    if (xhr.status === 503 && attempt < maxAttempts) {
                        console.log(`檢測到503錯誤,重試 ${attempt + 1}/${maxAttempts}...`);
                        setTimeout(() => submitReply(formData, $form, attempt + 1, maxAttempts), 2000);
                    } else if (xhr.status === 200 || xhr.status === 302 || xhr.responseText.includes('成功')) {
                        console.log('檢測到可能的成功提交,嘗試刷新線程');
                        refreshThread();
                    } else {
                        alert('回覆提交失敗(狀態碼: ' + xhr.status + '),請檢查網絡或稍後重試。手動刷新頁面可能顯示您的回覆。');
                        // 仍嘗試刷新以檢查是否成功
                        refreshThread();
                    }
                }
            });
        }

        // 表單提交事件
        $('#quickreply-form').on('submit', function(e) {
            e.preventDefault();

            var $form = $(this);
            var formData = new FormData(this);

            // 確保Cloudflare Turnstile token包含
            var $turnstileResponse = $('.cf-turnstile input[name="cf-turnstile-response"]');
            if ($turnstileResponse.length) {
                if (!$turnstileResponse.val()) {
                    console.warn('Turnstile token 為空,可能導致提交失敗');
                }
                formData.append('cf-turnstile-response', $turnstileResponse.val());
            } else {
                console.warn('未找到Cloudflare Turnstile token,可能導致提交失敗');
            }

            // 開始提交
            submitReply(formData, $form);
        });

        // 刷新線程函數(帶重試機制並規避$.isMobile錯誤)
        function refreshThread(attempt = 1, maxAttempts = 3) {
            var threadNo = $('#quickreply-form input[name="resto"]').val();
            if (!threadNo) {
                console.warn('無法獲取線程ID');
                alert('無法刷新線程,請手動重新整理頁面。');
                return;
            }

            var $thread = $(`div.thread[data-no="${threadNo}"]`);
            var existingReplyIds = $thread.find('.post.reply').map(function() {
                return $(this).attr('data-no');
            }).get();

            console.log('正在刷新線程:', threadNo, '現有回覆ID:', existingReplyIds);

            $.ajax({
                url: `pixmicat.php?res=${threadNo}`,
                type: 'GET',
                cache: false,
                success: function(data) {
                    console.log('線程數據獲取成功,解析新回覆...');
                    var $newContent = $('<div>').html(data);
                    var $newReplies = $newContent.find(`div.thread[data-no="${threadNo}"] .post.reply`);

                    if ($newReplies.length === 0) {
                        console.warn('未找到新回覆,可能是伺服器延遲');
                        if (attempt < maxAttempts) {
                            console.log(`重試 ${attempt + 1}/${maxAttempts}...`);
                            setTimeout(() => refreshThread(attempt + 1, maxAttempts), 2000);
                            return;
                        } else {
                            alert('未檢測到新回覆,請手動刷新頁面確認。');
                            return;
                        }
                    }

                    var newRepliesAdded = false;
                    $newReplies.each(function() {
                        var replyId = $(this).attr('data-no');
                        if (!existingReplyIds.includes(replyId)) {
                            try {
                                $thread.find('hr').before($(this));
                                newRepliesAdded = true;
                                console.log('添加新回覆:', replyId);
                            } catch (e) {
                                console.error('添加回覆時發生錯誤(可能是Komica原生腳本問題):', e);
                            }
                        }
                    });

                    if (newRepliesAdded) {
                        console.log('線程已刷新,新回覆已添加');
                        // 直接展開回覆,規避$.isMobile錯誤
                        $thread.find('.post.reply').each(function() {
                            var $post = $(this);
                            try {
                                $post.find('.post-content').show();
                            } catch (e) {
                                console.warn('展開回覆失敗:', e);
                            }
                        });
                    } else {
                        console.warn('未找到新回覆,可能是伺服器延遲或無新內容');
                        if (attempt < maxAttempts) {
                            console.log(`重試 ${attempt + 1}/${maxAttempts}...`);
                            setTimeout(() => refreshThread(attempt + 1, maxAttempts), 2000);
                        } else {
                            alert('未檢測到新回覆,請手動刷新頁面確認。');
                        }
                    }
                },
                error: function(xhr, status, error) {
                    console.error('線程刷新失敗:', status, error, '回應狀態:', xhr.status, '回應內容:', xhr.responseText);
                    if (attempt < maxAttempts) {
                        console.log(`重試 ${attempt + 1}/${maxAttempts}...`);
                        setTimeout(() => refreshThread(attempt + 1, maxAttempts), 2000);
                    } else {
                        alert('無法刷新線程,請手動重新整理頁面。');
                    }
                }
            });
        }
    });
})();