好色TV-优化

好色TV(hsex.tv)自动宽屏

// ==UserScript==
// @name         好色TV-优化
// @version      1.0.0
// @namespace    https://sleazyfork.org/zh-CN/users/1461640-%E6%98%9F%E5%AE%BF%E8%80%81%E9%AD%94
// @author       星宿老魔
// @description  好色TV(hsex.tv)自动宽屏
// @match        https://hsex.tv/video-*
// @match        https://hsex.men/video-*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=hsex.tv
// @license      MIT
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function(){"use strict";const CONFIG={wideScreenMode:true,debounceDelay:250,selectors:{videoContainer:".videos_box",
videoElement:".video-js",mainContainer:".container",videoCol:".col-md-8",sideCol:".col-md-4",
controlBar:".vjs-control-bar",panelDefault:".panel-default"}};class WideScreen{static init(){
console.log("[WideScreen] 初始化宽屏显示...");this.setWideScreenMode();this.setupResizeListener()}static setWideScreenMode(){
const t=document.querySelector(CONFIG.selectors.videoContainer)
;const e=document.querySelector(CONFIG.selectors.videoElement);if(!t&&!e){
console.log(`[WideScreen] ${window.location.hostname}宽屏模式: 未找到视频元素`);return}this.applyMainContainerStyles()
;this.applyVideoColStyles();this.applySideColStyles();this.applyPanelStyles();if(t){
if(!t.classList.contains("hsx-initialized"))t.classList.add("hsx-hidden-until-ready");t.style.width="100%"
;t.style.maxWidth="100%";t.style.margin="0 auto";t.style.position="relative"}if(e){e.style.height=""
;e.style.width="100%";e.style.maxWidth="100%";if(!e.classList.contains("vjs-fluid"))e.classList.add("vjs-fluid")}
const n=document.querySelector(CONFIG.selectors.videoContainer);if(n){n.classList.remove("hsx-hidden-until-ready")
;n.classList.add("hsx-initialized")}console.log(`[WideScreen] ${window.location.hostname}宽屏模式: 已启用宽屏模式`)}
static applyMainContainerStyles(){const t=document.querySelector(CONFIG.selectors.mainContainer);if(t){
t.style.width="100%";t.style.maxWidth="100%";t.style.padding="0"}}static applyVideoColStyles(){
const t=document.querySelector(CONFIG.selectors.videoCol);if(t){t.style.width="100%";t.style.maxWidth="100%"
;t.style.flexBasis="100%";t.style.padding="0 10px";t.classList.remove("col-md-8");t.classList.add("col-md-12")}}
static applySideColStyles(){const t=document.querySelector(CONFIG.selectors.sideCol);if(t)t.style.display="none"}
static applyPanelStyles(){const t=document.querySelector(CONFIG.selectors.panelDefault);if(t){
t.style.position="relative";t.style.clear="both";t.style.marginTop="15px";t.style.zIndex="1"}}
static setupResizeListener(){window.addEventListener("resize",()=>{this.setWideScreenMode()})}}class LayoutReflow{
static init(){console.log("[LayoutReflow] 初始化布局重排...");this.reflowLayout()}static reflowLayout(){try{
const t=this.findLeftColumn();const e=this.findRightColumn();if(!t)return
;const n=document.querySelector(CONFIG.selectors.panelDefault)
;const o=n||document.querySelector(CONFIG.selectors.videoContainer)||t;let i=document.querySelector(".hsx-two-col")
;if(!i)i=this.createTwoColumnLayout(o,t);const s=i.querySelector(".hsx-left");const l=i.querySelector(".hsx-right")
;this.handleRecommendedVideos(t,l);this.handleAuthorVideos(e,s)}catch(t){console.warn("[LayoutReflow] 布局重排失败:",t)}}
static findLeftColumn(){const t=document.querySelector(".videos");if(t){const e=t.closest(".col-md-8, .col-md-12")
;if(e)return e}const e=document.querySelector(CONFIG.selectors.panelDefault);if(e){
const t=e.closest(".col-md-8, .col-md-12");if(t)return t}
return document.querySelector(".col-md-8")||document.querySelector("#container .row > .col-md-12")}
static findRightColumn(){const t=document.querySelector(CONFIG.selectors.sideCol);if(t)return t
;const e=Array.from(document.querySelectorAll("h4")).find(t=>t.textContent&&-1!==t.textContent.indexOf("作者视频"))
;return e?e.closest(".col-md-4")||e.closest(".col-md-12"):null}static createTwoColumnLayout(t,e){
const n=document.createElement("div");n.className="hsx-switch";const o=document.createElement("div")
;o.className="hsx-switch-btn active";o.textContent="作者视频";const i=document.createElement("div")
;i.className="hsx-switch-btn";i.textContent="推荐视频";n.appendChild(o);n.appendChild(i)
;const s=document.createElement("div");s.className="hsx-two-col single-left";const l=document.createElement("div")
;l.className="hsx-left";const a=document.createElement("div");a.className="hsx-right";s.appendChild(l);s.appendChild(a)
;if(t&&t.parentNode){t.parentNode.insertBefore(n,t.nextSibling);n.parentNode.insertBefore(s,n.nextSibling)}else{
e.appendChild(n);e.appendChild(s)}o.addEventListener("click",()=>{o.classList.add("active");i.classList.remove("active")
;s.classList.add("single-left");s.classList.remove("single-right")});i.addEventListener("click",()=>{
i.classList.add("active");o.classList.remove("active");s.classList.add("single-right");s.classList.remove("single-left")
});return s}static handleRecommendedVideos(t,e){if(e&&0===e.childElementCount){
const n=Array.from(t.querySelectorAll("h4")).find(t=>t.textContent&&-1!==t.textContent.indexOf("推荐视频"));if(n){
let o=n.closest(".col-xs-12")||n.closest(".col-md-12")||n.parentElement;o=o?o.nextElementSibling:null
;while(o&&t.contains(o)){if(o.classList&&o.classList.contains("hsx-two-col"))break;const t=o.nextElementSibling
;if(o.querySelector&&o.querySelector(".thumbnail")){e.appendChild(o);const t=o.querySelector(".image");if(t){
t.style.backgroundSize="cover";t.style.backgroundPosition="center";t.style.minHeight="120px"}}o=t}}}}
static handleAuthorVideos(t,e){if(e&&0===e.childElementCount&&t){
const n=Array.from(t.querySelectorAll("h4")).find(t=>t.textContent&&-1!==t.textContent.indexOf("作者视频"));if(n){
let o=n.closest(".col-md-12")||n.closest(".col-xs-12")||t;o=o?o.nextElementSibling:null
;while(o&&(t.contains(o)||o.closest(".col-md-4"))){const t=o.nextElementSibling
;if(o.querySelector&&o.querySelector(".thumbnail")){e.appendChild(o);const t=o.querySelector(".image");if(t){
t.style.backgroundSize="cover";t.style.backgroundPosition="center";t.style.minHeight="90px"}}o=t}}
if(0===e.querySelectorAll(".thumbnail").length)Array.from(t.querySelectorAll(".thumbnail")).forEach(t=>{
const n=t.closest(".col-xs-6, .col-md-3, .col-xs-12, .col-md-12")||t;if(!e.contains(n)){e.appendChild(n)
;const t=n.querySelector(".image");if(t){t.style.backgroundSize="cover";t.style.backgroundPosition="center"
;t.style.minHeight="90px"}}});if(t&&t.parentElement)t.style.display="none"}}}const t=class _StyleInjector{static init(){
console.log("[StyleInjector] 初始化样式注入...");this.addStyles()}static addStyles(){const t=document.createElement("style")
;t.textContent=this.cssRules;document.head.appendChild(t);console.log("[StyleInjector] 样式注入完成")}}
;t.cssRules=`\n    .container {\n      width: 100% !important;\n      max-width: 100% !important;\n      padding: 0 8px !important; /* 两侧极窄边距 */\n    }\n    .videos_box {\n      width: 100% !important;\n      max-width: 100% !important;\n      margin: 0 auto !important;\n      position: relative !important;\n      z-index: 5 !important;\n      aspect-ratio: 16 / 9 !important; /* 预留高度,避免进入时闪烁 */\n    }\n    .videos_box.hsx-hidden-until-ready { visibility: hidden !important; }\n    .video-js {\n      width: 100% !important;\n      max-width: 100% !important;\n      position: relative !important;\n      z-index: 5 !important;\n    }\n    /* 保持流式比例,避免固定高度导致缩放错位 */\n    /* 在初始阶段用内边距占位,避免"黑块->瞬间跳变" */\n    .video-js.vjs-fluid { padding-top: 56.25% !important; height: auto !important; }\n    /* 初次渲染时隐藏原始 poster 的闪烁 */\n    .video-js .vjs-poster { opacity: 0.001 !important; }\n    /* 页面里引入的固定尺寸需要被覆盖 */\n    .video-play-dimensions { width: 100% !important; height: auto !important; }\n    /* 新布局:视频下方两列容器 */\n    .hsx-two-col {\n      display: grid !important;\n      /* 左列放"作者视频"(较窄),右列放"推荐视频"(较宽) */\n      grid-template-columns: minmax(280px, 1fr) minmax(0, 3fr) !important;\n      grid-gap: 16px !important;\n      margin-top: 16px !important;\n      width: 100% !important;\n    }\n    /* 单列模式:仅显示某一列 */\n    .hsx-two-col.single-left,\n    .hsx-two-col.single-right {\n      grid-template-columns: 1fr !important;\n    }\n    .hsx-two-col.single-left .hsx-right { display: none !important; }\n    .hsx-two-col.single-right .hsx-left { display: none !important; }\n    .hsx-left, .hsx-right { width: 100% !important; }\n    /* 左列作者视频:与右列一致,使用自适应网格 */\n    .hsx-left {\n      display: grid !important;\n      grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)) !important;\n      gap: 12px !important;\n      align-content: start !important;\n    }\n    /* 右列推荐视频:自适应网格,多列铺排 */\n    .hsx-right {\n      display: grid !important;\n      grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)) !important;\n      gap: 12px !important;\n      align-content: start !important;\n    }\n    /* 右列每个卡片强制为块级,避免被行内/浮动样式影响导致容器高度为0 */\n    .hsx-right > *, .hsx-left > * { display: block !important; }\n    /* 取消 Bootstrap 对卡片的浮动限制,使其在网格中自适应 */\n    .hsx-two-col .col-xs-6,\n    .hsx-two-col .col-md-3,\n    .hsx-two-col .col-md-12,\n    .hsx-two-col .col-xs-12,\n    .hsx-two-col .col-md-4,\n    .hsx-two-col .col-md-8 {\n      float: none !important;\n      width: auto !important;\n      max-width: 100% !important;\n      padding: 0 !important;\n    }\n    .hsx-two-col .row { margin: 0 !important; display: contents !important; }\n    .hsx-two-col .thumbnail { margin-bottom: 0 !important; display:block !important; }\n    /* 确保移动后缩略图正常展示 */\n    .hsx-two-col .thumbnail .image {\n      background-position: center center !important;\n      background-size: cover !important;\n      width: 100% !important;\n      min-height: 120px !important;\n    }\n    /* 切换控件 */\n    .hsx-switch { display: flex !important; gap: 8px !important; margin: 10px 0 !important; }\n    .hsx-switch .hsx-switch-btn {\n      padding: 6px 12px !important;\n      background: #2b2b2b !important;\n      color: #cfcfcf !important;\n      border-radius: 4px !important;\n      cursor: pointer !important;\n      user-select: none !important;\n    }\n    .hsx-switch .hsx-switch-btn.active { background: #4a90e2 !important; color: #fff !important; }\n    /* PC端始终保持左右两栏,不做折叠 */\n    .col-md-12 {\n      width: 100% !important;\n      max-width: 100% !important;\n      flex-basis: 100% !important;\n      padding: 0 10px !important;\n    }\n    .vjs-control-bar {\n      position: absolute !important;\n      left: 0 !important;\n      right: 0 !important;\n      bottom: 0 !important;\n      z-index: 10 !important;\n      clear: none !important;\n      width: auto !important;\n    }\n    .panel-default {\n      position: relative !important;\n      clear: both !important;\n      margin-top: 16px !important;\n      z-index: 1 !important; /* 保持在视频之下,避免遮挡 */\n      width: 100% !important;\n      float: none !important;\n    }\n    .col-md-12:after {\n      content: "" !important;\n      display: table !important;\n      clear: both !important;\n    }\n    .thumbnail {\n      margin-bottom: 15px;\n    }\n    .videos_box { min-height: 200px !important; overflow: hidden !important; }\n  `
;let e=t;const n=class _DOMObserver{static init(){console.log("[DOMObserver] 初始化DOM监听...");this.setupDocumentListeners()
;this.setupMutationObserver()}static setupDocumentListeners(){const t=0;const runUpdates=()=>{
WideScreen.setWideScreenMode();LayoutReflow.reflowLayout()}
;if("loading"===document.readyState)document.addEventListener("DOMContentLoaded",()=>{setTimeout(runUpdates,t)
});else setTimeout(runUpdates,t);document.addEventListener("load",t=>{const e=t.target
;if("VIDEO"===e.tagName||"IFRAME"===e.tagName){WideScreen.setWideScreenMode();LayoutReflow.reflowLayout()}},true)
;window.addEventListener("load",runUpdates)}static setupMutationObserver(){const runUpdates=()=>{
WideScreen.setWideScreenMode();LayoutReflow.reflowLayout()};this.observer=new MutationObserver(t=>{let e=false
;t.forEach(t=>{if(t.addedNodes.length>0)e=true});if(e)runUpdates()});this.observer.observe(document.body,{
childList:true,subtree:true})}static destroy(){if(this.observer){this.observer.disconnect();this.observer=null}}}
;n.observer=null;let o=n;console.log("[好色TV-优化] 开始加载");e.init();function init(){WideScreen.init();LayoutReflow.init()
;o.init();console.log(`[好色TV-优化] ${window.location.hostname}宽屏模式: 已启用`);console.log("[好色TV-优化] 所有模块加载完成")}init()})();