您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
PornHub toolbox (https://codeberg.org/aolko/userscripts)
当前为
// ==UserScript== // @name PH toolbox // @namespace http://tampermonkey.net/ // @version 0.6.0-pre7 // @description PornHub toolbox (https://codeberg.org/aolko/userscripts) // @author aolko // @license GPL-3.0-or-later // @match *://*.pornhub.com/* // @match *pornhub.com* // @icon https://www.google.com/s2/favicons?sz=64&domain=pornhub.com // @grant GM_getResourceText // @grant GM_addStyle // @grant GM_openInTab // @grant GM_getValue // @grant GM_setValue // @grant GM_listValues // @grant GM_registerMenuCommand // @resource PH_CSS https://codeberg.org/aolko/userscripts/raw/branch/master/ph_toolbox/ph.style.css?v1 // @require https://code.jquery.com/jquery-3.6.1.min.js // @require https://openuserjs.org/src/libs/sizzle/GM_config.js // ==/UserScript== /* Check the official repo: https://codeberg.org/aolko/userscripts */ /*! instant.page v5.1.1 - (C) 2019-2020 Alexandre Dieulot - https://instant.page/license */ let t,e;const n=new Set,o=document.createElement("link"),i=o.relList&&o.relList.supports&&o.relList.supports("prefetch")&&window.IntersectionObserver&&"isIntersecting"in IntersectionObserverEntry.prototype,s="instantAllowQueryString"in document.body.dataset,a="instantAllowExternalLinks"in document.body.dataset,r="instantWhitelist"in document.body.dataset,c="instantMousedownShortcut"in document.body.dataset,d=1111;let l=65,u=!1,f=!1,m=!1;if("instantIntensity"in document.body.dataset){const t=document.body.dataset.instantIntensity;if("mousedown"==t.substr(0,"mousedown".length))u=!0,"mousedown-only"==t&&(f=!0);else if("viewport"==t.substr(0,"viewport".length))navigator.connection&&(navigator.connection.saveData||navigator.connection.effectiveType&&navigator.connection.effectiveType.includes("2g"))||("viewport"==t?document.documentElement.clientWidth*document.documentElement.clientHeight<45e4&&(m=!0):"viewport-all"==t&&(m=!0));else{const e=parseInt(t);isNaN(e)||(l=e)}}if(i){const n={capture:!0,passive:!0};if(f||document.addEventListener("touchstart",function(t){e=performance.now();const n=t.target.closest("a");if(!h(n))return;v(n.href)},n),u?c||document.addEventListener("mousedown",function(t){const e=t.target.closest("a");if(!h(e))return;v(e.href)},n):document.addEventListener("mouseover",function(n){if(performance.now()-e<d)return;if(!("closest"in n.target))return;const o=n.target.closest("a");if(!h(o))return;o.addEventListener("mouseout",p,{passive:!0}),t=setTimeout(()=>{v(o.href),t=void 0},l)},n),c&&document.addEventListener("mousedown",function(t){if(performance.now()-e<d)return;const n=t.target.closest("a");if(t.which>1||t.metaKey||t.ctrlKey)return;if(!n)return;n.addEventListener("click",function(t){1337!=t.detail&&t.preventDefault()},{capture:!0,passive:!1,once:!0});const o=new MouseEvent("click",{view:window,bubbles:!0,cancelable:!1,detail:1337});n.dispatchEvent(o)},n),m){let t;(t=window.requestIdleCallback?t=>{requestIdleCallback(t,{timeout:1500})}:t=>{t()})(()=>{const t=new IntersectionObserver(e=>{e.forEach(e=>{if(e.isIntersecting){const n=e.target;t.unobserve(n),v(n.href)}})});document.querySelectorAll("a").forEach(e=>{h(e)&&t.observe(e)})})}}function p(e){e.relatedTarget&&e.target.closest("a")==e.relatedTarget.closest("a")||t&&(clearTimeout(t),t=void 0)}function h(t){if(t&&t.href&&(!r||"instant"in t.dataset)&&(a||t.origin==location.origin||"instant"in t.dataset)&&["http:","https:"].includes(t.protocol)&&("http:"!=t.protocol||"https:"!=location.protocol)&&(s||!t.search||"instant"in t.dataset)&&!(t.hash&&t.pathname+t.search==location.pathname+location.search||"noInstant"in t.dataset))return!0}function v(t){if(n.has(t))return;const e=document.createElement("link");e.rel="prefetch",e.href=t,document.head.appendChild(e),n.add(t)} /* globals $ */ var $ = window.jQuery; var frame = document.createElement('div'); document.body.appendChild(frame); GM_config.init( { 'id': 'ph__config', // The id used for this instance of GM_config 'title': "⚙ PH toolbox settings", 'fields': // Fields object { 'Layout': // This is the id of the field { 'label': 'Layout', 'type': 'radio', 'options': ['Default','Basic'], 'default': 'Default' }, 'HideShortVids': { 'label': 'Hide short videos', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': false // Default value if user doesn't change it }, 'ShortVidMin': { 'label': 'Minimum video length (in seconds)', // Appears next to field 'type': 'int', // Makes this setting a text input 'min': 0, // Optional lower range limit 'max': 600, // Optional upper range limit 'default': 60 // Default value if user doesn't change it } }, 'events': { 'open': function(){ GM_config.frame.setAttribute('style', ` position: fixed; /* Stay in place */ display: flex !important; flex-direction: column; align-items: center; z-index: 9999; /* Sit on top */ left: 0; top: 0; width: 100%; /* Full width */ height: 100%; /* Full height */ overflow: auto; /* Enable scroll if needed */ `); } }, 'frame': frame, 'css': ` #ph__config{background: hsl(0 0% 0% / .8);} #ph__config_wrapper{ position: relative; top: 20%; margin:auto !important; background: #000; border-radius: 8px; max-width: 500px; border: 2px solid #ff9000; transition: all .5s ease-in-out; } #ph__config_header,.config_var{padding: 10px;} ` }); if (typeof GM_registerMenuCommand === 'function') { GM_registerMenuCommand('Settings', function() { GM_config.open(); }); } function getElementByXpath(path) { return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; } function showVids(url){ var full_url = ph__domain + url+"/videos"; console.log(full_url); $(`body`).append(` <dialog class="ph_dialog ph_modelVideos__window"> <div class="heading"> <div class="left"><h2><i class="fa-solid fa-puzzle-piece-simple"></i> Model's videos</h2></div> <div class="right"><a id="ph_modal-close" class="button"><i class="fa-solid fa-times"></i></a></div> </div> <div class="ph_modelVideos__container"></div> </dialog> `) //$( "dialog.phmodelVideos__window" ).load( "${full_url}/videos #videosTab > div > div > div:nth-child(2)" ); $.ajax({ url:full_url, type: 'GET', cache: false, success: function(data){ $('dialog.ph_modelVideos__window > .ph_modelVideos__container').html($(data).find('#videosTab > .sectionWrapper > .profileVids').html()); } }); }; function parseURL(url){ var getQueryParams = function (query) { var params = {}; new URLSearchParams(query).forEach(function (value, key) { var decodedKey = decodeURIComponent(key); var decodedValue = decodeURIComponent(value); // This key is part of an array if (decodedKey.endsWith("[]")) { decodedKey = decodedKey.replace("[]", ""); params[decodedKey] || (params[decodedKey] = []); params[decodedKey].push(decodedValue); // Just a regular parameter } else { params[decodedKey] = decodedValue; } }); return params; }; var _url = new URL(url); _url._path = _url.pathname.split( '/' ).join(`#/#`).split(`#`); _url._path[0] = _url.origin; _url._params = getQueryParams(_url.searchParams); return _url; } function secondsToTime(e) { var h = Math.floor(e / 3600).toString().padStart(2, '0'), m = Math.floor(e % 3600 / 60).toString().padStart(2, '0'), s = Math.floor(e % 60).toString().padStart(2, '0'); if (h > 0) { // Include the hours value in the output string if it is greater than 0 return h + ':' + m + ':' + s; } else { // Omit the hours value if it is 0 or less return m + ':' + s; } } function timeToSeconds(e) { // Split the input time string into an array of hours, minutes, and seconds var [m, s] = e.split(":"); // Convert the hours, minutes, and seconds to integers and return the total number of seconds return parseInt(m, 10) * 60 + parseInt(s, 10); } const ph__domain = window.location.origin; // global namespace for placing cleanup functions in var cleanup = cleanup || {}; const ph__url = parseURL(window.location.href); (function() { 'use strict'; console.log(`[PH toolbox] Started`); console.log(GM_listValues()); console.log(ph__url); // TODO: // ✅ 1. group removals into functions // ✅ ___maybe even namespace those___ // ✅ 2. group page-specific replacements by urls // ✅ 3. add favorites: // ✅ - for models // ✅ 3.1. make "My favorites" page, get the details (avatar, name) via ajax // 4. add (preset) tags for models/videos // or maybe notes that will be displayed above the video // 5. bookmarks? (jumpToAction(<seconds>)) // 6. display messages/warnings based on: // - video name keywords/phrases (AND duration) // - gender descriptions? // - video tags // ✅ 7. user flagging (flag as...) /* { flags: { "videos": [ {"url": "www.asdf.com", "reason": "1", "timecode": "00:00"} ], "models": [ {"url": "www.asdf.com", "reason": "1"} ], } } */ // - flag model as... (by model id/slug) // - Spam account // - Service ads // - Premium // - Dead account // - Turn-off/unattractive // - Fake identity // - flag video as... (by video id) // - Wrong tags // - Wrong category // - Spam // - Premium ad // - Teaser // - Low quality // ✅ 8. Hide short videos? // hide videos shorter than X minutes cleanup.page = function(){ $(`#age-verification-container,#age-verification-wrapper,.abAlertShown,#js-abContainterMain`).remove(); } cleanup.header = function(){ $(`#js-networkBar`).remove(); $(`#menuItem4.livesex`).remove(); $(`#menuItem5.pornstar`).remove(); $(`#menuItem6`).remove(); $(`#menuItem7.community`).remove(); $(`#menuItem8.photos`).remove(); $(`#countryRedirectMessage`).remove(); $(`#welcome`).remove(); $(`body > div.wrapper > div.container > div.frontListingWrapper > div:nth-child(1) > div`).remove(); $(`#profileMenuDropdown > li.upgradeToPremiumCustom`).remove(); $(`#profileMenuDropdown > li.orders`).remove(); $(`#profileMenuDropdown > li.feed > a`).attr('href','/feeds?section=videos'); $(`#coummunityMenuItems > li:nth-child(3)`).remove(); $(getElementByXpath(`/html/body/div[4]/div[3]/div[5]/div[2]/comment()[3]`)).next().remove(); $(`#menuItem2 > div > div > div.leftPanel.videos > ul > li:nth-child(10)`).remove(); $(`#dropdownHeaderSubMenu > div.innerHeaderSubMenu.trendingWrapper`).remove(); $(`#menuItem3 > div > div > div.rightPanel`).remove(); $(`#menuItem3 > div > div > div.leftPanel > div.pornInLang`).remove(); } cleanup.body = function(){ $(`#player`).removeClass(`original`); $(`#player`).addClass(`wide`); $(`#hd-rightColVideoPage`).removeClass(`original`); $(`#hd-rightColVideoPage`).addClass(`wide`); $(`div.mgp_controlBar > div.mgp_front > div.mgp_cinema`).remove(); $(`#recommendedVideos`).attr('class','videos user-playlist allRecommendedVideos'); $(`#recommendedVideosVPage > a`).remove(); $(`#hd-leftColVideoPage > div.video-wrapper.js-relatedRecommended.js-relatedVideos.relatedVideos`).addClass('allRelatedVideos'); $(`#loadMoreRelatedVideosCenter`).remove(); } var flags = JSON.parse(localStorage.getItem('flags')) || {"videos":[],"models":[]}; // Global styles GM_addStyle(` /* https://sleazyfork.org/ru/scripts/368777-pornhub-crack-for-russia */ #age-verification-container,#age-verification-wrapper,.abAlertShown,#js-abContainterMain{display:none!important} @supports (display: grid) { html.supportsGridLayout #header #headerMenuContainer #headerMainMenuInner ul#headerMainMenu>li .wideDropdown.categories .innerDropdown { grid-template-columns: .75fr auto !important; } } #header #headerMenuContainer #headerMainMenuInner ul#headerMainMenu>li .wideDropdown.categories .middlePanel{ width: 100%; } .ph_dialog{ margin:auto !important; background: #000; border-radius: 8px; min-width: 500px; max-width: 800px; border: 2px solid #ff9000; transition: all .5s ease-in-out; } .ph_dialog > .heading{ display: flex; align-content: center; padding: 10px; background: hsl(0,0%,10%); } .ph_dialog > .heading > a{ text-decoration: unset; color: #ff9000; } .ph_dialog > .heading > *{ display: flex; align-content: center; } .ph_dialog > .heading > .left > .button,.ph_dialog > .heading > .right > .button{ display: flex; justify-content: center; align-items: center; width: 24px; height: 24px; font-size: 16pt; padding: 0; margin: 0; } .ph_dialog > .heading > .left{ flex: 1; } .ph_dialog > .heading > .right{ margin-left: auto; } .ph_dialog > .body{ color: var(--ph__white); padding: 10px; overflow-y: auto; max-height: 800px; } .ph_dialog > .body >*:not(:last-child){ margin: 0 0 10px 0; } .ph_comments__window > .ph_comments__container{ padding: 10px; } .ph_comments__window > .ph_comments__container .cmtHeader{ padding: 1em !important; } .ph_comments__window > .ph_comments__container #cmtContent{ overflow-y: auto; max-height: 500px; } .ph_recommended__window > .ph_recommended__container #recommendedVideos{ overflow-y: auto; max-height: 500px; } .ph_related__window > .ph_related__container #relatedVideosCenter{ overflow-y: auto; max-height: 500px; } .ph_modelVideos__window > .ph_modelVideos__container{ overflow-y: auto; max-height: 500px; } .ph_dialog::backdrop{ z-index: 1; background: rgba(0,0,0,.8); } .ph_video-actions button{ padding: 4px 24px; display: inline-block; margin-bottom: 5px; border-radius: 8px; padding: 8px 18px; background: #1b1b1b; font-weight: 400; font-size: 14px; color: #fff; text-transform: capitalize; white-space: nowrap; border: 1px solid #ff9000; } .ph_video-actions button:hover{ text-decoration: none; background-color: #2f2f2f; } .ph_videoShortcuts1{ display: inline-flex; gap: 4px; } .video-action-sub-tab.addToStream li .wrap .thumbnail-info-wrapper span.title, ul.videos li .wrap .thumbnail-info-wrapper span.title { max-height: min-content; } @media only screen and (min-width: 1350px){ .video-action-sub-tab.addToStream li .wrap .thumbnail-info-wrapper span.title, ul.videos li .wrap .thumbnail-info-wrapper span.title { max-height: min-content; } } `); GM_addStyle(GM_getResourceText("PH_CSS")); $(`header`).append(` <link href="//cdn.jsdelivr.net/npm/@sweetalert2/theme-dark@4/dark.css" rel="stylesheet"> <script src="https://github.com/lofcz/sweetalert2-neutral/releases/download/v11.6.15-NEUTRAL/sweetalert2.all.min.js" defer></script> `); $(`body`).append(` <script src="https://cdn.jsdelivr.net/gh/aolko/fontawesome-pro@master/fontawesome-pro-6.1.2-web/js/all.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/aolko/fontawesome-pro@master/fontawesome-pro-6.1.2-web/js/v4-shims.min.js"></script> `); console.info("[PH Toolbox] Cleaning up the page..."); cleanup.page(); cleanup.header(); cleanup.body(); console.info("[PH Toolbox] Guessing your location..."); // LOCAL: specific pages if(window.location.href.indexOf("/video/search") > -1 || window.location.href.indexOf("/transgender") > -1) { // PH search page console.info("[PH Toolbox] You are currently searching for a video"); if(GM_config.get("HideShortVids") === true){ var hiddenEl = 0; $(`ul.videos > .videoBox`).each(function(){ var videoDuration = $(`.linkVideoThumb > .marker-overlays > var.duration`,this).text(); if(timeToSeconds(videoDuration) < GM_config.get("ShortVidMin")){ $(this).hide(); hiddenEl++; } }); console.log(`[PH Toolbox] Hidden ${hiddenEl} videos shorter than ${secondsToTime(GM_config.get("ShortVidMin"))}`); } } else if(window.location.href.indexOf("/view_video.php") > -1) { // PH video page console.info("[PH Toolbox] You are currently watching a video"); var modelURL = $(`#hd-leftColVideoPage > div:nth-child(1) > div.video-actions-container > div.video-actions-tabs > div.video-action-tab.about-tab.active > div.video-detailed-info > div.video-info-row.userRow > div.userInfo > div > span > a`).attr('href'); $(`#hd-leftColVideoPage > div:nth-child(1) > div.video-actions-container > div.video-actions-tabs > div.video-action-tab.about-tab.active > div.video-detailed-info > div.video-info-row.userRow > div.userInfo > div.usernameWrap > span.usernameBadgesWrapper`).append(` <div class="ph_quickActions" style="display: flex; align-items: center; gap: 5px; margin: 0 5px 0 0;"> <a href="${modelURL}/photos" data-popup><i class="fa-solid fa-images-user"></i> images</a> <a href="${modelURL}/videos" data-popup><i class="fa-solid fa-film"></i> videos</a> </div> `); $(`#ph_loadVids`).click(function(){ var modelURL = $(`#hd-leftColVideoPage > div:nth-child(1) > div.video-actions-container > div.video-actions-tabs > div.video-action-tab.about-tab.active > div.video-detailed-info > div.video-info-row.userRow > div.userInfo > div > span > a`).attr('href'); showVids(modelURL); document.querySelector(`.ph_modelVideos__window`).showModal(); }); $(`#relatedVideosCenter > .pcVideoListItem`).each(function(){ var related_modelURL = $(`.wrap > .thumbnail-info-wrapper > .videoUploaderBlock > .usernameWrap > a`,this).attr('href'); var related_vidURL = $(`.wrap > .thumbnail-info-wrapper > .title > a`).attr('href'); $(`.wrap > .thumbnail-info-wrapper > .title`,this).append(` <div class="ph_quickActions"> <a href="https://armagan-easydl.herokuapp.com/?q=${encodeURIComponent("https://pornhub.com"+related_vidURL)}" class="tooltipTrig" data-title="Download"><i class="fa-solid fa-download"></i></a> </div> `); }); $(`#recommendedVideos > .pcVideoListItem`).each(function(){ var recommended_modelURL = $(`.wrap > .thumbnail-info-wrapper > .videoUploaderBlock > .usernameWrap > a`,this).attr('href'); var recommended_vidURL = $(`.wrap > .thumbnail-info-wrapper > .title > a`).attr('href'); $(`.wrap > .thumbnail-info-wrapper > .title`,this).append(` <div class="ph_quickActions"> <a href="https://armagan-easydl.herokuapp.com/?q=${encodeURIComponent("https://pornhub.com"+recommended_vidURL)}" class="tooltipTrig" data-title="Download"><i class="fa-solid fa-download"></i></a> </div> `); }); $(`body`).append(` <dialog class="ph_dialog ph_comments__window"> <div class="heading"> <div class="left"><h2><i class="fa-solid fa-puzzle-piece-simple"></i> Comments</h2></div> <div class="right"><a id="ph_modal-close" class="button"><i class="fa-solid fa-times"></i></a></div> </div> <div class="ph_comments__container"></div> </dialog> `); $(`body`).append(` <dialog class="ph_dialog ph_recommended__window"> <div class="heading"> <div class="left"><h2><i class="fa-solid fa-puzzle-piece-simple"></i> Recommended videos</h2></div> <div class="right"><a id="ph_modal-close" class="button"><i class="fa-solid fa-times"></i></a></div> </div> <div class="ph_recommended__container"></div> </dialog> `); $(`body`).append(` <dialog class="ph_dialog ph_related__window"> <div class="heading"> <div class="left"><h2><i class="fa-solid fa-puzzle-piece-simple"></i> Related videos</h2></div> <div class="right"><a id="ph_modal-close" class="button"><i class="fa-solid fa-times"></i></a></div> </div> <div class="ph_related__container"></div> </dialog> `); function isFlagged(){ var cur_url = ph__url.href; cur_url = cur_url.replace(/#+$/, ''); // Remove # character from the end of the URL if(localStorage.flags){ var flags = JSON.parse(localStorage.flags); // check against current url var video = $.grep(flags.videos, function(v) { return v.url === cur_url; })[0]; if (video) { return { flagged: true, reason: video.reason, url: video.url }; } } return { flagged: false }; } $(`body`).append(` <dialog class="ph_dialog ph_flagVideo__window"> <div class="heading"> <div class="left"><h2><i class="fa-solid fa-flag"></i> Flag video</h2></div> <div class="right"><a id="ph_modal-close" class="button"><i class="fa-solid fa-times"></i></a></div> </div> <div class="body"> <div style="display:flex; gap: 4px;"> <select id="ph_videoFlagReason" style="flex:1;"> <option value="scam">Scam</option> <option value="ad">Ad</option> <option value="low_quality">Low quality</option> <option value="no_finisher">No orgasm/cumshot/creampie/climax</option> <option value="teaser">Teaser</option> <option value="wrong_tags">Wrong tags</option> <option value="wrong_category">Wrong category</option> </select> <button id="ph_flagVideo_btn">Flag video</button> </div> <div style="display:flex; gap: 4px;"> <span style="flex:1;font-weight:600;" id="ph_flagVideo_status"></span> <button id="ph_flagVideo_clear_btn">Clear flags</button> </div> </div> </dialog> `); if(isFlagged().flagged){ $(`#ph_flagVideo_status`).html(`<i class="fa-solid fa-warning fa-fw"></i> This video was flagged as "${isFlagged().reason}"`); $(`#ph_videoFlagReason`).prop("disabled",true); $(`#ph_flagVideo_btn`).prop("disabled",true); } else { $(`#ph_flagVideo_status`).text(`This video wasn't flagged`); } $(`#under-player-comments`).appendTo(`.ph_comments__container`); $(`#hd-leftColVideoPage > div:nth-child(1) > div.video-actions-container > div.video-actions-tabs > div.video-action-tab.about-tab.active > div.video-detailed-info > div.video-info-row.userRow > div.userActions`).append(` <div class="ph_commentsButton videoSubscribeButton"> <button type="button"> <i class="buttonIcon"></i> <span class="buttonLabel">Comments</span> </button> </div> `); $(`#hd-leftColVideoPage > div:nth-child(1) > div.title-container.translate > h1`).append(`<div class="ph_videoShortcuts1"></div>`); $(`#hd-leftColVideoPage > div:nth-child(1) > div.title-container.translate > h1 > .ph_videoShortcuts1`).append(`<a id="ph_incognitoTab" href="#"><i class="fa-solid fa-user-secret"></i></a>`); $(`#hd-leftColVideoPage > div:nth-child(1) > div.title-container.translate > h1 > .ph_videoShortcuts1`).append(`<a id="ph_flag_btn" href="#"><i class="fa-solid fa-flag"></i></a>`); $(`#ph_incognitoTab`).click(function(){ GM_openInTab(window.location.href, {"incognito":true}); }); $(`.ph_commentsButton>button`).click(function(){ document.querySelector(`.ph_comments__window`).showModal(); }); $(`<div class="video-wrapper ph_video-actions" style="margin:20px 0; padding: 10px;"></div>`).insertAfter(`#hd-leftColVideoPage > div:nth-child(1)`); $(`.ph_video-actions`).html(` <button id="ph_videoOnly_btn">Basic layout</button> <button id="ph_videoDownload_btn">Video download</button> `); if(GM_config.get("Layout") === "Basic"){ $(`#ph_videoOnly_btn`).hide(); $(`.ph_video-actions`).append(` <button id="ph_relatedVids_btn">Related</button> <button id="ph_recommendedVids_btn">Recommended</button> `); $(`#ph_recommendedVids_btn`).click(function(){ document.querySelector(`.ph_recommended__window`).showModal(); }); $(`#ph_relatedVids_btn`).click(function(){ document.querySelector(`.ph_related__window`).showModal(); }); $(`#ph_flag_btn`).click(function(){ document.querySelector(`.ph_flagVideo__window`).showModal(); }); $(`#recommendedVideos`).appendTo(`.ph_recommended__container`); $(`#relatedVideosCenter`).appendTo(`.ph_related__container`); $(`#hd-rightColVideoPage`).hide(); $(`#hd-leftColVideoPage > div.video-wrapper.js-relatedRecommended.js-relatedVideos.relatedVideos.allRelatedVideos`).hide(); $(`#under-player-playlists`).hide(); GM_addStyle(` html.supportsGridLayout.fluidContainer #main-container #vpContentContainer:not(.premiumLocked) { grid-template-columns: 1fr; } `); } else { } $(`#ph_flagVideo_btn`).click(function(){ var url = ph__url.toString(); var videoFlag = {"url":url.replace("#", ""), "reason":$(`#ph_videoFlagReason`).val()} flags.videos.push(videoFlag); localStorage.setItem('flags', JSON.stringify(flags)); document.querySelector(`.ph_flagVideo__window`).close(); Swal.fire({ icon: 'success', title: 'Flagged', text: `Video was flagged with the reason "${$(`#ph_videoFlagReason`).val()}"`, }).then((result) => { if (result.isConfirmed) { document.location.reload(true); } }); }); $(`#ph_videoOnly_btn`).click(function(){ $(`.ph_video-actions`).append(` <button id="ph_relatedVids_btn">Related</button> <button id="ph_recommendedVids_btn">Recommended</button> `); $(`#ph_recommendedVids_btn`).click(function(){ document.querySelector(`.ph_recommended__window`).showModal(); }); $(`#ph_relatedVids_btn`).click(function(){ document.querySelector(`.ph_related__window`).showModal(); }); $(`#recommendedVideos`).appendTo(`.ph_recommended__container`); $(`#relatedVideosCenter`).appendTo(`.ph_related__container`); $(`#hd-rightColVideoPage`).hide(); $(`#hd-leftColVideoPage > div.video-wrapper.js-relatedRecommended.js-relatedVideos.relatedVideos.allRelatedVideos`).hide(); $(`#under-player-playlists`).hide(); GM_addStyle(` html.supportsGridLayout.fluidContainer #main-container #vpContentContainer:not(.premiumLocked) { grid-template-columns: 1fr; } `); }); // https://greasyfork.org/en/scripts/447477-armagan-s-easydl $(`#ph_videoDownload_btn`).click(function(){ var url = window.location; window.location = `https://armagan-easydl.herokuapp.com/?q=${encodeURIComponent(url)}` }); $(`.allActionsContainer .CTAs #ctaBox`).append(` <li><span style="display:inline-block;width:100%;height:5px;"></span></li> <li><a href="#"><span>Favorite</span></a></li> `); } else if(window.location.href.indexOf("/model/") > -1 || window.location.href.indexOf("/channels/") > -1 || window.location.href.indexOf("/users/") > -1) { // PH profile console.info("[PH Toolbox] You are currently watching a model/channel/user page"); // Get the cache from local storage var cache = JSON.parse(localStorage.getItem('favCache')) || {}; // Function to cache the response for a request function cacheResponse(url, response) { cache[url] = response; localStorage.setItem('favCache', JSON.stringify(cache)); } // Favorites check function isFavorite(url){ if(localStorage.favorites){ // get the favorites value from the localstorage var _fav = JSON.parse(localStorage.favorites); // check against current url if($.inArray(url, _fav.profiles) !== -1){ return true; } } return false; } function isFlagged(){ var cur_url = ph__url.href; cur_url = cur_url.replace(/#+$/, ''); // Remove # character from the end of the URL if(localStorage.flags){ var flags = JSON.parse(localStorage.flags); // check against current url var model = $.grep(flags.models, function(m) { return m.url === cur_url; })[0]; if (model) { return { flagged: true, reason: model.reason, url: model.url }; } } return { flagged: false }; } if(isFavorite(ph__url.href)){ $(`#mainMenuProfile > div.userButtonsMenu > div.userButtons`).append(` <div class="float-left mainButton"> <button id="ph_unfav_btn" class="buttonBase" type="button"> <i class="fa-regular fa-star fa-fw"></i> <span class="buttonLabel">Unfavorite</span> </button> </div> `); } else { $(`#mainMenuProfile > div.userButtonsMenu > div.userButtons`).append(` <div class="float-left mainButton"> <button id="ph_fav_btn" class="buttonBase" type="button"> <i class="fa-solid fa-star fa-fw"></i> <span class="buttonLabel">Favorite</span> </button> </div> `); }; $(`#mainMenuProfile > div.userButtonsMenu > div.userButtons`).append(` <div class="float-left mainButton"> <button id="ph_flag_btn" class="buttonBase" type="button"> <i class="fa-solid fa-flag fa-fw"></i> <span class="buttonLabel">Flag</span> </button> </div> `); $(`#ph_fav_btn`).click(function(e){ //e.preventDefault(); var info = {}; if (localStorage.favorites){ var favorites = JSON.parse(localStorage.favorites); if (favorites.profiles.length === 0){ var _fav = {"profiles":[ph__url],"vids":[],"playlists":[]}; localStorage.favorites = JSON.stringify(_fav); } else { favorites.profiles.push(ph__url); localStorage.favorites = JSON.stringify(favorites); info = { "name":$(".topProfileHeader > div.coverImage div.name > h1").text().trim(), "avatar":$(".topProfileHeader > #avatarPicture #getAvatar").attr("src") }; // Add the favorite item to the cache cacheResponse(ph__url, {"name": info.name, "avatar": info.avatar}); Swal.fire({ icon: 'success', title: 'Added to favorites', text: 'Model was added to favorites', }).then((result) => { if (result.isConfirmed) { document.location.reload(true); } }); } } else { console.log("[PH toolbox] no localstorage"); var _fav = {"profiles":[ph__url],"vids":[],"playlists":[]}; localStorage.favorites = JSON.stringify(_fav); } }); $(`#ph_unfav_btn`).click(function(e){ //e.preventDefault(); if (localStorage.favorites){ var favorites = JSON.parse(localStorage.favorites); if (favorites.profiles.length === 0){ var _fav = {"profiles":[ph__url],"vids":[],"playlists":[]}; localStorage.favorites = JSON.stringify(_fav); } else { favorites.profiles = favorites.profiles.filter(url => url !== ph__url.href); localStorage.favorites = JSON.stringify(favorites); // Remove the favorite item from the cache delete cache[ph__url]; localStorage.setItem('favCache', JSON.stringify(cache)); Swal.fire({ icon: 'success', title: 'Removed from favorites', text: 'Model was removed from favorites', }).then((result) => { if (result.isConfirmed) { document.location.reload(true); } }); } } else { console.log("[PH toolbox] no localstorage"); var _fav = {"profiles":[],"vids":[],"playlists":[]}; localStorage.favorites = JSON.stringify(_fav); } }); if(GM_config.get("HideShortVids") === true){ var hiddenEl = 0; $(`ul.videos > .videoBox`).each(function(){ var videoDuration = $(`.linkVideoThumb > .marker-overlays > var.duration`,this).text(); if(timeToSeconds(videoDuration) < GM_config.get("ShortVidMin")){ $(this).hide(); hiddenEl++; } }); console.log(`[PH Toolbox] Hidden ${hiddenEl} videos shorter than ${secondsToTime(GM_config.get("ShortVidMin"))}`); } $(`body`).append(` <dialog class="ph_dialog ph_flagModel__window"> <div class="heading"> <div class="left"><h2><i class="fa-solid fa-flag"></i> Flag model</h2></div> <div class="right"><a id="ph_modal-close" class="button"><i class="fa-solid fa-times"></i></a></div> </div> <div class="body"> <div style="display:flex; gap: 4px;"> <select id="ph_modelFlagReason" style="flex:1;"> <option value="scam">Scam</option> <option value="ad">Ads</option> <option value="premium">Premium account</option> <option value="no_finisher">Showoff/poser</option> <option value="teaser">Teaser</option> <option value="dead_profile">Dead profile</option> <option value="fake_profile">Fake profile</option> <option value="turnoff">Turn-off</option> <option value="wrong_gender">Wrong gender</option> </select> <button id="ph_flagModel_btn">Flag model</button> </div> <div style="display:flex; gap: 4px;"> <span style="flex:1;" id="ph_flagModel_status">This model wasn't flagged</span> <button id="ph_flagModel_clear_btn">Clear flags</button> </div> </div> </dialog> `); if(isFlagged().flagged){ $(`#ph_flagModel_status`).html(`<i class="fa-solid fa-warning fa-fw"></i> This profile was flagged as "${isFlagged().reason}"`); $(`#ph_modelFlagReason`).prop("disabled",true); $(`#ph_flagModel_btn`).prop("disabled",true); } else { $(`#ph_flagModel_status`).text(`This profile wasn't flagged`); } $(`#ph_flag_btn`).click(function(){ document.querySelector(`.ph_flagModel__window`).showModal(); }); $(`#ph_flagModel_btn`).click(function(){ var url = ph__url.toString(); var modelFlag = {"url":url.replace("#", ""), "reason":$(`#ph_modelFlagReason`).val()} flags.models.push(modelFlag); localStorage.setItem('flags', JSON.stringify(flags)); document.querySelector(`.ph_flagModel__window`).close(); Swal.fire({ icon: 'success', title: 'Flagged', text: `Profile was flagged with the reason "${$(`#ph_modelFlagReason`).val()}"`, }).then((result) => { if (result.isConfirmed) { document.location.reload(true); } }); }); } else if(window.location.href.indexOf("/playlist/") > -1) { // PH playlist console.info("[PH Toolbox] You are currently watching a playlist"); } else{ // Other cases } // GLOBAL: All pages $(`dialog.ph_dialog #ph_modal-close`).click(function(){ $(this).closest(`.ph_dialog`)[0].close(); console.log($(this)); }); // Add profile shortcuts on pages with video thumbs $(`div.thumbnail-info-wrapper.clearfix > div.videoUploaderBlock.clearfix`).each(function(){ var modelUrl_list = $(`.usernameWrap a`,this).attr('href'); $(this).append(` <div class="ph_quickActions" style="display: inline-flex; align-items: center; gap: 5px; margin: 0 5px 0 0;"> <a href="${modelUrl_list}/photos" data-popup><i class="fa-solid fa-images-user"></i> images</a> <a href="${modelUrl_list}/videos" data-popup><i class="fa-solid fa-film"></i> videos</a> </div> `); }); // Userscript pages if(window.location.href.indexOf("/toolbox") > -1) { console.info("[PH Toolbox] Page: Toolbox"); $(`head>title`).text(`PH toolbox`); $(`.wrapper > .container`).html(` <div class="sectionWrapper"> <div class="section" style="padding: 20px;"> <h1>PH Toolbox</h1> <h2>Links</h2> <p> <ul> <li><a href="/toolbox/favorites/">My favorites</a></li> </ul> </p> </div> </div> `); if(window.location.href.indexOf("/favorites") > -1) { var favorites = JSON.parse(localStorage.favorites); console.info("[PH Toolbox] Page: Toolbox » Favorites"); $(`head>title`).text(`PH toolbox: Favorites`); $(`head`).append(` <link rel="stylesheet" href="https://di.phncdn.com/www-static/css/./pornstar-beforeaction-pc.css?cache=2022121401" type="text/css" /> <link rel="stylesheet" href="https://di.phncdn.com/www-static/css/./pornstar-pornstars-pc.css?cache=2022121401" type="text/css" /> `); $(`.wrapper > .container`).addClass(`ph__root`); $(`.wrapper > .container`).html(` <div class="sectionWrapper"> <div class="section" style="padding: 20px;"> <a id="ph_getFavorites" href="#" class="buttonBase orangeButton big">Get favorites</a> </div> </div> <div class="sectionWrapper"> <div class="section" style="padding: 20px;"> <a href="/toolbox"><h1>PH Toolbox</h1></a> <h2>Favorites</h2> <p><i class="fa-regular fa-warning"></i> If your images or text appear to be broken or missing - wait a few moments and refresh the page.</p> </div> </div> <div class="pornstar_container"> <div class="sectionWrapper"> <!-- Model list --> <ul id="ph_favModels" class="videos row-5-thumbs popular-pornstar"> </ul> <!-- / --> </div> </div> `); $(`#ph_favModels`).append(`<div class="ph__loader">Loading the favorites...</div>`); //$(`.ph__loader`).show(); // Set the rate limit in milliseconds var rateLimit = 5000; // Set the maximum number of concurrent promises var maxConcurrentPromises = 2; var promises = []; function jsonInfo(url){ var Url = new URL(url); var relUrl = Url.pathname + Url.search; return new Promise(function(resolve, reject) { var info = {}; $.ajax({ type: "GET", url: relUrl, success: function (response) { info = { "name":$(".topProfileHeader > div.coverImage div.name > h1", response).text().trim(), "avatar":$(".topProfileHeader > #avatarPicture #getAvatar", response).attr("src") }; resolve(info); }, error: function(jqxhr, status, exception) { // Group the error message in the console console.groupCollapsed(`Error: ${exception.message}`); //console.error(exception); //alert('Exception:', exception); reject(exception); console.groupEnd(); } }); }); } // Get the cache from local storage var cache = JSON.parse(localStorage.getItem('favCache')) || {}; // Function to check if a request is cached function isCached(url) { return cache.hasOwnProperty(url); } // Function to get the cached response for a request function getCachedResponse(url) { return cache[url]; } // Function to cache the response for a request function cacheResponse(url, response) { cache[url] = response; localStorage.setItem('favCache', JSON.stringify(cache)); } // Create a function to process the promises function processPromises() { // Check if there are more promises in the array if (promises.length > 0) { // Get the next batch of promises const batch = promises.splice(0, maxConcurrentPromises); // Wait for the batch to complete Promise.all(batch) .then(function() { // Process the next batch of promises setTimeout(processPromises(),rateLimit); }) .catch(function(error) { // Group the error message in the console console.groupCollapsed(`Error: ${error.message}`); console.error(error); console.groupEnd(); // Process the next batch of promises setTimeout(processPromises(),rateLimit); }); } else { // Hide the loader element $(`.ph__loader`).hide(); } } function sendRequests() { $.each(favorites.profiles, function(index, profileUrl) { // Set the retry count to 0 var retryCount = 0; var info = jsonInfo(profileUrl); // Function to send the request and handle the response function sendRequest() { // Check if the request is already cached if (isCached(profileUrl)) { // Get the cached response var cachedResponse = getCachedResponse(profileUrl); // Check if the cached response is valid var isValid = true; for (var prop in cachedResponse) { /*if (!cachedResponse.hasOwnProperty(prop) && !cachedResponse[prop]) { isValid = false; break; }*/ if (cachedResponse.hasOwnProperty(prop) && cachedResponse[prop]) { // prop is not empty, so continue to the next iteration continue; } else { // prop is empty or does not exist, so set isValid to false isValid = false; break; } } if (isValid) { // Do something with the cached response var htmlItem = ` <li class="modelLi"> <div class="wrap"> <a href="${profileUrl}"> <span class="pornstar_label"> <span class="title-album"> <span>Model</span> </span> </span> <img class="lazy" src="${cachedResponse.avatar}" alt="${cachedResponse.name}"> </a> <div class="thumbnail-info-wrapper"> <a href="${profileUrl}" class="title"> <span class="modelName">${cachedResponse.name}</span> </a> </div> </div> </li> `; // Append the HTML to the DOM and fade it in $(`#ph_favModels`).append(htmlItem).find('.modelLi').fadeIn(); console.log(cachedResponse); } else { // Add the request promise to the array promises.push( jsonInfo(profileUrl) .then(function(info) { // Cache the response cacheResponse(profileUrl, info); // Do something with the response //console.log(info); var htmlItem = ` <li class="modelLi"> <div class="wrap"> <a href="${profileUrl}"> <span class="pornstar_label"> <span class="title-album"> <span>Model</span> </span> </span> <img class="lazy" src="${info.avatar}" alt="${info.name}"> </a> <div class="thumbnail-info-wrapper"> <a href="${profileUrl}" class="title"> <span class="modelName">${info.name}</span> </a> </div> </div> </li> `; // Append the HTML to the DOM and fade it in $(`#ph_favModels`).append(htmlItem).find('.modelLi').fadeIn(); console.log(info); }) .catch(function(error) { // Increment the retry count retryCount++; // If the retry count is less than the maximum number of retries, retry the request if (retryCount < 5) { console.warn(`[PH Toolbox] Can't get the model info, retrying... (${retryCount}/5)`) sendRequest(); } else { // Group the error message in the console console.groupCollapsed(`[PH toolbox] Error: ${error.message}`); console.error(error); console.groupEnd(); } }) ); } } else { // Add the request promise to the array promises.push( jsonInfo(profileUrl) .then(function(info) { // Cache the response cacheResponse(profileUrl, info); // Do something with the response //console.log(info); var htmlItem = ` <li class="modelLi"> <div class="wrap"> <a href="${profileUrl}"> <span class="pornstar_label"> <span class="title-album"> <span>Model</span> </span> </span> <img class="lazy" src="${info.avatar}" alt="${info.name}"> </a> <div class="thumbnail-info-wrapper"> <a href="${profileUrl}" class="title"> <span class="modelName">${info.name}</span> </a> </div> </div> </li> `; // Append the HTML to the DOM and fade it in $(`#ph_favModels`).append(htmlItem).find('.modelLi').fadeIn(); console.log(info); }) .catch(function(error) { // Increment the retry count retryCount++; // If the retry count is less than the maximum number of retries, retry the request if (retryCount < 5) { console.warn(`[PH Toolbox] Can't get the model info, retrying... (${retryCount}/5)`) sendRequest(); } else { // Group the error message in the console console.groupCollapsed(`[PH toolbox] Error: ${error.message}`); console.error(error); console.groupEnd(); } }) ); } } // Send the request in the background setTimeout(sendRequest, 0); }); }; $(`#ph_getFavorites`).click(function(){ Swal.fire({ toast: true, position: 'top-end', showConfirmButton: false, showCloseButton: false, title: "Getting favorites", timer: 5000, timerProgressBar: true }); if($(`#ph_favModels`).length){ $(`#ph_favModels`).html(""); } setTimeout(sendRequests,rateLimit); // Wait for all the promises to complete setTimeout(processPromises(),rateLimit); }); } } //--- $(`body > div.footerContentWrapper > h2`).html(`Running scripts`); $(`body > div.footerContentWrapper > p`).html(` <p><i class="fa-solid fa-puzzle-piece-simple"></i> <span>PH Toolbox</span>, <i class="fa-solid fa-puzzle-piece-simple"></i> <span>pornhub crack for Russia</span>, <i class="fa-solid fa-puzzle-piece-simple"></i> <span>Armagan's EasyDL</span></p> `); })();