您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Info preview, removal of lock from friends' vidoes, restored upload button, and more.
当前为
// ==UserScript== // @name Camwhores.tv Utilities Mod // @namespace https://sleazyfork.org/users/1281730-vipprograms // @version 1.11.2 // @description Info preview, removal of lock from friends' vidoes, restored upload button, and more. // @author vipprograms // @match https://www.camwhores.tv/* // @exclude *.camwhores.tv/*mode=async* // @grant GM_xmlhttpRequest // @grant GM.getValue // @grant GM_getValue // @grant GM.setValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant GM.registerMenuCommand // @grant GM_addStyle // @grant GM_download // @grant GM_openInTab // @grant window.close // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAMUExURQAAAP8ANwwA/////7gbQJkAAAABdFJOUwBA5thmAAAAAWJLR0QDEQxM8gAAAAd0SU1FB+gDHhIuCjXV/h8AAAA4SURBVAjXY2ANDQ1gEA0NDWEIYWBgZAhgAAIUghEiC1YHBhpMDRpIhBbXghUMXKtWLWBgWqHVAACjlwz/pN0YPwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNC0wMy0zMFQxODo0NjowOSswMDowME+iXNIAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjQtMDMtMzBUMTg6NDY6MDkrMDA6MDA+/+RuAAAAKHRFWHRkYXRlOnRpbWVzdGFtcAAyMDI0LTAzLTMwVDE4OjQ2OjEwKzAwOjAwMNiA/AAAAABJRU5ErkJggg== // @require https://cdn.jsdelivr.net/npm/@violentmonkey/shortcut@1 // @require https://code.jquery.com/jquery-3.7.1.slim.min.js // ==/UserScript== (function() { 'use strict'; var _GM_registerMenuCommand, _GM_notification, options, optionName; const refreshVideosMinutes = 30; const { register } = VM.shortcut; const currentVersion = GM_info.script.version; const currentDate = new Date(); const metaPage = "https://update.sleazyfork.org/scripts/491272/Camwhorestv%20Utilities%20Mod.meta.js"; VM.shortcut.register('c-i', () => { console.log('You just pressed Ctrl-I'); }); function isArrayEmpty(arr) { return arr.length === 0; } function retrieveValueFromStorage(key) { // If value/index NOT present, returns undefined if (typeof GM_setValue === "function") { return GM_getValue(key, false); // Default value set to false for boolean } else if (typeof GM === "object" && typeof GM.getValue === "function" && typeof GM.setValue === "function") { return GM.getValue(key, false).then(function(value) { return value; }); } else { console.error("Unsupported userscript manager."); return undefined; } } function saveValue(key, array) { GM.setValue(key, array).then(function() { console.log("Array saved successfully."); }).catch(function(error) { console.error("Error saving array:", error); }); } if (typeof GM_registerMenuCommand !== 'undefined') { _GM_registerMenuCommand = GM_registerMenuCommand; } else if (typeof GM !== 'undefined' && typeof GM.registerMenuCommand !== 'undefined') { _GM_registerMenuCommand = GM.registerMenuCommand; } else { // _GM_registerMenuCommand = (s, f) => { debug(s); debug(f); }; console.log("Oh no"); } function saveOption(optionName, currentValue){ let options = retrieveValueFromStorage("options") || {}; options[optionName] = currentValue; saveValue("options", options); } function toggleChange(optionName, currentValue = false){ // ONLY for menu commands var updatedOptions; let options = retrieveValueFromStorage("options"); var currentState = options[optionName] !== undefined ? options[optionName] : currentValue; _GM_registerMenuCommand((currentState ? "Disable " : "Enable ") + optionName, () => { currentState = !currentState; updatedOptions[optionName] = currentState; saveValue("options", updatedOptions); setTimeout(() => { location.reload(); }, 500); }); updatedOptions = retrieveValueFromStorage("options") || {}; // Ensure options exist if (updatedOptions[optionName] === undefined) { updatedOptions[optionName] = currentValue; saveValue("options", updatedOptions); } } function createForm(array_name, delimitedString){ return new Promise((resolve, reject) => { var form = document.createElement('form'); form.classList.add('form-container'); var textBox = document.createElement('textarea'); textBox.classList.add('textarea-input'); textBox.setAttribute('autofocus', 'autofocus'); var buttonsLine = document.createElement('div'); buttonsLine.classList.add('buttons-line'); var submitButton = document.createElement('button'); submitButton.type = 'submit'; submitButton.textContent = 'Submit'; submitButton.classList.add('submit-button'); var cancelButton = document.createElement('button'); cancelButton.type = 'button'; cancelButton.textContent = 'Cancel'; cancelButton.classList.add('cancel-button'); cancelButton.addEventListener('click', function() { document.body.removeChild(form); reject('Form cancelled'); }); window.addEventListener('click', function(event) { if (document.body.contains(form) && !form.contains(event.target)) { document.body.removeChild(form); reject('Form cancelled'); } }); textBox.value = delimitedString; form.appendChild(textBox); form.appendChild(buttonsLine); buttonsLine.appendChild(cancelButton); buttonsLine.appendChild(submitButton); document.body.appendChild(form); form.addEventListener('submit', function(event){ event.preventDefault(); var inputValue = textBox.value.split('\n').map(line => line.trim()).filter(line => line !== ''); document.body.removeChild(form); resolve(inputValue); }); }); } function optionsArrayEditor(array_name, optionsKeyLegible){ _GM_registerMenuCommand("Change " + optionsKeyLegible[array_name], () => { var originalArray = retrieveValueFromStorage(array_name); var delimitedString = originalArray.join("\n"); createForm(array_name, delimitedString).then(lines => { saveValue(array_name, lines); }); }); } function optionsStringEditor(string_name, optionsKeyLegible) { _GM_registerMenuCommand("Change " + optionsKeyLegible[string_name], () => { var originalString = retrieveValueFromStorage(string_name); createForm(string_name, originalString).then(lines => { // Convert array 'lines' to a string by joining values with '\n' let stringifiedLines = lines.join('\n'); saveValue(string_name, stringifiedLines); }); }); } const auto_replies_default = ["Next time you send me a request with 0 videos, I'll block you", "Very nice videos", "Why? What's wrong?", "Sorry, I don't like your videos", "You don't have any videos"]; const highlight_keywords_default = ['joi', 'cei', 'fuck', "cumshot"]; const friend_request_text_default = "Hi! I'm interested in this video:"; const alternative_thumbnails_users = ['deathstar45','usualsuspekt','MrPussyGod','peacebitch','ADCGHN11123']; var auto_replies = retrieveValueFromStorage("auto_replies"); var highlight_keywords = retrieveValueFromStorage("highlight_keywords"); var friend_request_text = retrieveValueFromStorage("friend_request_text"); if (!auto_replies) { auto_replies = auto_replies_default; saveValue("auto_replies", auto_replies_default); } if (!highlight_keywords) { highlight_keywords = highlight_keywords_default; saveValue("highlight_keywords", highlight_keywords_default); } if (!friend_request_text) { friend_request_text = friend_request_text_default; saveValue("friend_request_text", friend_request_text_default); } var optionsKeyLegible = { auto_replies: "template replies", highlight_keywords: "highlight keywords", friend_request_text: "friend requests text", alternative_thumbnails_users: "users with bad default thumbnails" } optionsArrayEditor("auto_replies", optionsKeyLegible) optionsArrayEditor("highlight_keywords", optionsKeyLegible) optionsStringEditor("friend_request_text", optionsKeyLegible) optionName = "restore upload button"; toggleChange(optionName, true) var restoreUploadButton = retrieveValueFromStorage("options")[optionName]; optionName = "notify me of processed videos"; toggleChange(optionName, false) var notifyProcessedVideos = retrieveValueFromStorage("options")[optionName]; let updateRemindersOptionName = "update reminders"; toggleChange(updateRemindersOptionName, true) var updateReminders = retrieveValueFromStorage("options")[updateRemindersOptionName]; const style = document.createElement('style'); // custom CSS style.textContent = ` a.button{color:#4e4e4e !important;}ul > li.next, ul > li.prev {display: list-item !important;}.item:hover > a > div.img > .friends-tag, .item:hover > a > div.img > .videos-tag{background-color:#1a1a1a !important;}.button{color: rgb(183, 176, 167);text-align: center;border: 1px solid transparent;font-size: 14px;padding: 5px 10px;cursor: pointer;background: linear-gradient(to bottom, #ffffff 0%, #cccccc 100%);border-radius: 3px;display: inline-block;margin: 0 .3rem .3rem 0;color: dimgrey;}.button:hover{color: #f56c08 !important;border: 1px solid transparent;background: #1e1e1e;}div.img span.unread-notification{background: #c45606ab;backdrop-filter: blur(5px) brightness(1);top: 0px;left: 0px;border-bottom-left-radius: 3px;border-bottom-right-radius: 3px;outline: 3px solid #f56c08;animation: glow 5s infinite;}@keyframes glow {0% {outline-color: #f56c08d6;}50% {outline-color: transparent;}100% {outline-color: #f56c08d6;}}.form-container {box-sizing: border-box;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);max-width: 100vw;width: 800px;padding: 2.5rem;border-radius: .25rem;z-index:99999;background-color: transparent !important;backdrop-filter: blur(1rem) brightness(.8) contrast(1.2) }.form-container * {box-sizing: inherit;}.textarea-input {width: 100%;min-height: 10rem;padding: 1rem;border-radius: .25rem;color-scheme: dark !important;}.buttons-line {margin-top: .3rem;gap:.3rem;width: 100%;display: flex;}.submit-button:hover, .cancel-button:hover{filter: brightness(.8) contrast(1.2) }.submit-button, .cancel-button{transform: .3s;}.submit-button {height: 50px;flex-grow: 1;cursor: pointer;border-radius: .25rem;color-scheme: dark !important;font-weight:bold;border:0;}.cancel-button {width:min-content;height: 50px;cursor: pointer;border-radius: .25rem;color-scheme: dark !important;background-color: red;font-weight:bold;padding-inline:.5rem;border:0;}input.accept-button, span.accept-button {color: #fff;background-image: linear-gradient(rgb(0, 128, 0) 0%, rgb(0, 255, 0) 100%);}input.accept-button:hover, span.accept-button:hover {color: #fff !important;background-image: linear-gradient(rgb(34, 139, 34) 0%, rgb(50, 205, 50) 100%) !important;}input.reject-button, span.reject-button {color: #fff;background-image: linear-gradient(rgb(255, 0, 0) 0%, rgb(128, 0, 0) 100%);}input.reject-button:hover, span.reject-button:hover {color: #fff !important;background-image: linear-gradient(rgb(220, 20, 60) 0%, rgb(178, 34, 34) 100%) !important;}#vid_previews {display: flex;flex-wrap: nowrap;height: 135px;margin-block: .5rem;gap: 5px;box-sizing: border-box;}#vid_previews .img-div {width:185px;height:100%;position: relative;box-sizing: inherit;}.list-messages .added {position: absolute;right: 0;}.list-messages .item {margin-right: 0;}#vid_previews .img-div img{box-sizing: inherit;width: 100%;height:100%;}#vid_previews .img-div h2{position: absolute;bottom: 0;background-color: rgb(0 0 0 / 65%);font-size: 1rem;line-height: 1.2rem;backdrop-filter: blur(5px);color: rgb(196 196 196);width: 100%;word-wrap: break-word;box-sizing: inherit;text-align: center;}.bottom-element{margin-top: 1em;margin-bottom: 1em;}form .bottom{padding-top: .5rem;}form .bottom .submit{float: initial;height: auto;padding: .45rem .5rem;margin: 0;}.margin-fix .bottom{margin:0;}#gen_joined_text{margin: .5rem 0 .25rem 0;}a[href="http://flowplayer.org"], a[class="fp-brand"]{opacity: 0 !important;pointer-events: none !important;}div.block-profile > div > div > div.about-me > div > em{white-space:pre;} h1.online:after{ content: ''; height: .45rem; aspect-ratio: 1; display: inline-block; background-color: green; position: relative; left: .5rem; border-radius: 50%; bottom: .1rem; } div.block-profile > div > div > div.about-me > div{ width: 100%; box-sizing: border-box; } div.block-profile > div > div > div.about-me > div>em{ width: 100%; display: inline-block; word-break: auto-phrase; word-wrap: break-word; box-sizing: border-box; text-wrap: pretty; } .user-search { float: right; /*min-width: 140px;*/ position: relative; margin-left: 3px; cursor: pointer; background: #f1f1f1; background: linear-gradient(to bottom, #f1f1f1 0%, #d8d8d8 100%); border-radius: 2px; padding:0; } .user-search strong { display: block; font-size: 12px; line-height: 15px; padding: 5px 12px 5px 28px; white-space: nowrap; color: #4e4e4e; cursor: pointer; max-width: 200px; overflow: hidden; } .user-search .type-search { background: url('https://shrph.altervista.org/img/search.png') 5px 4px no-repeat; } .user-search .icon { display: block; position: absolute; width: 100%; height: 100%; top:0; } #tab_screenshots > div > .item, #tab_screenshots > div > .item > .img { width: 250px; height: auto; } #tab_screenshots > div > .item > .img { } @keyframes fadeAnimation { 0% { opacity: 1; } 50% { opacity: .3; } 100% { opacity: 1; } } .fade { animation: fadeAnimation 1s infinite; } .switch { position: relative; display: inline-block; width: 30px; height: 17px; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; -webkit-transition: .4s; transition: .4s; } .slider:before { position: absolute; content: ""; height: 13px; width: 13px; left: 2px; bottom: 2px; background-color: white; -webkit-transition: .4s; transition: .4s; } input:checked + .slider { background-color: #f56c08; } input:focus + .slider { box-shadow: 0 0 1px #F28022; } input:checked + .slider:before { -webkit-transform: translateX(13px); transform: translateX(13px); } .slider.round { border-radius: 17px; } .slider.round:before { border-radius: 50%; } .list-comments .dim-comment p { opacity: 1; } .list-comments .dim-comment { background-color: #9e1e1e2b; background-image: none; } `; document.head.appendChild(style); function makeValidUrlString(inputString) { var validString = inputString.replace(/[^\w\s\/-]/g, ''); // Remove special characters validString = validString.replace(/[-_]{2,}/g, '-'); // Turn consecutive underscores or hyphens into single hyphens validString = validString.replace(/\s+/g, '-'); // Turn spaces into hyphens validString = validString.replace(/\//g, '-'); // Turn slashes into hyphens return validString; } function friendRequestSetup(video_title, video_url, userID){ var vid_code = video_url.replace("https://www.camwhores.tv/videos/", ""); var parts = vid_code.split("/"); var videoId = parts[0]; var code = parts[1]; let cumData = { title: video_title, videoId: videoId, userId: userID }; let lastCumVideoAdd = JSON.parse(localStorage.getItem('last_cum_video_data')) || {}; lastCumVideoAdd[userID] = cumData; localStorage.setItem('last_cum_video_data', JSON.stringify(lastCumVideoAdd)); } function convertToSeconds(timeString) { let [_, value, unit] = timeString.match(/(\d+) (\w+)/); value = parseInt(value); switch (unit) { case 'second': case 'seconds': return value; case 'minute': case 'minutes': return value * 60; case 'hour': case 'hours': return value * 3600; case 'day': case 'days': return value * 86400; case 'week': case 'weeks': return value * 604800; case 'month': case 'months': return value * 2592000; // assuming 30 days per month case 'year': case 'years': return value * 31536000; // assuming 365 days per year default: return 0; } } function fetchAndParseHTML(url, callback) { GM_xmlhttpRequest({ method: "GET", url: url, onload: function(response) { var parser = new DOMParser(); var htmlDoc = parser.parseFromString(response.responseText, "text/html"); callback(htmlDoc); } }); } function fetchAndExtract(url, callback) { GM_xmlhttpRequest({ method: "GET", url: url, onload: function(response) { document.evaluate('//*[@id="list_messages_my_conversation_messages_items"]/div/div[3]/img', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue?.remove(); var parser = new DOMParser(); var htmlDoc = parser.parseFromString(response.responseText, "text/html"); callback(htmlDoc); } }); } /* usage: fetchAndExtract(messageUrl, function(htmlDoc) { }); */ function getAllSessionStorage() { var sessionStorageItems = {}; for (var i = 0; i < sessionStorage.length; i++) { var key = sessionStorage.key(i); var value = sessionStorage.getItem(key); sessionStorageItems[key] = value; } return sessionStorageItems; } function getCurrentPage(){ var allSessionStorage = getAllSessionStorage(); var paramsStorageKey = Object.keys(allSessionStorage).find(key => key.endsWith(":params")); if(!allSessionStorage || !paramsStorageKey){ return 1; } // console.log(allSessionStorage) // console.log("paramsStorageKey:",paramsStorageKey) var paramsValue = JSON.parse(allSessionStorage[paramsStorageKey]).from_my_conversations; // console.log("getCurrentPage:",paramsValue) if(!paramsValue){ return 1; } let int = parseInt(paramsValue, 10); // console.log(int) return int; } function setUploadButtonTimestamp(){ var timestamp = Date.now(); var jsonData = JSON.stringify(timestamp); localStorage.setItem('UploadButtonTimestamp', jsonData); } function getCookie(name) { let cookieArr = document.cookie.split("; "); for(let cookie of cookieArr) { let [key, value] = cookie.split("="); if(key === name) return value; } return null; } function loadArrayLocalStorage(name='lastVideoData') { var jsonData = localStorage.getItem(name); if (!jsonData) { return []; } var data = JSON.parse(jsonData); return data; } function saveArrayLocalStorage(name='lastVideoData', data){ var timestamp = Date.now(); var jsonData = JSON.stringify(data); localStorage.setItem(name, jsonData); } function secondsSinceLocalStorage(name) { let storedItem = JSON.parse(localStorage.getItem(name)); if (storedItem) { let currentTime = Date.now(); let storedTime = storedItem.timestamp; return (currentTime - storedTime) / 1000; // Time difference in seconds } else { return null; } } function getNewUID() { let sessionStorageData = getAllSessionStorage(); if(!sessionStorageData){ return null; } for (let key in sessionStorageData) { let matches = key.match(/^(\d+):https:\/\/www\.camwhores\.tv/); if (matches) { return matches[1]; } } return null; } function saveUID(){ let uid = getNewUID(); if(uid){ let current_kt = getCookie("kt_member"); let data = {uid: uid, kt: current_kt}; saveArrayLocalStorage("cum_user_id", data); return uid; } return } function silentUidUpdater(){ let uidArray = loadArrayLocalStorage("cum_user_id"); if(!uidArray || getCookie("kt_member") !== uidArray.kt){ saveUID(); } } function currentUserID(){ let current_kt = getCookie("kt_member"); let uidArray = loadArrayLocalStorage("cum_user_id"); if(uidArray && uidArray.kt === current_kt){ return uidArray.uid; }else{ return saveUID() } return } async function getResponseStatus(url) { try { let response = await fetch(url, { method: 'HEAD' }); return response.status; } catch (error) { return null; } } function secondsSinceTimestamp(timestamp){ return (Date.now() - timestamp) / 1000; } let currentUID = currentUserID(); // console.log("User ID:", currentUID, "(https://www.camwhores.tv/members/" + currentUID + "/)") silentUidUpdater() function uploadRestored(){ alert("The upload button has been restored!") localStorage.removeItem("UploadButtonTimestamp"); } // UPLOAD button const nav = document.querySelector('.navigation .primary'); let lastCheck = localStorage.getItem("UploadButtonTimestamp"); // EXAMPLE: "1717655623061" let minutesSinceLastCheck = secondsSinceTimestamp(lastCheck) / 60; let roundedMinutes = Math.floor(minutesSinceLastCheck); if (nav && restoreUploadButton && ![...nav.querySelectorAll('a')].some(link => link.textContent.trim().includes('Upload'))) { const uploadLink = document.createElement('div'); uploadLink.style.backgroundColor = '#215521'; uploadLink.style.display = 'block'; uploadLink.style.padding = '11px 0'; uploadLink.style.cursor = 'pointer'; uploadLink.textContent = 'UPLOAD'; nav.appendChild(uploadLink); let uploadURL = '/upload-video/'; //'https://www.camwhores.tv/upload-video/' uploadLink.addEventListener('click', function() { getResponseStatus(uploadURL).then(status => { if (status === 200) { window.location.href = url; } else { if (confirm("Upload functionality is currently fully disabled\n(" + status.toString() + ")\nDo you want to be notified when it's available again?")) { setUploadButtonTimestamp(); } } }); }); if(lastCheck && minutesSinceLastCheck > 30){ getResponseStatus(uploadURL).then(status => { if (status === 200) { uplaodRestored(); } else { console.log("Upload button still unavailable. Last check",minutesSinceLastCheck,"minutes ago") setUploadButtonTimestamp(); } }); }else{ // console.log("Only",roundedMinutes, "minutes have passed since last upload button check,", 30 - roundedMinutes, "to go"); } }else{ // console.log("Couldn't/shouldn't restoreUploadButton", restoreUploadButton) if(lastCheck){ uploadRestored() } } if ((window.location.href.endsWith("?action=reject_add_to_friends_done")) || (window.location.href.endsWith("?action=confirm_add_to_friends_done"))) { let urlOfUser = document.querySelector('#list_messages_my_conversation_messages > div.headline > h2 > a:nth-child(2)') let username = urlOfUser.innerHTML.trim(); let userID = urlOfUser.getAttribute('href').match(/\/(\d+)\//)[1]; const storedData = JSON.parse(localStorage.getItem('closedWindow')); if (storedData) { let { uid, timestamp } = storedData; let currentTime = Date.now(); let timeDifference = (currentTime - timestamp) / 1000; // in seconds console.log(timeDifference + " seconds, uid: "+userID+" vs "+uid) if (timeDifference < 30 && userID == uid) { console.log(`Less than 30 seconds have passed since window closed. User ID: ${uid}`); window.close(); }else{ } } }else if (window.location.href == "https://www.camwhores.tv/my/messages/") { function myMessagesAsyncURL(pageInt=1){ const utcTimestamp = new Date().getTime(); const pageID = pageInt.toString(); return "https://www.camwhores.tv/my/messages/?mode=async&function=get_block&block_id=list_members_my_conversations&sort_by=added_date&from_my_conversations="+pageID+"&_="+utcTimestamp; } // console.log(myMessagesAsyncURL(3)) function messagePageInfo(pageN) { let urlToPage = myMessagesAsyncURL(pageN); // console.log(urlToPage) return new Promise((resolve, reject) => { fetchAndExtract(urlToPage, function(htmlDoc) { const conversations = []; const items = htmlDoc.querySelectorAll("#list_members_my_conversations_items .item"); // console.log("htmlDoc:",htmlDoc) items.forEach(item => { const name = item.querySelector('a').getAttribute('title'); const unread = item.classList.contains('unread'); conversations.push({ name, unread }); }); resolve(conversations); }); }); } async function hasUnreadMessage(currentPage) { const data = await messagePageInfo(currentPage); return data.some(message => message.unread); } async function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function lastUnreadPage() { let currentPage = 1; let hasUnread = true; while (hasUnread) { const data = await messagePageInfo(currentPage); hasUnread = data.some(message => message.unread); if (!hasUnread) break; currentPage++; await delay(75); } return currentPage - 1; } async function checkAndFixMessages() { const currentPage = getCurrentPage(); const data = await messagePageInfo(currentPage); // console.log(data); let hasNewElements = false; data.forEach(item => { const userItem = document.querySelector(`#list_members_my_conversations_items > div.item > a[title="${item.name}"]`); if (userItem) { const unreadNotification = userItem.querySelector('div.img .unread-notification'); if (unreadNotification && !item.unread) { unreadNotification.remove(); console.log("Message with", item.name, "was read"); } } else{ hasNewElements = true; } }); if (hasNewElements) { location.reload(); } } function processThumbnails() { // console.log("Processing thumbnails"); var thumbnails = document.querySelectorAll('strong.title'); if (thumbnails.length === 0) { console.log("Thumbnails not found. Retrying in 1000 milliseconds."); setTimeout(function() { processThumbnails(); // Retry processing thumbnails }, 1000); return false; // Return false if thumbnails not found } thumbnails.forEach(function(thumbnail) { var usernameText = thumbnail.textContent.trim(); if (usernameText) { var usernameLink = document.querySelector('a[title="' + usernameText + '"]'); // console.log("usernameLink:",usernameLink) if (usernameLink) { var href = usernameLink.getAttribute('href'); var userIdMatch = href.match(/\/(\d+)\/$/); if (userIdMatch && userIdMatch.length > 1) { var userId = userIdMatch[1]; var usernameUrl = "https://www.camwhores.tv/members/" + userId + "/"; GM_xmlhttpRequest({ method: "GET", url: usernameUrl, onload: function(response) { var parser = new DOMParser(); var htmlDoc = parser.parseFromString(response.responseText, "text/html"); var infoMessage = htmlDoc.querySelector('.info-message'); var usernameLink = document.querySelector('a[title="' + usernameText + '"]'); // console.log(usernameText + ": " + usernameUrl) // console.log(usernameLink) if (infoMessage && infoMessage.textContent.includes("is in your friends list.")) { if (usernameLink) { var divElement = document.createElement('div'); divElement.classList.add("friends-tag"); divElement.textContent = "Friends ✅"; divElement.style.position = "absolute"; divElement.style.top = "0"; divElement.style.right = "0"; divElement.style.backgroundColor = "#414141"; //#1a1a1a divElement.style.borderBottomLeftRadius = "3px"; divElement.style.color = "white"; divElement.style.padding = "3px 5px"; if (usernameLink) { var firstDivElement = usernameLink.querySelector('div.img'); if (firstDivElement) { firstDivElement.appendChild(divElement); } } } } if(infoMessage && infoMessage.textContent.includes("wants to be your friend.")){ divElement = document.createElement('div'); divElement.textContent = "👀"; divElement.title = "Wants to be your friend!"; divElement.style.position = "absolute"; divElement.style.bottom = "0"; divElement.style.left = "0"; // divElement.style.backgroundColor = "aquamarine"; divElement.style.color = "white"; divElement.style.fontSize = "1rem"; divElement.style.padding = ".5rem .25rem"; if (usernameLink) { firstDivElement = usernameLink.querySelector('div.img'); if (firstDivElement) { firstDivElement.appendChild(divElement); } } } var titleVideosElement = htmlDoc.evaluate('//*[@id="list_videos_uploaded_videos"]/div[1]/h2', htmlDoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); var videoNumber = 0; if (titleVideosElement && titleVideosElement.singleNodeValue) { var titleVideosText = titleVideosElement.singleNodeValue.textContent; if (titleVideosText) { var matches = titleVideosText.match(/\(([^)]+)\)/); videoNumber = matches ? matches[1] : 0; } } if(videoNumber || videoNumber === 0){ divElement = document.createElement('div'); divElement.classList.add("videos-tag"); divElement.textContent = videoNumber; divElement.style.position = "absolute"; divElement.style.bottom = "0"; divElement.style.right = "0"; divElement.style.backgroundColor = "CadetBlue"; divElement.style.color = "white"; divElement.style.padding = "3px 5px"; divElement.style.borderTopLeftRadius = "3px"; } if (usernameLink) { firstDivElement = usernameLink.querySelector('div.img'); if (firstDivElement) { firstDivElement.appendChild(divElement); } } } // end httpGET reponse }); } else { console.log("User ID not found in href for:", usernameText); } } else { console.log("Username link not found for:", usernameText); } } }); return true; // Return true if thumbnails processed successfully } function addButtonEventListener() { // console.log("Adding event listener to buttons"); document.addEventListener('click', function(event) { var target = event.target; if (target && target.matches('a[data-action="ajax"]')) { // console.log("Button clicked"); var h2Element = document.querySelector('#list_members_my_conversations div.headline h2'); const initialText = h2Element.textContent.trim(); // console.log("Initial text: " + initialText); const checkChangeInterval = setInterval(function() { h2Element = document.querySelector('#list_members_my_conversations div.headline h2'); const currentText = h2Element.textContent.trim(); // console.log("Current text: " + currentText); if (currentText !== initialText) { clearInterval(checkChangeInterval); processThumbnails(); } }, 100); } }); } setTimeout(function() { processThumbnails(); var thumbnailsProcessed = processThumbnails(); if (!thumbnailsProcessed) { console.log("Processing thumbnails failed. Retrying in 1000 milliseconds."); setTimeout(function() { processThumbnails(); // Retry processing thumbnails }, 1000); } addButtonEventListener(); }, 1000); setInterval(function() { processThumbnails() silentUidUpdater() checkAndFixMessages() }, 5000); setInterval(function() { addButtons() }, 500); function addButtons() { const h2Element = document.querySelector('#list_members_my_conversations .headline h2'); if (!h2Element) return console.log('h2Element not found'); if (!document.getElementById('refreshIcon')) { const refreshIcon = document.createElement('span'); refreshIcon.id = 'refreshIcon'; refreshIcon.innerHTML = '↻'; refreshIcon.title = 'Refresh Utilities Mod'; refreshIcon.style = 'cursor:pointer;margin-left:10px;'; refreshIcon.addEventListener('click', () => { processThumbnails(); console.log('Refreshing...'); }); h2Element.appendChild(refreshIcon); } if (!document.getElementById('lastUnreadButton')) { const lastUnreadButton = document.createElement('a'); lastUnreadButton.id = 'lastUnreadButton'; lastUnreadButton.innerHTML = '⏭'; lastUnreadButton.title = 'Go to oldest unread message'; lastUnreadButton.style = 'cursor:pointer;margin-left:10px;text-decoration:none;'; lastUnreadButton.addEventListener('click', async () => { lastUnreadButton.classList.add('fade'); const oldestUnreadPage = await lastUnreadPage(); console.log(oldestUnreadPage); const linkElement = document.querySelector(`a[href="/my/messages/${oldestUnreadPage}/"][data-block-id="list_members_my_conversations"]`); if (linkElement) { linkElement.click(); } else { console.log(`Element for page ${oldestUnreadPage} not found`); } lastUnreadButton.classList.remove('fade'); }); h2Element.appendChild(lastUnreadButton); } } addButtons() }else if(window.location.href.startsWith("https://www.camwhores.tv/my/messages/")) { // VM.shortcut.register('c-enter', () => { // console.log('You just pressed Ctrl-I'); // }); function updateButtonStyle(button, state) { if (state && button) { button.classList.add("accept-button"); } else if(button) { button.classList.add("reject-button"); // console.log(button) }else{ // console.log(button + " button absent") } } let textarea = document.querySelector("#send_message_message"); let divTextarea = document.createElement('div'); let urlOfUser = document.querySelector('#list_messages_my_conversation_messages > div.headline > h2 > a:nth-child(2)') let username = urlOfUser.innerHTML.trim(); let userID = urlOfUser.getAttribute('href').match(/\/(\d+)\//)[1]; let confirmButton = document.querySelector('input[name="confirm"]'); let rejectButton = document.querySelector('input[name="reject"]'); let buttonsParent = confirmButton ? confirmButton.parentElement : null; let confirmClose = null let denyClose = null // console.log(userID) if (sessionStorage.getItem('continue') === 'true') { sessionStorage.removeItem('continue'); if (history.length === 1) { window.location.href = "https://www.camwhores.tv/members/"+userID+"/#list_videos_my_uploaded_videos"; } } if (confirmButton){ confirmButton.addEventListener('click', function() { sessionStorage.setItem('continue', 'true'); }); } document.querySelector('input.submit').addEventListener('click', function() { divTextarea.innerHTML = ''; }); $(document).ready(function() { $(document).keyup(function(event) { if (event.ctrlKey && event.key === 'Enter') { event.preventDefault(); // alert("Submitting"); $("#send_message_form").submit(); } }); }); function copyContentToTextarea() { const tempDiv = document.createElement('div'); tempDiv.innerHTML = divTextarea.innerHTML; const content = []; tempDiv.childNodes.forEach(node => { if (node.nodeType === 3) { // Text node content.push(node.textContent); } else if (node.nodeType === 1 && node.tagName === 'IMG') { // Image node content.push(node.alt); } }); const finalText = content.join('').trim(); // Join text content and alt attributes with space textarea.value = finalText; // Set the final text to the textarea } textarea.style.display = "none"; divTextarea.innerHTML = textarea.value; divTextarea.contentEditable = true; divTextarea.style.minHeight = "5rem"; divTextarea.style.resize = "vertical"; divTextarea.style.overflow = "auto"; divTextarea.style.fontSize = "14px"; divTextarea.classList.add("textarea"); textarea.parentNode.insertBefore(divTextarea, textarea.nextSibling); document.querySelectorAll('.smileys-bar img').forEach(function(img) { img.addEventListener('click', function(event) { event.preventDefault(); event.stopPropagation(); var imgClone = img.cloneNode(true); imgClone.style.cursor = "auto"; // Add cursor style divTextarea.appendChild(imgClone); copyContentToTextarea() return false; }); }); divTextarea.addEventListener('input', copyContentToTextarea); var inlineTexts = document.querySelectorAll('span.inline-text, span.original-text'); inlineTexts.forEach(function(span) { var lineText = span.textContent.trim(); if (lineText.includes('##')) { var index = lineText.indexOf(':'); var videoText = lineText.substring(0, index).trim(); var videoInfo = lineText.substring(index + 1).trim().replace('##', ''); let parts = videoInfo.split("\n"); let videoCode = parts[0]; let videoID = parts[1]; let url = 'https://www.camwhores.tv/videos/' + videoID + "/" + makeValidUrlString(videoCode) + '/'; // console.log(url) fetch(url) .then(response => { if (response.ok) { span.innerHTML = videoText + ': <a href="' + url + '" class="toggle-button" style="display:inline-block">'+videoCode+'</a>'; } else if (response.status === 404) { console.log("URL is 404"); } else { console.error("Error:", response.status); } }) .catch(error => console.error("Error:", error)); // span.innerHTML = videoText + ': <a href="' + url + '" class="toggle-button" style="display:inline-block">Open video</a>'; } }); function andClosePage(){ const closedWindow = { uid: userID, timestamp: Date.now() }; localStorage.setItem('closedWindow', JSON.stringify(closedWindow)); console.log("Window should close now") window.close(); } function addCloseButtonsListeners(confirmButton, rejectButton) { var confirmClose, denyClose; if (confirmButton) { var buttonsParent = confirmButton.parentElement; confirmClose = document.createElement('span'); confirmClose.className = 'submit button'; confirmClose.innerHTML = 'Confirm & Close'; denyClose = document.createElement('span'); denyClose.className = 'submit button'; denyClose.innerHTML = 'Deny & Close'; confirmClose.addEventListener('click', function(event) { event.preventDefault(); // alert("Clicked! (when done debugging, REMOVE and CLOSE)") confirmButton.click(); andClosePage() }); denyClose.addEventListener('click', function(event) { event.preventDefault(); // alert("Clicked! (when done debugging, REMOVE and CLOSE)") rejectButton.click(); andClosePage() }); var closeButtonsContainer = document.createElement('div'); closeButtonsContainer.classList.add('closeInputs'); buttonsParent.appendChild(confirmClose); buttonsParent.appendChild(document.createTextNode(' ')); buttonsParent.appendChild(denyClose); buttonsParent.appendChild(closeButtonsContainer); confirmButton.style.width = confirmClose.offsetWidth + 'px'; rejectButton.style.width = denyClose.offsetWidth + 'px'; } return { confirmClose: confirmClose, denyClose: denyClose }; } function updateMessageDOM(htmlDoc, confirmClose, denyClose) { const twoYearsSeconds = 60 * 60 * 24 * 365 * 2; var titleText = htmlDoc.querySelector('#list_videos_uploaded_videos > div:nth-child(1) > h2')?.textContent.trim(); var lastUploadTime = htmlDoc.querySelector('#list_videos_uploaded_videos_items > div.item > a > div.wrap > div.added > em')?.textContent.trim(); var joinedDateText = htmlDoc.querySelector('div.block-profile > div.profile-list > div.margin-fix > div.column > div:nth-child(3) > em')?.textContent.trim(); var lastLogin = htmlDoc.querySelector('div.block-profile > div.profile-list > div.margin-fix > div.last-login > div.item')?.textContent.trim(); let secondsSinceOnline = convertToSeconds(lastLogin); let recentlyOnline = secondsSinceOnline <= 300; // let recentlyOnline = true; const headlineH2 = document.querySelector('#list_messages_my_conversation_messages .headline h2'); console.log("recentlyOnline:", recentlyOnline); var recentlyUploaded = false; console.log("Has focus:",document.hasFocus(),"titleText:",titleText) if(!document.hasFocus() && !titleText){ denyClose.click() window.close(); } if(lastUploadTime){ let lastUploadTimeSeconds = convertToSeconds(lastUploadTime); recentlyUploaded = lastUploadTimeSeconds < twoYearsSeconds; } if(recentlyOnline){ GM_addStyle(`.list-messages .item.new .added:after { background-color: green; }`); document.querySelector("#list_messages_my_conversation_messages_items > div.item.new > div.added").textContent += " (online)"; headlineH2.innerHTML += " (online)" } if (titleText) { // THERE ARE VIDEOS var extractedTitle = titleText.match(/\(([^)]+)\)/); if (extractedTitle && extractedTitle.length >= 1) { // THERE ARE VIDEOS if(recentlyUploaded){ updateButtonStyle(confirmButton, true); updateButtonStyle(confirmClose, true); }else{ updateButtonStyle(rejectButton, false); updateButtonStyle(denyClose, false); } var generatedTextDiv = document.createElement('div'); generatedTextDiv.id = 'gen_joined_text'; generatedTextDiv.innerHTML = `${extractedTitle[1]} videos, last ${lastUploadTime}<br>Joined ${joinedDateText}`; var messageDiv = document.querySelector('#list_messages_my_conversation_messages_items > div > div:nth-child(3)'); if (messageDiv) { messageDiv.appendChild(generatedTextDiv); } }else{ if(extractedTitle) console.log("extractedTitle:",extractedTitle) } if(confirmClose){ let imgData = []; for (let i = 1; i <= 5; i++) { let xpath = `//*[@id="list_videos_uploaded_videos_items"]/div[${i}]/a/div[@class="img"]/img`; let img = htmlDoc.evaluate(xpath, htmlDoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; if (img) { let parentAnchor = img.parentNode.parentNode; imgData.push({ src: img.getAttribute('data-original'), alt: img.alt, url: parentAnchor.getAttribute('href') }); } } let vidPreviewsDiv = document.createElement("div"); vidPreviewsDiv.id = "vid_previews"; if (!isArrayEmpty(imgData)) { imgData.forEach(data => { let imgDiv = document.createElement("div"); imgDiv.classList.add("img-div"); let imgLink = document.createElement("a"); // New line imgLink.href = data.url+"?please_check_friend"; // New line let img = document.createElement("img"); img.src = data.src; img.alt = data.alt; img.title = data.alt; let title = document.createElement("h2"); title.textContent = data.alt; imgLink.appendChild(img); // Updated line imgDiv.appendChild(imgLink); // Updated line imgDiv.appendChild(title); vidPreviewsDiv.appendChild(imgDiv); }); buttonsParent.appendChild(vidPreviewsDiv); } } } else { // THERE ARE NO VIDEOS console.log('No videos? Title: '+titleText+", content: "+lastUploadTime); updateButtonStyle(rejectButton, false); updateButtonStyle(denyClose, false); var messageDiv = document.querySelector('#list_messages_my_conversation_messages_items > div > div:nth-child(3)'); if (messageDiv) { var generatedTextDiv = document.createElement('div'); generatedTextDiv.id = 'gen_joined_text'; generatedTextDiv.innerHTML = `Joined ${joinedDateText}<br><b>No videos</b>`; messageDiv.appendChild(generatedTextDiv); } } } // return var bottomDiv = document.querySelector("#send_message_form > div > div.bottom"); var responsesDiv = document.createElement("div"); responsesDiv.id = "responses"; responsesDiv.style.marginTop = "1rem"; bottomDiv.insertAdjacentElement('afterend', responsesDiv); auto_replies.forEach(function(string) { var button = document.createElement("button"); button.textContent = string; button.classList.add("button"); button.addEventListener("click", function(event) { event.preventDefault(); if (textarea.value.trim() !== '') { textarea.value += "\n"; } textarea.value += string; document.querySelector('#send_message_form').submit(); }); button.style.padding = ".25rem .5rem" responsesDiv.appendChild(button); }); // return // var messageLink = document.evaluate('//*[@id="list_messages_my_conversation_messages"]/div[1]/h2/a[2]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); var messageLink = document.evaluate('//*[@id="list_messages_my_conversation_messages_items"]/div/div[1]/a', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); if (messageLink && messageLink.singleNodeValue) { var messageUrl = messageLink.singleNodeValue.href; const parentElement = document.evaluate('//*[@id="list_messages_my_conversation_messages_items"]/div/div[3]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; const img = document.createElement('img'); img.src = 'https://samherbert.net/svg-loaders/svg-loaders/three-dots.svg'; // loading spinner img.style.height = "32px"; img.style.width = "32px"; parentElement.appendChild(img); fetchAndExtract(messageUrl, function(htmlDoc) { var closeButtons = addCloseButtonsListeners(confirmButton, rejectButton); var confirmClose = closeButtons.confirmClose; var denyClose = closeButtons.denyClose; updateMessageDOM(htmlDoc, confirmClose, denyClose); }); } else { console.log('Message link not found.'); } // AESTHETIC CHANGE var bottomElement = document.evaluate('//*[@id="list_messages_my_conversation_messages_items"]/div/div[3]/form/div', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; if (bottomElement && bottomElement.singleNodeValue) { bottomElement.classList.add('bottom-element'); bottomElement.singleNodeValue.style.marginTop = "1em"; bottomElement.singleNodeValue.style.marginBottom = "1em"; bottomElement.singleNodeValue.style.outline = "2px solid red"; bottomElement.singleNodeValue.classList.remove("bottom"); } }else if(window.location.href !== "https://www.camwhores.tv/my/videos/") { // Set to store unique video elements const processedVideos = new Set(); function addPrivateVideos() { const private_videos = []; const videoElements = document.querySelectorAll('.line-premium, .line-private'); videoElements.forEach(video => { const parentDiv = video.parentElement; if ( parentDiv.tagName === 'DIV' && parentDiv.parentElement.tagName === 'A' && !processedVideos.has(parentDiv.parentElement) ) { private_videos.push(parentDiv.parentElement); processedVideos.add(parentDiv.parentElement); } }); return private_videos; } async function checkVideoPage(url) { try { const response = await fetch(url); if (!response.ok) { console.error('Error loading video page:', response.status); return { byFriend: false, usernameID: null }; } const html = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const hasElement1 = doc.querySelector('body > div.container > div.content > div.block-video > div.video-holder > div.player > div > div > span') !== null; const hasElement2 = doc.querySelector('body > div.container > div.content > div.block-album > div.album-holder > div.images > span.message') !== null; // basically the "This video is a private video uploaded by" message const userURL = doc.querySelector('.username a').href; // let username = doc.querySelector("#tab_video_info > div > div.block-user > div.username").textContent.trim(); let usernameBlock = doc.querySelector("#tab_video_info > div > div.block-user > div.username > a") || doc.querySelector("#tab_album_info > div > div.block-user > div > a"); // console.log(usernameBlock) let username = usernameBlock?.textContent.trim(); var vid_code = userURL.replace("https://www.camwhores.tv/members/", ""); var usernameID = vid_code.split("/")[0]; return { byFriend: hasElement1 || hasElement2, usernameID: usernameID, username: username }; } catch (error) { console.error('Error checking video page:', error); return { byFriend: false, usernameID: null }; } } function moveToAltThumb(image) { const src = image.getAttribute('src'); const newSrc = src.replace('1.jpg', '5.jpg'); if (src && src.endsWith('1.jpg')) { image.setAttribute('src', newSrc); } } async function applyStyleToPrivateVideos() { const privateVideos = addPrivateVideos(); for (const video of privateVideos) { let imgElement = video.querySelector('div > img'); let videoLink = video.getAttribute('href'); let videoTitle = video.querySelector('strong.title').textContent.trim(); let { byFriend: hasElement, usernameID, username } = await checkVideoPage(videoLink); // console.log(videoLink, "is by:", username) // console.log(videoLink + " " + hasElement); if (!hasElement) { video.style.outline = 'green solid 2px'; const linePrivate = video.querySelector('div > .line-private'); if (linePrivate) { linePrivate.style.display = 'none'; } if (imgElement) { imgElement.style.opacity = '1'; } }else{ // add ❌ const linePrivate = video.querySelector('div > .line-private > span'); if (linePrivate) { linePrivate.textContent += ' ❌'; const addFriend = document.createElement('a'); addFriend.textContent = '➕'; addFriend.title = 'Friend request'; addFriend.href = "https://www.camwhores.tv/members/" + usernameID + "/#friends"; addFriend.style.zIndex = '10'; addFriend.style.position = 'absolute'; addFriend.style.bottom = '20px'; addFriend.style.right = '0'; addFriend.style.fontSize = '1rem'; addFriend.style.padding = '5px 2.5px'; addFriend.style.backgroundColor = 'hsla(0, 0%, 0%, 0.7)'; addFriend.addEventListener('click', function(event) { // alert(videoTitle) event.stopImmediatePropagation(); friendRequestSetup(videoTitle, videoLink, usernameID) }); let thumbDiv = video.querySelector('.img') thumbDiv.appendChild(addFriend); // video.style.outline = "2px solid red" } } if (alternative_thumbnails_users.includes(username)) { moveToAltThumb(imgElement); // console.log(username, "IS in",alternative_thumbnails_users) }else{ // console.log(username, "not in",alternative_thumbnails_users) } await new Promise(resolve => setTimeout(resolve, 25)); // avoid 503 } } applyStyleToPrivateVideos(); function findRelevantKeywords() { const titles = document.querySelectorAll('.title'); titles.forEach(title => { const originalText = title.innerHTML; highlight_keywords.forEach(keyword => { const regex = new RegExp(keyword, 'gi'); if (originalText.match(regex)) { const highlightedText = originalText.replace(regex, '<span style="color: green;">$&</span>'); title.innerHTML = highlightedText; } }); }); } findRelevantKeywords() setInterval(() => { applyStyleToPrivateVideos(); findRelevantKeywords() }, 500); if (window.location.href.startsWith("https://www.camwhores.tv/members/")) { // USER PROFILE function userProfileAsyncURL(uid,pageInt){ const utcTimestamp = new Date().getTime(); const pageID = pageInt.toString(); return "https://www.camwhores.tv/members/"+uid+"/?mode=async&function=get_block&block_id=list_videos_uploaded_videos&sort_by=&from_videos="+pageID+"&_="+utcTimestamp; } function numberBetweenParenthesis(text){ if(!text){ return } const matches = text.match(/\((\d+)\)/); if (matches && matches.length > 1) { return parseInt(matches[1]); } return null; } function getRoundedTotalPages(userVideosH2) { const text = userVideosH2?.textContent; let videos_total = numberBetweenParenthesis(text); return Math.ceil(videos_total / 5); } // console.log("getRoundedTotalPages():",getRoundedTotalPages(userVideosH2)); function updateVideoH2() { let userVideosH2 = document.querySelector('#list_videos_uploaded_videos .headline h2'); if(!userVideosH2){ return; } const rounded_videos_total = getRoundedTotalPages(userVideosH2); let newText = '/' + rounded_videos_total; // console.log(userVideosH2) if (rounded_videos_total !== null) { const innerHTML = userVideosH2.innerHTML.trim(); if (innerHTML.includes("Page")) { userVideosH2.innerHTML = innerHTML + newText; } }else{ console.log("rounded_videos_total is null inside updateVideoH2()") } return newText; } const userVideosH2 = document.querySelector('#list_videos_uploaded_videos .headline h2'); const rounded_videos_total = getRoundedTotalPages(userVideosH2); const userDescription = document.querySelector("div.block-profile > div.profile-list > div > div.about-me > div > em") const lastLogin = document.querySelector('div.block-profile > div.profile-list > div.margin-fix > div.last-login > div.item')?.textContent.trim(); const userId = window.location.href.split('/').slice(-2, -1)[0]; let secondsSinceOnline = convertToSeconds(lastLogin); let recentlyOnline = secondsSinceOnline <= 300; let h1 = document.querySelector("h1"); const country = document.querySelector('div.block-profile > div.profile-list > div.margin-fix > div.column > div:nth-child(1) > em'); const countryName = country.textContent.trim() let countryCode = contryCodesArray()[countryName] || []; const parent = document.querySelector('div.block-profile > div.profile-list > div.margin-fix > div.column > div:nth-child(1)'); function addSearchButton(){ let sortElement = document.querySelector("#list_videos_uploaded_videos > div.headline > div.sort"); if(sortElement){ let searchButton = document.createElement('div'); let span = document.createElement('span'); span.classList.add('icon', 'type-search'); let strong = document.createElement('strong'); strong.textContent = 'Search videos'; searchButton.classList.add('user-search'); searchButton.appendChild(strong); searchButton.appendChild(span); sortElement.parentNode.insertBefore(searchButton, sortElement); searchButton.addEventListener('click', searchDialog); } } addSearchButton() function searchDialog() { let dialog = document.createElement('div'); dialog.id = "search-dialog"; dialog.style.position = 'fixed'; dialog.style.top = '50%'; dialog.style.left = '50%'; dialog.style.transform = 'translate(-50%, -50%)'; dialog.style.backdropFilter = 'blur(5px)'; dialog.style.backgroundColor = 'rgb(0 0 0 / 44%)'; dialog.style.padding = '20px'; dialog.style.borderRadius = '10px'; dialog.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.1)'; dialog.style.zIndex = '1000'; let form = document.createElement('form'); let input = document.createElement('input'); input.type = 'text'; input.autofocus = true; input.placeholder = 'Search...'; input.style.marginRight = '5px'; input.style.padding = '5px'; input.placeholder = 'blowjob'; let submitButton = document.createElement('button'); submitButton.type = 'submit'; submitButton.style = 'padding: 5px;box-sizing: border-box;height: 30px;cursor:pointer;'; submitButton.textContent = 'Search'; form.appendChild(input); form.appendChild(submitButton); dialog.appendChild(form); document.body.appendChild(dialog); form.addEventListener('submit', function(event) { event.preventDefault(); if(input.value && input.value !== ""){ displayResults(input.value); } document.body.removeChild(dialog); }); } async function displayResults(input) { try { const resultList = document.createElement('div'); resultList.id = 'cum_search_results'; resultList.classList = "list-videos"; // Create a container div for the loading image const loadingContainer = document.createElement('div'); loadingContainer.style.textAlign = 'center'; // Center horizontally const loadingImage = document.createElement('img'); loadingImage.src = "https://samherbert.net/svg-loaders/svg-loaders/three-dots.svg"; loadingImage.alt = "Loading..."; loadingImage.style.width = "50px"; loadingImage.style.height = "50px"; loadingContainer.appendChild(loadingImage); document.querySelector("#list_videos_uploaded_videos").appendChild(loadingContainer); const resultObject = await videoSearch(userVideosH2, userId, input); loadingContainer.remove(); // Remove the loading image container resultList.innerHTML = ` <div class="headline" style="padding: 15px 5px 7px 5px;"> <h2>Search results</h2> </div>`; if (!resultObject || Object.keys(resultObject).length === 0) { resultList.textContent = "No results found"; } else { const boxDiv = document.createElement('div'); boxDiv.classList.add('box'); for (const video of Object.values(resultObject)) { const { url, imgSrc, duration, title } = video; const videoDiv = document.createElement('div'); videoDiv.classList.add('item'); videoDiv.style.marginLeft = "11px"; videoDiv.innerHTML = ` <a href="${url}" title="${title}"> <div class="img"> <img class="thumb lazy-load" src="${imgSrc}" alt="${title}" width="180" height="135" style="display: block;"> </div> <strong class="title">${title}</strong> <div class="wrap"> <div class="duration">${duration}</div> </div> </a>`; boxDiv.appendChild(videoDiv); } resultList.appendChild(boxDiv); } const listContainer = document.querySelector("#list_videos_uploaded_videos"); const existingResult = document.querySelector("#cum_search_results"); existingResult ? existingResult.replaceWith(resultList) : listContainer.insertAdjacentElement('afterend', resultList); } catch (error) { console.error("Error:", error); } } async function videoSearch(userVideosH2, uid, query) { let totalVideoPages = getRoundedTotalPages(userVideosH2); let approxTotalVideos = totalVideoPages*5; var timeoout = 75; if (approxTotalVideos > 500){ timeoout = approxTotalVideos / 5; } if (totalVideoPages !== null) { let resultArray = []; let fetchPromises = []; // Array to store fetch promises for (let pageInt = 1; pageInt <= totalVideoPages; pageInt++) { let nextFivePages = userProfileAsyncURL(uid, pageInt); let fetchPromise = new Promise((resolve, reject) => { setTimeout(() => { fetchAndParseHTML(nextFivePages, function(htmlDoc) { let videos = htmlDoc.querySelectorAll('div#list_videos_uploaded_videos_items div.item'); videos.forEach(video => { let title = video.querySelector('a').getAttribute('title'); let url = video.querySelector('a').getAttribute('href'); let imgSrc = video.querySelector('img').getAttribute('data-original'); let duration = video.querySelector('.duration').textContent.trim(); let isPrivate = video.classList.contains('private'); if (title.toLowerCase().includes(query.toLowerCase())) { resultArray.push({ title: title, private: isPrivate, url: url, imgSrc: imgSrc, duration: duration }); } }); resolve(); // Resolve the promise once fetchAndParseHTML is completed }); }, 75 * (pageInt - 1)); // Delay each fetch by 50ms }); fetchPromises.push(fetchPromise); } // Wait for all fetch promises to resolve await Promise.all(fetchPromises); return resultArray; } else { console.log("ERROR in totalVideoPages:", totalVideoPages); return null; } } function addButtonEventListener() { document.addEventListener('click', function(event) { var target = event.target; if (target && target.matches('a[data-action="ajax"]')) { const sessionStorageIndex = getCurrentUserVideoLocation(); if (sessionStorageIndex) { // console.log("Session storage index found:", sessionStorageIndex); waitForSessionStorageChange(); } else { console.log("Session storage index not found"); } } }); } function getCurrentUserVideoLocation() { let uid = currentUserID(); let userVideoLocation = uid + ":https://www.camwhores.tv/members/" + userId + "/#list_videos_uploaded_videos:params"; return sessionStorage.getItem(userVideoLocation); } function waitForSessionStorageChange() { // console.log("Waiting for session storage change"); const initialSessionStorageValue = getCurrentUserVideoLocation(); // console.log("Initial session storage value:", initialSessionStorageValue); const checkChangeInterval = setInterval(function() { const currentSessionStorageValue = getCurrentUserVideoLocation(); // console.log("Current session storage value:", currentSessionStorageValue); if (currentSessionStorageValue !== initialSessionStorageValue) { // console.log("Session storage value changed"); clearInterval(checkChangeInterval); updateVideoH2(); addSearchButton(); } }, 50); } if(recentlyOnline){ h1.textContent += " (online)"; h1.className = "online"; } let newDescription = userDescription.textContent.replace(/^[\s\t]+/, ''); userDescription.textContent = newDescription; // console.log("replaced:",newDescription) if (countryCode && countryName !== "no info") { country.remove(); const img = document.createElement('img'); img.src = `https://flagcdn.com/${countryCode}.svg`; img.width = 35; img.alt = countryName; img.title = countryName; img.style ="position:absolute;top: 50%;transform: translateY(-50%);left:4rem;" parent.appendChild(img); parent.style.position = "relative"; } updateVideoH2() addButtonEventListener() // console.log(friend_request_text) if (window.location.href.endsWith("#friends") && !window.location.href.includes("add_to_friends_done")) { var userVideoData,lastCumTitle,lastVidCode,lastUserID; let addButton = document.querySelector('a[href="#friends"][data-action="add_to_friends"]'); let textarea = document.getElementById('add_to_friends_message'); let lastAutoFriend = localStorage.getItem('last_auto_friend'); let userId = window.location.href.split('/').slice(-2, -1)[0]; let confirmButton = document.querySelector('input[name="confirm"]'); let retrievedData = JSON.parse(localStorage.getItem('last_cum_video_data')) || {}; if (retrievedData[userId]) { userVideoData = retrievedData[userId]; console.log(userVideoData); lastCumTitle = userVideoData.title; lastVidCode = userVideoData.videoId; lastUserID = userVideoData.userId; } else { console.log("No data found for this user."); } let pageTitle = document.title; let username = pageTitle.replace("'s Page", ""); if (textarea !== null && !addButton.classList.contains('done') && username !== lastAutoFriend && lastCumTitle !== null && addButton !== null) { textarea.value = ""; if(userId === lastUserID){ textarea.value += friend_request_text + " " + lastCumTitle + "\n##" + lastVidCode; } document.querySelector('input[type="submit"].submit[value="Invite"]').click(); localStorage.setItem('last_auto_friend', username); addButton.click(); // final submit button } // console.log(confirmButton) if(confirmButton) confirmButton.click(); if (history.length === 1) { window.close(); } // console.log("Should add?") }else if(window.location.href.includes("add_to_friends_done")){ let addButton = document.querySelector('a[href="#friends"][data-action="add_to_friends"]'); if (addButton !== null && !addButton.classList.contains('done')) { addButton.classList.add('done'); } if (history.length === 1) { window.close(); } } // console.log("document.hasFocus():",document.hasFocus()) // Wait for the whole document, including stylesheets and images, to be loaded window.addEventListener('load', function() { // console.log("loaded") setTimeout(function() { // console.log("timeouted") if (window.location.href.includes('#list_videos_my_uploaded_videos')) { console.log("scroll!"); const element = document.querySelector("#list_videos_uploaded_videos > div.headline"); if (element) { element.scrollIntoView({ behavior: 'smooth' }); } } }, 2000); // Adjust the delay as needed }); } // END of member profile if(window.location.href.startsWith("https://www.camwhores.tv/videos/")){ const element1 = document.querySelector('body > div.container > div.content > div.block-video > div.video-holder > div.player > div > div > span'); const element2 = document.querySelector('body > div.container > div.content > div.block-album > div.album-holder > div.images > span.message'); let username = document.querySelector('.username a').textContent.trim(); let userId = document.querySelector('.username a').getAttribute('href').split('/').slice(-2, -1)[0]; // console.log(userId) if (element1 !== null || element2 !== null) { const href = document.querySelector('#tab_video_info > div > div.block-user > div > a').href; fetch(href) .then(response => response.text()) .then(html => { const htmlDoc = new DOMParser().parseFromString(html, 'text/html'); const infoMessage = htmlDoc.querySelector('.info-message'); if (infoMessage && infoMessage.textContent.includes("is in your friends list.")) { const friends_string = "You're already friends! Reloading in 4 seconds"; (element1 || element2).textContent = friends_string; setInterval(() => { location.reload(); }, 4000); }else if(window.location.href.includes("please_check_friend")){ (element1 || element2).innerHTML += "<br><br>Friendship confirmed? Reloading in 4 seconds"; setInterval(() => { location.reload(); }, 4000); } else { console.log("Not friends!"); var infoElement = null; if(element1 !== null){ infoElement = element1 }else{ infoElement = element2 } let headline = document.querySelector('body > div.container > div.content > div.headline > h1'); if (headline !== null) { let title = headline.textContent.trim(); var currentUrl = window.location.href; friendRequestSetup(title, currentUrl, userId); const userProfileUrl = infoElement.querySelector('a').getAttribute('href') + "#friends"; // console.log(userProfileUrl) const toggleButton = document.createElement('a'); toggleButton.classList.add("button"); toggleButton.textContent = "Send request"; toggleButton.href = userProfileUrl toggleButton.style.display= "inline-block"; toggleButton.style.display= "#4e4e4e"; infoElement.appendChild(document.createElement('br')); infoElement.appendChild(toggleButton); } else { console.log("Element not found"); } // Screenshots document.querySelectorAll('.block-screenshots .item.private').forEach(function(el) { let newEl = document.createElement('a'); newEl.innerHTML = el.innerHTML; el.parentNode.replaceChild(newEl, el); let img = newEl.querySelector('img'); if(!img) { return; } img.src = img.getAttribute('data-original'); let srcThumb = img.getAttribute('data-original'); let srcBig = srcThumb.replace('/videos_screenshots/', '/videos_sources/').replace('/180x135/', '/screenshots/'); newEl.href = srcBig; newEl.classList.add('item'); newEl.setAttribute('rel', 'screenshots'); newEl.setAttribute('data-fancybox-type', 'image'); }); } // END not friends }) .catch(error => console.error('Error fetching:', error)); } function waitForElementExists(parent, selector) { return new Promise((resolve, reject) => { const observer = new MutationObserver((mutations, me) => { const element = parent.querySelector(selector); if (element) { resolve(element); me.disconnect(); } }); observer.observe(parent, { childList: true, subtree: true }); }); } function addDownloadLink(video) { const url = video.getAttribute('src'); const name = document.querySelector('.headline').innerText + '.mp4'; // Check if the download link already exists if (document.getElementById('downloadVideoLink')) return; // Create the download link const link = document.createElement('a'); link.id = 'downloadVideoLink'; link.innerText = 'Download'; link.href = url; link.download = name; link.classList = "toggle-button"; const li = document.createElement('li'); li.appendChild(link); const ul = document.querySelector('div.video-holder > div.video-info > div > div.info-buttons > div.tabs-menu > ul'); ul.insertBefore(li, ul.firstChild); } waitForElementExists(document.body, 'video') .then(video => addDownloadLink(video)) .catch(error => console.error('Error:', error)); } if (window.location.href.startsWith("https://www.camwhores.tv/playlists/")) { console.log("Playlist!"); let h1Element = document.querySelector('h1'); let playlistItem = document.querySelector('#playlist_view_playlist_view_items a'); let defaultTitle = playlistItem.querySelector('.title').textContent.trim(); let defaultHref = playlistItem.href; h1Element.textContent = defaultTitle; let openVidButton = document.createElement('a'); openVidButton.classList.add("button"); openVidButton.textContent = "Open video"; openVidButton.href = defaultHref; openVidButton.style.padding = "5px 5px 0 5px"; h1Element.parentElement.appendChild(openVidButton); document.addEventListener('click', function(e) { let playlistItem = e.target.closest('#playlist_view_playlist_view_items a'); if (playlistItem) { let videoTitle = playlistItem.querySelector('.title').textContent.trim(); let videoHref = playlistItem.href; console.log("Clicked", videoTitle); h1Element.textContent = videoTitle; openVidButton.href = videoHref; } }); } if(window.location.href.startsWith("https://www.camwhores.tv/edit-video/")){ document.querySelector('.section-title.expand[data-expand-id="tab_screenshots"]').click(); const elements = document.querySelectorAll("#tab_screenshots > div > div:nth-child(-n+5) > div.item-control > div.item-control-holder"); elements.forEach(element => { element.addEventListener('click', () => { document.querySelector('input.submit[value="Save"]').click(); if (history.length === 1) { window.close(); } }); }); // console.log("history.length:",history.length) } } // end of (NOT "/my/videos/") if (window.location.href === "https://www.camwhores.tv/my/") { // console.log("HELLO PROFILE") let profileCSS = document.createElement('style'); profileCSS.className = "profile-css"; profileCSS.textContent = ` #edit_profile_about_me{ height:225px; } strong.popup-title, span.selection [role="combobox"]{ display:none; } body > div.fancybox-overlay.fancybox-overlay-fixed > div{ top:0 !important; height: 100svh !important; } body > div.fancybox-overlay.fancybox-overlay-fixed, body > div.fancybox-overlay.fancybox-overlay-fixed > *{ box-sizing: border-box; } div.fancybox-inner{ height:100% !important; width: max-content !important; } .fancybox-close{ top:9px !important; } `; document.head.appendChild(profileCSS); } if (window.location.href == "https://www.camwhores.tv/" || window.location.href == "https://www.camwhores.tv") { // HOME PAGE homepage let listVideos = document.querySelector("body > div.container > div.list_videos > div"); let headline = document.querySelector("body > div.container > div.content > div.main-content > div.headline"); let featuredVideosDates = document.querySelectorAll("#list_videos_featured_videos_items div.added"); let latestVideoUpSeconds = convertToSeconds(featuredVideosDates[0].innerText); let latestStoredUpSeconds = parseInt(localStorage.getItem("cum_last_featuredVideoUpDate")); // console.log(latestStoredUpSeconds) let thereIsANewerVideo = latestVideoUpSeconds < latestStoredUpSeconds; // latest is less seconds old than the last stored function hideFtVideos(show){ if (show) { listVideos.style.display = 'block'; headline.style.paddingTop = '20px'; document.querySelector("#🆕")?.style?.setProperty("display", "none"); } else { listVideos.style.display = 'none'; headline.style.paddingTop = '10px'; localStorage.setItem("cum_last_featuredVideoUpDate", latestVideoUpSeconds) } } let showFeaturedVids = retrieveValueFromStorage("options")["cum_show_top"]; console.log(showFeaturedVids) // if(showFeaturedVids === undefined) saveOption("cum_show_top", false) hideFtVideos(showFeaturedVids); let isChecked = showFeaturedVids ? 'checked' : ''; document.querySelector("body > div.container > div.list_videos").insertAdjacentHTML('afterbegin', ` <label class="switch" title="Top videos" id="cum_switch_top"> <input type="checkbox" id="cum_show_top" ${isChecked}> <span class="slider round"></span> </label> `); let checkbox = document.querySelector('#cum_show_top'); checkbox.addEventListener('change', function() { let checked = this.checked; hideFtVideos(checked) saveOption("cum_show_top", checked) }); if(!showFeaturedVids && thereIsANewerVideo){ let newEmoji = document.createElement('span'); newEmoji.textContent = ' 🆕'; newEmoji.id = '🆕'; newEmoji.style = 'font-size:1.5rem;vertical-align:bottom;vertical-align:-webkit-baseline-middle' document.querySelector("body > div.container > div.list_videos").appendChild(newEmoji); }else{ console.log("!showFeaturedVids:",!showFeaturedVids," && thereIsANewerVideo:",thereIsANewerVideo,"because:",latestVideoUpSeconds,">=",latestStoredUpSeconds) } // featuredVideosDates.forEach(div => { // let seconds = convertToSeconds(div.innerText); // console.log(div.innerText, seconds) // }); } // ANY PAGE function myVideosAsyncURL(pageInt){ const utcTimestamp = new Date().getTime(); const pageID = pageInt.toString(); return "https://www.camwhores.tv/my/videos/?mode=async&function=get_block&block_id=list_videos_my_uploaded_videos&sort_by=&from_my_videos="+pageID+"&_="+utcTimestamp; } /* fetchAndParseHTML("https://www.camwhores.tv/my/", function(htmlDoc) { console.log(htmlDoc) });*/ function pagesLastProcessedVideo(page, callback) { fetchAndParseHTML(myVideosAsyncURL(page), function(htmlDoc) { const videoItems = htmlDoc.querySelectorAll("#list_videos_my_uploaded_videos_items > form > div.item.private"); let lastProcessingIndex = -1; for (let i = videoItems.length - 1; i >= 0; i--) { if (videoItems[i].classList.contains('processing')) { lastProcessingIndex = i; break; } } if (lastProcessingIndex !== -1 && lastProcessingIndex < videoItems.length - 1) { const precedingItem = videoItems[lastProcessingIndex + 1]; const checkbox = precedingItem.querySelector(".item-control-holder .toggle-button input[type='checkbox']"); if (checkbox) { callback(checkbox.value); return; } } callback(false); }); } function lastProcessedVideoID(callback) { var found = false; var completedIterations = 0; let maxPages = 3; for (var pageN = 1; pageN <= maxPages; pageN++) { (function(page) { pagesLastProcessedVideo(page, function(checkboxValue) { completedIterations++; // Increment the counter for each completed iteration if (checkboxValue && !found) { found = true; callback(checkboxValue); } else if (completedIterations === maxPages && !found) { // Check if all iterations have completed and no checkbox value is found callback(false); } }); })(pageN); } } function loadLastVideoData() { var jsonData = localStorage.getItem('lastVideoData'); if (!jsonData) { return [null, null]; // No stored data, return null values } var data = JSON.parse(jsonData); return data; } function lastVideoDataAge(refreshMinutes=30) { var data = loadLastVideoData(); if (!data[1]) { // Timestamp console.log("Force recheck") var bigTime = (refreshMinutes * 60) + 1; // bigTime = 0; return bigTime; // No stored timestamp, assume age is 0 seconds } var timestamp = data[1]; var currentTime = Date.now(); var elapsedTimeSeconds = (currentTime - timestamp) / 1000; return elapsedTimeSeconds; } function saveLastVideoID(callback) { const lastID = loadLastVideoData()[0]; lastProcessedVideoID(function(currentID) { var timestamp = Date.now(); var data = [currentID, timestamp]; // Include lastID and currentID in the data array var jsonData = JSON.stringify(data); localStorage.setItem('lastVideoData', jsonData); callback(lastID, currentID); // Invoke the callback with both lastID and currentID console.log("Last ID:", lastID, "\nCurrent ID:", currentID, "(https://www.camwhores.tv/edit-video/"+currentID+"/)"); }); } function alertNewVideo(newID){ let text = "A new video of yours has been published.\nGo to My Videos?"; let url = "/my/videos/"; if (confirm(text)) { window.location.href = url; } } function updateLastVideoData(minutes = 30){ const waitTime = minutes * 60; let ageOfCheck = lastVideoDataAge(refreshVideosMinutes); // let ageOfCheck = 31*60; // console.log("seconds passed:",ageOfCheck,"\nwaitTime:",waitTime,"\n") let minutesOfAge = Math.round(ageOfCheck / 60); if(ageOfCheck > waitTime){ saveLastVideoID(function(lastID, newID) { // console.log("lastID:",lastID,"\nnewID:",newID) if(newID && lastID && lastID !== newID){ alertNewVideo(newID); }else{ console.log("No new videos were published") // console.log("Still the same video ("+lastID,"==",newID+")") } }); } else { // console.log("Only",minutesOfAge, "minutes have passed since updateLastVideoData,",(minutes - minutesOfAge), "to go"); } } // console.log("notifyProcessedVideos:",notifyProcessedVideos) if(notifyProcessedVideos){ updateLastVideoData(refreshVideosMinutes); } // console.log(GM_info['script']['version']); function contryCodesArray(){return{"Andorra":"ad","United Arab Emirates":"ae","Afghanistan":"af","Antigua and Barbuda":"ag","Anguilla":"ai","Albania":"al","Armenia":"am","Angola":"ao","Antarctica":"aq","Argentina":"ar","American Samoa":"as","Austria":"at","Australia":"au","Aruba":"aw","Åland Islands":"ax","Azerbaijan":"az","Bosnia and Herzegovina":"ba","Barbados":"bb","Bangladesh":"bd","Belgium":"be","Burkina Faso":"bf","Bulgaria":"bg","Bahrain":"bh","Burundi":"bi","Benin":"bj","Saint Barthélemy":"bl","Bermuda":"bm","Brunei":"bn","Bolivia":"bo","Caribbean Netherlands":"bq","Brazil":"br","Bahamas":"bs","Bhutan":"bt","Bouvet Island":"bv","Botswana":"bw","Belarus":"by","Belize":"bz","Canada":"ca","Cocos (Keeling) Islands":"cc","DR Congo":"cd","Central African Republic":"cf","Republic of the Congo":"cg","Switzerland":"ch","Côte d'Ivoire (Ivory Coast)":"ci","Cook Islands":"ck","Chile":"cl","Cameroon":"cm","China":"cn","Colombia":"co","Costa Rica":"cr","Cuba":"cu","Cape Verde":"cv","Curaçao":"cw","Christmas Island":"cx","Cyprus":"cy","Czechia":"cz","Germany":"de","Djibouti":"dj","Denmark":"dk","Dominica":"dm","Dominican Republic":"do","Algeria":"dz","Ecuador":"ec","Estonia":"ee","Egypt":"eg","Western Sahara":"eh","Eritrea":"er","Spain":"es","Ethiopia":"et","European Union":"eu","Finland":"fi","Fiji":"fj","Falkland Islands":"fk","Micronesia":"fm","Faroe Islands":"fo","France":"fr","Gabon":"ga","United Kingdom":"gb","England":"gb-eng","Northern Ireland":"gb-nir","Scotland":"gb-sct","Wales":"gb-wls","Grenada":"gd","Georgia":"ge","French Guiana":"gf","Guernsey":"gg","Ghana":"gh","Gibraltar":"gi","Greenland":"gl","Gambia":"gm","Guinea":"gn","Guadeloupe":"gp","Equatorial Guinea":"gq","Greece":"gr","South Georgia":"gs","Guatemala":"gt","Guam":"gu","Guinea-Bissau":"gw","Guyana":"gy","Hong Kong":"hk","Heard Island and McDonald Islands":"hm","Honduras":"hn","Croatia":"hr","Haiti":"ht","Hungary":"hu","Indonesia":"id","Ireland":"ie","Israel":"il","Isle of Man":"im","India":"in","British Indian Ocean Territory":"io","Iraq":"iq","Iran":"ir","Iceland":"is","Italy":"it","Jersey":"je","Jamaica":"jm","Jordan":"jo","Japan":"jp","Kenya":"ke","Kyrgyzstan":"kg","Cambodia":"kh","Kiribati":"ki","Comoros":"km","Saint Kitts and Nevis":"kn","North Korea":"kp","South Korea":"kr","Kuwait":"kw","Cayman Islands":"ky","Kazakhstan":"kz","Laos":"la","Lebanon":"lb","Saint Lucia":"lc","Liechtenstein":"li","Sri Lanka":"lk","Liberia":"lr","Lesotho":"ls","Lithuania":"lt","Luxembourg":"lu","Latvia":"lv","Libya":"ly","Morocco":"ma","Monaco":"mc","Moldova":"md","Montenegro":"me","Saint Martin":"mf","Madagascar":"mg","Marshall Islands":"mh","North Macedonia":"mk","Mali":"ml","Myanmar":"mm","Mongolia":"mn","Macau":"mo","Northern Mariana Islands":"mp","Martinique":"mq","Mauritania":"mr","Montserrat":"ms","Malta":"mt","Mauritius":"mu","Maldives":"mv","Malawi":"mw","Mexico":"mx","Malaysia":"my","Mozambique":"mz","Namibia":"na","New Caledonia":"nc","Niger":"ne","Norfolk Island":"nf","Nigeria":"ng","Nicaragua":"ni","Netherlands":"nl","Norway":"no","Nepal":"np","Nauru":"nr","Niue":"nu","New Zealand":"nz","Oman":"om","Panama":"pa","Peru":"pe","French Polynesia":"pf","Papua New Guinea":"pg","Philippines":"ph","Pakistan":"pk","Poland":"pl","Saint Pierre and Miquelon":"pm","Pitcairn Islands":"pn","Puerto Rico":"pr","Palestine":"ps","Portugal":"pt","Palau":"pw","Paraguay":"py","Qatar":"qa","Réunion":"re","Romania":"ro","Serbia":"rs","Russia":"ru","Rwanda":"rw","Saudi Arabia":"sa","Solomon Islands":"sb","Seychelles":"sc","Sudan":"sd","Sweden":"se","Singapore":"sg","Saint Helena, Ascension and Tristan da Cunha":"sh","Slovenia":"si","Svalbard and Jan Mayen":"sj","Slovakia":"sk","Sierra Leone":"sl","San Marino":"sm","Senegal":"sn","Somalia":"so","Suriname":"sr","South Sudan":"ss","São Tomé and Príncipe":"st","El Salvador":"sv","Sint Maarten":"sx","Syria":"sy","Eswatini (Swaziland)":"sz","Turks and Caicos Islands":"tc","Chad":"td","French Southern and Antarctic Lands":"tf","Togo":"tg","Thailand":"th","Tajikistan":"tj","Tokelau":"tk","Timor-Leste":"tl","Turkmenistan":"tm","Tunisia":"tn","Tonga":"to","Turkey":"tr","Trinidad and Tobago":"tt","Tuvalu":"tv","Taiwan":"tw","Tanzania":"tz","Ukraine":"ua","Uganda":"ug","United States Minor Outlying Islands":"um","United Nations":"un","United States":"us","Uruguay":"uy","Uzbekistan":"uz","Holy See (Vatican City State)":"va","Saint Vincent and the Grenadines":"vc","Venezuela":"ve","British Virgin Islands":"vg","United States Virgin Islands":"vi","Vietnam":"vn","Vanuatu":"vu","Wallis and Futuna":"wf","Samoa":"ws","Kosovo":"xk","Yemen":"ye","Mayotte":"yt","South Africa":"za","Zambia":"zm","Zimbabwe":"zw"}} // retrieveValueFromStorage // saveValue function updateAlert(){ let lastCheck = retrieveValueFromStorage('lastVersionCheckDate'); // console.log("lastCheck:",lastCheck) let lastVersionCheckDate; if (!lastCheck) { lastVersionCheckDate = currentDate; } else { lastVersionCheckDate = new Date(lastCheck); } let dateDifference = currentDate - lastVersionCheckDate; // console.log("dateDifference:",dateDifference) if(dateDifference > 3 * 24 * 60 * 60 * 1000){ saveValue('lastVersionCheckDate', currentDate.toString()); fetchAndParseHTML(metaPage, (htmlDoc) => { const metaContent = htmlDoc.body.textContent; const metaVersionMatch = metaContent.match(/@version\s+([^\s]+)/); if (metaVersionMatch) { const latestVersion = metaVersionMatch[1]; console.log("Current version:",currentVersion,"Latest version:",latestVersion) if (latestVersion !== currentVersion){ if (confirm('A new version of the CUM script is available.\nPlease allow automatic updates or update it manually.\nOpen in new tab?')){ GM_openInTab("https://sleazyfork.org/en/scripts/491272-camwhores-tv-utilities-mod"); }else{ toggleChange(updateRemindersOptionName, false); console.log("Didn't confirm") } } } }); } } if(updateReminders){ updateAlert(); } })();