// ==UserScript== // @name 巴哈姆特_新版B頁板務功能 // @namespace Bee10301 // @version 8.4 // @description 巴哈姆特哈拉區新體驗。 // @author Bee10301 // @match https://www.gamer.com.tw/ // @match https://www.gamer.com.tw/index2.php* // @match https://forum.gamer.com.tw/B.php?* // @match https://forum.gamer.com.tw/C.php?* // @homepage https://home.gamer.com.tw/home.php?owner=bee10301 // @icon https://home.gamer.com.tw/favicon.ico // @connect * // @grant GM_xmlhttpRequest // @license GPL // @downloadURL https://update.greasyfork.icu/scripts/375498/%E5%B7%B4%E5%93%88%E5%A7%86%E7%89%B9_%E6%96%B0%E7%89%88B%E9%A0%81%E6%9D%BF%E5%8B%99%E5%8A%9F%E8%83%BD.user.js // @updateURL https://update.greasyfork.icu/scripts/375498/%E5%B7%B4%E5%93%88%E5%A7%86%E7%89%B9_%E6%96%B0%E7%89%88B%E9%A0%81%E6%9D%BF%E5%8B%99%E5%8A%9F%E8%83%BD.meta.js // ==/UserScript== // noinspection SpellCheckingInspection,JSUnresolvedReference,BadExpressionStatementJS (async function () { ("use strict"); checkFirstRun(); await addSettingElement(); await worker_bPage(); await worker_cPage(); worker_home(); checkTips(); reportAlert(); })(); function checkFirstRun(reset = false) { console.log("[INFO] Init data"); // add_function > 標題後方插入功能 // preview_auto > 一律即時瀏覽(覆寫文章換頁) // preview_wait_load > 即時瀏覽:是否等待載入完成才跳出顯示 // preview_size > 即時瀏覽視窗的大小 // new_design > 自適型版面(根據下方自定比例適應) // new_design_box > 顯示區域佔比(文章顯示區+聊天室區的整體範圍) // new_design_box_Left > 文章佔比(佔上個設定「顯示區域」範圍內的比例) // new_design_box_Right > 聊天室佔比(佔上方設定「顯示區域」範圍內的比例) // new_design_LRSwitch > 左右對調(聊天室在左方,讓文章標題在螢幕中間) // bee_select_color > 勾選文章時的顏色(可含有透明度屬性) // preview_LR > 即時瀏覽視窗的位置 const settingsB = [ { key: "isFirstRun", defaultValue: "false" }, { key: "add_function", defaultValue: "true", }, { key: "preview_auto", defaultValue: "true", }, { key: "preview_wait_load", defaultValue: "false", }, { key: "preview_size", defaultValue: "65%", }, { key: "new_design", defaultValue: "true", }, { key: "new_design_box", defaultValue: "80%", }, { key: "new_design_box_Left", defaultValue: "70%", }, { key: "new_design_box_Right", defaultValue: "25%", }, { key: "new_design_LRSwitch", defaultValue: "true", }, { key: "bee_select_color", defaultValue: "#000000b3", }, { key: "addBorderInPicMode", defaultValue: "true", }, { key: "showTips", defaultValue: "true", }, { key: "preview_LR", defaultValue: "true", }, { key: "showAbuse", defaultValue: "true", }, { key: "addSummaryBtn", defaultValue: "true", }, { key: "oaiBaseUrl", defaultValue: "https://api.openai.com/v1/chat/completions", }, { key: "oaiKey", defaultValue: "sk-yourKey", }, { key: "oaiModel", defaultValue: "gpt-3.5-turbo", }, { key: "oaiPrompt", defaultValue: `## workflow 1. 總結:精確的讀懂和理解文章,然後用一句話脈絡清晰的語句,總結出[文章的主旨]。 2. 提煉重點:根據文章的邏輯和結構,清楚列出文章的主要論點,並按照下方範例的格式輸出。 總結: - 要點1: - 要點2: ...(依情況增加或減少要點) ## MUST/IMPORTANT/RULES - 不能添加其他個人觀點或註釋。 - 使用繁體中文 `, }, { key: "oaiPromptCmd", defaultValue: "以下是一段群組聊天的對話,總結對話中的話題,用條列式列出使用者的想法。\n## workflow \n 1. 整理話題:理解各個使用者討論的話題並以話題為單位整理出整串對話的話題 \n 2. 將相同話題中,對同一件事有相似想法的對話整理在一起(例如 `@user1/@user2:認為太貴了`) ,不同看法則單獨列出。\n 3. 輸出:把冗餘贅字優化,但保留具體描述。(劣例:`@user1/@user2:提及角色在世界觀中的地位和特徵` 在這個例子中沒有具體描述提即了什麼樣的地位或特徵)。使用者以 @id 標記並且不再添加其他md語法。 \n ## MUST/IMPORTANT/RULES \n- 不能添加其他個人觀點或註釋。\n- 使用繁體中文\n", }, { key: "oaiPromptChat", defaultValue: "根據文章內容,使用繁體中文流暢語言,簡潔的回答使用者的問題。", }, { key: "custom_oaiPrompt", defaultValue: "", }, { key: "custom_oaiPromptCmd", defaultValue: "", }, { key: "custom_oaiPromptChat", defaultValue: "", }, { key: "oaiPromptSystemMode", defaultValue: "true", }, { key: "oaiPromptDate", defaultValue: "20241101", }, { key: "oaiPromptUpdateDate", defaultValue: "20241101", }, { key: "oaiPromptUpdateURL", defaultValue: "https://gamercomtwnew.bee.moe/gamer.prompts.json", }, { key: "oaiPromptUpdateSleep", defaultValue: "1", }, // Add other settings as needed ]; const settingsHome = [ { key: "homeStyleSwitch", defaultValue: "true" }, { key: "homeTips", defaultValue: "true", }, ]; let settings = window.location.href.includes("forum.gamer.com.tw/B.php") ? settingsB : settingsHome; settings.forEach((setting) => { if ( localStorage.getItem(setting.key) === "" || localStorage.getItem(setting.key) === null || reset === true ) { localStorage.setItem(setting.key, setting.defaultValue); } }); if (window.location.href.includes("forum.gamer.com.tw/B.php")) { if ( localStorage.getItem("oaiPromptUpdateURL") === "https://gamercomtwnew.bee.moe/gamer.prompts.js" ) { localStorage.setItem( "oaiPromptUpdateURL", "https://gamercomtwnew.bee.moe/gamer.prompts.json" ); } } } function checkTips() { if (window.location.href.includes("forum.gamer.com.tw/B.php")) { if (localStorage.getItem("showTips") === "true") { loadTips(); localStorage.setItem("showTips", "false"); } } if (window.location.href.includes("www.gamer.com.tw")) { if (localStorage.getItem("homeTips") === "true") { loadTips_home(); localStorage.setItem("homeTips", "false"); } } } async function addSettingElement() { if (!window.location.href.includes("forum.gamer.com.tw/B.php")) { return; } const navAddTag = document.querySelector(".BH-menuE"); const navAdd = document.createElement("li"); navAdd.className = "beeSettingTag"; navAdd.innerHTML = "插件設定"; navAdd.addEventListener("click", function () { let sectionTitleWarp = document.querySelector(".beeSettingWarp"); popElement(sectionTitleWarp, "toggle", "ud"); scrollIntoBee(document.querySelector(".b-list-wrap"), 7); }); navAddTag.appendChild(navAdd); // 取得 management-item 元素 const settingsWarp = document.querySelector(".b-list-wrap"); // 插入新內容到最後一個 management-item 元素中 const lastManagementItem = document.createElement("div"); lastManagementItem.className = "beeSettingWarp"; const sectionTitle = document.createElement("h3"); sectionTitle.className = "section-title"; sectionTitle.textContent = "插件設定(再點一次上方的【插件設定】即可返回【文章列表】)"; sectionTitle.style.margin = "0.6rem 0 0.7rem 0.7rem"; lastManagementItem.appendChild(sectionTitle); lastManagementItem.appendChild( createItemCard("add_function", "標題後方插入功能按鈕") ); lastManagementItem.appendChild( createItemCard("preview_auto", "點擊文章時使用即時瀏覽") ); lastManagementItem.appendChild( createItemCard(null, null, { inputId: "preview_size", labelText: " └ 即時瀏覽視窗的大小", }) ); lastManagementItem.appendChild( createItemCard("preview_LR", "即時瀏覽從右方彈出(取消則從左)") ); lastManagementItem.appendChild( createItemCard("new_design", "自適型版面(根據下方自定比例適應)") ); lastManagementItem.appendChild( createItemCard(null, null, { inputId: "new_design_box", labelText: " └ 整體顯示區域佔比(文章+聊天室佔整個畫面的比例,< 100%)", }) ); lastManagementItem.appendChild( createItemCard(null, null, { inputId: "new_design_box_Left", labelText: "   ├ 文章佔比(與聊天室佔比總和 <= 100%)", }) ); lastManagementItem.appendChild( createItemCard(null, null, { inputId: "new_design_box_Right", labelText: "   └ 聊天室佔比", }) ); lastManagementItem.appendChild( createItemCard( "new_design_LRSwitch", "左右對調(聊天室在左方,讓文章標題在螢幕中間)" ) ); lastManagementItem.appendChild( createItemCard("addBorderInPicMode", "縮圖列表模式中,加上分隔線") ); lastManagementItem.appendChild( createItemCard("showAbuse", "有檢舉時,自動以即時瀏覽開啟") ); //summary lastManagementItem.appendChild( createItemCard( "addSummaryBtn", "跳過樓層按鈕/AI總結(AI功能需自備KEY填入下方)" ) ); lastManagementItem.appendChild( createItemCard(null, null, { inputId: "oaiBaseUrl", labelText: " ├ oai URL", }) ); lastManagementItem.appendChild( createItemCard(null, null, { inputId: "oaiModel", labelText: " ├ oai model", }) ); lastManagementItem.appendChild( createItemCard(null, null, { inputId: "oaiKey", labelText: " ├ oai key", }) ); lastManagementItem.appendChild( createItemCard(null, null, { inputId: "custom_oaiPrompt", labelText: " ├ 「懶人包」提示詞(留空=預設)", }) ); lastManagementItem.appendChild( createItemCard(null, null, { inputId: "custom_oaiPromptCmd", labelText: " ├ 「留言統整」自訂提示詞(留空=預設)", }) ); lastManagementItem.appendChild( createItemCard(null, null, { inputId: "custom_oaiPromptChat", labelText: " ├ 「問問」自訂提示詞(留空=預設)", }) ); lastManagementItem.appendChild( createItemCard("oaiPromptSystemMode", "├ 自訂提示詞使用 system 模式") ); lastManagementItem.appendChild( createItemCard(null, null, { inputId: "oaiPromptUpdateURL", labelText: " └ oai prompt settings URL", }) ); lastManagementItem.appendChild(createItemCard("showTips", "重新觀看TIPs")); // add one btn in a div ,click to reload the page const reloadBtn = document.createElement("button"); reloadBtn.textContent = "重新載入"; reloadBtn.style.margin = "0.5rem 0 0.7rem 0.7rem"; reloadBtn.addEventListener("click", () => { location.reload(); }); const reloadBtnDiv = document.createElement("div"); reloadBtnDiv.className = "BH-rbox BH-qabox1"; reloadBtnDiv.appendChild(reloadBtn); lastManagementItem.appendChild(reloadBtnDiv); settingsWarp.insertBefore(lastManagementItem, settingsWarp.firstChild); await popElementInit(lastManagementItem, false, "ud"); } // 項目卡函數 function createItemCard(inputId, labelText, additionalContent = null) { const isDarkTheme = window.getComputedStyle(document.getElementById("BH-menu-path")) .backgroundColor === "rgb(28, 28, 28)"; const itemCard = document.createElement("div"); itemCard.className = "item-card management_guild-check single-choice"; const checkGroup = document.createElement("div"); checkGroup.className = "check-group"; checkGroup.style.margin = "0rem 0 0.1rem 0.7rem"; if (inputId) { const input = document.createElement("input"); input.id = inputId; input.type = "checkbox"; // 如果 localStorage 有儲存的值,則設置為該值,否則預設為 checked input.checked = localStorage.getItem(inputId) === "true"; const label = document.createElement("label"); label.htmlFor = inputId; label.className = "is-active"; const labelIcon = document.createElement("div"); labelIcon.className = "label-icon"; const icon = document.createElement("i"); icon.className = "fa fa-check"; labelIcon.appendChild(icon); const h6 = document.createElement("h6"); h6.textContent = labelText; h6.style.display = "inline-block"; h6.style.color = isDarkTheme ? "#C7C6CB" : "#117e96"; label.appendChild(labelIcon); label.appendChild(h6); checkGroup.appendChild(input); checkGroup.appendChild(label); // 添加 input 事件監聽器,將值保存到 localStorage input.addEventListener("input", function () { localStorage.setItem(inputId, this.checked.toString()); }); } if (additionalContent) { const h6 = document.createElement("h6"); h6.textContent = additionalContent.labelText; h6.style.display = "inline-block"; checkGroup.appendChild(h6); const input = document.createElement("input"); input.className = "form-control"; input.id = additionalContent.inputId; input.type = "text"; input.size = 25; input.style.margin = "0px"; input.style.width = additionalContent.inputId.startsWith("custom_") ? "auto" : "70px"; checkGroup.appendChild(input); // 如果 localStorage 有儲存的值,則設置為該值 input.value = localStorage.getItem(additionalContent.inputId) || ""; // 添加 input 事件監聽器,將值保存到 localStorage input.addEventListener("input", function () { localStorage.setItem(additionalContent.inputId, this.value); }); } itemCard.appendChild(checkGroup); return itemCard; } async function worker_cPage() { if (!window.location.href.includes("forum.gamer.com.tw/C.php")) { return; } let styleSheet = document.createElement("style"); document.head.appendChild(styleSheet); let sheet = styleSheet.sheet; sheet.insertRule( ".managertools { position: fixed; bottom: 0; right: 0; z-index: 100; }", 0 ); if (localStorage.getItem("addSummaryBtn") === "false") { return; } await postAddBtn(); } async function worker_bPage() { if (window.location.href.includes("forum.gamer.com.tw/B.php")) { if (localStorage.getItem("preview_auto") === "true") { bPage_previewAuto(); } await bPage_addFrame(); bPage_addMenu(); bPage_new_checkbox(); if (localStorage.getItem("new_design") === "true") { bPage_new_design(); } if (localStorage.getItem("new_design_LRSwitch") === "true") { document.getElementById("BH-master").style.float = "right"; document.getElementById("BH-slave").style.float = "left"; } if (localStorage.getItem("add_function") === "true") { bPage_addFunction(); } //add border in pic mode must be excute after, because previewAuto does change the structure if (localStorage.getItem("addBorderInPicMode") === "true") { bPage_addBorderInPicMode(); } } } function worker_home() { if ( !window.location.href.includes("www.gamer.com.tw") || !document.querySelectorAll("div.BA-lbox.BA-lbox3") ) { return; } // add btn const baServeElement = document.querySelector(".BA-serve"); const newElement = document.createElement("li"); newElement.innerHTML = `首頁滿版切換`; baServeElement.appendChild(newElement); // 切換 localStorage 中 homeStyleSwitch 的值 newElement.addEventListener("click", () => { const currentValue = localStorage.getItem("homeStyleSwitch") === "true"; localStorage.setItem("homeStyleSwitch", (!currentValue).toString()); location.reload(); // 刷新頁面以應用更改 }); // if active if (localStorage.getItem("homeStyleSwitch") === "true") { // Get the elements const hotboardContainer = document.getElementById("hotboardContainer"); const guildContainer = document.getElementById("guildContainer"); const hothalaContainer = document.getElementById("hothalaContainer"); // Append the elements to the "hothalaContainer" hothalaContainer.appendChild(hotboardContainer); hothalaContainer.appendChild(guildContainer); // 2nd left nav const bahaStoreContainer = document.querySelectorAll( "div.BA-lbox.BA-lbox3" )[0]; const bahaAnimeContainer = document.querySelectorAll( "div.BA-lbox.BA-lbox3" )[1]; let secondDivLeft = document.createElement("div"); secondDivLeft.className = "BA-left"; secondDivLeft.style.flex = "0 0 11em"; secondDivLeft.style.margin = "0 0 0 1em"; secondDivLeft.appendChild(document.querySelectorAll("h1.BA-ltitle")[1]); secondDivLeft.appendChild(bahaAnimeContainer); secondDivLeft.appendChild(document.querySelectorAll("h1.BA-ltitle")[0]); secondDivLeft.appendChild(bahaStoreContainer); document .querySelectorAll("div.BA-wrapper.BA-main")[0] .insertBefore( secondDivLeft, document.querySelectorAll("div.BA-center")[0] ); // Create a new style element const newStyle = document.createElement("style"); // Set the CSS content newStyle.textContent = ` /* 父容器設置 */ .BA-wrapper.BA-main { display: flex; flex-wrap: wrap; width: auto; } /* 第一層左側固定寬度 */ .BA-left { flex: 0 0 11em; } /* 第一層右側容器 */ .BA-center { flex: 1; /* 占據剩餘所有空間 */ display: flex; /* 使其內部也成為flex容器 */ flex-wrap: wrap; /* 允許內部元素換行 */ } #gnnContainer { flex: 0 0 45%; margin: 0 1% 2% 1%; order: 1; } #hothalaContainer { flex: 45%; margin: 0 1% 2% 1%; order: 2; } #homeContainer { flex: 45%; margin: 0 1% 2% 1%; order: 3; } #buyContainer { flex: 0 0 45%; margin: 0 1% 2% 1%; order: 4; } #liveContainer { flex: 45%; margin: 0 1% 2% 1%; order: 5; } #gamecrazyContainer { flex: 0 0 45%; margin: 0 1% 2% 1%; order: 6; } .BA-cbox7 p{ text-align: left !important; } `; // Append the style element to the head of the document document.head.appendChild(newStyle); } } async function bPage_addFrame() { //frame let beePreviewWd = document.createElement("div"); beePreviewWd.className = "bee_preview_wd"; beePreviewWd.style.height = "100%"; //beePreviewWd.style.width = '0rem'; beePreviewWd.style.width = localStorage.getItem("preview_size"); beePreviewWd.style.transform = "scaleX(" + 0 + ")"; beePreviewWd.style.zIndex = "100"; beePreviewWd.style.position = "fixed"; beePreviewWd.style.top = "0px"; if (localStorage.getItem("preview_LR") === "true") { beePreviewWd.style.right = "1%"; } else { beePreviewWd.style.left = "1%"; } //beePreviewWd.style.transition = 'all 0.5s cubic-bezier(0.21, 0.3, 0.18, 1.37) 0s'; //document.body.appendChild(beePreviewWd); let beeFrame = document.createElement("iframe"); beeFrame.id = "bee_frame"; beeFrame.title = "bee_frame"; beeFrame.src = ""; //beeFrame.style.transition = 'all 0.5s cubic-bezier(0.21, 0.3, 0.18, 1.37) 0s'; beeFrame.style.border = "0em solid rgb(170, 50, 220, 0)"; beeFrame.width = "100%"; beeFrame.height = "100%"; //document.querySelector('.bee_preview_wd').appendChild(beeFrame); beePreviewWd.appendChild(beeFrame); document.body.appendChild(beePreviewWd); await popElementInit( beePreviewWd, false, localStorage.getItem("preview_LR") === "true" ? "rl" : "lr", false ); //close frame by top menu let BHMenuPath = document.querySelector("#BH-menu-path"); BHMenuPath.style.transition = "all 0.5s cubic-bezier(0.21, 0.3, 0.18, 1.37) 0s"; BHMenuPath.style.height = "40px"; BHMenuPath.style.opacity = "1"; //BHMenuPath.style.backgroundColor = '#0e4355cc'; BHMenuPath.addEventListener("click", () => { /*document.querySelector('.bee_preview_wd').style.transform = 'translateX(100%)'; document.querySelector('.bee_preview_wd').style.opacity = '0';*/ popElement( document.querySelector(".bee_preview_wd"), "false", localStorage.getItem("preview_LR") === "true" ? "rl" : "lr" ); BHMenuPath.style.height = "40px"; BHMenuPath.style.opacity = "1"; }); } function bPage_addMenu() { try { // 獲取 .managertools 元素 const managertools = document.querySelector(".managertools"); // 創建 .b-manager 容器 const bManagerDiv = document.createElement("div"); bManagerDiv.className = "b-manager managertools bee_manager"; bManagerDiv.style.zIndex = "100"; bManagerDiv.style.position = "fixed"; bManagerDiv.style.width = "auto"; // 創建 .checkbox 和