// ==UserScript== // @name 创会 // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description 创会脚本 // @author lhq // @match https://meeting.tencent.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=tencent.com // @grant GM_xmlhttpRequest // @connect 159.75.172.230 // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/528517/%E5%88%9B%E4%BC%9A.user.js // @updateURL https://update.greasyfork.icu/scripts/528517/%E5%88%9B%E4%BC%9A.meta.js // ==/UserScript== const meetingDetail = "https://meeting.tencent.com/user-center/user-meeting-list/detailed-meeting-info"; const meetingList = "https://meeting.tencent.com/user-center/user-meeting-list"; let timer = null; const baseUrl = "http://159.75.172.230:8084/"; let user = null; let meetingArr = [] let meetingInfo = { id: '', meetingName: '', startTime:'', meetingStartBufferTime:'', endTime:'', meetingEndBufferTime: '', secret: '' } //获取页面类型 const pageType = () => { if (window.location.href === meetingList) { return "meetingList"; } else if (window.location.href.startsWith(meetingDetail)) { return "meetingDetail"; } else { return null; } }; const setInputValue = (inputElement, key) => { Object.defineProperty(inputElement, "value", { get: function () { return this._value; }, set: function (newValue) { this._value = newValue; this.dispatchEvent(new Event("input", { bubbles: true })); }, }); inputElement.value = key; }; //触发输入框事件 const simulateInputEvent = (inputElement) => { const inputEvent = new Event("input", { bubbles: true, cancelable: true, }); const changeEvent = new Event("change", { bubbles: true, cancelable: true, }); // 派发input事件 inputElement.dispatchEvent(inputEvent); // 派发change事件 inputElement.dispatchEvent(changeEvent); }; //给输入框赋值 const simulateKeyboardInput = (inputElement, value) => { inputElement.value = ""; simulateInputEvent(inputElement); const chars = value.split(""); chars.forEach((char) => { const event = new KeyboardEvent("keypress", { bubbles: true, cancelable: true, charCode: char.charCodeAt(0), }); // 模拟输入字符 inputElement.value += char; }); simulateInputEvent(inputElement); }; //获取用户信息 const getUserInfo = () => { const res = sessionStorage.getItem('persist:root') if(res) { const res1 = JSON.parse(res)?.userInfos if(res1) { return JSON.parse(res1) } return null } return null } //选择50分页 const setPageSize = () => { const endDialog = document.querySelector(".meetinglist-pagination .met-dropdown-btn"); if (endDialog) { endDialog.click(); setTimeout(() => { const listItems = Array.from(document.querySelectorAll('#met-overlay-root li')) .filter(li => li.textContent.trim() === '50'); if (listItems[0]) listItems[0].click(); },1000) } } //判断是否为今天 function checkAndFormatDate(dateStr) { const today = new Date(); const currentYear = today.getFullYear(); const currentMonth = today.getMonth() + 1; const currentDay = today.getDate(); const [month, day] = dateStr.split('月').map(str => parseInt(str, 10)); if (month === currentMonth && day === currentDay) { return '今天'; } else { const formattedMonth = month < 10 ? `0${month}` : `${month}`; const formattedDay = day < 10 ? `0${day}` : `${day}`; return `${formattedMonth}月${formattedDay}日`; } } //创建符合条件的会议数据集合 function findElementsAndExtractParentClasses(className, searchString) { const elements = document.querySelectorAll(`.${className}`); const resultArray = []; elements.forEach(element => { if (element.textContent.includes(searchString)) { const parentElement = element.closest('tr'); if (parentElement) { const classValue = parentElement.className; const clickEle = `[class="${classValue}"] .meeting-subject-btn` resultArray.push({ meetingId:classValue, clickEle, startTime: '', endTime: '' }) } } }) return resultArray } //进入详情页获取数据并退出 function getStartAndEndTimeLabels() { setTimeout(() => { const storedData = sessionStorage.getItem('persist:root'); if (storedData) { try { const parsedData = JSON.parse(storedData); const items = document.querySelectorAll('.met-form__item'); if (parsedData.meetingItemInfo) { const meetingItemInfo = JSON.parse(parsedData.meetingItemInfo); const mItem = meetingArr.find(i => i.meetingId == meetingItemInfo.meeting_code) console.log(mItem,meetingItemInfo.meeting_code); if (mItem) { mItem.startTime = items[3].querySelector('.met-form__text').textContent.replace("年", "/").replace("月", "/").replace("日", "") mItem.endTime = items[4].querySelector('.met-form__text').textContent.replace("年", "/").replace("月", "/").replace("日", "") } const elements = document.querySelector('.step-1'); elements.click() setTimeout(() => { setPageSize() }, 1000); } } catch (error) { console.error('Error parsing JSON data:', error); } } }, 2000); } //执行收集数据 function getData() { const pollInterval = setInterval(() => { console.log("Polling meeting array..."); let allItemsSatisfied = true; // 标志所有项是否都满足条件 meetingArr.forEach(item => { const { startTime, endTime, clickEle } = item; // startTime if (!startTime || !endTime) { const elements = document.querySelector(clickEle); // 模拟点击事件 if (elements) { elements.click(); // 触发点击事件 getStartAndEndTimeLabels() } else { console.warn(`Element not found for selector: ${clickEle}`); } // 如果有任一项未满足条件,则将标志设置为false allItemsSatisfied = false; } else { console.log(`MeetingId: ${item.meetingId} is satisfied.`); } }); // 如果所有项都满足条件,则停止轮询 if (allItemsSatisfied) { console.log("停止轮询"); clearInterval(pollInterval); // 获取缓冲时间 const startBuffer = parseBufferTime(meetingInfo.meetingStartBufferTime); const endBuffer = parseBufferTime(meetingInfo.meetingEndBufferTime); // 计算新会议的时间范围 const newMeetingRange = calculateTimeRange( meetingInfo.startTime, meetingInfo.endTime, startBuffer, endBuffer ); // 检查是否有交集 const hasIntersection = checkIntersection(meetingArr, newMeetingRange); if (hasIntersection) { taskFail() }else { setMeeting() } } }, 6000); } // 将时间字符串转换为时间戳 function convertToTimestamp(dateTimeStr) { // 替换 / 为 - 以兼容 Date 构造函数 const formattedDate = dateTimeStr.replace(/\//g, '-'); const date = new Date(formattedDate); return date.getTime(); // 返回毫秒级时间戳 } // 将缓冲时间字符串转换为毫秒 function parseBufferTime(bufferStr) { const parts = bufferStr.split(':').map(Number); const hours = parts[0] || 0; const minutes = parts[1] || 0; return hours * 3600 * 1000 + minutes * 60 * 1000; // 转换为毫秒 } // 计算时间范围 function calculateTimeRange(startTimeStr, endTimeStr, startBuffer, endBuffer) { const startTime = convertToTimestamp(startTimeStr); const endTime = convertToTimestamp(endTimeStr); const start = startTime - startBuffer; const end = endTime + endBuffer; return { start, end }; } // 检查时间范围是否有交集 function checkIntersection(existingMeetings, newRange) { const newStart = newRange.start; const newEnd = newRange.end; for (const meeting of existingMeetings) { const existingStart = convertToTimestamp(meeting.startTime); const existingEnd = convertToTimestamp(meeting.endTime); // 检查是否有交集 if (newStart < existingEnd && newEnd > existingStart) { return true; // 存在交集 } } return false; // 不存在交集 } // 预定会议 function setMeeting() { const elements = document.querySelector('.met-btn.toolbar-schedule-btn'); if (elements) elements.click(); setTimeout(() => { inputInfo() },2000) } // 填写会议 function inputInfo() { const formItems = document.querySelectorAll('.met-form__item'); if (formItems.length > 0) { // 获取第一个.met-form__item中的元素 const firstFormItem = formItems[0]; const inputElement = firstFormItem.querySelector('input'); if (inputElement) { setInputValue(inputElement,meetingInfo.meetingName) } // 获取第一个.met-form__item中的元素 const firstFormItem1 = formItems[1]; const inputElement4 = firstFormItem1.querySelector('.end .met-datepicker input'); const inputElement5 = firstFormItem1.querySelector('.end .custom-time-picker .hour'); const inputElement6 = firstFormItem1.querySelector('.end .custom-time-picker .minute'); console.log(inputElement4,inputElement5,inputElement6); const inputele2 = firstFormItem1.querySelector('.end .met-datepicker__input-normal'); inputele2.click() setTimeout(() => { const eles2 = document.querySelectorAll('.met-calendar__cell.met-calendar__cell--date'); if (inputElement4 && inputElement5 && inputElement6) { const [startTime1, startTime2] = meetingInfo.endTime.split(" "); const [hourPart, minutePart] = startTime2.split(":"); console.log(startTime1,hourPart,minutePart); //setInputValue(inputElement4,startTime1) setTimeout(() => { const index = timeSub(meetingInfo.endTime) clickTime(index) },1000) setInputValue(inputElement5,hourPart) setInputValue(inputElement6,minutePart) } setTimeout(() => { const inputElement1 = firstFormItem1.querySelector('.start .met-datepicker input'); const inputElement2 = firstFormItem1.querySelector('.start .custom-time-picker .hour'); const inputElement3 = firstFormItem1.querySelector('.start .custom-time-picker .minute'); const inputele1 = firstFormItem1.querySelector('.start .met-datepicker__input-normal'); console.log(inputElement1,inputElement2,inputElement3); inputele1.click() setTimeout(() => { const eles1 = document.querySelectorAll('.met-calendar__cell.met-calendar__cell--date'); if (inputElement1 && inputElement2 && inputElement3) { const [startTime1, startTime2] = meetingInfo.startTime.split(" "); const [hourPart, minutePart] = startTime2.split(":"); console.log(startTime1,hourPart,minutePart); //setInputValue(inputElement1,startTime1) setTimeout(() => { const index = timeSub(meetingInfo.endTime) clickTime(index) setCheckbox() },1000) setInputValue(inputElement2,hourPart) setInputValue(inputElement3,minutePart) } },1000) },3000) },1000) } } const setCheckbox = () => { const passEle = document.querySelector('#host-pass-code input'); if (passEle) { passEle.click(); setTimeout(() => { const passwordEle = document.querySelector('#host-pass-code input[type="password"]'); if (passwordEle) setInputValue(passwordEle,meetingInfo.secret) const waterEle = document.querySelector('label[name="water_mark"] input'); if (waterEle) waterEle.click(); const confirmEle = document.querySelector('.met-btn.meeting-button-area-confirm'); if (confirmEle) confirmEle.click(); setTimeout(() => { if(pageType() == 'meetingDetail') { taskSuccess() }else { taskFail() } },5000) },1000) } } const timeSub = (time) => { const now = new Date(); const targetTime = new Date(time); const timeDifference = targetTime - now; const daysDifference = timeDifference / (24 * 60 * 60 * 1000); const daysDifferenceFloor = Math.floor(daysDifference); return daysDifferenceFloor } const formatTime = (time) => { const dateString = time; const date = new Date(dateString); const month = date.getMonth() + 1; const day = date.getDate(); return `${month}月${day}日`; } const clickTime = (i) => { const allCells = document.querySelectorAll('.met-calendar__cell.met-calendar__cell--date'); let selectedIndex = -1; allCells.forEach((cell, index) => { if (cell.classList.contains('is-selected')) { selectedIndex = index; } }); if (selectedIndex === -1) { console.error('未找到包含 is-selected 类的元素'); } else { const offset = i; const targetIndex = selectedIndex + offset; if (targetIndex >= 0 && targetIndex < allCells.length) { const targetCell = allCells[targetIndex]; console.log('目标元素:', targetCell); targetCell.click() } else { console.error('目标位置超出范围'); } } } //开始任务 const start = () => { if(pageType() === 'meetingList'){ meetingArr = [] const time = formatTime(meetingInfo.startTime) console.log(time); const dateStr = checkAndFormatDate(time) console.log(dateStr); setPageSize() setTimeout(() => { const arr = findElementsAndExtractParentClasses('meeting-begin-time-in-date',dateStr) meetingArr = arr if(meetingArr.length > 0) { getData() }else { setMeeting() } }, 2000); } else { window.location.href = meetingList } } //请求API const requestApi = (userId) => { user = getUserInfo() GM_xmlhttpRequest({ method: "GET", url: `${baseUrl}refreshMeetingRoomState?userId=${user.userid}&userState=1`, onload: function (response) { const res = response?.responseText ? JSON.parse(response.responseText) : null; console.log('------------------------------response',response); console.log('------------------------------res',res); if (res) { meetingInfo.id = res.id meetingInfo.secret = res.secret meetingInfo.meetingName = res.meetingName meetingInfo.meetingStartBufferTime = res.meetingStartBufferTime meetingInfo.meetingEndBufferTime = res.meetingEndBufferTime meetingInfo.startTime = `${res.meetingStartDay.replace(/-/g, "/")} ${res.meetingStartTime}` meetingInfo.endTime = `${res.meetingEndDay.replace(/-/g, "/")} ${res.meetingEndTime}` console.log(meetingInfo); clearInterval(timer); start() } }, onerror: function (response) { console.log("请求失败"); }, }); }; // 获取任务 const getTask = (userId) => { timer = setInterval(() => { requestApi(); }, 5000); }; // 任务成功 const taskSuccess = (userId) => { GM_xmlhttpRequest({ method: "GET", url: `${baseUrl}refreshMeetingRoomState?userId=${user.userid}&userState=3&meetingRoomId=${meetingInfo.id}`, onload: function (response) { getTask() }, onerror: function (response) { console.log("请求失败"); }, }); }; // 任务失败 const taskFail = (userId) => { GM_xmlhttpRequest({ method: "GET", url: `${baseUrl}refreshMeetingRoomState?userId=${user.userid}&userState=4&meetingRoomId=${meetingInfo.id}`, onload: function (response) { getTask() }, onerror: function (response) { console.log("请求失败"); }, }); }; (function() { getTask() })();