您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
(我已经安装了用户样式管理器,让我安装!)
// ==UserScript==
// @name GPT-4 自动请求计数器(2023.07适配)
// @namespace http://tampermonkey.net/
// @version 0.3
// @description 自动记录gpt-4的剩余使用次数,以及剩余重置时间(总共2小时50分钟),方便规划管理,显示于右上角
// @author GPT4 learn from Mojibake-1 (https://greasyfork.org/zh-CN/scripts/462961-gpt-4-%E6%89%8B%E5%8A%A8%E8%AF%B7%E6%B1%82%E8%AE%A1%E6%95%B0%E5%99%A8-chatgpt-gpt-4-request-counter-manual-only) and mefengl (https://greasyfork.org/zh-CN/scripts/466663-chatgpt-auto-continue)
// @match https://chat.openai.com/*
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
const SECONDS_IN_7_2_MINUTES = 7.2 * 60;
const MAX_REQUEST_COUNT = 50;
const RESET_TIME = 2 * 60 + 50; // 2小时50分钟,单位为分钟
const wrapperDiv = document.createElement('div');
wrapperDiv.style.position = 'fixed';
wrapperDiv.style.top = '6px';
wrapperDiv.style.right = '6px';
wrapperDiv.style.zIndex = '9999';
document.body.appendChild(wrapperDiv);
const counterButton = document.createElement('button');
counterButton.style.padding = '1px';
counterButton.style.backgroundColor = '#007bff';
counterButton.style.color = '#ffffff';
counterButton.style.border = 'solid';
counterButton.style.cursor = 'pointer';
counterButton.textContent = '手动扣除一次';
wrapperDiv.appendChild(counterButton);
const resetButton = document.createElement('button');
resetButton.style.marginTop = '5px';
resetButton.style.padding = '1px';
resetButton.style.backgroundColor = '#dc3545';
resetButton.style.color = '#ffffff';
resetButton.style.border = 'solid';
resetButton.style.cursor = 'pointer';
resetButton.textContent = '重置';
wrapperDiv.appendChild(resetButton);
const requestCountSpan = document.createElement('span');
requestCountSpan.style.display = 'block';
requestCountSpan.style.marginTop = '1px';
requestCountSpan.style.color = '#007bff';
requestCountSpan.style.fontSize = '1px';
wrapperDiv.appendChild(requestCountSpan);
const lastChangeSpan = document.createElement('span');
lastChangeSpan.style.display = 'block';
lastChangeSpan.style.marginTop = '1px';
lastChangeSpan.style.color = '#007bff';
lastChangeSpan.style.fontSize = '1px';
wrapperDiv.appendChild(lastChangeSpan);
const startInput = document.createElement('input');
startInput.type = 'time'; // Set the input type to 'time'
startInput.style.display = 'block';
startInput.style.marginTop = '1px';
startInput.style.padding = '1px';
startInput.style.fontSize = '1px';
wrapperDiv.appendChild(startInput);
const startButton = document.createElement('button');
startButton.style.marginTop = '1px';
startButton.style.padding = '1px';
startButton.style.backgroundColor = '#28a745';
startButton.style.color = '#ffffff';
startButton.style.border = 'solid';
startButton.style.cursor = 'pointer';
startButton.textContent = '手动开始计时';
wrapperDiv.appendChild(startButton);
const countdownSpan = document.createElement('span');
countdownSpan.style.display = 'block';
countdownSpan.style.marginTop = '1px';
countdownSpan.style.color = '#007bff';
countdownSpan.style.fontSize = '1px';
wrapperDiv.appendChild(countdownSpan);
const resetTimeSpan = document.createElement('span');
resetTimeSpan.style.display = 'block';
resetTimeSpan.style.marginTop = '1px';
resetTimeSpan.style.color = '#007bff';
resetTimeSpan.style.fontSize = '1px';
wrapperDiv.appendChild(resetTimeSpan);
let requestCount = parseInt(localStorage.getItem('gpt4RequestCount')) || MAX_REQUEST_COUNT;
let remainingTime = parseInt(localStorage.getItem('gpt4RemainingTime')) || RESET_TIME * 60;
let isCountdownStarted = localStorage.getItem('gpt4CountdownStarted') === 'true' || false;
let lastChangeTime = localStorage.getItem('gpt4LastChangeTime') || '';
let startTime = localStorage.getItem('gpt4StartTime');
function updateRequestCountDisplay() {
requestCountSpan.textContent = `剩余次数:${requestCount}`;
}
function formatTime(date) {
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
return `${hours}:${minutes}`;
}
function updateCountdownDisplay() {
const remainingHours = Math.floor(remainingTime / 3600);
const remainingMinutes = Math.floor((remainingTime % 3600) / 60);
const remainingSeconds = remainingTime % 60;
countdownSpan.textContent = `剩余重置时间:${remainingHours}小时 ${remainingMinutes}分钟`;
// 计算并显示重置时间
const currentTime = new Date();
const resetTime = new Date(currentTime.getTime() + remainingTime * 1000);
const resetHours = resetTime.getHours().toString().padStart(2, '0');
const resetMinutes = resetTime.getMinutes().toString().padStart(2, '0');
resetTimeSpan.textContent = `重置时间:${resetHours}:${resetMinutes}`;
if (remainingTime === 0) {
resetCountdown();
requestCount = MAX_REQUEST_COUNT;
localStorage.setItem('gpt4RequestCount', requestCount);
updateRequestCountDisplay();
alert('剩余次数已重置!');
}
}
function startCountdown() {
isCountdownStarted = true;
localStorage.setItem('gpt4CountdownStarted', 'true');
}
function resetCountdown() {
remainingTime = RESET_TIME * 60;
isCountdownStarted = false;
localStorage.setItem('gpt4RemainingTime', remainingTime);
localStorage.removeItem('gpt4CountdownStarted');
}
function saveRemainingTime() {
localStorage.setItem('gpt4RemainingTime', remainingTime);
}
function restoreRemainingTime() {
remainingTime = parseInt(localStorage.getItem('gpt4RemainingTime')) || RESET_TIME * 60;
}
function handleWindowClose() {
saveRemainingTime();
}
window.addEventListener('beforeunload', handleWindowClose);
updateRequestCountDisplay();
updateCountdownDisplay();
setInterval(() => {
if (isCountdownStarted) {
const currentTime = new Date();
const elapsedTime = Math.floor((currentTime - new Date(startTime)) / 1000);
remainingTime = Math.max(0, RESET_TIME * 60 - elapsedTime);
saveRemainingTime();
updateCountdownDisplay();
}
}, 1000);
counterButton.addEventListener('click', () => {
if (requestCount === 50 && !isCountdownStarted) {
startCountdown();
startTime = new Date().toISOString();
lastChangeTime = formatTime(new Date());
localStorage.setItem('gpt4LastChangeTime', lastChangeTime);
localStorage.setItem('gpt4StartTime', startTime);
updateLastChangeDisplay();
}
if (requestCount > 0) {
requestCount--;
localStorage.setItem('gpt4RequestCount', requestCount);
updateRequestCountDisplay();
}
});
resetButton.addEventListener('click', () => {
if (confirm('确定要重置剩余次数和倒计时吗?')) {
resetCountdown();
requestCount = MAX_REQUEST_COUNT;
localStorage.setItem('gpt4RequestCount', requestCount);
updateRequestCountDisplay();
updateCountdownDisplay();
startTime = null;
lastChangeTime = '';
localStorage.removeItem('gpt4StartTime');
localStorage.removeItem('gpt4LastChangeTime');
updateLastChangeDisplay();
}
});
startButton.addEventListener('click', () => {
const timeInput = startInput.value.trim();
if (validateTimeFormat(timeInput)) {
startCountdown();
// 清空自动开始时间
localStorage.removeItem('gpt4StartTime');
startTime = getStartTimeFromInput(timeInput);
lastChangeTime = formatTime(new Date());
localStorage.setItem('gpt4LastChangeTime', lastChangeTime);
localStorage.setItem('gpt4StartTime', startTime);
updateLastChangeDisplay();
} else {
alert('请输入正确的时间格式(hh:mm)');
}
});
function validateTimeFormat(time) {
const pattern = /^([01]\d|2[0-3]):([0-5]\d)$/;
return pattern.test(time);
}
function getStartTimeFromInput(time) {
const currentTime = new Date();
const [hours, minutes] = time.split(':');
currentTime.setHours(parseInt(hours));
currentTime.setMinutes(parseInt(minutes));
return currentTime.toISOString();
}
// 以下是原有的代码,未做修改
function getTextarea() {
const form = document.querySelector("form");
if (!form)
return;
const textareas = form.querySelectorAll("textarea");
const result = textareas[0];
return result;
}
function getthreeButton() {
const divs = document.querySelectorAll("div");
const result = Array.from(divs).find((div) => {
var _a;
return (_a = div.textContent) == null ? void 0 : ["model: gpt-4", "model: web browsing", "model: plugins", "Model: Plugins•Enabled plugins:"].includes(_a.trim().toLowerCase());
});
return result;
}
function getSubmitButton() {
const textarea = getTextarea();
if (!textarea)
return;
return textarea.nextElementSibling;
}
function getRegenerateButton() {
const form = document.querySelector("form");
if (!form)
return;
const buttons = form.querySelectorAll("button");
const result = Array.from(buttons).find((button) => {
var _a;
return (_a = button.textContent) == null ? void 0 : _a.trim().toLowerCase().includes("regenerate");
});
return result;
}
function getSaveSubmitButton() {
const cancelButtons = Array.from(document.querySelectorAll('.btn-neutral'));
for (let i = 0; i < cancelButtons.length; i++) {
if (cancelButtons[i].textContent.includes("Cancel")) {
// Check if previous sibling element is the "Save & Submit" button
const saveSubmitButton = cancelButtons[i].previousElementSibling;
if (saveSubmitButton && saveSubmitButton.textContent.includes("Save & Submit")) {
return saveSubmitButton;
}
}
}
return null; // Return null if no matching button found
}
function getContinueGeneratingButton2() {
const form = document.querySelector("form");
if (!form)
return;
const buttons = form.querySelectorAll("button");
const result = Array.from(buttons).find((button) => {
var _a;
return (_a = button.textContent) == null ? void 0 : _a.trim().toLowerCase().includes("continue generating");
});
return result;
}
function getStopGeneratingButton() {
const form = document.querySelector("form");
if (!form)
return;
const buttons = form.querySelectorAll("button");
const result = Array.from(buttons).find((button) => {
var _a;
return (_a = button.textContent) == null ? void 0 : _a.trim().toLowerCase().includes("stop generating");
});
return result;
}
function send(message) {
setTextarea(message);
const textarea = getTextarea();
if (!textarea)
return;
textarea.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true }));
}
function updateRequestCountAndDisplay() {
if (requestCount < MAX_REQUEST_COUNT) {
requestCount++;
updateRequestCountDisplay();
}
}
function getBgRedDiv() {
const divs = document.querySelectorAll("div");
const result = Array.from(divs).find((div) => {
return div.classList.contains("bg-red-500/10");
});
return result;
}
function listenToGpt4Button() {
const gpt4Button = getthreeButton();
const urlParams = new URLSearchParams(window.location.search);
const model = urlParams.get('model');
if (gpt4Button || model === 'gpt-4' || model === 'gpt-4-browsing' || model.includes("gpt-4-plugins")) {
listenToButtons();
}
}
function listenToButtons() {
const submitButton = getSubmitButton();
const saveSubmitButton = getSaveSubmitButton();
const regenerateButton = getRegenerateButton();
const continueGeneratingButton = getContinueGeneratingButton2();
const BgRedDiv = getBgRedDiv();
const textarea = getTextarea();
if (submitButton && !submitButton.hasAttribute('listener-added')) {
submitButton.addEventListener('click', () => {
counterButton.click();
});
submitButton.setAttribute('listener-added', '');
}
if (regenerateButton && !regenerateButton.hasAttribute('listener-added')) {
regenerateButton.addEventListener('click', () => {
counterButton.click();
});
regenerateButton.setAttribute('listener-added', '');
}
if (saveSubmitButton && !saveSubmitButton.hasAttribute('listener-added')) {
saveSubmitButton.addEventListener('click', () => {
counterButton.click();
});
saveSubmitButton.setAttribute('listener-added', '');
}
if (continueGeneratingButton && !continueGeneratingButton.hasAttribute('listener-added')) {
continueGeneratingButton.addEventListener('click', () => {
counterButton.click();
});
continueGeneratingButton.setAttribute('listener-added', '');
}
if (BgRedDiv && !BgRedDiv.hasAttribute('listener-added')) {
updateRequestCountAndDisplay();
BgRedDiv.setAttribute('listener-added', '');
}
if (textarea && !textarea.hasAttribute('listener-added')) {
textarea.addEventListener('keydown', (event) => {
if (event.key === 'Enter' && !event.shiftKey) {
counterButton.click();
}
});
textarea.setAttribute('listener-added', '');
}
}
const observer = new MutationObserver((mutationsList, observer) => {
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
listenToGpt4Button();
}
}
});
observer.observe(document, { childList: true, subtree: true });
// 页面加载时恢复剩余时间并继续倒计时
window.addEventListener('load', () => {
restoreRemainingTime();
updateCountdownDisplay();
restoreLastChangeTime();
updateLastChangeDisplay();
});
// 以下是新增的代码
function restoreLastChangeTime() {
lastChangeTime = localStorage.getItem('gpt4LastChangeTime') || '';
}
function updateLastChangeDisplay() {
lastChangeSpan.textContent = `自动开始时间:${lastChangeTime}`;
}
restoreLastChangeTime();
updateLastChangeDisplay();
})();