Sleazy Fork is available in English.

Camwhores.tv Utilities Mod

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.6.6
// @description  Info preview, removal of lock from friends' vidoes, restored upload button, and more.
// @author       vipprograms
// @match        https://www.camwhores.tv/*
// @grant        GM_xmlhttpRequest
// @grant        GM.getValue
// @grant        GM_getValue
// @grant        GM.setValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @grant        GM.registerMenuCommand
// @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, options;
    const refreshMessagesTimer = 2500;

    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); };
    }

    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")

    toggleChange(options, "alternative thumbnails", true)
    var altThumbs = retrieveValueFromStorage("options")["alternative thumbnails"];

    toggleChange(options, "message page auto refresh", true)
    var refreshMessagePage = retrieveValueFromStorage("options")["auto refresh message page"];

    toggleChange(options, "upload button restore", true)
    var restoreUploadButton = retrieveValueFromStorage("options")["restore upload button"];



    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;
  /*display: none !important;*/
  pointer-events: none !important;
}

    `;
    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){
    var vid_code = video_url.replace("https://www.camwhores.tv/videos/", "");
    var parts = vid_code.split("/");
    var videoId = parts[0];
    var code = parts[1];
    localStorage.setItem('last_cum_title', video_title);
    localStorage.setItem('last_cum_vid_id', videoId);
  }

       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;
    }
}


  // add the upload button back
  const nav = document.querySelector('.navigation .primary');
  if (restoreUploadButton && ![...nav.querySelectorAll('a')].some(link => link.textContent.trim().includes('Upload'))) {
    const uploadLink = document.createElement('a');
    uploadLink.href = '/upload-video/';
    uploadLink.style.backgroundColor = '#215521';
    uploadLink.textContent = 'Upload';
    nav.appendChild(uploadLink);
  }

     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/") {

        let fiveMinutesAgo = Date.now() - 5 * 60 * 1000;
        if(refreshMessagePage){
            $(document).ready(function() {
                var linkClicked = parseInt(localStorage.getItem("linkClicked")) > fiveMinutesAgo;
                console.log("Initial linkClicked value:", linkClicked);

                $(window).on("focus", function() {
                    localStorage.setItem("linkClicked", fiveMinutesAgo);
                    linkClicked = false;
                    console.log("Window is focused");
                    if (interval !== null) {
                        clearInterval(interval);
                    }
                });

                if (linkClicked) {
                        console.log("Reloading...");
                        var interval = setInterval(function() {
                            location.reload();
                        }, refreshMessagesTimer);
                }

                $(document).on("click auxclick", "a", function(event) {
                    var href = $(this).attr("href");
                    if (event.button === 0 || event.button === 1) {
                        // alert("You're trying to go to " + href);
                        localStorage.setItem("linkClicked", Date.now());
                        linkClicked = true;
                        console.log("Link clicked. Will refresh");
                    }
                });

                $(window).on("blur", function() {
                    console.log("Window blur event");
                    if (linkClicked) {
                        console.log("Reloading...");
                        var interval = setInterval(function() {
                            location.reload();
                        }, refreshMessagesTimer);
                    }
                });


            });

        }




        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 to add event listener to buttons
        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");

                    const h2Element = document.querySelector('#list_members_my_conversations div.headline h2');
                    const initialText = h2Element.textContent.trim();
                    // console.log("Initial text: " + initialText);
                    const checkChangeInterval = setInterval(function() {
                        const 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);
                }
            });
        }


        console.log("Calling functions to apply styles and process thumbnails");

        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()
            console.log("Updating status of users")
        }, 3000);


        const refreshIcon = document.createElement('span');
        refreshIcon.innerHTML = '&#8635;'; // 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 = '';
        });


        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>';
            }
        });





        document.addEventListener('keydown', function(event) {
          if (event.ctrlKey && event.key === 'Enter') {
            event.preventDefault();
            document.querySelector('#send_message_form input[type="submit"]').click();
          }
        });

          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 fetchAndExtract(url, callback) {
          // return
            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();

                    // Parse the response text into a HTML document
                    var parser = new DOMParser();
                    var htmlDoc = parser.parseFromString(response.responseText, "text/html");


                    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') });
                        }
                    }

                    // console.log(imgData);
                        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);
                        }

                  callback(htmlDoc);


                }
            });
        }


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;
    console.log(recentlyOnline);

    if (titleText) {
        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);
            }
        } else {
            console.log('Text inside parentheses in title not found.');
        }
    } 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)
                            friendRequestSetup(videoTitle, videoLink)
                        });


                        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/")) {
            console.log("NOT messages, user PROFILE");

          function updateH2Element() {
                const h2Element = document.querySelector('#list_videos_uploaded_videos .headline h2');

                if (h2Element) {
                    const text = h2Element.textContent;
                    const startIndex = text.indexOf('(');
                    const endIndex = text.indexOf(')', startIndex);

                    if (startIndex !== -1 && endIndex !== -1 && text.includes("Page")) {
                        const videos_total = parseInt(text.substring(startIndex + 1, endIndex));
                        const rounded_videos_total = Math.ceil(videos_total / 5);
                        const innerHTML = h2Element.innerHTML.trim();
                        if (!innerHTML.includes('/')) {
                            h2Element.innerHTML = innerHTML + '/' + rounded_videos_total;
                        }
                    }
                }
            }

            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");

                        const h2Element = document.querySelector('#list_videos_uploaded_videos .headline h2');
                        const initialText = h2Element.textContent.trim();
                        // console.log("Initial text: " + initialText);
                        const checkChangeInterval = setInterval(function() {
                            const h2Element = document.querySelector('#list_videos_uploaded_videos .headline h2');
                            const currentText = h2Element.textContent.trim();
                            // console.log("Current text: " + currentText);
                            if (currentText !== initialText) {
                                clearInterval(checkChangeInterval);
                                updateH2Element();
                            }
                        }, 100);
                    }
                });
            }


            updateH2Element()
            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 lastCumUsername = localStorage.getItem('last_cum_username_fr');
          let pageTitle = document.title;
          let username = pageTitle.replace("'s Page", "");
          if (textarea !== null && !addButton.classList.contains('done') && username !== lastCumUsername && lastCumTitle !== null && addButton !== null) {
              textarea.value = "";
              textarea.value += friend_request_text + " " + lastCumTitle + "\n##" + lastVidCode;
              console.log("Textarea text set");
              document.querySelector('input[type="submit"].submit[value="Invite"]').click();
              localStorage.setItem('last_cum_username_fr', username);
              addButton.click();
          }
      }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');
              }
      }


  } // 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');

            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);

                            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 defaultTitle = document.querySelector('#playlist_view_playlist_view_items a .title').textContent.trim();
    console.log("Default Title: " + defaultTitle);
    document.querySelector('h1').textContent = defaultTitle;

    document.addEventListener('click', function(e) {
        if (e.target.closest('#playlist_view_playlist_view_items a')) {
            let titleElement = e.target.closest('#playlist_view_playlist_view_items a').querySelector('.title');
            if (titleElement) {
                console.log("Clicked " + titleElement.textContent.trim());
                document.querySelector('h1').textContent = titleElement.textContent.trim();
            }
        }
    });
}








    }
})();