// ==UserScript==
// @name yes24座位分析助手
// @namespace http://tampermonkey.net/
// @version 1.3
// @description 分析yes24网站上的座位可选状态,支持自动抢票、自动锁票和自动刷新功能
// @author yoki
// @match *://ticket.yes24.com/*
// @match *://*.ticket.yes24.com/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_notification
// @grant window.focus
// @run-at document-end
// ==/UserScript==
(()=>{"use strict";function e(e){try{var t={allSeats:'#divSeatArray div[class^="s"]',availableSeats:"#divSeatArray div.s9, #divSeatArray div.s6, #divSeatArray div.s8",vipSeats:"#divSeatArray div.s9",rSeats:"#divSeatArray div.s6",sSeats:"#divSeatArray div.s8",selectedList:"#liSelSeat p"},n=Array.from(e.querySelectorAll(t.allSeats)||[]),a=Array.from(e.querySelectorAll(t.availableSeats)||[]),o=Array.from(e.querySelectorAll(t.vipSeats)||[]),s=Array.from(e.querySelectorAll(t.rSeats)||[]),i=Array.from(e.querySelectorAll(t.sSeats)||[]),r=Array.from(e.querySelectorAll(t.selectedList)||[]),l=n.map((function(e){var t=e.getAttribute("title")||"",n=e.id||"",a=e.getAttribute("grade")||"",o="";return e.classList.contains("s9")?(o="VIP席",{id:n,element:e,title:t,grade:a||o,type:o,isAvailable:!0}):e.classList.contains("s6")?(o="R席",{id:n,element:e,title:t,grade:a||o,type:o,isAvailable:!0}):e.classList.contains("s8")?(o="S席",{id:n,element:e,title:t,grade:a||o,type:o,isAvailable:!0}):{id:n,element:e,title:t,grade:a||"普通席",type:o="已售/不可用",isAvailable:!1}})),c=o.map((function(e){return{id:e.id||"",element:e,title:e.getAttribute("title")||"",grade:e.getAttribute("grade")||"VIP席",type:"VIP席",isAvailable:!0}})),d=s.map((function(e){return{id:e.id||"",element:e,title:e.getAttribute("title")||"",grade:e.getAttribute("grade")||"R席",type:"R席",isAvailable:!0}})),u=i.map((function(e){return{id:e.id||"",element:e,title:e.getAttribute("title")||"",grade:e.getAttribute("grade")||"S席",type:"S席",isAvailable:!0}})),v=a.map((function(e){var t="普通席";return e.classList.contains("s9")?t="VIP席":e.classList.contains("s6")?t="R席":e.classList.contains("s8")&&(t="S席"),{id:e.id||"",element:e,title:e.getAttribute("title")||"",grade:e.getAttribute("grade")||t,type:t,isAvailable:!0}})),f=r.map((function(e){var t=e.textContent||"";return{id:t,text:t}})),m={total:n.length,available:a.length,vip:o.length,r:s.length,s:i.length,selected:r.length,seatsWithInfo:l,selectedSeatsInfo:f,vipInfo:c,rInfo:d,sInfo:u,availableInfo:v,allSeatsInfo:l};return console.log("分析座位信息完成,共发现:",{总座位:m.total,可选座位:m.available,VIP席:m.vip,R席:m.r,S席:m.s,已选座位:m.selected,seatsWithInfo:m.seatsWithInfo,selectedSeatsInfo:m.selectedSeatsInfo,vipInfo:m.vipInfo,rInfo:m.rInfo,sInfo:m.sInfo,availableInfo:m.availableInfo,allSeatsInfo:m.allSeatsInfo}),m}catch(e){return console.error("分析座位信息时出错:",e),{total:0,available:0,vip:0,r:0,s:0,selected:0,seatsWithInfo:[],selectedSeatsInfo:[],vipInfo:[],rInfo:[],sInfo:[],availableInfo:[],allSeatsInfo:[]}}}function t(e){if(document.getElementById("yes24SeatAssistant"))return console.log("面板已存在,更新数据"),void n(e);var t;console.log("创建座位助手面板"),(t=document.createElement("style")).textContent='#yes24SeatAssistant{position:fixed;top:20px;right:20px;width:280px;background-color:rgba(33,37,41,.95);color:#fff;border-radius:8px;box-shadow:0 4px 15px rgba(0,0,0,.3);z-index:10000;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.1);overflow:hidden;transition:all .3s ease}.seat-assistant-header{display:flex;justify-content:space-between;align-items:center;padding:12px 15px;background:linear-gradient(135deg,#4568dc,#3a6073);border-bottom:1px solid rgba(255,255,255,.1)}.seat-assistant-title{font-size:16px;font-weight:700;display:flex;align-items:center}.seat-assistant-icon{margin-right:8px;font-size:18px}.seat-assistant-close{cursor:pointer;font-size:18px;opacity:.8;transition:opacity .2s;width:24px;height:24px;display:flex;align-items:center;justify-content:center;border-radius:50%}.seat-assistant-close:hover{opacity:1;background-color:rgba(255,255,255,.1)}.seat-assistant-body{padding:15px}.seat-assistant-section{margin-bottom:15px;background:rgba(0,0,0,.2);border-radius:6px;padding:12px}.seat-assistant-section-title{margin-bottom:10px;font-size:14px;font-weight:500;color:#adb5bd;border-bottom:1px solid rgba(255,255,255,.1);padding-bottom:5px}.seat-count-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.seat-count-item{text-align:center;background:rgba(0,0,0,.2);border-radius:4px;padding:8px 4px}.seat-count-label{font-size:12px;color:#adb5bd;margin-bottom:4px}.seat-count-value{font-size:18px;font-weight:700}.vip-seat{color:#20c997}.r-seat{color:#339af0}.s-seat{color:#fcc419}.available-seat{color:#51cf66}.selected-seat{color:#ff6b6b}.selected-seats-list{max-height:120px;overflow-y:auto;background:rgba(0,0,0,.15);border-radius:4px;margin-top:8px}.selected-seat-item{padding:6px 10px;border-bottom:1px solid rgba(255,255,255,.05);font-size:13px}.selected-seat-item.empty{color:#868e96;text-align:center;padding:15px}.auto-seat-controls{display:flex;flex-direction:column;gap:10px;padding:5px 0}.auto-seat-item{display:flex;align-items:center;gap:8px}.seat-input{width:50px;padding:4px 8px;background:rgba(255,255,255,0.1);border:1px solid rgba(255,255,255,0.2);border-radius:4px;color:#fff;text-align:center}.seat-select{padding:4px 8px;background:rgba(255,255,255,0.1);border:1px solid rgba(255,255,255,0.2);border-radius:4px;color:#fff;min-width:120px}.seat-checkbox{width:16px;height:16px;accent-color:#4568dc;cursor:pointer}.checkbox-container{margin:5px 0}.seat-button{background:linear-gradient(135deg,#4568dc,#3a6073);border:none;border-radius:4px;padding:8px 12px;color:#fff;cursor:pointer;transition:all 0.2s;width:100%;margin-top:5px}.seat-button:hover{background:linear-gradient(135deg,#5478ec,#4a7083)}.seat-hint{font-size:11px;color:#adb5bd}.status-indicator{font-size:12px;margin-top:8px;height:16px;color:#adb5bd;text-align:center}.status-indicator.active{color:#51cf66}.refresh-countdown{font-weight:bold}#yes24SeatAssistant *::-webkit-scrollbar{width:6px;height:6px}#yes24SeatAssistant *::-webkit-scrollbar-track{background:rgba(0,0,0,0.1);border-radius:3px}#yes24SeatAssistant *::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.2);border-radius:3px;transition:background 0.2s}#yes24SeatAssistant *::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,0.3)}#yes24SeatAssistant *::-webkit-scrollbar-corner{background:transparent}.selected-seats-list{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,0.2) rgba(0,0,0,0.1);padding-right:2px}',document.head.appendChild(t);var a=document.createElement("div");a.id="yes24SeatAssistant",a.innerHTML='\n
\n \n
\n
座位概况
\n
\n
\n
全部座位
\n
'.concat(e.total,'
\n
\n
\n
可选座位
\n
').concat(e.available,'
\n
\n
\n
已选座位
\n
').concat(e.selected,'
\n
\n
\n
\n \n
\n
可选座位类型
\n
\n
\n
VIP席
\n
').concat(e.vip,'
\n
\n
\n
R席
\n
').concat(e.r,'
\n
\n
\n
S席
\n
').concat(e.s,'
\n
\n
\n
\n \n
\n
自动选座设置
\n
\n
\n \n \n (0-9,0表示不自动选座)\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n (0表示不刷新,1-180秒)\n
\n
\n
\n
\n \n
\n
已选座位
\n
\n ').concat(e.selectedSeatsInfo.length>0?e.selectedSeatsInfo.map((function(e){return'
'.concat(e.text,"
")})).join(""):'
暂无已选座位
',"\n
\n
\n
\n "),document.body.appendChild(a),document.querySelector("#yes24SeatAssistant .seat-assistant-close").addEventListener("click",(function(){a.remove()})),document.getElementById("startAutoSeat").addEventListener("click",(function(){var e=parseInt(document.getElementById("seatCount").value)||0,t=document.getElementById("seatType").value,n=document.getElementById("autoLock").checked,a=parseInt(document.getElementById("refreshInterval").value)||0,o=new CustomEvent("autoSeatRequest",{detail:{count:e,type:t,autoLock:n,refreshInterval:a}});document.dispatchEvent(o)})),console.log("面板创建完成")}function n(e){if(document.getElementById("yes24SeatAssistant")){document.getElementById("totalSeatsCount").textContent=e.total,document.getElementById("availableSeatsCount").textContent=e.available,document.getElementById("selectedSeatsCount").textContent=e.selected,document.getElementById("vipSeatsCount").textContent=e.vip,document.getElementById("rSeatsCount").textContent=e.r,document.getElementById("sSeatsCount").textContent=e.s;var t=document.getElementById("selectedSeatsList");e.selectedSeatsInfo.length>0?t.innerHTML=e.selectedSeatsInfo.map((function(e){return''.concat(e.text,"
")})).join(""):t.innerHTML='暂无已选座位
'}}function a(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=document.getElementById("autoRefreshStatus");n&&(e?(n.classList.add("active"),n.innerHTML=null!==t?'自动刷新中: '.concat(t,"秒后刷新"):"自动刷新中..."):(n.classList.remove("active"),n.innerHTML=""))}function o(e){e.forEach((function(e){return function(e){console.log("自动点击座位: ".concat(e));var t=S().contentDocument.getElementById(e);t?t.click():console.warn("座位元素未找到: ".concat(e))}(e)}))}var s=null,i=!1,r=null,l=null,c=null,d={isActive:!1,interval:0,count:0,type:"any",autoLock:!1},u=null;function v(n){if(!i)try{console.log("初始化座位助手..."),s=n;var a=e(n.contentDocument);r=a,t(a),function(e){var t=e.contentDocument,n=t.querySelector(".seatarea");if(!n)return void console.warn("未找到座位区域,无法设置监控");new MutationObserver((function(e){e.some((function(e){return"attributes"===e.type?["class","style"].includes(e.attributeName):"childList"===e.type}))&&(console.log("检测到座位变化,更新数据"),f())})).observe(n,{childList:!0,attributes:!0,subtree:!0,attributeFilter:["class","style"]});var a=t.querySelector("#liSelSeat");a&&new MutationObserver((function(){console.log("检测到已选座位列表变化"),f()})).observe(a,{childList:!0,subtree:!0});console.log("座位监控已设置")}(n),document.addEventListener("autoSeatRequest",m),i=!0}catch(e){console.error("初始化座位助手时出错:",e)}}function f(){if(s&&i){var t=e(s.contentDocument);r=t,n(t)}}function m(e){var t=e.detail,n=t.count,a=t.type,o=t.autoLock,r=t.refreshInterval;console.log("收到自动选座请求: 数量=".concat(n,", 类型=").concat(a,", 自动锁票=").concat(o,", 刷新间隔=").concat(r,"秒")),s&&i?(b(),r>0&&r<=180?(d={isActive:!0,interval:r,count:n,type:a,autoLock:o},g(r),p(n,a,o)):p(n,a,o)):console.warn("无法执行自动选座,座位信息不可用")}function p(e,t,n){if(r)if(0!==e){var a=[];switch(t){case"vip":a=r.vipInfo.length>0?r.vipInfo.slice(0,e):r.availableInfo.slice(0,e);break;case"r":a=r.rInfo.length>0?r.rInfo.slice(0,e):r.availableInfo.slice(0,e);break;case"s":a=r.sInfo.length>0?r.sInfo.slice(0,e):r.availableInfo.slice(0,e);break;default:a=r.availableInfo.slice(0,e)}if(a.length>0){console.log("准备自动选择".concat(a.length,"个座位:"),a);var s=a.map((function(e){return e.id}));o(s),n&&s.length>0&&setTimeout((function(){console.log("准备自动点击锁票按钮"),function(){console.log("自动点击锁票按钮");var e=S(),t=e.contentDocument.querySelector('a[href="javascript:ChoiceEnd();"]');t?(t.click(),console.log("锁票按钮已成功点击")):(console.warn("锁票按钮未找到,尝试执行ChoiceEnd()"),e.contentWindow.ChoiceEnd())}(),b()}),1e3)}else console.warn("没有找到符合条件的可用座位")}else console.log("座位数为0,不执行自动选座");else console.warn("无法执行自动选座,座位信息不可用")}function g(t){t<=0||t>180?console.warn("刷新间隔无效:",t):(console.log("启动自动刷新,间隔".concat(t,"秒")),d.isActive=!0,a(!0,c=t),u=setInterval((function(){a(!0,--c),c<=0&&clearInterval(u)}),1e3),l=setTimeout((function(){d.isActive&&(console.log("执行自动刷新..."),new Promise((function(t){var a=S();if(!a)return console.warn("找不到iframe,无法刷新"),void t();var o=function(){a.removeEventListener("load",o),setTimeout((function(){if(a.contentDocument){var o=e(a.contentDocument);r=o,n(o)}t()}),500)};a.addEventListener("load",o);try{a.contentWindow.location.reload()}catch(e){console.error("刷新iframe时出错:",e),a.removeEventListener("load",o),t()}})).then((function(){console.log("iframe已刷新,重新执行自动选座"),setTimeout((function(){p(d.count,d.type,d.autoLock),g(t)}),1e3)})))}),1e3*t))}function b(){l&&(clearTimeout(l),l=null),u&&(clearInterval(u),u=null),d.isActive=!1,a(!1),console.log("已停止自动刷新")}function y(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(e){if("string"==typeof e)return h(e,t);var n={}.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?h(e,t):void 0}}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var a=0,o=function(){};return{s:o,n:function(){return a>=e.length?{done:!0}:{done:!1,value:e[a++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,i=!0,r=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return i=e.done,e},e:function(e){r=!0,s=e},f:function(){try{i||null==n.return||n.return()}finally{if(r)throw s}}}}function h(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=Array(t);n=e.length?{done:!0}:{done:!1,value:e[a++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,i=!0,r=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return i=e.done,e},e:function(e){r=!0,s=e},f:function(){try{i||null==n.return||n.return()}finally{if(r)throw s}}}}function w(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=Array(t);n