// ==UserScript==
// @name Camwhores.tv Utilities Mod
// @namespace https://sleazyfork.org/users/1281730-vipprograms
// @version 1.7.4
// @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 window.close
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAMUExURQAAAP8ANwwA/////7gbQJkAAAABdFJOUwBA5thmAAAAAWJLR0QDEQxM8gAAAAd0SU1FB+gDHhIuCjXV/h8AAAA4SURBVAjXY2ANDQ1gEA0NDWEIYWBgZAhgAAIUghEiC1YHBhpMDRpIhBbXghUMXKtWLWBgWqHVAACjlwz/pN0YPwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNC0wMy0zMFQxODo0NjowOSswMDowME+iXNIAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjQtMDMtMzBUMTg6NDY6MDkrMDA6MDA+/+RuAAAAKHRFWHRkYXRlOnRpbWVzdGFtcAAyMDI0LTAzLTMwVDE4OjQ2OjEwKzAwOjAwMNiA/AAAAABJRU5ErkJggg==
// @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;
function isArrayEmpty(arr) {
return arr.length === 0;
}
function retrieveValueFromStorage(key) {
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 toggleChange(options, optionName, defaultValue = false){
var updatedOptions;
var currentState = options[optionName] !== undefined ? options[optionName] : defaultValue;
_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] = defaultValue;
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:";
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"
}
optionsArrayEditor("auto_replies", optionsKeyLegible)
optionsArrayEditor("highlight_keywords", optionsKeyLegible)
optionsStringEditor("friend_request_text", optionsKeyLegible)
// BOOL OPTIONS
options = retrieveValueFromStorage("options")
optionName = "alternative thumbnails";
toggleChange(options, optionName, true)
var altThumbs = retrieveValueFromStorage("options")[optionName];
optionName = "restore upload button";
toggleChange(options, optionName, true)
var restoreUploadButton = retrieveValueFromStorage("options")[optionName];
optionName = "notify me of processed videos";
toggleChange(options, optionName, false)
var notifyProcessedVideos = retrieveValueFromStorage("options")[optionName];
const style = document.createElement('style');
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;
}
`;
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
};
localStorage.setItem('last_cum_video_add', JSON.stringify(cumData));
}
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:",getCurrentPage)
return paramsValue;
}
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 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;
}
}
let currentUID = currentUserID();
// console.log("User ID:", currentUID, "(https://www.camwhores.tv/members/" + currentUID + "/)")
silentUidUpdater()
// UPLOAD button
const nav = document.querySelector('.navigation .primary');
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 {
alert("Upload functionality is currently fully disabled\n(" + status.toString() + ")");
// console.log(status)
}
});
});
}else{
console.log("Couldn't restoreUploadButton", restoreUploadButton)
}
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())
function currentPageInfo() {
let urlToPage = myMessagesAsyncURL(getCurrentPage());
// 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 fixUnreadItem() {
const infoArray = await currentPageInfo();
infoArray.forEach(item => {
const conversationLink = document.querySelector(`#list_members_my_conversations_items > div.item > a[title="${item.name}"]`);
if (conversationLink) {
const unreadNotification = conversationLink.querySelector('div.img .unread-notification');
if (unreadNotification && !item.unread) {
unreadNotification.remove();
console.log("Message with",item.name,"was read")
}
}
});
}
// fixUnreadItem();
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 + '"]');
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()
fixUnreadItem()
silentUidUpdater()
}, 5000);
const refreshIcon = document.createElement('span');
refreshIcon.innerHTML = '↻'; // Unicode for refresh icon
refreshIcon.title = 'Refresh Utilities Mod';
refreshIcon.style.cursor = 'pointer';
refreshIcon.style.marginLeft = '10px'; // Adjust margin as needed
refreshIcon.addEventListener('click', function() {
processThumbnails()
console.log('Refreshing...');
});
const h2Element = document.querySelector('#list_members_my_conversations .headline h2');
// console.log("adding..?")
h2Element.appendChild(refreshIcon);
}else if(window.location.href.startsWith("https://www.camwhores.tv/my/messages/")) {
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)
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) {
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 seconds = convertToSeconds(lastLogin);
let recentlyOnline = seconds <= 300;
// let recentlyOnline = true;
const headlineH2 = document.querySelector('#list_messages_my_conversation_messages .headline h2');
console.log("recentlyOnline:", recentlyOnline);
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
updateButtonStyle(confirmButton, true);
updateButtonStyle(confirmClose, true);
var generatedTextDiv = document.createElement('div');
generatedTextDiv.id = 'gen_joined_text';
generatedTextDiv.innerHTML = `Joined ${joinedDateText}<br>${extractedTitle[1]} videos, last ${lastUploadTime}`;
var messageDiv = document.querySelector('#list_messages_my_conversation_messages_items > div > div:nth-child(3)');
if (messageDiv) {
messageDiv.appendChild(generatedTextDiv);
}
}
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; // 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);
// Check if the response status code indicates an error
if (!response.ok) {
console.error('Error loading video page:', response.status);
return { byFriend: true, usernameID: null }; // Return true if there's an error loading the page
}
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;
var vid_code = userURL.replace("https://www.camwhores.tv/members/", "");
var usernameID = vid_code.split("/")[0];
return { byFriend: hasElement1 || hasElement2, usernameID: usernameID };
} catch (error) {
console.error('Error checking video page:', error);
return { byFriend: false, usernameID: null };
}
}
async function applyStyleToPrivateVideos() {
const privateVideos = addPrivateVideos();
for (const video of privateVideos) {
let videoLink = video.getAttribute('href');
let videoTitle = video.querySelector('strong.title').textContent.trim();
let { byFriend: hasElement, usernameID } = await checkVideoPage(videoLink);
// 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';
}
let imgElement = video.querySelector('div > img');
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"
}
}
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()
// Define a global array to store blacklisted image sources
const blacklist = [];
function moveToSecondThumbnail() {
$('.thumb.lazy-load').off('mouseover').off('mouseout');
document.querySelectorAll('.thumb.lazy-load').forEach(image => {
const src = image.getAttribute('src');
if (blacklist.includes(src)) {
return;
}
const newSrc = src.replace('1.jpg', '2.jpg');
// console.log("ye")
if (src && src.endsWith('1.jpg')) {
image.setAttribute('src', newSrc);
}
const images = ['3.jpg', '4.jpg', '5.jpg', '1.jpg', '2.jpg'];
let currentIndex = 0;
let intervalId;
const loopImages = () => {
if (src && src.endsWith('jpg')) {
const newSrcName = images[currentIndex];
const newSrc = src.substring(0, src.length - 5) + newSrcName;
// console.log(newSrc)
image.setAttribute('src', newSrc);
currentIndex = (currentIndex + 1) % images.length;
}
};
const mouseoverHandler = () => {
clearInterval(intervalId);
intervalId = setInterval(loopImages, 500);
};
const mouseoutHandler = () => {
if (src && src.endsWith('1.jpg') && !(blacklist.includes(src))) {
image.setAttribute('src', newSrc);
}
clearInterval(intervalId);
};
// Create a new image element to check if the original image was loaded successfully
const testImage = new Image();
testImage.src = src;
testImage.onload = function() {
// Image loaded successfully
// console.log('Image loaded successfully:', src);
};
testImage.onerror = function() {
// Image failed to load (404 error)
// console.log('Image failed to load (404 error):', src);
blacklist.push(src);
image.setAttribute('src', src);
// Remove previous mouseover and mouseout event listeners
image.removeEventListener('mouseover', mouseoverHandler);
image.removeEventListener('mouseout', mouseoutHandler);
};
// Add mouseover and mouseout event listeners
image.addEventListener('mouseover', mouseoverHandler);
image.addEventListener('mouseout', mouseoutHandler);
});
// console.log(blacklist);
}
altThumbs && moveToSecondThumbnail();
setInterval(() => {
applyStyleToPrivateVideos();
findRelevantKeywords()
altThumbs && moveToSecondThumbnail();
}, 750); // Interval in milliseconds (every second)
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 seconds = convertToSeconds(lastLogin);
let recentlyOnline = seconds <= 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 videoSearch(userVideosH2, uid, query) {
let videosTotal = getRoundedTotalPages(userVideosH2);
if (videosTotal !== null) {
let resultArray = [];
for (let pageInt = 1; pageInt <= videosTotal; pageInt++) {
let nextFivePages = userProfileAsyncURL(uid, pageInt);
// console.log(nextFivePages)
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.includes(query)) {
resultArray.push({
private: isPrivate,
url: url,
imgSrc: imgSrc,
duration: duration
});
}
});
});
}
return resultArray;
}
return null;
}
// let search = videoSearch(userVideosH2, userId, "Becky");
// console.log(search)
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();
}
}, 50);
}
if(recentlyOnline){
h1.textContent += " (online)";
h1.className = "online";
}
userDescription.textContent = userDescription.textContent.replace(/^[\s\t]+/, '');
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")) {
let addButton = document.querySelector('a[href="#friends"][data-action="add_to_friends"]');
let textarea = document.getElementById('add_to_friends_message');
// let lastCumTitle = localStorage.getItem('last_cum_title');
// let lastVidCode = localStorage.getItem('last_cum_vid_id');
let lastAutoFriend = localStorage.getItem('last_auto_friend');
let userId = window.location.href.split('/').slice(-2, -1)[0];
// console.log(userId)
let retrievedData = JSON.parse(localStorage.getItem('last_cum_video_add'));
let lastCumTitle = retrievedData.title;
let lastVidCode = retrievedData.videoId;
let lastUserID = retrievedData.userId;
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
if(!document.hasFocus()){
window.close();
}
}else if(!document.hasFocus() && addButton.classList.contains('done')){
window.close();
}
}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');
}
}
// console.log("document.hasFocus():",document.hasFocus())
} // 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 {
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));
}
}
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;
}
});
}
} // 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);
}
// 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,",(minutes - minutesOfAge), "to go");
}
}
// console.log("notifyProcessedVideos:",notifyProcessedVideos)
if(notifyProcessedVideos){
updateLastVideoData(refreshVideosMinutes);
}
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",
"Vatican City (Holy See)": "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"}
}
})();