import { BilibiliApiProxy } from "@/api/BilibiliCDNProxy"; import { BilibiliSearchApi, type BilibiliSearchBangumiResultEntity } from "@/api/BilibiliSearchApi"; import { $, $$, addStyle, DOMUtils, log, utils } from "@/env"; import { Panel } from "@components/setting/panel"; import { CommonUtil } from "@components/utils/CommonUtil"; import { VueUtils } from "@components/utils/VueUtils"; import Qmsg from "qmsg"; import type { QmsgMsg } from "qmsg/dist/src/QmsgInst.js"; import beautifyCSS from "./css/beautify.css?raw"; /** * 额外搜索 */ export const BilibiliExtraSearch = { $flag_css: { enableOtherAreaSearchBangumi: false, }, init() { addStyle(beautifyCSS); DOMUtils.onReady(() => { Panel.execMenu("bili-search-enableOtherAreaSearchBangumi", () => { this.enableOtherAreaSearchBangumi(); }); }); }, /** * 初始化搜索的tab */ enableOtherAreaSearchBangumi() { if (!this.$flag_css.enableOtherAreaSearchBangumi) { this.$flag_css.enableOtherAreaSearchBangumi = true; addStyle(/*css*/ ` .m-search-result .tabs{ overflow: auto; white-space: nowrap; } .m-search-result .tabs .tab-item{ display: inline-block; height: 8vmin; line-height: 8vmin; color: #757575; font-size: 3.73333vmin; margin-top: 1.86667vmin; padding: 0 2.33vmin; } .m-search-result .tabs .tab-item:first-child{ padding-left: 0; } .m-search-result .tabs .tab-item:last-child{ padding-right: 0; } .m-search-result .tabs .tab-item.on{ color: var(--bili-color); border-bottom: 0.53333vmin solid var(--bili-color); } `); } let $loading: QmsgMsg | null = null; DOMUtils.waitNode(".m-search-result .tabs:not(:has(.gm-tab-item))").then(($tabs) => { // 先获取设置了搜索服务器的配置 const enableSearchServer = BilibiliApiProxy.getSearchProxyHost(); enableSearchServer.forEach((proxyServerInfo) => { const $tab = DOMUtils.createElement( "a", { className: "tab-item gm-tab-item", innerHTML: `番剧(${proxyServerInfo.name})`, }, { "data-area": proxyServerInfo.area, "data-host": proxyServerInfo.host, } ); $tabs.appendChild($tab); }); /** * 刷新tab选中状态 */ const refreshTabActive = ($tab: HTMLElement) => { $tabs.querySelectorAll(".tab-item").forEach(($ele) => $tab != $ele && $ele.classList.remove("on")); // 给自己添加选中状态 $tab.classList.add("on"); // 移除loading $loading?.close(); }; const updateSearchHost = () => { const enableSearchServer = BilibiliApiProxy.getSearchProxyHost(); $$(".tab-item.gm-tab-item").forEach(($el) => { const area = $el.getAttribute("data-area"); const findValue = enableSearchServer.find((item) => item.area === area); if (findValue) { $el.setAttribute("data-host", findValue.host); } }); }; DOMUtils.on($tabs, "click", ".tab-item", async (event) => { const $tab = event.target as HTMLElement; // 更新代理服务器 updateSearchHost(); // 先取消其它的item的选中状态 refreshTabActive($tab); const $resultPanel = $(".result-panel")!; const $oldGmResultPanel = $(".gm-result-panel"); if ($oldGmResultPanel) { // 移除旧的结果 $oldGmResultPanel.remove(); // 显示页面的搜索结果 DOMUtils.show($resultPanel!); } if (!$tab.classList.contains("gm-tab-item")) { // 页面的tab,返回 return; } const area = $tab.dataset.area!; const host = $tab.dataset.host!; /** 搜索结果 */ const $searchResult = $(".m-search-result")!; const vueInst = VueUtils.getVue($searchResult)!; // 切换tab为2(番剧)页面 vueInst.switchTab(233); // 隐藏页面的原始搜索结果 DOMUtils.hide($resultPanel); /** 搜索关键词 */ const keyword = vueInst.keyword; $loading = Qmsg.loading("搜索中,请稍后...", { onClose() { $loading = null; }, }); // 搜索 const searchBangumiResultInfo = await BilibiliSearchApi.getBangumiSearchResult({ keyword: keyword, area: area as any, host: host, }); $loading.close(); if (!searchBangumiResultInfo) { return; } const searchBangumiResultData = searchBangumiResultInfo.data; if (!searchBangumiResultInfo.isSuccess || !Array.isArray(searchBangumiResultData)) { alert(CommonUtil.toStr(searchBangumiResultData)); return; } log.info("搜索结果:", searchBangumiResultData); // 自定义搜索结果元素添加到页面中 const $gmResultPanel = DOMUtils.createElement("div", { className: "gm-result-panel", innerHTML: /*html*/ `
`, }); const $gmCardBox = $gmResultPanel.querySelector(".gm-card-box")!; $searchResult.appendChild($gmResultPanel); const $fragment = document.createDocumentFragment(); searchBangumiResultData.forEach((searchBangumiResultItem) => { const $item = this.createSearchResultVideoItem(searchBangumiResultItem); $fragment.appendChild($item); }); $gmCardBox.appendChild($fragment); }); }); }, /** * 创建搜索结果项 */ createSearchResultVideoItem(option: BilibiliSearchBangumiResultEntity) { let $item = DOMUtils.createElement( "div", { className: "gm-card-item", innerHTML: /*html*/ `
${option.season_type_name}
封面
${option.title}
${ option.styles || Reflect.get(option, "style") || Reflect.get(option, "styles_v2") || "" }
`, }, { "data-url": option.url, "data-type": option.type, "data-media_id": option.media_id, "data-pgc_season_id": option.pgc_season_id, "data-is_follow": option.is_follow, "data-is_selection": option.is_selection, } ); Reflect.set($item, "data-option", option); DOMUtils.on($item, "click", (event) => { DOMUtils.preventEvent(event); window.open(option.url, "_blank"); }); // 显示信息,包括发布时间、发布区域信息 // 排在前面的是display_info内的信息 let $displayInfo = $item.querySelector(".gm-card-display-info")!; let totalDisplayInfo: BilibiliSearchBangumiResultEntity["badges"] = []; if (Array.isArray(option?.display_info)) { totalDisplayInfo = totalDisplayInfo.concat(option.display_info); } if (Array.isArray(option?.badges)) { totalDisplayInfo = totalDisplayInfo.concat(option.badges); } // 去重 totalDisplayInfo = utils.uniqueArray(totalDisplayInfo, (item) => item.text); totalDisplayInfo.forEach((displayInfo) => { let $displayInfoItem = DOMUtils.createElement("span", { className: "gm-card-badge-info-item", innerText: displayInfo.text, }); if (typeof displayInfo.border_color === "string") { // 边框颜色 $displayInfoItem.style.border = `1px solid ${displayInfo.border_color}`; // 字体跟随边框 $displayInfoItem.style.color = displayInfo.border_color; } DOMUtils.append($displayInfo, $displayInfoItem); }); if (option.pubtime) { // 发布时间 DOMUtils.append( $displayInfo, /*html*/ ` ${utils.formatTime(option.pubtime * 1000, "yyyy")} ` ); } let areas = option.areas || Reflect.get(option, "area"); if (areas) { // 发布区域 if ($displayInfo.children.length) { DOMUtils.append( $displayInfo, /*html*/ ` | ` ); } DOMUtils.append( $displayInfo, /*html*/ ` ${areas} ` ); } // 添加评分信息 let $mediaScore = $item.querySelector(".gm-card-media_score")!; if (option.media_score && option.media_score.user_count) { // 有人评分才添加信息 DOMUtils.append( $mediaScore, /*html*/ ` ${option.media_score?.score || 0}分 ${option.media_score?.user_count || 0}人参与 ` ); } // 添加集数信息 let $eps = $item.querySelector(".gm-card-eps")!; // 兼容一下漫游服务器的公告信息 let epsList: BilibiliSearchBangumiResultEntity["eps"] = [ ...(option.eps || []), ...(Reflect.get(option, "episodes_new") || []), ].filter((item) => utils.isNotNull(item)); epsList.forEach((epsItem) => { let title = epsItem.title || epsItem.long_title; let url = epsItem.url || Reflect.get(epsItem, "uri"); let $epItem = DOMUtils.createElement( "div", { className: "gm-card-ep-conatiner", innerHTML: /*html*/ `
${title}
`, }, { "data-id": epsItem.id, "data-url": url, "data-title": title, "data-long_title": epsItem.long_title, } ); // 右上角标志 let $epBadges = $epItem.querySelector(".gm-card-ep-badges-container")!; // 番剧集数 let $epInfo = $epItem.querySelector(".gm-card-ep-info-container")!; if (Array.isArray(epsItem.badges) && epsItem.badges.length) { // 添加badges // 只添加1个 let epItemBadgeInfo = epsItem.badges[0]; let $badge = DOMUtils.createElement("span", { className: "gm-card-ep-badge-top-right", innerText: epItemBadgeInfo.text, }); if (typeof epItemBadgeInfo.bg_color === "string") { // 背景颜色 $badge.style.backgroundColor = epItemBadgeInfo.bg_color; } if (typeof epItemBadgeInfo.text_color === "string") { // 字体颜色 $badge.style.color = epItemBadgeInfo.text_color; } DOMUtils.append($epBadges, $badge); } DOMUtils.on($epItem, "click", (event) => { DOMUtils.preventEvent(event); window.open(url, "_blank"); }); $eps.appendChild($epItem); }); return $item; }, /** * 搜索番剧(从自定义服务器拉取搜索结果) */ searchBangumi() {}, };