您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Many improvements mainly in details view of a video for recherche: easier collect of Google Drive and Rapidgator links for JDownloader (press <), save/show favorite actresses, recherche links for actresses, auto reload on Cloudflare rate limit, save cover with actress names just by clicking, advertising photos in full size
当前为
// ==UserScript== // @name JAVLibrary Improvements // @description Many improvements mainly in details view of a video for recherche: easier collect of Google Drive and Rapidgator links for JDownloader (press <), save/show favorite actresses, recherche links for actresses, auto reload on Cloudflare rate limit, save cover with actress names just by clicking, advertising photos in full size // @version 20240921 // @author resykano // @icon https://icons.duckduckgo.com/ip2/javlibrary.com.ico // @match *://*.javlibrary.com/* // @match *://x75p.com/* // @match *://*.y78k.com/* // @match *://javx357.com/* // @match *://arcjav.com/* // @match *://javgg.me/* // @match *://maxjav.com/* // @match *://jav.guru/* // @match *://supjav.com/* // @match *://missav.com/* // @match *://video-jav.net/* // @match *://www.akiba-online.com/search/* // @grant GM_xmlHttpRequest // @grant GM_download // @grant GM_setClipboard // @grant GM_getValue // @grant GM_setValue // @grant GM_addStyle // @grant GM_openInTab // @grant window.close // @run-at document-start // @compatible chrome // @license GPL3 // @noframes // @namespace https://greasyfork.org/users/1342111 // ==/UserScript== "use strict"; // --------------------------------------------------------------------------------------- // Config/Requirements // --------------------------------------------------------------------------------------- let avidCopiedToClipboard = false; const url = window.location.href; const originalDocumentTitle = document.title; let avid = null; function getTitleElement() { return document.querySelector("#video_id > table > tbody > tr > td.text"); } function getAvid() { if (!avid) { avid = getTitleElement()?.textContent; } } function castContainer() { return document.querySelector("#video_cast"); } function createBase64Svg(fillColor) { const svgTemplate = ` <svg class="mr-1 md:mr-2 h-3 w-3 xs:h-4 xs:w-4" xmlns="http://www.w3.org/2000/svg" fill="${fillColor}" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z"></path> </svg>`; return `"data:image/svg+xml;base64,${btoa(svgTemplate)}"`; } let favoriteImage = createBase64Svg("red"); let nonFavoriteImage = createBase64Svg("lightgray"); /** * Waits for an element until it exists * * @param {string} selector CSS selector of a NodeList/HTMLCollection * @param {number} index * @see source: {@link https://stackoverflow.com/a/61511955/13427318} * @returns Element */ function waitForElement(selector, index = 0) { return new Promise((resolve) => { if (selector && document.querySelector(selector) && document.querySelectorAll(selector)[index]) { return resolve(document.querySelectorAll(selector)[index]); } const observer = new MutationObserver(() => { if (selector && document.querySelectorAll(selector) && document.querySelectorAll(selector)[index]) { resolve(document.querySelectorAll(selector)[index]); observer.disconnect(); } }); observer.observe(document, { childList: true, subtree: true, }); }); } // --------------------------------------------------------------------------------------- // Functions // --------------------------------------------------------------------------------------- function addCSS() { GM_addStyle(` /* Saving space on top and left */ #topmenu { z-index: 2; } #toplogo { position: absolute; top: 0; height: 28px; left: unset; background: unset; overflow: unset; } #toplogo .languagemenu { padding-right: 16px; top: 34px; z-index: 1; } #toplogo .topbanner1, #toplogo .sitelogo { display: none; } div#topbanner11 { height: unset; } #content { padding-top: 0; } div.boxtitle { top: 0; padding: unset; } /* improve space on smaller viewports */ @media screen and (max-width: 1300px) { #leftmenu { display: none; } #rightcolumn { margin-left: 10px; } } `); switch (true) { // JAV Details case /[a-z]{2}\/\?v=jav.*/.test(url): { GM_addStyle(` #toplogo .languagemenu { top: 45px; } #video_title h3.post-title { padding-right: 78px; top: 30px; } #video_info { min-width: 430px; } .added-links { margin-left: 107px; max-width: 370px; height: 17px; display: flex; align-items: flex-end; justify-content: space-between; } .added-links-separator { margin-top: 10px; } /* addSearchLinkAndOpenAllButton & addFaceRecognitionSearchToCasts */ button.smallbutton-mod { margin-left: 8px; margin-top: 0; margin-bottom: 0; padding: 3px; width: 150px; height: 22px; user-select = none; } /* preview video separated from advertising photos */ a.btn_videoplayer { display: block; text-align: center; } /* prevent video metadata from becoming too narrow */ #video_jacket_info > tbody > tr > td:nth-child(2) { min-width: 370px; } @media screen and (min-width: 1301px) { /* reduce FOUC for cover image */ img#video_jacket_img { width: 800px; object-fit: contain; /* not too high, especially portraits */ max-height: 800px; } } @media screen and (max-width: 1300px) { /* same size for cover and metadata area */ #video_jacket_info > tbody > tr > td { width: 50%; } img#video_jacket_img { width: 100% !important; } } /* addImageSearchToCasts */ .customButton { font-size: 12px; cursor: default; background-color: buttonface; padding-block: 2px; padding-inline: 6px; border-width: 1px; border-style: solid; border-color: #767676; border-radius: 2px; color: black; transition: background-color 0.3s ease; user-select: none; } .customButton:visited { color: #aaa; } .customButton:hover { background-color: #e0e0e0; } `); break; } // no video found case /\/vl_searchbyid.php/.test(url): { GM_addStyle(` .added-links { margin-left: 107px; height: 17px; display: flex; align-items: flex-end; justify-content: space-between; max-width: 400px; margin-left: auto; margin-right: auto; } .added-links-separator { margin-top: 10px; } `); break; } } } function removeRedirects() { let externalLinks = document.querySelectorAll("table[id^=comment] > tbody > tr:nth-child(1) > td.t > div a[href^='redirect.php']"); for (let externalLink of externalLinks) { externalLink.href = decodeURIComponent( externalLink.href?.replace(/https:\/\/www\.javlibrary\.com\/.*\/redirect\.php\?url=/, "").replace(/\&ver=.*/, "") ); } } function addTitleCopyPerClick() { let titleElement = getTitleElement(); titleElement.style.cursor = "pointer"; titleElement.addEventListener("click", function () { copyTitleToClipboard(); }); } function executeInitialLocalSearch(source) { const textElement = getTitleElement(); if (textElement && !avidCopiedToClipboard && document.hasFocus()) { // only put once to clipboard console.log(`${source}: ${avid}`); // if tab was opened with link if (history.length === 1) { copyTitleToClipboard(avid) .then(() => { avidCopiedToClipboard = true; runLocalSearch(); }) .catch(function (err) { console.error("Failed to copy text: ", err); avidCopiedToClipboard = false; }); } } } /** * requires a local script such as AHK, which recognizes the window title * as information for the execution of another local script * Button and auto execute disabled if GM variable privateMode is not set */ async function addLocalSearchButton() { const authorsMode = await GM_getValue("authorsMode", false); if (authorsMode) { let targetElement = getTitleElement(); let newButton = document.createElement("button"); newButton.textContent = "Local-Search"; newButton.className = "smallbutton localsearch"; newButton.style = "position:relative;top:-3px;margin-left:10px"; targetElement.insertAdjacentElement("afterend", newButton); newButton.addEventListener( "click", function () { copyTitleToClipboard().then(() => { runLocalSearch(); }); }, false ); } } function runLocalSearch() { // not on image videos if (!document.querySelector("#genre199")) { document.title = "Browser Local-Search"; setTimeout(() => { document.title = originalDocumentTitle; }, 50); } } function copyTitleToClipboard() { return navigator.clipboard.writeText(avid); } function coverImageDownload() { // big preview screen shots const screenShots = document.querySelectorAll("#rightcolumn > div.previewthumbs > img"); for (let img of screenShots) { srcBigPictures = img.src.replace(/(.*)(-[0-9].*)$/i, "$1jp$2"); img.src = srcBigPictures; } // rename cover image let casts = document.querySelectorAll("[id^=cast] > span.star > a"); let newFilename = avid + " - "; let iteration = casts.length; for (let cast of casts) { // also replace non-ASCII characters newFilename += cast.textContent.replace(/[^\x00-\x7F]/g, ""); // do as long not last iteration if (--iteration) newFilename += ", "; } const coverPicture = document.querySelector("#video_jacket_img"); const coverPictureUrl = coverPicture?.src; coverPicture?.addEventListener( "click", function () { GM_download({ url: coverPictureUrl, headers: { referer: coverPictureUrl, origin: coverPictureUrl }, name: newFilename, onload: function (download) { // Create an invisible <a> element const downloadLink = document.createElement("a"); // Set the Blob URL as the HREF value and the filename for download downloadLink.setAttribute("download", newFilename); // Trigger the click event on the invisible <a> element downloadLink.click(); }, onerror: function (error) { console.error("Download failed:", error); }, }); }, { once: true, } ); } function setSearchLinks() { // add search links and buttons addSearchLinkAndOpenAllButton( "DuckDuckGo Screens", "https://duckduckgo.com/?kp=-2&iax=images&ia=images&q=" + '"' + avid + '"' + " JAV", "" ); addSearchLinkAndOpenAllButton("DuckDuckGo", "https://duckduckgo.com/?kp=-2&q=" + '"' + avid + '"' + " JAV", "", true); addSearchLinkAndOpenAllButton("JavPlace | alternative research platform", "https://jav.place/?q=" + avid, ""); addSearchLinkAndOpenAllButton("JAV-Menu | alternative research platform", "https://jjavbooks.com/en/" + avid, "", true); addSearchLinkAndOpenAllButton("JAV BIGO | Stream", "https://javbigo.com/?s=" + avid, "Stream-Group"); addSearchLinkAndOpenAllButton("JAVHDMost | Stream", "https://javhdmost.com/?s=" + avid, "Stream-Group"); addSearchLinkAndOpenAllButton("Jable | Stream", "https://jable.tv/search/" + avid + "/", "Stream-Group"); addSearchLinkAndOpenAllButton("MDTAIWAN | Stream", "https://mdtaiwan.com/?s=" + avid, "Stream-Group"); addSearchLinkAndOpenAllButton("HORNYJAV | Stream", "https://hornyjav.com/?s=" + avid, "Stream-Group", true); addSearchLinkAndOpenAllButton("JAV GDRIVE | Google Drive", "https://javx357.com/?s=" + avid, "GDrive-Group"); addSearchLinkAndOpenAllButton("Arc JAV | Google Drive", "https://arcjav.com/?s=" + avid, "GDrive-Group"); addSearchLinkAndOpenAllButton("JAVGG | Google Drive", "https://javgg.me/?s=" + avid, "GDrive-Group", true); addSearchLinkAndOpenAllButton("JAVDAILY | RG (optional)", "https://javdaily31.blogspot.com/search?q=" + avid, ""); addSearchLinkAndOpenAllButton("BLOGJAV.NET | RG (optional)", "https://blogjav.net/?s=" + avid, "", true); addSearchLinkAndOpenAllButton("MissAV | RG | Stream", "https://missav.com/en/search/" + avid, "Rapidgator-Group"); addSearchLinkAndOpenAllButton("Supjav | RG", "https://supjav.com/?s=" + avid, "Rapidgator-Group"); addSearchLinkAndOpenAllButton("JAV Guru | RG | Stream", "https://jav.guru/?s=" + avid, "Rapidgator-Group", true); addSearchLinkAndOpenAllButton("3xPlanet | Preview", "https://3xplanet.com/?s=" + avid, "Preview-Group-2"); addSearchLinkAndOpenAllButton("JAVAkiba | Preview", "https://javakiba.org/?s=" + avid, "Preview-Group-2"); addSearchLinkAndOpenAllButton("Video-JAV | Preview", "http://video-jav.net/?s=" + avid, "Preview-Group-2", true); addSearchLinkAndOpenAllButton("JAV Max Quality | Preview", "https://maxjav.com/?s=" + avid, "Preview-Group-1"); addSearchLinkAndOpenAllButton( "Akiba-Online | Preview", "https://www.akiba-online.com/search/?q=" + avid + "&c%5Btitle_only%5D=1&o=date&search=" + avid, "Preview-Group-1", true ); addSearchLinkAndOpenAllButton("Torrent-Search", "https://bt4gprx.com/search?q=" + avid + "&orderby=size", "", true); } /** * Adds a search links and open all links buttons * * @param {*} name Name * @param {*} href URL * @param {*} separator Adds a space on top * @param {*} className Adds a class */ function addSearchLinkAndOpenAllButton(name, href, className, separator = false) { // styles in addCSS if (separator) { separator = "added-links-separator"; } if (className === "") className = undefined; // after the casting container or "search tips" if the search does not return any results let existingContainer = castContainer() || document.querySelector("#rightcolumn > div.titlebox"); let newElementContainer = document.createElement("div"); newElementContainer.classList.add("added-links"); newElementContainer.classList.add(separator); newElementContainer.classList.add(className); let newElement = document.createElement("a"); newElement.href = href; newElement.textContent = name; newElementContainer.appendChild(newElement); // add open all links buttons if (separator && className) { const openAllButton = document.createElement("button"); const buttonTitle = className.replace(/-/g, " "); openAllButton.textContent = "Open " + buttonTitle; openAllButton.className = "smallbutton smallbutton-mod"; openAllButton.addEventListener("click", function () { let linksToOpen = document.querySelectorAll(`.${className}.added-links a`); let reversedLinks = Array.from(linksToOpen).reverse(); // allow batch search on external sites GM_setValue("externalSearchMode", true); // TODO: needs a more solid solution without brute force setTimeout(async () => { GM_setValue("externalSearchMode", false); console.log("externalSearchMode off"); }, 7000); // open in background tabs if (className === "Rapidgator-Group") { reversedLinks.forEach(function (link) { GM_openInTab(link.href); }); } else { reversedLinks.forEach(function (link) { window.open(link.href); }); } }); newElementContainer.appendChild(openAllButton); } existingContainer.insertAdjacentElement("afterend", newElementContainer); } function collectingLinksFromCommentsAndRgGroupButton() { const target = document.querySelector("#video_info > div.added-links.added-links-separator.Rapidgator-Group ~ div"); function addButton(text, action) { let button = document.createElement("button"); button.textContent = text; button.title = "Hotkey <"; button.className = "smallbutton smallbutton-mod"; button.style = "position: relative; top: 7px;"; button.onclick = function () { action(); }; target.appendChild(button); } addButton("+ Links from Comments", collectingLinksFromCommentsAndRgGroup); } // Execute when button pressed with collecting comments for importing into Jdownloader function collectingLinksFromCommentsAndRgGroup() { // press Open Rapidgator Group button document.querySelector("#video_info > div.added-links.added-links-separator.Rapidgator-Group > button")?.click(); // go to comments page, if not already there const allCommentsLink = document.querySelector("#video_comments_all > a"); if (allCommentsLink) { // open link GM_setValue("executingCollectingComments", true); setTimeout(() => { window.open(allCommentsLink.href, "_self"); }, 200); } else if (document.querySelector("#rightcolumn > div.page_selector > a.page.last")) { // if already on comments page GM_setValue("executingCollectingComments", true); location.reload(); } else { copyLinksFromCommentsToClipboard(); } } // Function to copy the contents of the #video_comments element to the clipboard // for collecting download links in apps like JDownloader function copyLinksFromCommentsToClipboard() { const commentsElement = document.querySelector("#video_comments"); if (commentsElement) { const links = commentsElement.querySelectorAll("a"); // collect href attributes of links in an array const commentsContent = Array.from(links) // allows to disable the collection of links from a hoster by using display: none // The !! converts link.offsetParent to a boolean value .filter((link) => !!link.offsetParent) // filter not usable .filter((link) => !link.href.match(/(\.gif|\.jpg|\.jpeg|user\.php|userposts\.php|ouo\.io)/i)) .map((link) => link.href) .join("\n"); GM_setClipboard(commentsContent); } } function addCastImageSearchButtons() { // styles in addCSS let castElements = document.querySelectorAll("[id^=cast]"); castElements.forEach(function (castElement) { function addButton(text, link) { let a = document.createElement("a"); a.target = "_blank"; a.textContent = text; a.className = "customButton"; let castName = castElement.querySelector("span.star > a").textContent; // Reverse the order of names for better search results if (castName.split(" ").length === 2) { castName = castName.split(" ").reverse().join(" "); } if (link && castName) { if (link.includes("duckduckgo") || link.includes("yandex")) { a.href = link + '"' + castName + '"'; } else { a.href = link + castName; } } let span = document.createElement("span"); span.appendChild(a); castElement.appendChild(span); } addButton("XsList", "https://duckduckgo.com/?iar=images&iax=images&ia=images&q=site:xslist.org "); addButton("Yandex", "https://yandex.com/images/search?text="); addButton("AVDBS", "https://www.avdbs.com/menu/search.php?seq=42978591&tab=1&kwd="); addButton("V2PH", "https://www.v2ph.com/search/?q="); addButton("JJGirls", "https://jjgirls.com/match.php?model="); addButton("KawaiiThong", "https://kawaiithong.com/search_kawaii_pics/"); }); } function addFaceRecognitionSearchButton() { const castContainer = document.querySelector("#video_cast > table > tbody > tr > td.text"); function addButton(text, link) { let button = document.createElement("button"); button.textContent = text; button.className = "smallbutton smallbutton-mod"; button.style = "width: unset"; button.onclick = function () { window.open(link, "_blank"); }; let span = document.createElement("span"); span.style = "display: block; margin-top: 5px"; span.appendChild(button); castContainer.appendChild(span); } addButton("Find cast with facial recognition", "https://xslist.org/en/searchByImage"); } async function makeFavoriteCastVisible() { const favoriteClass = "favorite-star"; function addCss() { GM_addStyle(` span[class^="icn_fav"].favorite-star { background-image: url(${favoriteImage}); } span[class^="icn_fav"] { background-image: url(${nonFavoriteImage}); background-size: contain; background-position: unset; background-color: #252525; border-radius: 4px; } `); } function toggleFavoriteCast(event) { const element = event.target; const elementId = element.id; const isFavorite = element.classList.toggle(favoriteClass); // hide and auto close modal asking if cast should be added to favorites waitForElement("div.noty_bar.center.alert.default").then(() => { function addTemporaryCssRule() { var styleElement = GM_addStyle(` div.noty_bar.center.alert.default, div.noty_modal { display: none !important; } `); // Remove the CSS after the specified duration setTimeout(function () { styleElement.parentNode.removeChild(styleElement); }, 2000); } // Hide modal until we have clicked it away addTemporaryCssRule(); // The "ok" and "close" buttons are always created immediately in the DOM and then adjusted afterwards. // This means that the decision as to what must be clicked does not work with the if clause. // close with ok let okButton = document.querySelector( "div.noty_bar.center.alert.default > div.noty_message > div.noty_text > div.noty_buttons > button.button.green" ); okButton?.click(); // if not closed with ok, then with close button which can only be clicked after a delay setTimeout(() => { let closeButton = document.querySelector("div.noty_bar.center.alert.default > div.noty_message > div.noty_close"); closeButton?.click(); }, 1000); }); if (isFavorite) { GM_setValue(elementId, true); } else { GM_deleteValue(elementId); } } addCss(); const starElements = document.querySelectorAll("[id^=star]"); for (const element of starElements) { const elementId = element.id; const isFavoriteStar = await GM_getValue(elementId, false); if (isFavoriteStar) { element.classList.add(favoriteClass); } element.addEventListener("click", toggleFavoriteCast); } } async function removeResizingOfCoverImage() { const coverImage = await waitForElement("#video_jacket_img"); if (!coverImage) return; coverImage.removeAttribute("width"); coverImage.removeAttribute("height"); const observer = new MutationObserver((mutations) => { for (let mutation of mutations) { if (mutation.type === "attributes") { coverImage.removeAttribute("width"); coverImage.removeAttribute("height"); // observer.disconnect(); return; } } }); observer.observe(coverImage, { attributes: true }); } function setAdvertisingPhotosToFullSize() { const advertisingPreviewImageLinks = document.querySelectorAll("#rightcolumn > div.previewthumbs > a:not(.btn_videoplayer)"); advertisingPreviewImageLinks.forEach((anchor) => { const img = anchor.querySelector("img"); if (img) { img.src = anchor.href; img.removeAttribute("width"); img.removeAttribute("height"); anchor.href; } }); } // --------------------------------------------------------------------------------------- // external search // --------------------------------------------------------------------------------------- class ExternalSearch { constructor() { this.currentURL = window.location.href; this.hostname = window.location.hostname; } openLink(url, target = "_self") { return window.open(url, target); } handleSearchResults() { const selectors = [ //default "[id^=post]", //jav.guru "#main div.row", //missjav.com "div.my-2.text-sm.text-nord4.truncate", //supjav.com ".post", ]; let posts = []; for (let selector of selectors) { posts = document.querySelectorAll(selector); if (posts.length > 0) break; } if (posts[0]?.textContent.includes("404") || posts.length === 0) { if (document.title !== "Just a moment...") { window.close(); } } else if (posts.length === 1) { const link = posts[0].querySelector("a"); if (link && !link.href.includes("#")) { link.click(); } else { window.close(); } } else if (posts.length <= 30) { let openWindowCheck; posts.forEach((post, index) => { const link = post.querySelector("a"); let title = post.textContent; const paramName = "s"; let searchTerm = new URLSearchParams(window.location.search).get(paramName); if (!searchTerm) { const url = window.location.href; const searchPattern = /\/search\/([^\/]+)/; searchTerm = url.match(searchPattern)[1]; } if (link && title) { const regex = new RegExp(`\\b${searchTerm}\\b`, "i"); if (regex.test(title)) { setTimeout(() => { openWindowCheck = GM_openInTab(link.href); }, index * 100); } } }); if (openWindowCheck !== null) { setTimeout(() => window.close(), 2000); } else { console.log("window.open blocked"); } } } handleGoogleDrivePages() { const links = document.querySelectorAll("[id^=post] a"); let isFirstIteration = true; links.forEach((link) => { if ( link.textContent.includes("FHD") || link.textContent.includes("GOOGLE DRIVE – ALL IN ONE") || link.textContent.includes("GB") || link.textContent.includes("1080") ) { if (isFirstIteration) { isFirstIteration = false; link.scrollIntoView({ block: "center" }); } } }); if (this.hostname === "javgg.me") { const postContentElement = document.querySelector("article.status-publish.hentry > div > p"); if (postContentElement && postContentElement.textContent.includes("drive.google.com/file/")) { GM_setClipboard(postContentElement.textContent) .then(() => window.close()) .catch((err) => console.error("Error copying content:", err)); } } } async handleRapidgatorPages() { console.log("handleRapidgatorPages"); if (this.hostname === "jav.guru") { // not on redirecting page if (!this.currentURL.includes("/?r=")) { const sources = document.querySelectorAll("#dl_jav_free"); const rapidgatorSources = Array.from(sources).filter((source) => source.innerText.includes("Rapidgator")); if (rapidgatorSources.length === 0) { window.close(); return; } for (let source of rapidgatorSources) { const link = source.querySelector("a"); if (link) { let onClickContent = link.getAttribute("onclick"); if (onClickContent) { const match = onClickContent.match(/window\.open\s*\(\s*['"]([^'"]*)['"]/); if (match) { const url = match[1]; onClickContent = onClickContent.replace(/window\.open\s*\([^)]*\)/, `window.open('${url}', '_self')`); link.setAttribute("onclick", onClickContent); link.click(); } else { window.open(link.href, "_self"); } } } } } } else { const link = document.querySelector("a[href*=rapidgator]"); if (link) { console.log("handle details pages to get rapidgator links"); window.open(link.href, "_self"); setTimeout(() => { link.click(); setTimeout(() => window.close(), 1000); }, 100); } else { window.close(); } } } main() { switch (true) { case this.currentURL.includes("/?s=") || this.currentURL.includes("/search"): this.handleSearchResults(); break; case ["arcjav.com", "javgg.me", "javx357.com"].includes(this.hostname): this.handleGoogleDrivePages(); break; case ["jav.guru", "supjav.com", "missav.com"].includes(this.hostname): this.handleRapidgatorPages(); break; } } } // --------------------------------------------------------------------------------------- // Main // --------------------------------------------------------------------------------------- async function main() { // Cloudflare restricted access if (/.*/.test(url)) { if (document.title.includes("Access denied")) { setTimeout(() => { location.reload(); }, 10000); } } getAvid(); switch (true) { // JAV Details case /[a-z]{2}\/\?v=jav.*/.test(url): { console.log("JAV Details"); // TODO: needs a more solid solution than just a blind timeout // maybe possible with GM_openInTab let externalSearchMode = await GM_getValue("externalSearchMode", false); if (externalSearchMode) { setTimeout(async () => { GM_setValue("externalSearchMode", false); console.log("externalSearchMode off"); }, 5000); } // add title textbox addTitleCopyPerClick(); // adds posibility for local search but disabled by default as needs addinal scripts addLocalSearchButton(); // add search links setSearchLinks(); // increase advertising previews setAdvertisingPhotosToFullSize(); // add Cover Image Download button coverImageDownload(); // Remove link by converting <a> to <span> element (function () { let linkElement = document.querySelector("#video_title > h3 > a"); if (linkElement) { let spanElement = document.createElement("span"); spanElement.innerHTML = linkElement.innerHTML; linkElement.insertAdjacentElement("beforebegin", spanElement); linkElement.parentNode.removeChild(linkElement); } })(); // remove redirects from external links setTimeout(() => { removeRedirects(); }, 500); // autorun local search const authorsMode = await GM_getValue("authorsMode", false); if (authorsMode) { (function () { // Handle the case when the window is opened in the background window.addEventListener("focus", function () { executeInitialLocalSearch("EventListener"); }); // Handle the case when the window is opened in the foreground // IntersectionObserver is used for better performance and reliability // compared to repeated DOM queries or fixed timeouts const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { executeInitialLocalSearch("IntersectionObserver"); } }); }); // Set up the observer after a short delay to ensure DOM is loaded setTimeout(() => { const textElement = getTitleElement(); if (textElement) { observer.observe(textElement); } }, 500); })(); } addCastImageSearchButtons(); addFaceRecognitionSearchButton(); collectingLinksFromCommentsAndRgGroupButton(); makeFavoriteCastVisible(); window.addEventListener("keydown", function (event) { if (event.key === "<") { collectingLinksFromCommentsAndRgGroup(); } }); break; } // Redirect Page case /\/redirect.php/.test(url): { document.querySelector("#ckbSkipURLWarning").click(); document.querySelector("#redirection").click(); break; } // Video Star Listings case /\/vl_star.php/.test(url): { console.log("Video Star Listings"); // ToDo: highlight visited videos let videoLinks = document.querySelectorAll('div[id^="vid_"] a'); for (let i = 0; i < videoLinks.length; i++) { if (videoLinks[i].visited) { videoLinks[i].parentNode.style.backgroundColor = "#ffe7d3"; } } // open in same tab setTimeout(() => { document.querySelectorAll(".video > a").forEach(function (element) { element.removeAttribute("target"); }); }, 2000); break; } // Search Page case /\/search.php/.test(url): { console.log("Advanced Search Section"); // open Combination Search // document.querySelector("#ui-accordion-accordion-header-1 > span")?.click(); break; } // if video is not in JAVLibrary case /\/vl_searchbyid.php/.test(url): { if (document.querySelector("#rightcolumn > p > em") && document.querySelector("#rightcolumn > div.titlebox")) { console.log("no search results"); avid = new URLSearchParams(window.location.search).get("keyword"); if (avid) { setSearchLinks(); } } // open found links in same tab document.querySelectorAll(".video > a")?.forEach(function (element) { element.removeAttribute("target"); }); break; } case /\/videocomments.php/.test(url): { console.log("Comments Page"); async function loadNextPage() { copyLinksFromCommentsToClipboard(); // Copy the comments content before loading the next page let currentPage = new URL(window.location.href).searchParams.get("page"); let lastPageUrl = document.querySelector("#rightcolumn > div.page_selector > a.page.last")?.href; let lastPage = await GM_getValue("lastPage", null); // If lastPage is not set and the last page URL is available, extract and store the last page number if (!lastPage && lastPageUrl) { lastPage = new URL(lastPageUrl).searchParams.get("page"); GM_setValue("lastPage", lastPage); } if (!currentPage) currentPage = 1; else currentPage = parseInt(currentPage); // If the current page is not the last page, load the next page if (currentPage < lastPage) { let nextPage = currentPage + 1; let nextUrl = new URL(window.location.href); nextUrl.searchParams.set("page", nextPage); window.location.href = nextUrl.href; } else { // not if cloudflare check happens if (!document.title.includes("Just a moment...")) { GM_deleteValue("lastPage"); GM_deleteValue("executingCollectingComments"); // go back to main page const mainPageLink = document.querySelector("#video_jacket > a"); console.log(mainPageLink); if (mainPageLink) { // open link window.open(mainPageLink.href, "_self"); } } } } // initialize (async function () { let executingCollectingComments = await GM_getValue("executingCollectingComments", false); if (executingCollectingComments) { // await new Promise((resolve) => setTimeout(resolve, 1000)); loadNextPage(); } else { window.addEventListener("keydown", function (event) { if (event.key === "<") { collectingLinksFromCommentsAndRgGroup(); } }); } })(); break; } // batch external download link and preview searches case /^https?:\/\/javx357\.com\/.*/i.test(url): case /^https?:\/\/arcjav\.com\/.*/i.test(url): case /^https?:\/\/javgg\.me\/.*/i.test(url): case /^https?:\/\/maxjav\.com\/.*/i.test(url): case /^https?:\/\/jav\.guru\/.*/i.test(url): case /^https?:\/\/supjav\.com\/.*/i.test(url): case /^https?:\/\/missav\.com\/.*/i.test(url): case /^https?:\/\/video-jav\.net\/.*/i.test(url): case /^https?:\/\/javakiba\.org\/.*/i.test(url): { let externalSearchMode = await GM_getValue("externalSearchMode", false); if (externalSearchMode) { const externalSearcher = new ExternalSearch(); externalSearcher.main(); } break; } // copy GDrive & Rapidgator links into clipboard for JDownloader Linkgrabber and auto close case /^https:\/\/drive\.google\.com\/uc.*/i.test(url): case /^https:\/\/drive\.google\.com\/file\/.*/i.test(url): case /^https:\/\/rapidgator\.net\/.*/i.test(url): { let externalSearchMode = await GM_getValue("externalSearchMode", false); if (externalSearchMode) { const urls = ["https://drive.google.com", "https://rapidgator.net/file/*"]; const currentUrl = window.location.href; const match = urls.some((url) => currentUrl.match(url)); if (match) { // Clipboard operation and window close function function copyToClipboardAndClose() { // (clipboard needs focus else gone) // navigator.clipboard.writeText(location.href); GM_setClipboard(location.href); setTimeout(() => { window.close(); }, 100); } copyToClipboardAndClose(); } if (document.body.textContent.includes("404 File not found")) { window.close(); } } break; } // Akiba auto search and open case /^https?:\/\/www\.akiba-online\.com\/search\/.*/i.test(url): { function search() { // Extract the current parameter const paramName = "search"; const searchTerm = new URLSearchParams(window.location.search).get(paramName); if (searchTerm) { document .querySelector( "#top > div.p-body > div > div.uix_contentWrapper > div > div > div > form > div > dl > dd > div > div.formSubmitRow-controls > button" ) .click(); // close window if no result setTimeout(() => { if (document.querySelector("body > div.flashMessage.is-active > div").textContent === "No results found.") { window.close(); } }, 200); } } function autoOpenResults() { let posts = document.querySelectorAll("div.block-container > ol > li"); if (posts.length === 1) { let post = posts[0]; let childLink = post.querySelector("a"); childLink?.click(); } else if (posts.length >= 2) { const paramName = "q"; const searchTerm = new URLSearchParams(window.location.search).get(paramName); let postTitle = document.querySelectorAll("div.block-container > ol > li h3 a"); let fileJokerExclusive = document.querySelector("div.block-container > ol > li span.label--royalBlue"); if ( fileJokerExclusive && fileJokerExclusive.parentElement.textContent.toLowerCase().includes(searchTerm.toLowerCase()) ) { fileJokerExclusive.parentElement?.click(); return; } for (let i = 0; i < postTitle.length; i++) { let title = postTitle[i]; if (!title.textContent.includes(searchTerm)) { title.parentElement.parentElement.parentElement.parentElement.style.display = "none"; } else { window.open(title.href, "_blank"); } } setTimeout(function () { window.close(); }, 500); } } let externalSearchMode = await GM_getValue("externalSearchMode", false); if (externalSearchMode) { // if this url then no result, so close window if (/^https?:\/\/www\.akiba-online\.com\/search\/search/i.test(url)) { window.close(); } // use get parameter for search with form as only post parameters are allowed search(); // open result if only one result saves clicking autoOpenResults(); } break; } } } function initializeBeforeRender() { addCSS(); switch (true) { // JAV Details case /[a-z]{2}\/\?v=jav.*/.test(url): // on low resolutions cover image get fixed size by site javascript removeResizingOfCoverImage(); break; } } // do nothing if cloudflare check happens if (!document.title.includes("Just a moment...")) { initializeBeforeRender(); // Sometimes the EventListener is not executed to prevent this: // Check if the DOM is already loaded before adding the event listener // If it's still loading, add the event listener for "DOMContentLoaded" // If it's already loaded, execute the main function immediately if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", main, { once: true }); } else { main(); } } // GM_setValue("authorsMode", true);