xhamster-优化

自动宽屏,自动最高画质,自动播放,隐藏已观看,收藏夹内视频快速移除

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         xhamster-优化
// @version      1.0.7
// @namespace    https://sleazyfork.org/zh-CN/users/1461640-%E6%98%9F%E5%AE%BF%E8%80%81%E9%AD%94
// @author       星宿老魔
// @description  自动宽屏,自动最高画质,自动播放,隐藏已观看,收藏夹内视频快速移除
// @match        https://zh.xhamster.com/*
// @match        https://xhamster.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=xhamster.com
// @license      MIT
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @grant        GM_deleteValue
// @run-at       document-start
// ==/UserScript==

(function(){"use strict";const CONFIG={domains:["zh.xhamster.com","xhamster.com"],pageTypes:{search:"/search/",category:"/categories/",tags:"/tags/",
video:"/videos/",excludedPrefixes:["/photos/","/users/","/my/","/messages","/live","/creators","/p/","/info"]},selectors:{playButton:".play-inner",
settingsButton:".settings",qualityOptions:".xp-settings-inner-list span[data-value]",menuContainer:".items-3b1bc",menuContainerAlt:".container-3b1bc",
moreButton:".dropdown-3b1bc",menuItem:".container-64b3c",menuLink:".root-48288.invert-48288.link-64b3c",
menuText:".h4-8643e.invert-8643e.linkText-64b3c",videoItems:".thumb-list__item.video-thumb",watchedIndicator:".thumb-image-container__watched",
hiddenByScript:".hidden-by-script",adContainers:".thumbContainer-53a78, .thumb-53a78",redirectLinks:'a[href*="/fh/out?url="]',
badges:".badge-cb84e, .badge",favoriteVideos:".video-thumb[data-video-id]",removeButton:".remove-btn",imageContainer:".thumb-image-container",
commentTabSet:".tabSet-792ed.tabSet-0c900",commentNoTabSet:".noTabs-0c900",commentBox:"#commentBox, .commentsWrap-99011",commentTab:".tab-98bb0",
commentCount:".comments-heading .value-42516, .triggerBlock-42516 .value-42516",commentItems:".commentItem-5228f",commentForm:".form-42516",
commentInput:".root-77ac5.desktop-77ac5",commentPagination:".pagerSection-99011, .pager-section",relatedTabTitle:".relatedTabTitleDesktop-0c900",
showMoreButton:'.container-90841.desktop-90841[data-role="show-more-container"]',
topMenuAds:['[data-nav-item-id="cams"]','[data-nav-item-id="dating"]','[data-nav-item-id="priority-vpn"]','[data-nav-item-id="ai-friend"]','[data-nav-item-id="flirtify"]','[data-item="premium"]']
},adKeywords:["已支付","付费","PAID","Premium","24/7不间断直播","约会","Free VPN","AI Girlfriend","性爱聊天","独家视频"],
adLinkPatterns:["/cam/out","/dating","/fh/out","/ff/out","priorityvpn.app","lovescape.com"],performance:{debounceDelay:300,retryLimit:20,
retryInterval:500,cleanupInterval:5e3}};class VideoEnhancer{static init(){let e=!1,t=!1;const n=()=>{if(e&&t){
const e=document.querySelector(".play-inner");e&&e.click()}},i=()=>{if(!e){const t=document.querySelector(".settings");t?.offsetParent&&(t.click(),
setTimeout(()=>{const t=document.querySelector(".quality.chooser-control.xp-settings-inner-list-inner");if(t)for(let i=0;i<t.childNodes.length;i++){
const o=t.childNodes[i],a=o.getAttribute?.("data-value");if(a&&"auto"!==a){o.click(),e=!0,n();break}}},100))}if(!t){
const e=document.querySelector(".large-mode");if(e?.offsetParent){const i=e.getAttribute("data-xp-tooltip");"Exit large mode"===i?(t=!0,
n()):"Large mode"===i&&(e.click(),t=!0,n())}}e&&t&&clearInterval(a)};i();let o=0;const a=setInterval(()=>{if(++o>50){clearInterval(a)
;const e=document.querySelector(".play-inner");e?.click()}else i()},100)}}class AdBlocker{static init(){void 0,this.addAdBlockStyles(),
this.removeTopMenuAds(),this.removeVideoAds()}static addAdBlockStyles(){
if("undefined"!=typeof GM_addStyle)GM_addStyle("\n        .menu-ad-hidden { display: none !important; }\n      ");else{void 0
;const e=document.createElement("style");e.textContent="\n        .menu-ad-hidden { display: none !important; }\n      ",document.head.appendChild(e)}
}static removeTopMenuAds(){try{let e=0
;['[data-nav-item-id="cams"]','[data-nav-item-id="dating"]','[data-nav-item-id="priority-vpn"]','[data-nav-item-id="ai-friend"]','[data-nav-item-id="flirtify"]','[data-item="premium"]'].forEach(t=>{
document.querySelectorAll(t).forEach(t=>{t&&t.parentNode&&(t.classList.add("menu-ad-hidden"),e++)})})
;const t=["24/7不间断直播","约会","Free VPN","AI Girlfriend","性爱聊天","独家视频"];return document.querySelectorAll(".container-64b3c").forEach(n=>{
const i=n.textContent?.trim();i&&t.some(e=>i.includes(e))&&(n.classList.contains("menu-ad-hidden")||(n.classList.add("menu-ad-hidden"),e++))}),e>0,e
}catch(e){return void 0,0}}static removeVideoAds(){let e=0;try{return document.querySelectorAll(".thumbContainer-53a78, .thumb-53a78").forEach(t=>{
t&&t.parentNode&&(t.remove(),e++)}),document.querySelectorAll('a[href*="/fh/out?url="]').forEach(t=>{
const n=t.closest(".thumb-list__item, .thumbContainer-53a78, .video-thumb");n&&n.parentNode&&(n.remove(),e++)}),
document.querySelectorAll(".thumb-list__item .title, .thumb-list__item .caption, .thumbContainer-53a78 .title, .video-thumb .title").forEach(t=>{
if(t.textContent&&(t.textContent.includes("已支付")||t.textContent.includes("付费")||t.textContent.includes("PAID")||t.textContent.includes("Premium"))){
const n=t.closest(".thumb-list__item, .thumbContainer-53a78, .video-thumb");n&&n.parentNode&&(n.remove(),e++)}}),e>0,e}catch(t){return void 0,0}}}
class Storage{static get(e,t=null){try{const n=GM_getValue(e);if(null==n)return t;try{return JSON.parse(n)}catch{return n}}catch(n){return void 0,t}}
static set(e,t){try{const n=JSON.stringify(t);return GM_setValue(e,n),!0}catch(n){return void 0,!1}}static delete(e){try{return GM_deleteValue(e),!0
}catch(t){return void 0,!1}}static listKeys(){try{return GM_listValues()}catch(e){return void 0,[]}}static migrateFromLocalStorage(e,t=!0){try{
const n=localStorage.getItem(e);if(null!==n){try{const t=JSON.parse(n);this.set(e,t)}catch{GM_setValue(e,n)}return t&&localStorage.removeItem(e),!0}
return!1}catch(n){return void 0,!1}}}const e={GLOBAL_HIDE_WATCHED:"xhamster_global_hide_watched",OLD_KEYS:["hideWatchedVideos"]};class StorageManager{
static cleanupOldSettings(){e.OLD_KEYS.forEach(e=>{Storage.delete(e)})}static getGlobalHideWatchedSetting(){
return Storage.get(e.GLOBAL_HIDE_WATCHED,!1)??!1}static setGlobalHideWatchedSetting(t){Storage.set(e.GLOBAL_HIDE_WATCHED,t)}}class PageDetector{
static getCurrentPageType(){const e=window.location.pathname
;return e.startsWith(CONFIG.pageTypes.search)?"search":e.startsWith(CONFIG.pageTypes.category)?"category":e.startsWith(CONFIG.pageTypes.tags)?"tags":e.startsWith(CONFIG.pageTypes.video)?"video":CONFIG.pageTypes.excludedPrefixes.some(t=>e.startsWith(t))?null:"home"
}static shouldApplyHideWatchedFeature(){const e=window.location.pathname
;return!![CONFIG.pageTypes.search,CONFIG.pageTypes.category,CONFIG.pageTypes.tags,CONFIG.pageTypes.video].some(t=>e.startsWith(t))||!CONFIG.pageTypes.excludedPrefixes.some(t=>e.startsWith(t))
}static isInFavoritesPage(){const e=window.location.href;return e.includes("watch-later")||e.includes("/my/favorites/videos")}}
class WatchedVideoFilter{static init(){void 0,this.addFilterStyles(),this.applyFilter()}static addFilterStyles(){
if("undefined"!=typeof GM_addStyle)GM_addStyle("\n        .hidden-by-script { display: none !important; }\n      ");else{void 0
;const e=document.createElement("style");e.textContent="\n        .hidden-by-script { display: none !important; }\n      ",
document.head.appendChild(e)}}static applyFilter(){if(PageDetector.shouldApplyHideWatchedFeature()&&StorageManager.getGlobalHideWatchedSetting())try{
const e=this.safeQuerySelectorAll(".thumb-list__item.video-thumb");let t=0;e.forEach(e=>{
e&&this.safeQuerySelector(".thumb-image-container__watched",e)&&(e.classList.add("hidden-by-script"),t++)}),t>0}catch(e){void 0}}
static showWatchedVideos(){try{const e=this.safeQuerySelectorAll(".hidden-by-script");let t=0;e.forEach(e=>{
e&&e.classList&&(e.classList.remove("hidden-by-script"),t++)}),t>0}catch(e){void 0}}static toggleWatchedVideos(e){
StorageManager.setGlobalHideWatchedSetting(!e),e?this.showWatchedVideos():this.applyFilter()}static getCurrentHideWatchedSetting(){
return StorageManager.getGlobalHideWatchedSetting()}static safeQuerySelector(e,t=document){try{return t.querySelector(e)}catch(n){return void 0,null}}
static safeQuerySelectorAll(e,t=document){try{return t.querySelectorAll(e)}catch(n){return void 0,document.querySelectorAll("never-match")}}}
class FavoritesManager{static init(){void 0,this.initRemoveFeature()}static addRemoveButtons(){
if(window.location.href.includes("watch-later")||window.location.href.includes("/my/favorites/videos"))return document.querySelector(".xh-icon")?(document.querySelectorAll(".video-thumb[data-video-id]").forEach(e=>{
if(e.querySelector(".remove-btn"))return;const t=e.getAttribute("data-video-id");let n=null
;if(window.location.href.includes("watch-later"))n=window.location.pathname.match(/\/videos\/([^-]+)-watch-later/)?.[1]||null;else if(window.location.href.includes("/my/favorites/videos")){
const t=window.location.pathname.match(/\/videos\/([^\/]+)/);if(t)n=t[1];else{
const t=document.querySelector(".favorites-collection.active, .active[data-id]");if(t)n=t.getAttribute("data-id");else{
const t=e.closest(".favorites-collection, [data-collection-id]");t&&(n=t.getAttribute("data-collection-id")||t.getAttribute("data-id"))}}}
if(!t||!n)return;const i=document.createElement("div");i.className="remove-btn",
i.style.cssText="\n        position: absolute;\n        top: 5px;\n        right: 5px;\n        width: 24px;\n        height: 24px;\n        background: rgba(0, 0, 0, 0.7);\n        border-radius: 50%;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        cursor: pointer;\n        z-index: 10;\n        transition: background 0.2s;\n        opacity: 1;\n        visibility: visible;\n      "
;const o=document.createElement("i");o.className="xh-icon bucket cobalt",o.style.cssText="color: white; font-size: 12px; display: inline-block;",
i.appendChild(o),i.addEventListener("mouseenter",()=>{i.style.background="rgba(255, 0, 0, 0.8)"}),i.addEventListener("mouseleave",()=>{
i.style.background="rgba(0, 0, 0, 0.7)"}),i.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.removeFromFavorites(t,n)})
;const a=e.querySelector(".thumb-image-container");a&&(a.style.position="relative",a.appendChild(i))}),
void 0):(setTimeout(()=>this.addRemoveButtons(),100),void 0)}static async removeFromFavorites(e,t){try{if((await fetch("/x-api",{method:"POST",
headers:{"Content-Type":"text/plain","X-Requested-With":"XMLHttpRequest"},body:JSON.stringify([{name:"favoriteVideosModelSync",requestData:{model:{
id:null,$id:this.generateUUID(),modelName:"favoriteVideosModel",itemState:"changed",collections:[],contentType:"videos",contentEntity:{id:e}}}}])
})).ok){const t=document.querySelector(`[data-video-id="${e}"]`);t&&t.remove()}else void 0}catch(n){void 0}}static generateUUID(){
return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){const t=16*Math.random()|0;return("x"==e?t:3&t|8).toString(16)})}
static initRemoveFeature(){
(window.location.href.includes("watch-later")||window.location.href.includes("/my/favorites/videos"))&&("complete"===document.readyState?setTimeout(()=>this.addRemoveButtons(),500):window.addEventListener("load",()=>{
setTimeout(()=>this.addRemoveButtons(),500)}))}}function debounce(e,t){let n;return(...i)=>{clearTimeout(n),n=setTimeout(()=>e(...i),t)}}
const t=class{static init(){void 0,StorageManager.cleanupOldSettings(),this.addPreloadStyles(),this.createToggleUI(),this.initUnifiedObserver()}
static addPreloadStyles(){const e=document.createElement("style");e.id="xh-preload-styles",
e.textContent='\n      /* 防止广告闪烁的预加载样式 */\n      .menu-ad-hidden { display: none !important; }\n      .hidden-by-script { display: none !important; }\n      \n      /* 预隐藏已知广告选择器 */\n      [data-nav-item-id="cams"],\n      [data-nav-item-id="dating"],\n      [data-nav-item-id="priority-vpn"],\n      [data-nav-item-id="ai-friend"],\n      [data-nav-item-id="flirtify"],\n      [data-item="premium"] {\n        display: none !important;\n      }\n      \n      /* 通过选择器隐藏广告(比:has()更兼容) */\n    ',
document.head.insertBefore(e,document.head.firstChild)}static createToggleUI(){if(!PageDetector.shouldApplyHideWatchedFeature())return
;if(document.querySelector("#xh-toggle-compact-btn"))return;const e=(()=>{let e=document.querySelector(".items-3b1bc")
;if(e||(e=document.querySelector(".container-3b1bc")),e||(e=document.querySelector("nav .container-3b1bc, header .container-3b1bc")),e){
const t=e.querySelector(".dropdown-3b1bc");if(t)return{container:e,insertAfter:t};const n=e.querySelector(".container-64b3c:last-child");return n?{
container:e,insertAfter:n}:{container:e,insertAfter:null}}return null})();if(e){const i=document.createElement("div");i.id="xh-toggle-compact-btn",
i.className="container-64b3c",
i.style.cssText="\n        display: flex;\n        align-items: center;\n        cursor: pointer;\n        transition: all 0.3s ease;\n        margin: 0;\n        padding: 0;\n        position: relative;\n        z-index: 1000;\n      "
;const o=document.createElement("a");o.className="root-48288 invert-48288 link-64b3c",o.href="#",
o.style.cssText="\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        padding: 6px 12px;\n        height: 100%;\n        text-decoration: none;\n        color: inherit;\n        position: relative;\n        z-index: 1001;\n      "
;const a=document.createElement("div");a.className="h4-8643e invert-8643e linkText-64b3c",a.textContent="已观看",
a.style.cssText="\n         white-space: nowrap;\n         transition: all 0.3s ease;\n         position: relative;\n         z-index: 1002;\n       ",
o.appendChild(a),i.appendChild(o);const r=()=>{WatchedVideoFilter.getCurrentHideWatchedSetting()?(a.textContent="已观看",
a.style.textDecoration="line-through",a.style.color="#999"):(a.textContent="已观看",a.style.textDecoration="none",a.style.color="")}
;i.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation();const t=!WatchedVideoFilter.getCurrentHideWatchedSetting()
;WatchedVideoFilter.toggleWatchedVideos(!t),r()});try{if(e.insertAfter){const t=e.insertAfter.nextSibling
;t?e.container.insertBefore(i,t):e.container.appendChild(i)}else e.container.appendChild(i);void 0}catch(t){void 0;try{document.body.appendChild(i)
}catch(n){void 0}}r(),this.monitorButtonStability(i)}else void 0,setTimeout(()=>this.createToggleUI(),1e3)}static monitorButtonStability(e){let t=0
;const n=10,i=()=>{if(t++,!document.contains(e))return void 0,e.remove(),setTimeout(()=>this.createToggleUI(),500),void 0
;const o=e.getBoundingClientRect();0!==o.width&&0!==o.height||(void 0,e.style.display="flex",e.style.visibility="visible",e.style.opacity="1"),
t<n&&setTimeout(i,2e3)};setTimeout(i,1e3)}static initUnifiedObserver(){this.debouncedContentHandler=debounce(()=>{AdBlocker.removeVideoAds(),
WatchedVideoFilter.applyFilter(),FavoritesManager.addRemoveButtons(),AdBlocker.removeTopMenuAds()},150),setTimeout(()=>{AdBlocker.removeVideoAds(),
WatchedVideoFilter.applyFilter(),AdBlocker.removeTopMenuAds()},100),this.intervalId=window.setInterval(()=>{AdBlocker.removeVideoAds(),
WatchedVideoFilter.applyFilter(),AdBlocker.removeTopMenuAds()},3e3),this.mutationObserver=new MutationObserver(e=>{let t=!1;e.forEach(e=>{
if("childList"===e.type&&e.addedNodes.length>0&&e.addedNodes.forEach(e=>{if(e.nodeType===Node.ELEMENT_NODE){
const n=e,i=n.classList&&(n.classList.contains("thumb-list__item")||n.classList.contains("thumbContainer-53a78")||n.classList.contains("video-thumb")||n.classList.contains("thumb-53a78")||n.classList.contains("thumb-image-container__watched")||n.classList.contains("content")||n.classList.contains("main")||n.classList.contains("tabSet-792ed")||n.classList.contains("commentsWrap-99011")),o=n.querySelector&&(n.querySelector(".thumb-list__item")||n.querySelector(".video-thumb")||n.querySelector(".thumb-image-container__watched")||n.querySelector('a[href*="/fh/out?url="]')||n.querySelector(".badge-cb84e")||n.querySelector(".tabSet-792ed")||n.querySelector(".commentsWrap-99011"))
;(i||o)&&(t=!0)}}),"attributes"===e.type&&e.target.nodeType===Node.ELEMENT_NODE){const n=e.target
;(n.classList.contains("thumb-image-container__watched")||n.closest(".thumb-list__item.video-thumb"))&&(t=!0)}}),t&&this.debouncedContentHandler()})
;const e=[document.querySelector(".thumb-list"),document.querySelector(".videos-list"),document.querySelector(".content-container"),document.querySelector("main"),document.querySelector("#content")].filter(Boolean),t={
childList:!0,subtree:!0,attributes:!0,attributeFilter:["class"]};e.length>0?e.forEach(e=>{
e&&e.nodeType===Node.ELEMENT_NODE&&this.mutationObserver.observe(e,t)
}):document.body&&document.body.nodeType===Node.ELEMENT_NODE?this.mutationObserver.observe(document.body,t):void 0}static triggerUpdate(){
this.debouncedContentHandler&&this.debouncedContentHandler()}static cleanup(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),
this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null)}};t.mutationObserver=null,t.intervalId=null,
t.debouncedContentHandler=null;let n=t;function init(){try{VideoEnhancer.init(),AdBlocker.init(),WatchedVideoFilter.init(),FavoritesManager.init(),
n.init()}catch(e){void 0}}function i(){setTimeout(()=>{n.triggerUpdate()},300)}function o(){n.cleanup()}init(),
"complete"===document.readyState?i():window.addEventListener("load",i),window.addEventListener("beforeunload",o),window.XhamsterOptimizer={
config:CONFIG,modules:{VideoEnhancer:VideoEnhancer,AdBlocker:AdBlocker,WatchedVideoFilter:WatchedVideoFilter,FavoritesManager:FavoritesManager,
AppController:n},utils:{triggerUpdate:()=>n.triggerUpdate(),cleanup:()=>n.cleanup()}}})();