import { BasePlugin } from '../core/base-plugin.js'; import { __publicField, isJavBus, isJavDb, isSearchPage, currentHref, Status_FILTER, Status_FAVORITE, Status_HAS_DOWN, Status_HAS_WATCH, NO, YES } from '../core/constants.js'; import { HotkeyManager } from './preview-video.js'; import { translateText, TAG_STYLES } from './list-page-button.js'; class ListPagePlugin extends BasePlugin { constructor() { super(...arguments); __publicField(this, "currentPageFilterCount", 0); __publicField(this, "currentPageFavoriteCount", 0); __publicField(this, "currentPageHasDownCount", 0); __publicField(this, "currentPageHasWatchCount", 0); __publicField(this, "currentPageKeywordFilterCount", 0); __publicField(this, "currentPageActorFilterCount", 0); __publicField(this, "currentPageWaitCheckCount", 0); __publicField(this, "currentPageTotalCount", 0); __publicField(this, "cache", localStorage.getItem("jhs_translate") ? JSON.parse(localStorage.getItem("jhs_translate")) : {}); __publicField(this, "writeQueue", Promise.resolve()); } getName() { return "ListPagePlugin"; } async handle() { this.cleanRepeatId(); this.replaceHdImg(); this.addJumpPageControl(); this.fixBusTitleBox(); await this.doFilter(); this.bindClick().then(); this.bindListPageHotKey().then(); this.rememberTagExpand(); $(this.getSelector().itemSelector + " a").attr("target", "_blank"); this.checkDom(); } rememberTagExpand() { if (!window.location.href.includes("actors")) return; const $expandButton = $(".tag-expand"); if (0 === $expandButton.length) return; const isExpanded = "true" === localStorage.getItem("jhs_tag_expand"), $actorTagsContent = $(".actor-tags .content"); isExpanded && $actorTagsContent.hasClass("collapse") && $expandButton[0].click(); $expandButton.on("click", (function() { const newState = !$actorTagsContent.hasClass("collapse"); localStorage.setItem("jhs_tag_expand", newState.toString()); })); } checkDom() { if (!window.isListPage) return; const selector = this.getSelector(), targetNode = document.querySelector(selector.boxSelector); if (!targetNode) { console.error("没有找到容器节点!"); return; } const observer = new MutationObserver((async mutations => { observer.disconnect(); try { this.replaceHdImg(); this.addJumpPageControl(); this.fixBusTitleBox(); this.getBean("CoverButtonPlugin").addSvgBtn().then(); await this.doFilter(); await this.getBean("ListPageButtonPlugin").sortItems(); $(this.getSelector().itemSelector + " a").attr("target", "_blank"); this.getBean("AutoPagePlugin").checkLoad(); } finally { observer.observe(targetNode, config); } })), config = { childList: !0, subtree: !1 }; observer.observe(targetNode, config); } fixBusTitleBox() { if (!isJavBus) return; $(this.getSelector().itemSelector).toArray().forEach((ele => { var _a2; let $box2 = $(ele); if ($box2.find(".avatar-box").length > 0) return; const title = (null == (_a2 = $box2.find("img").attr("title")) ? void 0 : _a2.trim()) || ""; $box2.find(".photo-info span:first").contents().first().wrap(`${title}`); $box2.find("br").remove(); })); } cleanRepeatId() { if (!isJavBus) return; $("#waterfall_h").removeAttr("id").attr("id", "no-page"); const $waterfalls = $('[id="waterfall"]'); 0 !== $waterfalls.length && $waterfalls.each((function() { const $current = $(this); if (!$current.hasClass("masonry")) { $current.children().insertAfter($current); $current.remove(); } })); } async doFilter() { if (!window.isListPage) return; let movieList = $(this.getSelector().itemSelector).toArray(); if (movieList.length) { await this.filterMovieList(movieList); await this.getBean("WangPan115MatchPlugin").matchMovieList(movieList); isJavBus && await this.getBean("BusImgPlugin").logImageHeightsByRow(); } } async filterMovieList(movieList) { utils.time("累计耗费时间"); utils.time("读取数据耗时"); const [carList, filterKeywordList, blacklist, blacklistCarList, settingObj] = await Promise.all([ storageManager.getCarList(), storageManager.getTitleFilterKeyword(), storageManager.getBlacklist(), storageManager.getBlacklistCarList(), storageManager.getSetting() ]), t1 = utils.time("读取数据耗时"), carNumSets = carList.reduce(((dataMap, item) => { const statusKey = item.status; dataMap.hasOwnProperty(statusKey) && dataMap[statusKey].add(item.carNum); return dataMap; }), { [Status_FILTER]: new Set, [Status_FAVORITE]: new Set, [Status_HAS_DOWN]: new Set, [Status_HAS_WATCH]: new Set }); utils.time("组装数据耗时"); const starIdToRoleMap = new Map(blacklist.map((item => [ item.starId, item.role ]))), {actorCarNumToNameMap: actorCarNumToNameMap, actressCarNumToNameMap: actressCarNumToNameMap} = blacklistCarList.reduce(((dataMap, carItem) => { const role = starIdToRoleMap.get(carItem.starId); if (!role) { clog.error("黑名单数据源丢失演员信息", carItem); return dataMap; } const targetMap = "actor" === role ? dataMap.actorCarNumToNameMap : dataMap.actressCarNumToNameMap; targetMap.has(carItem.carNum) || targetMap.set(carItem.carNum, carItem.names); return dataMap; }), { actorCarNumToNameMap: new Map, actressCarNumToNameMap: new Map }), t2 = utils.time("组装数据耗时"), settings = { showFilterItem: (null == settingObj ? void 0 : settingObj.showFilterItem) ?? NO, showFilterActorItem: (null == settingObj ? void 0 : settingObj.showFilterActorItem) ?? NO, showFilterKeywordItem: (null == settingObj ? void 0 : settingObj.showFilterKeywordItem) ?? NO, showFavoriteItem: (null == settingObj ? void 0 : settingObj.showFavoriteItem) ?? YES, showHasDownItem: (null == settingObj ? void 0 : settingObj.showHasDownItem) ?? YES, showHasWatchItem: (null == settingObj ? void 0 : settingObj.showHasWatchItem) ?? YES, showAllItem: (null == settingObj ? void 0 : settingObj.showAllItem) ?? NO, tagPosition: (null == settingObj ? void 0 : settingObj.tagPosition) || "rightTop", movieShowType: (null == settingObj ? void 0 : settingObj.movieShowType) || "hide" }; this.currentPageFilterCount = 0; this.currentPageFavoriteCount = 0; this.currentPageHasDownCount = 0; this.currentPageHasWatchCount = 0; this.currentPageKeywordFilterCount = 0; this.currentPageActorFilterCount = 0; this.currentPageWaitCheckCount = 0; this.currentPageTotalCount = 0; utils.time("处理页面耗时"); await Promise.all(movieList.map((async ele => { let $box2 = $(ele); if (isJavBus && $box2.find(".avatar-box").length > 0) return; const {carNum: carNum2, title: title} = this.getBoxCarInfo($box2), {filter: filter, favorite: favorite, hasDown: hasDown, hasWatch: hasWatch} = carNumSets, isFavorite = favorite.has(carNum2), isHasDown = hasDown.has(carNum2), isHasWatch = hasWatch.has(carNum2), isFiltered = filter.has(carNum2), isFilterActorMale = actorCarNumToNameMap.has(carNum2), isFilterActorFemale = actressCarNumToNameMap.has(carNum2), isFilterActor = isFilterActorMale || isFilterActorFemale, foundKeyword = filterKeywordList.find((kw => title.includes(kw) || carNum2.startsWith(kw))), isFilterKeyword = !!foundKeyword; if (!isSearchPage) { let shouldHide = settings.showFavoriteItem === NO && isFavorite || settings.showHasDownItem === NO && isHasDown || settings.showHasWatchItem === NO && isHasWatch || settings.showFilterItem === NO && isFiltered && !(isFavorite || isHasDown || isHasWatch) || settings.showFilterActorItem === NO && isFilterActor || settings.showFilterKeywordItem === NO && isFilterKeyword; if ($box2.attr("data-movieShowType") !== settings.movieShowType) { $box2.css("border", ""); $box2.children().css("visibility", ""); $box2.removeAttr("data-hide"); $box2.show(); } const isCurrentlyHidden = $box2.attr("data-hide") === YES; settings.showAllItem === YES && (shouldHide = !1); if (shouldHide !== isCurrentlyHidden) { shouldHide ? $box2.attr("data-hide", YES) : $box2.removeAttr("data-hide"); if ("hide" === settings.movieShowType) shouldHide ? $box2.hide() : $box2.show(); else { if ("visibility" !== settings.movieShowType) throw new Error("movieShowType值有误:" + settings.movieShowType); { const $content = $box2.children(), borderStyle = shouldHide ? "1px solid rgb(192 176 176)" : "none", visibilityValue = shouldHide ? "hidden" : "visible"; $box2.css("border", borderStyle); $content.css("visibility", visibilityValue); } } $box2.attr("data-movieShowType") !== settings.movieShowType && $box2.attr("data-movieShowType", settings.movieShowType); } } let tag = TAG_STYLES.IS_WAIT_CHECK, filterReason = null; if (isFiltered) tag = TAG_STYLES.IS_FILTERED; else if (isFavorite) tag = TAG_STYLES.IS_FAVORITE; else if (isHasDown) tag = TAG_STYLES.IS_HAS_DOWN; else if (isHasWatch) tag = TAG_STYLES.IS_HAS_WATCH; else if (isFilterKeyword) { tag = TAG_STYLES.IS_KEYWORD_FILTER; filterReason = foundKeyword || "未知"; } else if (isFilterActorMale) { tag = TAG_STYLES.IS_ACTOR_FILTER; filterReason = actorCarNumToNameMap.get(carNum2) || ""; } else if (isFilterActorFemale) { tag = TAG_STYLES.IS_ACTRESS_FILTER; filterReason = actressCarNumToNameMap.get(carNum2) || ""; } filterReason || (filterReason = tag.reasonType); tag.isCounted && this[tag.countKey]++; this.currentPageTotalCount++; $box2.find(".status-tag").remove(); const tagPositionCss = "rightTop" === settings.tagPosition ? "right: 0; top:5px;" : "left: 0; top:5px;"; if (tag.text) { const tagHtml = isJavDb ? `\n ${tag.text}\n ` : `\n ${tag.text}\n `; isJavDb && $box2.find(".tags").append(tagHtml); if (isJavBus) { const $itemTag = $box2.find(".item-tag"); $itemTag.length ? $itemTag.append(tagHtml) : $box2.find(".photo-info > span > div").append(tagHtml); } } await this.translate($box2); }))); const t3 = utils.time("处理页面耗时"), t4 = utils.time("累计耗费时间"); $("#waitDownBtn span").text(`打开已收藏 (${carNumSets.favorite.size})`); clog.log(`\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
${t1}${t2}
${t3}${t4}
项目数量项目数量
屏蔽单番号${this.currentPageFilterCount}收藏${this.currentPageFavoriteCount}
屏蔽演员${this.currentPageActorFilterCount}已下载${this.currentPageHasDownCount}
屏蔽关键词${this.currentPageKeywordFilterCount}已观看${this.currentPageHasWatchCount}
待鉴定${this.currentPageWaitCheckCount}
总数${this.currentPageTotalCount}
\n `); } async bindClick() { let selector = this.getSelector(); $(selector.boxSelector).on("click", ".item img", (async event => { event.preventDefault(); event.stopPropagation(); if ($(event.target).closest("div.meta-buttons").length) return; const $box2 = $(event.target).closest(".item"), {carNum: carNum2, aHref: aHref} = this.getBoxCarInfo($box2); let dialogOpenDetail = await storageManager.getSetting("dialogOpenDetail", YES); if (carNum2.includes("FC2-")) { let movieId = this.parseMovieId(aHref); this.getBean("Fc2Plugin").openFc2Dialog(movieId, carNum2, aHref); } else if (dialogOpenDetail === YES) { utils.openPage(aHref, carNum2, !0, event); this.$currentImage = null; } else window.open(aHref); })); $(selector.boxSelector).on("click", ".item video", (async event => { const video = event.currentTarget; video.paused ? video.play().catch((e => console.error("播放失败:", e))) : video.pause(); event.preventDefault(); event.stopPropagation(); })); $(selector.boxSelector).on("click", ".item .video-title", (async event => { if ($(event.target).closest('[class^="jhs-match-"]').length) return; const $box2 = $(event.currentTarget).closest(".item"), {carNum: carNum2, aHref: aHref} = this.getBoxCarInfo($box2); if (carNum2.includes("FC2-")) { event.preventDefault(); let movieId = this.parseMovieId(aHref); this.getBean("Fc2Plugin").openFc2Dialog(movieId, carNum2, aHref); } })); $(selector.boxSelector).on("contextmenu", ".item img, .item video", (async event => { event.preventDefault(); const $box2 = $(event.target).closest(".item"), {carNum: carNum2, url: url, publishTime: publishTime} = this.getBoxCarInfo($box2); let $actor = isJavDb ? $(".actor-section-name") : $(".avatar-box .photo-info .pb10"), actorName = ""; $actor.length && (actorName = $actor.text().trim().split(",")[0].replace("(無碼)", "")); utils.q(event, `是否屏蔽番号 ${carNum2}?`, (async () => { setTimeout((async () => { actorName || (actorName = await this.parseActressName(url)); await storageManager.saveCar({ carNum: carNum2, url: url, names: actorName, actionType: Status_FILTER, publishTime: publishTime }); window.refresh(); show.ok("操作成功"); })); })); })); } async parseActressName(url) { let actorName = null; if (await storageManager.getSetting("enableSaveActressCarInfo", NO) === YES) { clog.debug("鉴定补录演员信息-已启用, 开始解析详情页"); clog.debug("开始解析演员详情页", url); const html = await gmHttp.get(url), $dom = utils.htmlTo$dom(html); isJavDb ? actorName = $dom.find(".female").prev().map(((i, el) => $(el).text())).get().join(" ") : isJavBus && (actorName = $dom.find('span[onmouseover*="star_"] a').map(((i, el) => $(el).text())).get().join(" ")); clog.debug("解析到名称:", actorName); } return actorName; } async bindListPageHotKey() { this.$currentImage = null; $(document).on("mouseenter", this.getSelector().coverImgSelector, (e => { this.$currentImage = $(e.currentTarget); })).on("mouseleave", this.getSelector().coverImgSelector, (() => { this.$currentImage = null; })); let settingObj = await storageManager.getSetting(); this.filterHotKey = settingObj.filterHotKey; this.favoriteHotKey = settingObj.favoriteHotKey; this.hasDownHotKey = settingObj.hasDownHotKey; this.hasWatchHotKey = settingObj.hasWatchHotKey; this.enableImageHotKey = settingObj.enableImageHotKey || NO; this.clogHotKey = settingObj.clogHotKey; this.foldCategoryHotKey = settingObj.foldCategoryHotKey; this.showFilterItemHotKey = settingObj.showFilterItemHotKey; this.showFilterActorItemHotKey = settingObj.showFilterActorItemHotKey; this.showFilterKeywordItemHotKey = settingObj.showFilterKeywordItemHotKey; this.showFavoriteItemHotKey = settingObj.showFavoriteItemHotKey; this.showHasDownItemHotKey = settingObj.showHasDownItemHotKey; this.showHasWatchItemHotKey = settingObj.showHasWatchItemHotKey; this.showAllItemHotKey = settingObj.showAllItemHotKey; const HOTKEY_REGISTRY = { showFilterItemHotKey: "showFilterItem", showFilterActorItemHotKey: "showFilterActorItem", showFilterKeywordItemHotKey: "showFilterKeywordItem", showFavoriteItemHotKey: "showFavoriteItem", showHasDownItemHotKey: "showHasDownItem", showHasWatchItemHotKey: "showHasWatchItem", showAllItemHotKey: "showAllItem" }, registerToggleHotkey = (hotkeyName, settingKey) => { const hotkeyString = this[hotkeyName]; hotkeyString && HotkeyManager.registerHotkey(hotkeyString, (async event => { const newVal = await storageManager.getSetting(settingKey) === YES ? NO : YES; await storageManager.saveSettingItem(settingKey, newVal); window.refresh(); })); }; for (const hotkeyName in HOTKEY_REGISTRY) if (HOTKEY_REGISTRY.hasOwnProperty(hotkeyName)) { registerToggleHotkey(hotkeyName, HOTKEY_REGISTRY[hotkeyName]); } if (this.enableImageHotKey === NO) return; const handleAction = async (boxInfo, status) => { setTimeout((async () => { let actorName = await this.parseActressName(boxInfo.url); await storageManager.saveCar({ carNum: boxInfo.carNum, url: boxInfo.url, names: actorName, actionType: status, publishTime: boxInfo.publishTime }); window.refresh(); show.ok("操作成功"); })); }, handlers = {}; this.filterHotKey && (handlers[this.filterHotKey] = boxInfo => { handleAction(boxInfo, Status_FILTER); }); this.favoriteHotKey && (handlers[this.favoriteHotKey] = boxInfo => { handleAction(boxInfo, Status_FAVORITE); }); this.hasDownHotKey && (handlers[this.hasDownHotKey] = boxInfo => { handleAction(boxInfo, Status_HAS_DOWN); }); this.hasWatchHotKey && (handlers[this.hasWatchHotKey] = boxInfo => { handleAction(boxInfo, Status_HAS_WATCH); }); this.clogHotKey && HotkeyManager.registerHotkey(this.clogHotKey, (event => { clog.toggleExpandCollapsed(); })); this.foldCategoryHotKey && HotkeyManager.registerHotkey(this.foldCategoryHotKey, (event => { const $btn = $("#foldCategoryBtn"); $btn.length && $btn[0].click(); })); const registerImageHotkey = (key, handler) => { HotkeyManager.registerHotkey(key, (event => { const activeElement = document.activeElement; if (!("INPUT" === activeElement.tagName || "TEXTAREA" === activeElement.tagName || activeElement.isContentEditable) && this.$currentImage) { const $box2 = this.$currentImage.closest(".item"), boxInfo = this.getBoxCarInfo($box2); handler(boxInfo); } })); }; Object.entries(handlers).forEach((([key, handler]) => { registerImageHotkey(key, handler); })); } replaceHdImg(coverImgNodeList) { coverImgNodeList && "string" == typeof coverImgNodeList.jquery && (coverImgNodeList = coverImgNodeList.toArray()); coverImgNodeList || (coverImgNodeList = document.querySelectorAll(this.getSelector().coverImgSelector)); isJavDb && coverImgNodeList.forEach((img => { img.src = img.src.replace("thumbs", "covers"); img.title = ""; })); if (isJavBus) { const THUMB_PATH_REGEX = /\/(imgs|pics)\/(thumb|thumbs)\//, IMG_EXT_REGEX = /(\.jpg|\.jpeg|\.png)$/i, replaceWithHd = img => { if (img.src && THUMB_PATH_REGEX.test(img.src) && "true" !== img.dataset.hdReplaced) { img.src = img.src.replace(THUMB_PATH_REGEX, "/$1/cover/").replace(IMG_EXT_REGEX, "_b$1"); img.dataset.hdReplaced = "true"; img.dataset.title = img.title; img.title = ""; } }, DMM_THUMB_REGEX = /ps(\.jpg|\.jpeg|\.png)$/i, replaceWithHdForDMM = img => { if (img.src && DMM_THUMB_REGEX.test(img.src) && "true" !== img.dataset.hdReplaced) { img.src = img.src.replace(DMM_THUMB_REGEX, "pl$1"); img.dataset.hdReplaced = "true"; img.dataset.title = img.title; img.title = ""; } }; coverImgNodeList.forEach((img => { replaceWithHd(img); replaceWithHdForDMM(img); })); } storageManager.getSetting("hoverBigImg", NO).then((hoverBigImg => { hoverBigImg === YES && (window.imageHoverPreviewObj ? window.imageHoverPreviewObj.bindEvents() : window.imageHoverPreviewObj = new ImageHoverPreview({ selector: this.getSelector().coverImgSelector })); })); } async translate($box2) { if (await storageManager.getSetting("translateTitle", YES) !== YES) return; let content, carNum2, $title = $box2.find(".video-title"); if (isJavDb) { content = $title.contents().filter(((i, node) => 3 === node.nodeType && "" !== node.textContent.trim())).text().trim(); carNum2 = $box2.find(".video-title strong").text().trim(); } else { content = $box2.find("img").attr("data-title").trim(); carNum2 = $box2.find("a").attr("href").split("/").filter(Boolean).pop().trim(); } if (this.cache[carNum2]) { let _this = this; $title.attr("data-original-title", content); $title.contents().each((function() { 3 === this.nodeType && "" !== this.textContent.trim() && (this.textContent = " " + _this.cache[carNum2] + " "); })); $title.attr("title", _this.cache[carNum2]); } else translateText(content).then((result => { $title.attr("data-original-title", content); if (isJavDb) { $title.contents().each((function() { 3 !== this.nodeType || "" === this.textContent.trim() || this.textContent.includes(carNum2) || (this.textContent = " " + result + " "); })); $title.attr("title", result); } else $title.text(result); this.writeQueue = this.writeQueue.then((() => { this.cache[carNum2] = result; localStorage.setItem("jhs_translate", JSON.stringify(this.cache)); })); })).catch((error => { console.error("翻译失败:", error); })); } async revertTranslation() { $(this.getSelector().itemSelector).toArray().forEach((ele => { let $box2 = $(ele); const originalContent = $box2.find(".video-title").attr("data-original-title") || $box2.find(".box").attr("title") || $box2.find(".video-title").attr("title") || $box2.find("img").attr("data-title"); let carNum2; isJavDb && (carNum2 = $box2.find(".video-title strong").text().trim()); const $title = $box2.find(".video-title"); $title.contents().each((function() { 3 !== this.nodeType || "" === this.textContent.trim() || this.textContent.includes(carNum2) || (this.textContent = " " + originalContent + " "); })); $title.removeAttr("title"); })); } addJumpPageControl() { if ($("#gemini-jump-page-control").length > 0) return; if (0 === $(".pagination-link.is-current").length) return; const currentPageNum = utils.getUrlParam(currentHref, "page") || 1, $input = $("", { type: "number", id: "jumpPageInput", placeholder: "页码", min: "1", style: "width: 60px; margin-left: 10px; padding: 10px; border: 1px solid #ccc; font-size: 14px;", value: currentPageNum + 1 }), $button = $("