Camwhores.tv Utilities Mod

Info preview, removal of lock from friends' vidoes, restored upload button, and more.

Fra 07.08.2024. Se den seneste versjonen.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Camwhores.tv Utilities Mod
// @namespace    https://sleazyfork.org/users/1281730-vipprograms
// @version      1.14.0
// @description  Info preview, removal of lock from friends' vidoes, restored upload button, and more.
// @author       vipprograms
// @match        https://www.camwhores.tv/*
// @exclude      *.camwhores.tv/*mode=async*
// @grant        GM_xmlhttpRequest
// @grant        GM.getValue
// @grant        GM_getValue
// @grant        GM.setValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @grant        GM.registerMenuCommand
// @grant        GM_addStyle
// @grant        GM_download
// @grant        GM_openInTab
// @grant        window.close
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAMUExURQAAAP8ANwwA/////7gbQJkAAAABdFJOUwBA5thmAAAAAWJLR0QDEQxM8gAAAAd0SU1FB+gDHhIuCjXV/h8AAAA4SURBVAjXY2ANDQ1gEA0NDWEIYWBgZAhgAAIUghEiC1YHBhpMDRpIhBbXghUMXKtWLWBgWqHVAACjlwz/pN0YPwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNC0wMy0zMFQxODo0NjowOSswMDowME+iXNIAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjQtMDMtMzBUMTg6NDY6MDkrMDA6MDA+/+RuAAAAKHRFWHRkYXRlOnRpbWVzdGFtcAAyMDI0LTAzLTMwVDE4OjQ2OjEwKzAwOjAwMNiA/AAAAABJRU5ErkJggg==
// @require      https://cdn.jsdelivr.net/npm/@violentmonkey/shortcut@1
// @require      https://code.jquery.com/jquery-3.7.1.slim.min.js
// ==/UserScript==

(function () {
    'use strict';


    let _GM_registerMenuCommand, _GM_notification, options, optionName;
    let backgroundChecksMinutes = 60;

    const { register } = VM.shortcut;
    const currentVersion = GM_info.script.version;
    const currentDate = new Date();
    const metaPage = "https://update.sleazyfork.org/scripts/491272/Camwhorestv%20Utilities%20Mod.meta.js";
    const capitalize = s => (s && s[0].toUpperCase() + s.slice(1)) || "";
    const isArrayEmpty = arr => !arr.length;
    const processedVideos = new Set();

    VM.shortcut.register('c-i', () => {
        console.log('You just pressed Ctrl-I');
    });

    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 saveValue(key, array) {
        GM.setValue(key, array).then(function () {
            console.log("Array saved successfully.");
        }).catch(function (error) {
            console.error("Error saving array:", error);
        });
    }

    function saveArraySettings(arrayName, optionName, currentValue) {
        let settings = retrieveValueFromStorage(arrayName) || {};
        settings[optionName] = currentValue;
        saveValue(arrayName, settings);
    }


    function retrieveValueFromStorage(key) {
        if (typeof GM_getValue === "function") {
            return GM_getValue(key, false);
        }
        if (typeof GM === "object" && typeof GM.getValue === "function") {
            return GM.getValue(key, false).then(value => value);
        }
        console.error("Unsupported userscript manager.");
        return undefined;
    }

    function toggleChange(optionName, defaultValue = false, negativeDont = false) { // ONLY for menu commands
        let options = retrieveValueFromStorage("options") || {};
        let currentState = options[optionName] !== undefined ? options[optionName] : defaultValue;

        let commandLabel = negativeDont ? (currentState ? `Don't ${optionName}` : capitalize(optionName))
            : (currentState ? `Disable ${optionName}` : `Enable ${optionName}`);

        _GM_registerMenuCommand(commandLabel, () => {
            options[optionName] = !currentState;
            saveValue("options", options);
            setTimeout(() => location.reload(), 500);
        });

        if (options[optionName] === undefined) {
            options[optionName] = defaultValue;
            saveValue("options", options);
        }
    }

    function createForm(array_name, delimitedString) {
        return new Promise((resolve, reject) => {
            const form = document.createElement('form');
            form.className = 'form-container';
            form.innerHTML = `
            <textarea class="textarea-input" autofocus>${delimitedString}</textarea>
            <div class="buttons-line">
                <button type="button" class="cancel-button">Cancel</button>
                <button type="submit" class="submit-button">Submit</button>
            </div>`;
            document.body.appendChild(form);

            const removeForm = (message) => {
                document.body.removeChild(form);
                reject(message);
            };

            form.querySelector('.cancel-button').onclick = () => removeForm('Form cancelled');
            window.onclick = (event) => !form.contains(event.target) && removeForm('Form cancelled');

            form.onsubmit = (event) => {
                event.preventDefault();
                const inputValue = form.querySelector('textarea').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]}`, async () => {
            const originalString = retrieveValueFromStorage(string_name);
            const lines = await createForm(string_name, originalString);
            saveValue(string_name, lines.join('\n'));
        });
    }

    let 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"];
    let highlight_keywords_default = ['joi', 'cei', 'fuck', "cumshot"];
    let friend_request_text_default = "Hi! I'm interested in this video:";
    let alternative_thumbnails_users = ['deathstar45', 'usualsuspekt', 'MrPussyGod', 'peacebitch', 'ADCGHN11123', 'Garbage Pile'];

    let auto_replies = retrieveValueFromStorage("auto_replies");
    let highlight_keywords = retrieveValueFromStorage("highlight_keywords");
    let friend_request_text = retrieveValueFromStorage("friend_request_text");

    if (!auto_replies) {
        auto_replies = auto_replies_default;
        saveValue("auto_replies", auto_replies_default);
    }
    if (!highlight_keywords) {
        highlight_keywords = highlight_keywords_default;
        saveValue("highlight_keywords", highlight_keywords_default);
    }
    if (!friend_request_text) {
        friend_request_text = friend_request_text_default;
        saveValue("friend_request_text", friend_request_text_default);
    }


    var optionsKeyLegible = {
        auto_replies: "template replies",
        highlight_keywords: "highlight keywords",
        friend_request_text: "friend requests text",
        alternative_thumbnails_users: "users with bad default thumbnails"
    }
    optionsArrayEditor("auto_replies", optionsKeyLegible)
    optionsArrayEditor("highlight_keywords", optionsKeyLegible)
    optionsStringEditor("friend_request_text", optionsKeyLegible)


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

    optionName = "notify me of processed videos";
    toggleChange(optionName, false)
    var notifyProcessedVideos = retrieveValueFromStorage("options")[optionName];

    let updateRemindersOptionName = "update reminders";
    toggleChange(updateRemindersOptionName, true)
    var updateReminders = retrieveValueFromStorage("options")[updateRemindersOptionName];

    optionName = "blur images";
    toggleChange(optionName, false, true); // name, default, don't as negative
    let blurImages = retrieveValueFromStorage("options")[optionName];



    const style = document.createElement('style');
    // custom CSS
    style.textContent = `a.button {color: dimgrey !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;}.button:hover {color: #f56c08 !important;background: #1e1e1e;}div.img span.unread-notification {background: #c45606ab;backdrop-filter: blur(5px) brightness(1);top: 0;left: 0;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, .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: rgba(0, 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.fp-brand {opacity: 0 !important;pointer-events: none !important;}div.block-profile > div > div > div.about-me > div > em {white-space: pre;}h1.online:after {content: '';height: .45rem;aspect-ratio: 1;display: inline-block;background-color: green;position: relative;left: .5rem;border-radius: 50%;bottom: .1rem;}div.block-profile > div > div > div.about-me > div {width: 100%;box-sizing: border-box;}div.block-profile > div > div > div.about-me > div > em {width: 100%;display: inline-block;word-break: auto-phrase;word-wrap: break-word;box-sizing: border-box;text-wrap: pretty;}

   .user-search {float: right;position: relative;margin-left: 3px;cursor: pointer;background: linear-gradient(to bottom, #f1f1f1 0%, #d8d8d8 100%);border-radius: 2px;padding: 0;}
    .user-search strong {display: block;font-size: 12px;line-height: 15px;padding: 5px 12px 5px 28px;white-space: nowrap;color: #4e4e4e;cursor: pointer;max-width: 200px;overflow: hidden;}
    .user-search .type-search {background: url('https://shrph.altervista.org/img/search.png') 5px 4px no-repeat;}
    .user-search .icon {display: block;position: absolute;width: 100%;height: 100%;top: 0;}
    .user-search:hover {
    background: linear-gradient(to bottom, #e1e1e1 0%, #c8c8c8 100%);
}

.user-search:active {
    background: linear-gradient(to bottom, #d1d1d1 0%, #b8b8b8 100%);
}

.user-search:hover strong {
    color: #333;
}

.user-search:active strong {
    color: #111;
}

    #tab_screenshots > div > .item, #tab_screenshots > div > .item > .img {width: 250px;height: auto;}
    @keyframes fadeAnimation {0% {opacity: 1;}50% {opacity: .3;}100% {opacity: 1;}}.fade {animation: fadeAnimation 1s infinite;}.switch {position: relative;display: inline-block;width: 30px;height: 17px;}.switch input {opacity: 0;width: 0;height: 0;}.slider {position: absolute;cursor: pointer;top: 0;left: 0;right: 0;bottom: 0;background-color: #ccc;transition: .4s;}.slider:before {position: absolute;content: "";height: 13px;width: 13px;left: 2px;bottom: 2px;background-color: white;transition: .4s;}input:checked + .slider {background-color: #f56c08;}input:focus + .slider {box-shadow: 0 0 1px #F28022;}input:checked + .slider:before {transform: translateX(13px);}.slider.round {border-radius: 17px;}.slider.round:before {border-radius: 50%;}.list-comments .dim-comment {background-color: #9e1e1e2b;background-image: none;}.list-comments .dim-comment p {opacity: 1;}
`;
    // old:

    //  style.textContent = `a.button{color:#4e4e4e !important;}ul > li.next, ul > li.prev {display: list-item !important;}.item:hover > a > div.img > .friends-tag, .item:hover > a > div.img > .videos-tag{background-color:#1a1a1a !important;}.button{color: rgb(183, 176, 167);text-align: center;border: 1px solid transparent;font-size: 14px;padding: 5px 10px;cursor: pointer;background: linear-gradient(to bottom, #ffffff 0%, #cccccc 100%);border-radius: 3px;display: inline-block;margin: 0 .3rem .3rem 0;color: dimgrey;}.button:hover{color: #f56c08 !important;border: 1px solid transparent;background: #1e1e1e;}div.img span.unread-notification{background: #c45606ab;backdrop-filter: blur(5px) brightness(1);top: 0px;left: 0px;border-bottom-left-radius: 3px;border-bottom-right-radius: 3px;outline: 3px solid #f56c08;animation: glow 5s infinite;}@keyframes glow {0% {outline-color: #f56c08d6;}50% {outline-color: transparent;}100% {outline-color: #f56c08d6;}}.form-container {box-sizing: border-box;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);max-width: 100vw;width: 800px;padding: 2.5rem;border-radius: .25rem;z-index:99999;background-color: transparent !important;backdrop-filter: blur(1rem) brightness(.8) contrast(1.2) }.form-container * {box-sizing: inherit;}.textarea-input {width: 100%;min-height: 10rem;padding: 1rem;border-radius: .25rem;color-scheme: dark !important;}.buttons-line {margin-top: .3rem;gap:.3rem;width: 100%;display: flex;}.submit-button:hover, .cancel-button:hover{filter: brightness(.8) contrast(1.2) }.submit-button, .cancel-button{transform: .3s;}.submit-button {height: 50px;flex-grow: 1;cursor: pointer;border-radius: .25rem;color-scheme: dark !important;font-weight:bold;border:0;}.cancel-button {width:min-content;height: 50px;cursor: pointer;border-radius: .25rem;color-scheme: dark !important;background-color: red;font-weight:bold;padding-inline:.5rem;border:0;}input.accept-button, span.accept-button {color: #fff;background-image: linear-gradient(rgb(0, 128, 0) 0%, rgb(0, 255, 0) 100%);}input.accept-button:hover, span.accept-button:hover {color: #fff !important;background-image: linear-gradient(rgb(34, 139, 34) 0%, rgb(50, 205, 50) 100%) !important;}input.reject-button, span.reject-button {color: #fff;background-image: linear-gradient(rgb(255, 0, 0) 0%, rgb(128, 0, 0) 100%);}input.reject-button:hover, span.reject-button:hover {color: #fff !important;background-image: linear-gradient(rgb(220, 20, 60) 0%, rgb(178, 34, 34) 100%) !important;}#vid_previews {display: flex;flex-wrap: nowrap;height: 135px;margin-block: .5rem;gap: 5px;box-sizing: border-box;}#vid_previews .img-div {width:185px;height:100%;position: relative;box-sizing: inherit;}.list-messages .added {position: absolute;right: 0;}.list-messages .item {margin-right: 0;}#vid_previews .img-div img{box-sizing: inherit;width: 100%;height:100%;}#vid_previews .img-div h2{position: absolute;bottom: 0;background-color: rgb(0 0 0 / 65%);font-size: 1rem;line-height: 1.2rem;backdrop-filter: blur(5px);color: rgb(196 196 196);width: 100%;word-wrap: break-word;box-sizing: inherit;text-align: center;}.bottom-element{margin-top: 1em;margin-bottom: 1em;}form .bottom{padding-top: .5rem;}form .bottom .submit{float: initial;height: auto;padding: .45rem .5rem;margin: 0;}.margin-fix .bottom{margin:0;}#gen_joined_text{margin: .5rem 0 .25rem 0;}a[href="http://flowplayer.org"], a[class="fp-brand"]{opacity: 0 !important;pointer-events: none !important;}div.block-profile > div > div > div.about-me > div > em{white-space:pre;}h1.online:after{content: '';height: .45rem;aspect-ratio: 1;display: inline-block;background-color: green;position: relative;left: .5rem;border-radius: 50%;bottom: .1rem;}div.block-profile > div > div > div.about-me > div{width: 100%;box-sizing: border-box;}div.block-profile > div > div > div.about-me > div>em{width: 100%;display: inline-block;word-break: auto-phrase;word-wrap: break-word;box-sizing: border-box;text-wrap: pretty;}.user-search {float: right;position: relative;margin-left: 3px;cursor: pointer;background: #f1f1f1;background: linear-gradient(to bottom, #f1f1f1 0%, #d8d8d8 100%);border-radius: 2px;padding:0;}.user-search strong {display: block;font-size: 12px;line-height: 15px;padding: 5px 12px 5px 28px;white-space: nowrap;color: #4e4e4e;cursor: pointer;max-width: 200px;overflow: hidden;}.user-search .type-search {background: url('https://shrph.altervista.org/img/search.png') 5px 4px no-repeat;}.user-search .icon {display: block;position: absolute;width: 100%;height: 100%;top:0;}#tab_screenshots > div > .item, #tab_screenshots > div > .item > .img {width: 250px;height: auto;}#tab_screenshots > div > .item > .img {}@keyframes fadeAnimation {0% {opacity: 1;}50% {opacity: .3;}100% {opacity: 1;}}.fade {animation: fadeAnimation 1s infinite;}.switch {position: relative;display: inline-block;width: 30px;height: 17px;}.switch input {opacity: 0;width: 0;height: 0;}.slider {position: absolute;cursor: pointer;top: 0;left: 0;right: 0;bottom: 0;background-color: #ccc;-webkit-transition: .4s;transition: .4s;}.slider:before {position: absolute;content: "";height: 13px;width: 13px;left: 2px;bottom: 2px;background-color: white;-webkit-transition: .4s;transition: .4s;}input:checked + .slider {background-color: #f56c08;}input:focus + .slider {box-shadow: 0 0 1px #F28022;}input:checked + .slider:before {-webkit-transform: translateX(13px);transform: translateX(13px);}.slider.round {border-radius: 17px;}.slider.round:before {border-radius: 50%;}.list-comments .dim-comment p {opacity: 1;}.list-comments .dim-comment {background-color: #9e1e1e2b;background-image: none;}
    //  `;
    document.head.appendChild(style);


    function isNotPage(...pages) {
        const currentUrl = window.location.href.split(/[?#]/)[0];
        return !pages.includes(currentUrl);
    }

    function makeValidUrlString(inputString) {
        var validString = inputString.replace(/[^\w\s\/-]/g, ''); // Remove special characters
        validString = validString.replace(/[-_]{2,}/g, '-'); // Turn consecutive underscores or hyphens into single hyphens
        validString = validString.replace(/\s+/g, '-'); // Turn spaces into hyphens
        validString = validString.replace(/\//g, '-'); // Turn slashes into hyphens
        return validString;
    }

    function friendRequestSetup(video_title, video_url, userID) {
        var vid_code = video_url.replace("https://www.camwhores.tv/videos/", "");
        var parts = vid_code.split("/");
        var videoId = parts[0];
        var code = parts[1];
        let cumData = {
            title: video_title,
            videoId: videoId,
            userId: userID
        };

        let lastCumVideoAdd = JSON.parse(localStorage.getItem('last_cum_video_data')) || {};
        lastCumVideoAdd[userID] = cumData;
        localStorage.setItem('last_cum_video_data', JSON.stringify(lastCumVideoAdd));

    }

    function convertToSeconds(timeString) {
        const [_, value, unit] = timeString.match(/(\d+) (\w+)/);
        const conversion = {
            second: 1,
            seconds: 1,
            minute: 60,
            minutes: 60,
            hour: 3600,
            hours: 3600,
            day: 86400,
            days: 86400,
            week: 604800,
            weeks: 604800,
            month: 2592000, // 30 days
            months: 2592000, // 30 days
            year: 31536000, // 365 days
            years: 31536000 // 365 days
        };
        return value * (conversion[unit] || 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();
                const htmlDoc = new DOMParser().parseFromString(response.responseText, "text/html");
                callback(htmlDoc);
            }
        });
    }

    function getAllSessionStorage() {
        const sessionStorageItems = {};
        for (let i = 0; i < sessionStorage.length; i++) {
            const key = sessionStorage.key(i);
            sessionStorageItems[key] = sessionStorage.getItem(key);
        }
        return sessionStorageItems;
    }

    function getCurrentPage() {
        const allSessionStorage = getAllSessionStorage();
        const paramsStorageKey = Object.keys(allSessionStorage).find(key => key.endsWith(":params"));
        if (!paramsStorageKey) return 1;

        const paramsValue = JSON.parse(allSessionStorage[paramsStorageKey])?.from_my_conversations;
        return parseInt(paramsValue, 10) || 1;
    }

    function setUploadButtonTimestamp() {
        localStorage.setItem('UploadButtonTimestamp', JSON.stringify(Date.now()));
    }

    function getCookie(name) {
        let cookieArr = document.cookie.split("; ");
        for (let cookie of cookieArr) {
            let [key, value] = cookie.split("=");
            if (key === name) return value;
        }
        return null;
    }

    function loadArrayLocalStorage(name = 'lastVideoData') {
        var jsonData = localStorage.getItem(name);
        if (!jsonData) {
            return [];
        }

        var data = JSON.parse(jsonData);
        return data;
    }

    function saveArrayLocalStorage(name='lastVideoData',data) {
        var timestamp = Date.now();
        var jsonData = JSON.stringify(data);
        localStorage.setItem(name, jsonData);
    }

    function secondsSinceLocalStorage(name) {
        const storedItem = JSON.parse(localStorage.getItem(name));
        return storedItem ? (Date.now() - storedItem.timestamp) / 1000 : null;
    }

    function getNewUID() {
        const sessionStorageData = getAllSessionStorage();
        if (!sessionStorageData) return null;

        for (const key in sessionStorageData) {
            const match = key.match(/^(\d+):https:\/\/www\.camwhores\.tv/);
            if (match) return match[1];
        }
        return null;
    }

    function saveUID() {
        const uid = getNewUID();
        if (uid) {
            const current_kt = getCookie("kt_member");
            saveArrayLocalStorage("cum_user_id", { uid, kt: current_kt });
            return uid;
        }
        return null;
    }

    function silentUidUpdater() {
        const uidArray = loadArrayLocalStorage("cum_user_id");
        if (!uidArray || getCookie("kt_member") !== uidArray.kt) {
            saveUID();
        }
    }

    function currentUserID() {
        const current_kt = getCookie("kt_member");
        const uidArray = loadArrayLocalStorage("cum_user_id");

        return uidArray && uidArray.kt === current_kt ? uidArray.uid : saveUID();
    }

    async function getResponseStatus(url) {
        try {
            const response = await fetch(url, { method: 'HEAD' });
            return response.status;
        } catch {
            return null;
        }
    }

    function secondsSinceTimestamp(timestamp) {
        return (Date.now() - timestamp) / 1000;
    }

    const currentUID = currentUserID();
    // console.log("User ID:", currentUID, "(https://www.camwhores.tv/members/" + currentUID + "/)")

    silentUidUpdater();

    function uploadRestored() {
        alert("The upload button has been restored!");
        localStorage.removeItem("UploadButtonTimestamp");
    }


    async function handleUploadButton() {
        const nav = document.querySelector('.navigation .primary');
        const lastCheck = localStorage.getItem("UploadButtonTimestamp");
        const minutesSinceLastCheck = lastCheck ? secondsSinceTimestamp(lastCheck) / 60 : null;

        if (nav && restoreUploadButton && ![...nav.querySelectorAll('a')].some(link => link.textContent.trim() === 'Upload')) {
            const uploadLink = document.createElement('a');
            uploadLink.style.cssText = 'background-color: #215521; display: block; padding: 11px 0; cursor: pointer;';
            uploadLink.textContent = 'UPLOAD';
            uploadLink.href = '/upload-video/';
            nav.appendChild(uploadLink);

            uploadLink.addEventListener('click', async (event) => {
                event.preventDefault();
                const status = await getResponseStatus('/upload-video/');
                if (status === 200) {
                    window.location.href = '/upload-video/';
                } else if (confirm(`Upload functionality is disabled (${status}). Notify me when available?`)) {
                    setUploadButtonTimestamp();
                }
            });

            if (lastCheck && minutesSinceLastCheck > 30) {
                const status = await getResponseStatus('/upload-video/');
                status === 200 ? uploadRestored() : (console.log(`Upload button still unavailable. Last check ${Math.floor(minutesSinceLastCheck)} minutes ago`), setUploadButtonTimestamp());
            }
        } else if (lastCheck) {
            uploadRestored();
        }
    }

    handleUploadButton();



    if (window.location.href.endsWith("?action=reject_add_to_friends_done") ||
        window.location.href.endsWith("?action=confirm_add_to_friends_done")) {

        const urlOfUser = document.querySelector('#list_messages_my_conversation_messages > div.headline > h2 > a:nth-child(2)');
        const username = urlOfUser.innerHTML.trim();
        const userID = urlOfUser.getAttribute('href').match(/\/(\d+)\//)[1];

        const storedData = JSON.parse(localStorage.getItem('closedWindow'));
        if (storedData) {
            const { uid, timestamp } = storedData;
            const timeDifference = (Date.now() - timestamp) / 1000; // in seconds
            if (timeDifference < 30 && userID === uid) {
                console.log(`Less than 30 seconds have passed since window closed. User ID: ${uid}`);
                window.close();
            }
        }
    }








    if (window.location.href == "https://www.camwhores.tv/my/messages/") {

      document.addEventListener('visibilitychange', function() {
          if (document.visibilityState === 'visible') {
              window.location.reload();
          }
      });


        function myMessagesAsyncURL(pageInt = 1) {
            const utcTimestamp = new Date().getTime();
            const pageID = pageInt.toString();
            return "https://www.camwhores.tv/my/messages/?mode=async&function=get_block&block_id=list_members_my_conversations&sort_by=added_date&from_my_conversations=" + pageID + "&_=" + utcTimestamp;
        }
        // console.log(myMessagesAsyncURL(3))






        function messagePageInfo(pageN) {
            let urlToPage = myMessagesAsyncURL(pageN);
            // console.log(urlToPage)
            return new Promise((resolve, reject) => {
                fetchAndExtract(urlToPage, function (htmlDoc) {
                    const conversations = [];
                    const items = htmlDoc.querySelectorAll("#list_members_my_conversations_items .item");
                    // console.log("htmlDoc:",htmlDoc)
                    items.forEach(item => {
                        const name = item.querySelector('a').getAttribute('title');
                        const unread = item.classList.contains('unread');
                        conversations.push({ name, unread });
                    });
                    resolve(conversations);
                });
            });
        }

        async function hasUnreadMessage(currentPage) {
            const data = await messagePageInfo(currentPage);
            return data.some(message => message.unread);
        }

        async function delay(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
        }

async function lastUnreadPage() {
    let currentPage = 1;
    let hasUnread = true;
    let lastUnreadPage = 0;
    let pagesChecked = 0;

    while (pagesChecked < 10 || hasUnread) {
        const data = await messagePageInfo(currentPage);
        hasUnread = data.some(message => message.unread);

        if (hasUnread) {
            lastUnreadPage = currentPage;
        }

        pagesChecked++;
        currentPage++;
        await delay(75);
    }

    return lastUnreadPage;
}





        async function checkAndFixMessages() {
            const currentPage = getCurrentPage();
            const data = await messagePageInfo(currentPage);
            // console.log(data);

            let hasNewElements = false;

            data.forEach(item => {
                const userItem = document.querySelector(`#list_members_my_conversations_items > div.item > a[title="${item.name}"]`);
                if (userItem) {
                    const unreadNotification = userItem.querySelector('div.img .unread-notification');
                    if (unreadNotification && !item.unread) {
                        unreadNotification.remove();
                        console.log("Message with", item.name, "was read");
                    }
                } else {
                    hasNewElements = true;
                }
            });

            if (hasNewElements) {
                location.reload();
            }
        }









        function processThumbnails() {
            // console.log("Processing thumbnails");
            var thumbnails = document.querySelectorAll('strong.title');
            if (thumbnails.length === 0) {
                console.log("Thumbnails not found. Retrying in 1000 milliseconds.");
                setTimeout(function () {
                    processThumbnails(); // Retry processing thumbnails
                }, 1000);
                return false; // Return false if thumbnails not found
            }

            thumbnails.forEach(function (thumbnail) {
                var usernameText = thumbnail.textContent.trim();
                if (usernameText) {
                    var usernameLink = document.querySelector('a[title="' + usernameText + '"]');
                    // console.log("usernameLink:",usernameLink)
                    if (usernameLink) {
                        var href = usernameLink.getAttribute('href');
                        var userIdMatch = href.match(/\/(\d+)\/$/);
                        if (userIdMatch && userIdMatch.length > 1) {
                            var userId = userIdMatch[1];
                            var usernameUrl = "https://www.camwhores.tv/members/" + userId + "/";
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: usernameUrl,
                                onload: function (response) {
                                    var parser = new DOMParser();
                                    var htmlDoc = parser.parseFromString(response.responseText, "text/html");
                                    var infoMessage = htmlDoc.querySelector('.info-message');
                                    var usernameLink = document.querySelector('a[title="' + usernameText + '"]');
                                    // console.log(usernameText + ": " + usernameUrl)
                                    // console.log(usernameLink)
                                    if (infoMessage && infoMessage.textContent.includes("is in your friends list.")) {
                                        if (usernameLink) {
                                            var divElement = document.createElement('div');
                                            divElement.classList.add("friends-tag");
                                            divElement.textContent = "Friends ✅";
                                            divElement.style.position = "absolute";
                                            divElement.style.top = "0";
                                            divElement.style.right = "0";
                                            divElement.style.backgroundColor = "#414141"; //#1a1a1a
                                            divElement.style.borderBottomLeftRadius = "3px";
                                            divElement.style.color = "white";
                                            divElement.style.padding = "3px 5px";

                                            if (usernameLink) {
                                                var firstDivElement = usernameLink.querySelector('div.img');
                                                if (firstDivElement) {
                                                    firstDivElement.appendChild(divElement);
                                                }
                                            }
                                        }
                                    }
                                    if (infoMessage && infoMessage.textContent.includes("wants to be your friend.")) {
                                        divElement = document.createElement('div');
                                        divElement.textContent = "👀";
                                        divElement.title = "Wants to be your friend!";
                                        divElement.style.position = "absolute";
                                        divElement.style.bottom = "0";
                                        divElement.style.left = "0";
                                        // divElement.style.backgroundColor = "aquamarine";
                                        divElement.style.color = "white";
                                        divElement.style.fontSize = "1rem";
                                        divElement.style.padding = ".5rem .25rem";

                                        if (usernameLink) {
                                            firstDivElement = usernameLink.querySelector('div.img');
                                            if (firstDivElement) {
                                                firstDivElement.appendChild(divElement);
                                            }
                                        }
                                    }

                                    var titleVideosElement = htmlDoc.evaluate('//*[@id="list_videos_uploaded_videos"]/div[1]/h2', htmlDoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
                                    var videoNumber = 0;

                                    if (titleVideosElement && titleVideosElement.singleNodeValue) {
                                        var titleVideosText = titleVideosElement.singleNodeValue.textContent;
                                        if (titleVideosText) {
                                            var matches = titleVideosText.match(/\(([^)]+)\)/);
                                            videoNumber = matches ? matches[1] : 0;
                                        }
                                    }

                                    if (videoNumber || videoNumber === 0) {
                                        divElement = document.createElement('div');
                                        divElement.classList.add("videos-tag");
                                        divElement.textContent = videoNumber;
                                        divElement.style.position = "absolute";
                                        divElement.style.bottom = "0";
                                        divElement.style.right = "0";
                                        divElement.style.backgroundColor = "CadetBlue";
                                        divElement.style.color = "white";
                                        divElement.style.padding = "3px 5px";
                                        divElement.style.borderTopLeftRadius = "3px";
                                    }


                                    if (usernameLink) {
                                        firstDivElement = usernameLink.querySelector('div.img');
                                        if (firstDivElement) {
                                            firstDivElement.appendChild(divElement);
                                        }
                                    }
                                } // end httpGET reponse

                            });
                        } else {
                            console.log("User ID not found in href for:", usernameText);
                        }
                    } else {
                        console.log("Username link not found for:", usernameText);
                    }
                }




            });
            return true; // Return true if thumbnails processed successfully
        }

        function addButtonEventListener() {
            // console.log("Adding event listener to buttons");
            document.addEventListener('click', function (event) {
                var target = event.target;
                if (target && target.matches('a[data-action="ajax"]')) {
                    // console.log("Button clicked");

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

        setTimeout(function () {
            processThumbnails();
            var thumbnailsProcessed = processThumbnails();
            if (!thumbnailsProcessed) {
                console.log("Processing thumbnails failed. Retrying in 1000 milliseconds.");
                setTimeout(function () {
                    processThumbnails(); // Retry processing thumbnails
                }, 1000);
            }
            addButtonEventListener();
        }, 1000);

        setInterval(function () {
            processThumbnails()
            silentUidUpdater()
            checkAndFixMessages()
        }, 5000);

        setInterval(function () {
            addButtons()
        }, 500);


        function addButtons() {
            const h2Element = document.querySelector('#list_members_my_conversations .headline h2');
            if (!h2Element) return console.log('h2Element not found');

            if (!document.getElementById('refreshIcon')) {
                const refreshIcon = document.createElement('span');
                refreshIcon.id = 'refreshIcon';
                refreshIcon.innerHTML = '&#8635;';
                refreshIcon.title = 'Refresh Utilities Mod';
                refreshIcon.style = 'cursor:pointer;margin-left:10px;';
                refreshIcon.addEventListener('click', () => {
                    processThumbnails();
                    console.log('Refreshing...');
                });
                h2Element.appendChild(refreshIcon);
            }

            if (!document.getElementById('lastUnreadButton')) {
                const lastUnreadButton = document.createElement('a');
                lastUnreadButton.id = 'lastUnreadButton';
                lastUnreadButton.innerHTML = '⏭';
                lastUnreadButton.title = 'Go to oldest unread message';
                lastUnreadButton.style = 'cursor:pointer;margin-left:10px;text-decoration:none;';
                lastUnreadButton.addEventListener('click', async () => {
                    lastUnreadButton.classList.add('fade');
                    const oldestUnreadPage = await lastUnreadPage();
                    console.log(oldestUnreadPage);
                    const linkElement = document.querySelector(`a[href="/my/messages/${oldestUnreadPage}/"][data-block-id="list_members_my_conversations"]`);
                    if (linkElement) {
                        linkElement.click();
                    } else {
                        console.log(`Element for page ${oldestUnreadPage} not found`);
                    }
                    lastUnreadButton.classList.remove('fade');

                });
                h2Element.appendChild(lastUnreadButton);
            }
        }

        addButtons()



    }
    if (window.location.href.startsWith("https://www.camwhores.tv/my/messages/") && window.location.href !== "https://www.camwhores.tv/my/messages/") {


        function updateButtonStyle(button, state) {
            button?.classList.add(state ? "accept-button" : "reject-button");
        }


        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

        if (sessionStorage.getItem('continue') === 'true') {
            sessionStorage.removeItem('continue');
            if (history.length === 1) window.location.href = `https://www.camwhores.tv/members/${userID}/#list_videos_my_uploaded_videos`;
        }

        confirmButton?.addEventListener('click', () => sessionStorage.setItem('continue', 'true'));

        document.querySelector('input.submit')?.addEventListener('click', () => divTextarea.innerHTML = '');

        $(document).ready(() => {
            $(document).keyup(event => {
                if (event.ctrlKey && event.key === 'Enter') {
                    event.preventDefault();
                    $("#send_message_form").submit();
                }
            });
        });


        function copyContentToTextarea() {
            const content = Array.from(divTextarea.childNodes).map(node =>
                node.nodeType === 3 ? node.textContent : node.tagName === 'IMG' ? node.alt : ''
            ).join('').trim();

            textarea.value = content;
        }



        textarea.style.display = "none";
        Object.assign(divTextarea.style, {
            display: "block",
            minHeight: "5rem",
            resize: "vertical",
            overflow: "auto",
            fontSize: "14px"
        });
        divTextarea.classList.add("textarea");
        divTextarea.contentEditable = true;
        textarea.parentNode.insertBefore(divTextarea, textarea.nextSibling);

        document.querySelectorAll('.smileys-bar img').forEach(img =>
            img.onclick = e => {
                e.preventDefault();
                e.stopPropagation();
                divTextarea.appendChild(Object.assign(img.cloneNode(true), { style: { cursor: "auto" } }));
                copyContentToTextarea();
            }
        );

        divTextarea.oninput = copyContentToTextarea;


        document.querySelectorAll('span.inline-text, span.original-text').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() {
            localStorage.setItem('closedWindow', JSON.stringify({ uid: userID, timestamp: Date.now() }));
            window.close();
        }

        function addCloseButtonsListeners(confirmButton, rejectButton) {
            if (!confirmButton) return {};

            const createButton = (text, action) => {
                const btn = document.createElement('span');
                btn.className = 'submit button';
                btn.textContent = text;
                btn.addEventListener('click', event => {
                    event.preventDefault();
                    action();
                    andClosePage();
                });
                return btn;
            };

            const buttonsParent = confirmButton.parentElement;
            const confirmClose = createButton('Confirm & Close', () => confirmButton.click());
            const denyClose = createButton('Deny & Close', () => rejectButton.click());

            buttonsParent.append(confirmClose, ' ', denyClose);
            confirmButton.style.width = `${confirmClose.offsetWidth}px`;
            rejectButton.style.width = `${denyClose.offsetWidth}px`;

            return { confirmClose, denyClose };
        }





function updateMessageDOM(htmlDoc, confirmClose, denyClose) {
    const twoYearsSeconds = 60 * 60 * 24 * 365 * 2;
    var titleText = htmlDoc.querySelector('#list_videos_uploaded_videos > div:nth-child(1) > h2')?.textContent.trim();
    var lastUploadTime = htmlDoc.querySelector('#list_videos_uploaded_videos_items > div.item > a > div.wrap > div.added > em')?.textContent.trim();

    var joinedDateText = htmlDoc.querySelector('div.block-profile > div.profile-list > div.margin-fix > div.column > div:nth-child(3) > em')?.textContent.trim();
    var lastLogin = htmlDoc.querySelector('div.block-profile > div.profile-list > div.margin-fix > div.last-login > div.item')?.textContent.trim();
    let secondsSinceOnline = convertToSeconds(lastLogin);
    let recentlyOnline = secondsSinceOnline <= 300;
    // let recentlyOnline = true;
    const headlineH2 = document.querySelector('#list_messages_my_conversation_messages .headline h2');
    console.log("recentlyOnline:", recentlyOnline);
    var recentlyUploaded = false;
    console.log("Has focus:",document.hasFocus(),"titleText:",titleText)
    if(!document.hasFocus() && !titleText){
      denyClose.click()
      window.close();
    }

    if(lastUploadTime){
      let lastUploadTimeSeconds = convertToSeconds(lastUploadTime);
      recentlyUploaded = lastUploadTimeSeconds < twoYearsSeconds;
    }

    if(recentlyOnline){
      GM_addStyle(`.list-messages .item.new .added:after {
          background-color: green;
        }`);

      document.querySelector("#list_messages_my_conversation_messages_items > div.item.new > div.added").textContent += " (online)";
      headlineH2.innerHTML += " (online)"

    }

    if (titleText) { // THERE ARE VIDEOS
        var extractedTitle = titleText.match(/\(([^)]+)\)/);
        if (extractedTitle && extractedTitle.length >= 1) {
            // THERE ARE VIDEOS

            if(recentlyUploaded){
                updateButtonStyle(confirmButton, true);
                updateButtonStyle(confirmClose, true);
            }else{
                updateButtonStyle(rejectButton, false);
                updateButtonStyle(denyClose, false);
            }

            var generatedTextDiv = document.createElement('div');
            generatedTextDiv.id = 'gen_joined_text';
            generatedTextDiv.innerHTML = `${extractedTitle[1]} videos, last ${lastUploadTime}<br>Joined ${joinedDateText}`;
            var messageDiv = document.querySelector('#list_messages_my_conversation_messages_items > div > div:nth-child(3)');
            if (messageDiv) {
                messageDiv.appendChild(generatedTextDiv);
            }
        }else{
          if(extractedTitle) console.log("extractedTitle:",extractedTitle)
        }


              if(confirmClose){
                    let imgData = [];
                    for (let i = 1; i <= 5; i++) {
                        let xpath = `//*[@id="list_videos_uploaded_videos_items"]/div[${i}]/a/div[@class="img"]/img`;
                        let img = htmlDoc.evaluate(xpath, htmlDoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
                        if (img) {
                            let parentAnchor = img.parentNode.parentNode;
                            imgData.push({ src: img.getAttribute('data-original'), alt: img.alt, url: parentAnchor.getAttribute('href') });
                        }
                    }
                        let vidPreviewsDiv = document.createElement("div");
                        vidPreviewsDiv.id = "vid_previews";
                        if (!isArrayEmpty(imgData)) {
                            imgData.forEach(data => {
                                let imgDiv = document.createElement("div");
                                imgDiv.classList.add("img-div");
                                let imgLink = document.createElement("a"); // New line
                                imgLink.href = data.url+"?please_check_friend"; // New line
                                let img = document.createElement("img");
                                img.src = data.src;
                                img.alt = data.alt;
                                img.title = data.alt;
                                let title = document.createElement("h2");
                                title.textContent = data.alt;
                                imgLink.appendChild(img); // Updated line
                                imgDiv.appendChild(imgLink); // Updated line
                                imgDiv.appendChild(title);

                                vidPreviewsDiv.appendChild(imgDiv);
                            });

                            buttonsParent.appendChild(vidPreviewsDiv);
                        }

                }


    } else {
        // THERE ARE NO VIDEOS
        console.log('No videos? Title: '+titleText+", content: "+lastUploadTime);
        updateButtonStyle(rejectButton, false);
        updateButtonStyle(denyClose, false);

        var messageDiv = document.querySelector('#list_messages_my_conversation_messages_items > div > div:nth-child(3)');
        if (messageDiv) {
            var generatedTextDiv = document.createElement('div');
            generatedTextDiv.id = 'gen_joined_text';
            generatedTextDiv.innerHTML = `Joined ${joinedDateText}<br><b>No videos</b>`;
            messageDiv.appendChild(generatedTextDiv);

        }
    }

}


        const bottomDiv = document.querySelector("#send_message_form > div > div.bottom");
        const responsesDiv = document.createElement("div");
        responsesDiv.id = "responses";
        responsesDiv.style.marginTop = "1rem";
        bottomDiv.insertAdjacentElement('afterend', responsesDiv);

        auto_replies.forEach(string => {
            const button = document.createElement("button");
            button.textContent = string;
            button.className = "button";
            button.style.padding = ".25rem .5rem";
            button.addEventListener("click", e => {
                e.preventDefault();
                textarea.value += textarea.value.trim() ? `\n${string}` : string;
                document.querySelector('#send_message_form').submit();
            });
            responsesDiv.appendChild(button);
        });

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


    }

    if (isNotPage("https://www.camwhores.tv/my/videos/", "https://www.camwhores.tv/my/")) {


      function addPrivateVideos() {
            const private_videos = [];

            const videoElements = document.querySelectorAll('.line-premium, .line-private');

            videoElements.forEach(video => {
                const parentDiv = video.parentElement;
                if (
                    parentDiv.tagName === 'DIV' &&
                    parentDiv.parentElement.tagName === 'A' &&
                    !processedVideos.has(parentDiv.parentElement)
                ) {
                    private_videos.push(parentDiv.parentElement);
                    processedVideos.add(parentDiv.parentElement);
                }
            });

            return private_videos;
        }

async function checkVideoPage(url) {
    try {
        const response = await fetch(url);
        if (!response.ok) {
            console.error('Error loading video page:', response.status);
            return { byFriend: false, usernameID: null };
        }

        const html = await response.text();
        const parser = new DOMParser();
        const doc = parser.parseFromString(html, 'text/html');
        const hasElement1 = doc.querySelector('body > div.container > div.content > div.block-video > div.video-holder > div.player > div > div > span') !== null;
        const hasElement2 = doc.querySelector('body > div.container > div.content > div.block-album > div.album-holder > div.images > span.message') !== null;
        let username = doc.querySelector("#tab_video_info > div > div.block-user > div.username > a") || doc.querySelector("#tab_album_info > div > div.block-user > div > a")?.textContent.trim();

        var vid_code = doc.querySelector('.username a').href.replace("https://www.camwhores.tv/members/", "");
        var usernameID = vid_code.split("/")[0];

        return { byFriend: hasElement1 || hasElement2, usernameID: usernameID, username: username };
    } catch (error) {
        console.error('Error checking video page:', error);
        return { byFriend: false, usernameID: null };
    }
}

        function updateImageSrc(image) {
            const src = image?.src;
            if (src?.endsWith('1.jpg')) image.src = src.replace('1.jpg', '5.jpg');
        }

        async function applyStyleToPrivateVideos() {
            for (const video of addPrivateVideos()) {
                const img = video.querySelector('div > img');
                const link = video.href;
                if(!link) continue;
                const { byFriend, usernameID, username } = await checkVideoPage(link);

                if (!byFriend) {
                    video.style.outline = 'green solid 2px';
                    let linePrivate = video.querySelector('.line-private');
                    if (linePrivate) linePrivate.style.display = 'none';

                    if (img) img.style.opacity = '1';

                } else {
                    const linePrivate = video.querySelector('.line-private > span');
                    if (linePrivate) {
                        linePrivate.textContent += ' ❌';
                        const addFriend = document.createElement('a');
                        Object.assign(addFriend, {
                            textContent: '➕',
                            title: 'Friend request',
                            href: `https://www.camwhores.tv/members/${usernameID}/#friends`,
                            style: 'z-index: 10; position: absolute; bottom: 20px; right: 0; font-size: 1rem; padding: 5px 2.5px; background-color: hsla(0, 0%, 0%, 0.7);'
                        });
                        addFriend.addEventListener('mousedown', e => {
                            e.stopImmediatePropagation();
                            friendRequestSetup(video.querySelector('strong.title').textContent.trim(), link, usernameID);
                            // console.log("Added video to data")
                        });

                        video.querySelector('.img').appendChild(addFriend);
                    }
                }
                if (alternative_thumbnails_users.includes(username)) updateImageSrc(img);
                await new Promise(resolve => setTimeout(resolve, 25)); // avoid 503
            }
        }

        function highlightKeywords() {
            document.querySelectorAll('.title').forEach(title => {
                highlight_keywords.forEach(keyword => {
                    title.innerHTML = title.innerHTML.replace(new RegExp(keyword, 'gi'), '<span style="color: green;">$&</span>');
                });
            });
        }

        applyStyleToPrivateVideos();
        highlightKeywords();
        setInterval(() => {
            applyStyleToPrivateVideos();
            highlightKeywords();
        }, 500);

    }

    if (window.location.href.startsWith("https://www.camwhores.tv/members/")) {
        const userId = window.location.href.split('/').slice(-2, -1)[0];
        const userVideosH2 = document.querySelector('#list_videos_uploaded_videos .headline h2');
        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 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();
        const countryCode = contryCodesArray()[countryName] || [];
        const parent = document.querySelector('div.block-profile > div.profile-list > div.margin-fix > div.column > div:nth-child(1)');
        const recentlyOnline = convertToSeconds(lastLogin) <= 300;

        function userProfileAsyncURL(uid, page) {
            return `https://www.camwhores.tv/members/${uid}/?mode=async&function=get_block&block_id=list_videos_uploaded_videos&sort_by=&from_videos=${page}&_=${Date.now()}`;
        }

        function numberBetweenParenthesis(text) {
            return text?.match(/\((\d+)\)/)?.[1] ?? null;
        }

        function getRoundedTotalPages(h2) {
            const total = numberBetweenParenthesis(h2?.textContent);
            return total ? Math.ceil(total / 5) : null;
        }

        function updateVideoH2() {
            const roundedPages = getRoundedTotalPages(userVideosH2);
            if (roundedPages) {
                userVideosH2.innerHTML = userVideosH2.innerHTML.includes("Page") ? userVideosH2.innerHTML : userVideosH2.innerHTML.trim() + `/${roundedPages}`;
            } else {
                console.log("No rounded pages.");
            }
        }

        function addSearchButton() {
            if(document.querySelector('#cum_vid_search')) return;
            let sortElement = document.querySelector("#list_videos_uploaded_videos > div.headline > div.sort");
            if (sortElement) {
                const searchButton = document.createElement('div');
                searchButton.className = 'user-search';
                searchButton.innerHTML = '<strong>Search videos</strong><span class="icon type-search"></span>';
                searchButton.id = 'cum_vid_search';
                searchButton.addEventListener('click', searchDialog);
                sortElement.parentNode.insertBefore(searchButton, sortElement);
            }
        }


        function searchDialog() {
                if (document.querySelector('#search-dialog')) return;


                console.log("Creating dialog...");
            let dialog = document.createElement('div');
            dialog.id = "search-dialog";
            dialog.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%, -50%);backdrop-filter:blur(5px);background:rgba(0,0,0,0.44);padding:20px;border-radius:10px;box-shadow:0 4px 8px rgba(0,0,0,0.1);z-index:1000;';
            let searchHighlights = retrieveValueFromStorage("highlights_search") || [];
            dialog.innerHTML = `
            <form style="padding-top:10px" id="cum_form_query">
                <div class="fancybox-item fancybox-close" style="position:absolute;top:5px;right:5px;"></div>
                <input type="text" autofocus placeholder="Search..." style="margin-right:5px;padding:5px;">
                <button type="submit" style="padding:5px;box-sizing:border-box;height:30px;cursor:pointer;">Search</button>
            </form>
            <hr style="margin-top:10px">
            <form style="padding-top:10px" id="cum_form_checkbox">
            ${highlight_keywords.map((keyword, index) => `
                <label>
                    <input type="checkbox" name="${keyword}" style="padding:5px;" ${searchHighlights.includes(keyword) ? 'checked' : ''}>
                    ${keyword}
                </label>
            `).join('')}

                <button id="cum_search_checkbox" type="button" style="display:block;padding:5px;box-sizing:border-box;height:30px;cursor:pointer;width:100%;margin:10px 0;">Search selected</button>
            </form>
                <button id="cum_search_all" type="button" style="display:block;padding:5px;box-sizing:border-box;height:30px;cursor:pointer;width:100%;margin-top:5px;" title="Search, ${highlight_keywords.join(", ")}">Search all highlights</button>
            `;

    document.body.insertBefore(dialog, document.body.firstChild);
    console.log("Dialog added to body.");

              dialog.querySelector('#cum_search_checkbox').addEventListener('click', e => {
                  e.preventDefault();
                  const selectedKeywords = Array.from(dialog.querySelectorAll('input[type="checkbox"]:checked'))
                      .map(checkbox => checkbox.name);
                  saveValue("highlights_search", selectedKeywords)
                  console.log(selectedKeywords)
                  displayResults(selectedKeywords);
                  document.body.removeChild(dialog);
              });




            dialog.querySelector('#cum_form_query').addEventListener('submit', e => {
                e.preventDefault();
                const input = dialog.querySelector('input').value;
                if (input) displayResults(input);
                document.body.removeChild(dialog);
            });
            dialog.querySelector('#cum_search_all').addEventListener('click', e => {
                e.preventDefault();
                displayResults("");
                document.body.removeChild(dialog);
            });
            dialog.querySelector('.fancybox-close').addEventListener('click', e => {
                e.preventDefault();
                document.body.removeChild(dialog);
            });
        }


        async function displayResults(query) {
            try {
                const resultList = document.createElement('div');
                resultList.id = 'cum_search_results';
                resultList.className = "list-videos";
                const loadingContainer = document.createElement('div');
                loadingContainer.style.textAlign = 'center';
                loadingContainer.innerHTML = '<img src="https://samherbert.net/svg-loaders/svg-loaders/three-dots.svg" alt="Loading..." style="width:50px;height:50px;">';
                document.querySelector("#list_videos_uploaded_videos").appendChild(loadingContainer);

                const results = await videoSearch(userVideosH2, userId, query);
                loadingContainer.remove();
                resultList.innerHTML = `<div class="headline" style="padding:15px 5px 7px 5px;"><h2>Search results</h2></div>`;
                if (!results.length) {
                    resultList.textContent = "No results found";
                } else {
                    resultList.innerHTML += results.map(video => `
                    <div class="item" style="margin-left:11px;">
                        <a href="${video.url}" title="${video.title}">
                            <div class="img"><img class="thumb lazy-load" src="${video.imgSrc}" alt="${video.title}" width="180" height="135"></div>
                            <strong class="title">${video.title}</strong>
                            <div class="wrap"><div class="duration">${video.duration}</div></div>
                        </a>
                    </div>`).join('');
                }

                const existingResult = document.querySelector("#cum_search_results");
                if (existingResult) existingResult.replaceWith(resultList);
                else document.querySelector("#list_videos_uploaded_videos").insertAdjacentElement('afterend', resultList);
            } catch (error) {
                console.error("Error:", error);
            }
        }



async function videoSearch(userVideosH2, uid, query) {
    let searchTerms = null;
    let totalVideoPages = getRoundedTotalPages(userVideosH2);
    let approxTotalVideos = totalVideoPages * 5;
    let timeout;
    if (approxTotalVideos > 1000) {
        timeout = approxTotalVideos / 2;
    }else if (approxTotalVideos > 500) {
        timeout = approxTotalVideos / 5;
    } else {
        timeout = 75;
    }
    if (Array.isArray(query)) {
        searchTerms = query.map(q => q.toLowerCase());
    } else {
        searchTerms = query ? [query.toLowerCase()] : highlight_keywords.map(k => k.toLowerCase());
    }
    if (totalVideoPages !== null) {
        let resultArray = [];
        let fetchPromises = [];

        for (let pageInt = 1; pageInt <= totalVideoPages; pageInt++) {
            let nextFivePages = userProfileAsyncURL(uid, pageInt);
            let fetchPromise = new Promise((resolve) => {
                setTimeout(() => {
                    fetchAndParseHTML(nextFivePages, (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');
                            let lowerTitle = title.toLowerCase();
                            if (searchTerms.some(term => lowerTitle.includes(term))) {
                                resultArray.push({ title, private: isPrivate, url, imgSrc, duration });
                            }
                        });
                        resolve();
                    });
                }, timeout * (pageInt - 1));
            });
            fetchPromises.push(fetchPromise);
        }

        await Promise.all(fetchPromises);
        return resultArray;
    } else {
        console.log("ERROR in totalVideoPages:", totalVideoPages);
        return null;
    }
}


        function getCurrentUserVideoLocation() {
            return sessionStorage.getItem(`${currentUserID()}:https://www.camwhores.tv/members/${userId}/#list_videos_uploaded_videos:params`);
        }

        function waitForSessionStorageChange() {
            const initialValue = getCurrentUserVideoLocation();
            const interval = setInterval(() => {
                if (getCurrentUserVideoLocation() !== initialValue) {
                    clearInterval(interval);
                    updateVideoH2();
                    addSearchButton();
                }
            }, 50);
        }

        if (recentlyOnline) {
            h1.textContent += " (online)";
            h1.className = "online";
        }
        userDescription.textContent = userDescription.textContent.trim();

        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.cssText = "position:absolute;top:50%;transform:translateY(-50%);left:4rem;";
            parent.appendChild(img);
            parent.style.position = "relative";
        }

        updateVideoH2();
        // addButtonEventListener();
      new MutationObserver(() => addSearchButton())
  .observe(document.body, { childList: true, subtree: true });


    if (window.location.href.endsWith("#friends") && !window.location.href.includes("add_to_friends_done")) {
          var userVideoData,lastCumTitle,lastVidCode,lastUserID;
          let addButton = document.querySelector('a[href="#friends"][data-action="add_to_friends"]');
          let textarea = document.getElementById('add_to_friends_message');
          let userId = window.location.href.split('/').slice(-2, -1)[0];
          let confirmButton = document.querySelector('input[name="confirm"]');


          let retrievedData = JSON.parse(localStorage.getItem('last_cum_video_data')) || {};
          console.log("uid:",userId,retrievedData[userId])
          if (retrievedData[userId]) {
              userVideoData = retrievedData[userId];
              console.log(userVideoData);
              lastCumTitle = userVideoData.title;
              lastVidCode = userVideoData.videoId;
              lastUserID = userVideoData.userId;
          } else {
              console.log("No data found for this user.");
          }


          let pageTitle = document.title;
          let username = pageTitle.replace("'s Page", "");
          if (textarea !== null
              && !addButton.classList.contains('done')
              // && username !== lastAutoFriend
              && lastCumTitle !== null
              && addButton !== null) {
              textarea.value = "";
              textarea.value += friend_request_text + " " + lastCumTitle + "\n##" + lastVidCode;

              // addButton.click();
              document.querySelector('input[type="submit"].submit[value="Invite"]').click();  // final submit button
          }


          // console.log(confirmButton)
          // if(confirmButton) confirmButton.click();


          if (addButton.classList.contains('done') && history.length === 1) {
              window.close();
          }
        // console.log("Should add?")
      }


      else if (window.location.href.includes("add_to_friends_done")) {
          let addButton = document.querySelector('a[href="#friends"][data-action="add_to_friends"]');
          if (addButton && !addButton.classList.contains('done')) {
              addButton.classList.add('done');
          }
          if (history.length === 1 || !document.hasFocus()) window.close();
      }

    }

    if (window.location.href.startsWith("https://www.camwhores.tv/videos/")) {
        const el = document.querySelector('body > div.container > div.content > div.block-video > div.video-holder > div.player > div > div > span') ||
            document.querySelector('body > div.container > div.content > div.block-album > div.album-holder > div.images > span.message');
        const href = document.querySelector('#tab_video_info > div > div.block-user > div > a').href;
        const userId = document.querySelector('.username a')?.getAttribute('href').split('/').slice(-2, -1)[0];

        if (el) {
            fetch(href)
                .then(response => response.text())
                .then(html => {
                    const doc = new DOMParser().parseFromString(html, 'text/html');
                    const infoMsg = doc.querySelector('.info-message');
                    const headline = document.querySelector('body > div.container > div.content > div.headline > h1');
                    const isFriends = infoMsg?.textContent.includes("is in your friends list.");
                    const isPending = window.location.href.includes("please_check_friend");

                    if (isFriends) {
                        el.textContent = "You're already friends! Reloading in 4 seconds";
                        setTimeout(() => location.reload(), 4000);
                    } else if (isPending) {
                        el.innerHTML += "<br><br>Friendship confirmed? Reloading in 4 seconds";
                        setTimeout(() => location.reload(), 4000);
                    } else if (headline) {
                        friendRequestSetup(headline.textContent.trim(), window.location.href, userId);
                        el.innerHTML += `<br><a class="button" href="${el.querySelector('a').href}#friends" style="display:inline-block;">Send request</a>`;
                    }

                    document.querySelectorAll('.block-screenshots .item.private').forEach(el => {
                        const img = el.querySelector('img');
                        if (img) {
                            el.replaceWith(Object.assign(document.createElement('a'), {
                                innerHTML: el.innerHTML,
                                href: img.dataset.original.replace('/videos_screenshots/', '/videos_sources/').replace('/180x135/', '/screenshots/'),
                                className: 'item',
                                rel: 'screenshots',
                                'data-fancybox-type': 'image'
                            }));
                        }
                    });
                })
                .catch(console.error);
        }

        function waitForElementExists(parent, selector) {
            return new Promise(resolve => {
                new MutationObserver((_, observer) => {
                    const el = parent.querySelector(selector);
                    if (el) {
                        resolve(el);
                        observer.disconnect();
                    }
                }).observe(parent, { childList: true, subtree: true });
            });
        }

        function addDownloadLink(video) {
            if (document.getElementById('downloadVideoLink')) return;
            const url = video.getAttribute('src');
            const name = `${document.querySelector('.headline').innerText}.mp4`;
            document.querySelector('div.video-holder > div.video-info > div > div.info-buttons > div.tabs-menu > ul')
                .insertAdjacentHTML('afterbegin', `<li><a id="downloadVideoLink" class="toggle-button" href="${url}" download="${name}">Download</a></li>`);
        }

        waitForElementExists(document.body, 'video').then(addDownloadLink).catch(console.error);

function addTimestampsToVideo(timestamps){
      var tabScreenshots = document.getElementById('tab_screenshots');
      var timestampsDiv = document.getElementById('timestamps');
      if (timestampsDiv) return;
                          // Check if #tab_screenshots exists

      // Check if #timestamps exists inside #tab_screenshots
          timestampsDiv = document.createElement('div');
          timestampsDiv.id = 'timestamps';
          timestampsDiv.style = 'display:flex;gap:.1rem';
          tabScreenshots.appendChild(timestampsDiv);


      timestamps.forEach(function (timestamp, index) {
          var formattedTimestamp = formatTimeFromSeconds(timestamp);

          // Create button for timestampsDiv
          var button1 = document.createElement('button');
          button1.textContent = formattedTimestamp;
          button1.addEventListener('click', function () {
              flowplayer().seek(timestamp);
          });
          timestampsDiv.appendChild(button1);

          // Create button for screenshot link
          var screenshotLinks = document.querySelectorAll('.block-screenshots a[rel="screenshots"]');
          if (screenshotLinks[index]) {
              var button2 = document.createElement('button');
              button2.textContent = formattedTimestamp;
              button2.style.position = 'absolute';
              button2.addEventListener('click', function () {
                  flowplayer().seek(timestamp);
              });
              screenshotLinks[index].style.position = 'relative';
              screenshotLinks[index].appendChild(button2);
          }
      });



}
            function waitForVideoDuration(maxAttempts, intervalMs) {
                var attempts = 0;

                // Approximated percentages
                var percentages = [/* 0:14, */ 25, 40, 59.75, 79]; // CONSIDER 0:14 IN FRONT IF EVERYTHING! (15:49)

                function checkDuration() {
                    var player = flowplayer();
                  // console.log(player, typeof player.video.duration === 'number')
                    if (player && player.video && typeof player.video.duration === 'number') {
                        var videoDuration = player.video.duration;

                        // Calculate percentages based on approximations
                        var calculatedPercentages = percentages.map(function (percent) {
                            return (percent / 100) * videoDuration;
                        });

                        console.log("Video Duration:", videoDuration);
                        console.log("Calculated Percentages:", calculatedPercentages);

                        // Determine the first timestamp as the minimum between 14 seconds and 5% of video duration
                        var firstTimestamp = 14;



                        // Create buttons with timestamps
                        var timestamps = [firstTimestamp].concat(calculatedPercentages); // Include the first timestamp
                        addTimestampsToVideo(timestamps);

                    } else {
                        attempts++;
                        setTimeout(checkDuration, intervalMs);
                    }
                }

                checkDuration();
            }

            // Helper function to format time from seconds to mm:ss
            function formatTimeFromSeconds(seconds) {
                var date = new Date(null);
                date.setSeconds(seconds);
                return date.toISOString().substr(14, 5);
            }

            waitForVideoDuration(10, 500);

            document.addEventListener('visibilitychange', function() {
                if (document.getElementById('tab_screenshots')) return;
                if (document.visibilityState === 'visible') {
                  console.log("retrying timestamps")
                   waitForVideoDuration(10, 500);
                }
            });



    }

    if (window.location.href.startsWith("https://www.camwhores.tv/playlists/") && window.location.href !== "https://www.camwhores.tv/playlists/") {
        const h1Element = document.querySelector('h1');
        const playlistItem = document.querySelector('#playlist_view_playlist_view_items a');
        h1Element.textContent = playlistItem.querySelector('.title').textContent.trim();

        h1Element.parentElement.insertAdjacentHTML('beforeend', `<a class="button" style="padding: 5px 5px 0 5px;" href="${playlistItem.href}">Open video</a>`);

        document.addEventListener('click', e => {
            const clickedItem = e.target.closest('#playlist_view_playlist_view_items a');
            if (clickedItem) {
                h1Element.textContent = clickedItem.querySelector('.title').textContent.trim();
                document.querySelector('.button').href = clickedItem.href;
            }
        });
    }

    if (window.location.href.startsWith("https://www.camwhores.tv/edit-video/")) {
        document.querySelector('.section-title.expand[data-expand-id="tab_screenshots"]').click();
        document.querySelectorAll("#tab_screenshots > div > div:nth-child(-n+5) > div.item-control > div.item-control-holder").forEach(el =>
            el.addEventListener('click', () => {
                document.querySelector('input.submit[value="Save"]').click();
                if (history.length === 1) window.close();
            })
        );
    }

    if (window.location.href === "https://www.camwhores.tv/my/") {
        const profileCSS = document.createElement('style');
        profileCSS.className = "profile-css";
        profileCSS.textContent = `
        #edit_profile_about_me{height:225px;}
        strong.popup-title,span.selection [role="combobox"]{display:none;}
        body > div.fancybox-overlay.fancybox-overlay-fixed > div{top:0 !important;height:100svh !important;}
        body > div.fancybox-overlay.fancybox-overlay-fixed,body > div.fancybox-overlay.fancybox-overlay-fixed > *{box-sizing:border-box;}
        div.fancybox-inner{height:100% !important;width:max-content !important;}
        .fancybox-close{top:9px !important;}
    `;
        document.head.appendChild(profileCSS);
    }

    if (window.location.href === "https://www.camwhores.tv/" || window.location.href === "https://www.camwhores.tv") {
        const listVideos = document.querySelector("body > div.container > div.list_videos > div");
        const headline = document.querySelector("body > div.container > div.content > div.main-content > div.headline");
        const latestVideoUpSeconds = convertToSeconds(document.querySelector("#list_videos_featured_videos_items div.added").innerText);
        const latestStoredUpSeconds = parseInt(localStorage.getItem("cum_last_featuredVideoUpDate"));
        const showFeaturedVids = retrieveValueFromStorage("options")["cum_show_top"];
        const thereIsANewerVideo = latestVideoUpSeconds < latestStoredUpSeconds;

        const hideFtVideos = show => {
            listVideos.style.display = show ? 'block' : 'none';
            headline.style.paddingTop = show ? '20px' : '10px';
            if (!show) localStorage.setItem("cum_last_featuredVideoUpDate", latestVideoUpSeconds);
            document.querySelector("#🆕")?.style.setProperty("display", "none");
        };

        hideFtVideos(showFeaturedVids);

        document.querySelector("body > div.container > div.list_videos").insertAdjacentHTML('afterbegin', `
      <label class="switch" title="Top videos" id="cum_switch_top">
        <input type="checkbox" id="cum_show_top" ${showFeaturedVids ? 'checked' : ''}>
        <span class="slider round"></span>
      </label>
    `);

        document.querySelector('#cum_show_top').addEventListener('change', function () {
            hideFtVideos(this.checked);
            saveArraySettings("options", "cum_show_top", this.checked);
        });

        if (!showFeaturedVids && thereIsANewerVideo) {
            document.querySelector("body > div.container > div.list_videos").insertAdjacentHTML('beforeend', `
            <span id="🆕" style="font-size:1.5rem;vertical-align:middle;"> 🆕</span>
        `);
        }
    }


function extractVideoId(url) {
    if(!url) return console.error("url:", url)
    const parts = url.split('/');
    return parts[4] + '/' + parts[5].replace(/\/$/, '');
}


function extractLatestVideoId(dom = document){
    let latestVid = dom.querySelector("#list_videos_videos_list_search_result_items > div > a");
    if (!latestVid) return null;
    return extractVideoId(latestVid.href)
}

function currentSearchTerm() {
    let string = window.location.pathname.split('/search/')[1]?.split('/')[0].trim() ||
                 h1.textContent.split(':')[1].trim() || null;
    if (!string) return null;
    return string.replace(/%20|-/g, ' ').replace(/\s+/g, ' ').toLowerCase();
}


function updateLatestVideo(dom = document, searchTerm = null){
    let h1 = dom.querySelector('h1');
    if (!h1) return;

    if (!searchTerm) searchTerm = currentSearchTerm();
    if (!searchTerm) return;

    let data = {
        timestamp: Date.now(),
        id: extractLatestVideoId()
    };
    saveArraySettings("auto_search", searchTerm, data);
}

  if (window.location.pathname.startsWith('/search/')) {

        let searchTerm = currentSearchTerm();
        console.log(searchTerm)

        let hypotheticalPresence = retrieveValueFromStorage("auto_search")[searchTerm];
        if(hypotheticalPresence) updateLatestVideo()


        let buttonAutoSearch = document.createElement('button');
        buttonAutoSearch.id = 'cum-auto-search';
        buttonAutoSearch.textContent = 'Add to Wish List';
        buttonAutoSearch.classList.add('btn');
        buttonAutoSearch.style = "transform:translate(5px, 3px);cursor:pointer"
        buttonAutoSearch.addEventListener('click', () => {
            updateLatestVideo();

            buttonAutoSearch.textContent = 'Done!';
            buttonAutoSearch.disabled = true;


        });

        document.querySelector('h1')?.insertAdjacentElement('afterend', buttonAutoSearch);

}









    function myVideosAsyncURL(pageInt) {
        return `https://www.camwhores.tv/my/videos/?mode=async&function=get_block&block_id=list_videos_my_uploaded_videos&sort_by=&from_my_videos=${pageInt}&_=${Date.now()}`;
    }

    function pagesLastProcessedVideo(page, callback) {
        fetchAndParseHTML(myVideosAsyncURL(page), doc => {
            const items = doc.querySelectorAll("#list_videos_my_uploaded_videos_items > form > div.item.private");
            const idx = Array.from(items).reverse().findIndex(item => item.classList.contains('processing'));

            const checkbox = items[items.length - 1 - idx]?.querySelector(".item-control-holder .toggle-button input[type='checkbox']");
            callback(checkbox ? checkbox.value : false);
        });
    }

    async function lastProcessedVideoID(callback) {
        let found = false;
        const promises = Array.from({ length: 3 }, (_, page) =>
            new Promise(resolve => pagesLastProcessedVideo(page + 1, value => {
                if (value) found = true;
                resolve(value);
            }))
        );

        const results = await Promise.all(promises);
        callback(results.find(value => value) || false);
    }

    function loadLastVideoData() {
        return JSON.parse(localStorage.getItem('lastVideoData') || '[]') || [null, null];
    }

    function lastVideoDataAge(refreshMinutes = 30) {
        const [, timestamp] = loadLastVideoData();
        return timestamp ? (Date.now() - timestamp) / 1000 : refreshMinutes * 60 + 1;
    }

    function saveLastVideoID(callback) {
        lastProcessedVideoID(currentID => {
            localStorage.setItem('lastVideoData', JSON.stringify([currentID, Date.now()]));
            callback(loadLastVideoData()[0], currentID);
            console.log(`Last ID: ${loadLastVideoData()[0]}\nCurrent ID: ${currentID} (https://www.camwhores.tv/edit-video/${currentID}/)`);
        });
    }

    function alertNewVideo(newID) {
        if (confirm("A new video of yours has been published.\nGo to My Videos?")) {
            window.location.href = "/my/videos/";
        }
    }

    function updateLastVideoData(minutes = backgroundChecksMinutes) {
        const waitTime = minutes * 60;
        const ageOfCheck = lastVideoDataAge(backgroundChecksMinutes);
        if (ageOfCheck > waitTime) {
            saveLastVideoID((lastID, newID) => {
                if (newID && lastID && lastID !== newID) {
                    alertNewVideo(newID);
                } else {
                    console.log("No new videos were published");
                }
            });
        } else {
            // Optionally log how much time is left before the next check
            // console.log(`Only ${Math.round(ageOfCheck / 60)} minutes have passed, ${minutes - Math.round(ageOfCheck / 60)} to go.`);
        }
    }




    notifyProcessedVideos && updateLastVideoData(backgroundChecksMinutes);


    function contryCodesArray() { return { "Andorra": "ad", "United Arab Emirates": "ae", "Afghanistan": "af", "Antigua and Barbuda": "ag", "Anguilla": "ai", "Albania": "al", "Armenia": "am", "Angola": "ao", "Antarctica": "aq", "Argentina": "ar", "American Samoa": "as", "Austria": "at", "Australia": "au", "Aruba": "aw", "Åland Islands": "ax", "Azerbaijan": "az", "Bosnia and Herzegovina": "ba", "Barbados": "bb", "Bangladesh": "bd", "Belgium": "be", "Burkina Faso": "bf", "Bulgaria": "bg", "Bahrain": "bh", "Burundi": "bi", "Benin": "bj", "Saint Barthélemy": "bl", "Bermuda": "bm", "Brunei": "bn", "Bolivia": "bo", "Caribbean Netherlands": "bq", "Brazil": "br", "Bahamas": "bs", "Bhutan": "bt", "Bouvet Island": "bv", "Botswana": "bw", "Belarus": "by", "Belize": "bz", "Canada": "ca", "Cocos (Keeling) Islands": "cc", "DR Congo": "cd", "Central African Republic": "cf", "Republic of the Congo": "cg", "Switzerland": "ch", "Côte d'Ivoire (Ivory Coast)": "ci", "Cook Islands": "ck", "Chile": "cl", "Cameroon": "cm", "China": "cn", "Colombia": "co", "Costa Rica": "cr", "Cuba": "cu", "Cape Verde": "cv", "Curaçao": "cw", "Christmas Island": "cx", "Cyprus": "cy", "Czechia": "cz", "Germany": "de", "Djibouti": "dj", "Denmark": "dk", "Dominica": "dm", "Dominican Republic": "do", "Algeria": "dz", "Ecuador": "ec", "Estonia": "ee", "Egypt": "eg", "Western Sahara": "eh", "Eritrea": "er", "Spain": "es", "Ethiopia": "et", "European Union": "eu", "Finland": "fi", "Fiji": "fj", "Falkland Islands": "fk", "Micronesia": "fm", "Faroe Islands": "fo", "France": "fr", "Gabon": "ga", "United Kingdom": "gb", "England": "gb-eng", "Northern Ireland": "gb-nir", "Scotland": "gb-sct", "Wales": "gb-wls", "Grenada": "gd", "Georgia": "ge", "French Guiana": "gf", "Guernsey": "gg", "Ghana": "gh", "Gibraltar": "gi", "Greenland": "gl", "Gambia": "gm", "Guinea": "gn", "Guadeloupe": "gp", "Equatorial Guinea": "gq", "Greece": "gr", "South Georgia": "gs", "Guatemala": "gt", "Guam": "gu", "Guinea-Bissau": "gw", "Guyana": "gy", "Hong Kong": "hk", "Heard Island and McDonald Islands": "hm", "Honduras": "hn", "Croatia": "hr", "Haiti": "ht", "Hungary": "hu", "Indonesia": "id", "Ireland": "ie", "Israel": "il", "Isle of Man": "im", "India": "in", "British Indian Ocean Territory": "io", "Iraq": "iq", "Iran": "ir", "Iceland": "is", "Italy": "it", "Jersey": "je", "Jamaica": "jm", "Jordan": "jo", "Japan": "jp", "Kenya": "ke", "Kyrgyzstan": "kg", "Cambodia": "kh", "Kiribati": "ki", "Comoros": "km", "Saint Kitts and Nevis": "kn", "North Korea": "kp", "South Korea": "kr", "Kuwait": "kw", "Cayman Islands": "ky", "Kazakhstan": "kz", "Laos": "la", "Lebanon": "lb", "Saint Lucia": "lc", "Liechtenstein": "li", "Sri Lanka": "lk", "Liberia": "lr", "Lesotho": "ls", "Lithuania": "lt", "Luxembourg": "lu", "Latvia": "lv", "Libya": "ly", "Morocco": "ma", "Monaco": "mc", "Moldova": "md", "Montenegro": "me", "Saint Martin": "mf", "Madagascar": "mg", "Marshall Islands": "mh", "North Macedonia": "mk", "Mali": "ml", "Myanmar": "mm", "Mongolia": "mn", "Macau": "mo", "Northern Mariana Islands": "mp", "Martinique": "mq", "Mauritania": "mr", "Montserrat": "ms", "Malta": "mt", "Mauritius": "mu", "Maldives": "mv", "Malawi": "mw", "Mexico": "mx", "Malaysia": "my", "Mozambique": "mz", "Namibia": "na", "New Caledonia": "nc", "Niger": "ne", "Norfolk Island": "nf", "Nigeria": "ng", "Nicaragua": "ni", "Netherlands": "nl", "Norway": "no", "Nepal": "np", "Nauru": "nr", "Niue": "nu", "New Zealand": "nz", "Oman": "om", "Panama": "pa", "Peru": "pe", "French Polynesia": "pf", "Papua New Guinea": "pg", "Philippines": "ph", "Pakistan": "pk", "Poland": "pl", "Saint Pierre and Miquelon": "pm", "Pitcairn Islands": "pn", "Puerto Rico": "pr", "Palestine": "ps", "Portugal": "pt", "Palau": "pw", "Paraguay": "py", "Qatar": "qa", "Réunion": "re", "Romania": "ro", "Serbia": "rs", "Russia": "ru", "Rwanda": "rw", "Saudi Arabia": "sa", "Solomon Islands": "sb", "Seychelles": "sc", "Sudan": "sd", "Sweden": "se", "Singapore": "sg", "Saint Helena, Ascension and Tristan da Cunha": "sh", "Slovenia": "si", "Svalbard and Jan Mayen": "sj", "Slovakia": "sk", "Sierra Leone": "sl", "San Marino": "sm", "Senegal": "sn", "Somalia": "so", "Suriname": "sr", "South Sudan": "ss", "São Tomé and Príncipe": "st", "El Salvador": "sv", "Sint Maarten": "sx", "Syria": "sy", "Eswatini (Swaziland)": "sz", "Turks and Caicos Islands": "tc", "Chad": "td", "French Southern and Antarctic Lands": "tf", "Togo": "tg", "Thailand": "th", "Tajikistan": "tj", "Tokelau": "tk", "Timor-Leste": "tl", "Turkmenistan": "tm", "Tunisia": "tn", "Tonga": "to", "Turkey": "tr", "Trinidad and Tobago": "tt", "Tuvalu": "tv", "Taiwan": "tw", "Tanzania": "tz", "Ukraine": "ua", "Uganda": "ug", "United States Minor Outlying Islands": "um", "United Nations": "un", "United States": "us", "Uruguay": "uy", "Uzbekistan": "uz", "Holy See (Vatican City State)": "va", "Saint Vincent and the Grenadines": "vc", "Venezuela": "ve", "British Virgin Islands": "vg", "United States Virgin Islands": "vi", "Vietnam": "vn", "Vanuatu": "vu", "Wallis and Futuna": "wf", "Samoa": "ws", "Kosovo": "xk", "Yemen": "ye", "Mayotte": "yt", "South Africa": "za", "Zambia": "zm", "Zimbabwe": "zw" } }

    async function updateAlert() {
        const lastCheck = await retrieveValueFromStorage('lastVersionCheckDate');
        const lastVersionCheckDate = lastCheck ? new Date(lastCheck) : currentDate;
        if (currentDate - lastVersionCheckDate > 3 * 24 * 60 * 60 * 1000) {
            await saveValue('lastVersionCheckDate', currentDate.toString());
            const htmlDoc = await fetchAndParseHTML(metaPage);
            const metaContent = htmlDoc.body.textContent;
            const metaVersionMatch = metaContent.match(/@version\s+([^\s]+)/);
            if (metaVersionMatch) {
                const latestVersion = metaVersionMatch[1];
                if (latestVersion !== currentVersion) {
                    if (confirm('A new version of the CUM script is available.\nPlease allow automatic updates or update it manually.\nOpen in new tab?')) {
                        GM_openInTab("https://sleazyfork.org/en/scripts/491272-camwhores-tv-utilities-mod");
                    } else {
                        toggleChange(updateRemindersOptionName, false);
                    }
                }
            }
        }
    }

    updateReminders && updateAlert();



    blurImages &&
        GM_addStyle(`
        img:not(.smileys-bar img),div.logo a{
            filter: blur(20px);
            transition: filter 0s;
        }
        img:not(.smileys-bar img):hover,div.logo:hover a{
            filter: blur(0px);
            transition: filter .3s;
        }
    `);




})();