Xhamster Auto Clean Boost - v.2.15

Auto Clean Playlist by deleting Unavailable Videos after clicking on its button and Count the number of deleting items. "Auto Clean" button became red when there is something to delete

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Xhamster Auto Clean Boost - v.2.15
// @namespace    http://tampermonkey.net/
// @version      2.15
// @description  Auto Clean Playlist by deleting Unavailable Videos after clicking on its button and Count the number of deleting items. "Auto Clean" button became red when there is something to delete
// @icon         https://external-content.duckduckgo.com/ip3/fr.xhamster.com.ico
// @author       janvier57
// @match        https://xhamster.com/my/favorites/videos/*
// @match        https://xhvid.com/my/favorites/videos/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_openInTab
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    const DELAY = 1000; // 1 second
    const PAGINATION_DELAY = 5000; // 5 seconds

    // Selectors
    const deletedVideoSelector = '[data-role="favorites-video-collections"] > [class*="isDesktop-"] > [class^="header-"] + .thumb-list.thumb-list--sidebar .thumb-list__item.video-thumb.video-thumb--type-video:has(.thumb-image-container__status-text)';
    const privateVideoSelectors = [
        '[data-role="favorites-video-collections"] > [class*="isDesktop-"] > [class^="header-"] + .thumb-list.thumb-list--sidebar .thumb-list__item.video-thumb.video-thumb--type-video:has(.thumb-image-container__status-text, .xh-icon.lock)',
        '[data-role="favorites-video-collections"] > [class*="isDesktop-"] > [class^="header-"] + .thumb-list.thumb-list--sidebar .thumb-list__item.video-thumb.video-thumb--type-video:has(.thumb-image-container__status-text, .xh-icon.photo-error2)' ,
        '[data-role="favorites-video-collections"] > [class*="isDesktop-"] > [class^="header-"] + .thumb-list.thumb-list--sidebar .thumb-list__item.video-thumb.video-thumb--type-video:has(.thumb-image-container__status-text, .xh-icon.lock-vb)' ,
// UNavaiable in your Country
        '[data-role="favorites-video-collections"] > [class*="isDesktop-"] > [class^="header-"] + .thumb-list.thumb-list--sidebar .thumb-list__item.video-thumb.video-thumb--type-video:has(.thumb-plug__image)'
    ];
    const paginationSelector = 'nav.desktop-pagination[data-role="pagination-cleaner"]';
    //const nextButtonSelector = `${paginationSelector} .prev-next-list-button:nth-child(2)`;
    // nav[class^="desktop-pagination pagination-"][data-role="pagination-cleaner"] .prev-next-list .page-list-wrapper .page-list-container ol.page-list li:has( .page-button-link--active) + li button.page-button-link
    const nextButtonSelector = `${paginationSelector} .prev-next-list .page-list-wrapper .page-list-container ol.page-list li:has(.page-button-link--active) + li .page-button-link`;
    GM_addStyle(`
        .xhamster-auto-clean-button {
            position: fixed;
            top: 3vh;
            right: 150px;
            z-index: 1000;
            background: linear-gradient(to bottom, #33cc33, #009900);
            color: white;
            padding: 5px 10px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
            font-weight: bold;
        }

        .xhamster-auto-clean-button.has-items-to-delete {
            background: linear-gradient(to bottom, #ff0000, #cc0000);
        }
        .dialog-desktop-container__backing,
        .dialog-mobile-container__backing {
             background-color: transparent;
}
/* XHAM GM AUTO CLEAN BOOST - PAGINATION TEST */

.favorites-nav-container:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) + .content-column [data-role="favorites-video-collections"] .desktop-pagination {
	position: absolute ;
    display: flex;
    justify-content: center;
	top: 1vh ;
	right:  15% !important;
	margin:  0 0 0 0 ;
}
/* SUPP */
.user-page.favorites-page .desktop-dialog.desktop-dialog--small.desktop-dialog--fixed-footer:has(.desktop-dialog__footer [class*="color-brand-"]) .search-form ,
[data-role="promo-messages-wrapper"] {
    display: none  !important;
}
/* SMALL THUMBNAIL */
.main-wrap:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) {
    width: 100%;
	min-width: 100% ;
	max-width: 100% ;
    margin: 0 0 0 0 ;
    min-height: 100%;
}
.main-wrap:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) .width-wrap {
	width: 100%;
	min-width: 100% ;
	max-width: 100% ;
}
.favorites-nav-container:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) + .content-column [data-role="favorites-video-collections"] .thumb-list.thumb-list--sidebar .thumb-list__item {
	width: 6%;
/*border: 1px solid aqua  !important;*/
}
.favorites-nav-container:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) + .content-column [data-role="favorites-video-collections"] .thumb-list.thumb-list--sidebar .thumb-list__item .thumb-image-container {
        height: 5vh;
        width: 100%;
 }
.favorites-nav-container:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) + .content-column [data-role="favorites-video-collections"] .thumb-list.thumb-list--sidebar .thumb-list__item .thumb-image-container .thumb-image-container__image {
    height: 100%;
    object-fit: contain;
    width: 100%;
}
.favorites-nav-container:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) + .content-column [data-role="favorites-video-collections"] .thumb-list.thumb-list--sidebar .thumb-list__item .video-thumb-info .video-thumb__trigger +.video-thumb-info__name,
.favorites-nav-container:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) + .content-column [data-role="favorites-video-collections"] .thumb-list.thumb-list--sidebar .thumb-list__item .video-thumb-info .xh-dropdown+.video-thumb-info__name {
	display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
	padding-right: 20px;
	font-size: 12px;
    line-height: 12px;
}
/* DELETED */
.favorites-nav-container:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) + .content-column [data-role="favorites-video-collections"] .thumb-list.thumb-list--sidebar .thumb-list__item:has(.ist-trigger.disabled) .thumb-image-container__status.status {
	top: 34%;
	background-color: red ;
}

/* VIDEO - LEFT FAV NAV CONTAINER */
.user-page.user-videos-page.my-uploads-page .user-content-section .user-content-body:has(.favorites-nav-container) .favorites-nav-container ,
.main-wrap:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) .favorites-nav-container:has([class*="link-"],[class*="isActive-"]) {
	position: absolute  !important;
    display: inline-block ;
    width: 10%;
	margin: 4vh 0 0px 0 ;
	left: -10%;
	z-index: 5000000;
background-color: red ;
}
.user-page.user-videos-page.my-uploads-page .user-content-section .user-content-body:has(.favorites-nav-container) .favorites-nav-container:before ,
.main-wrap:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) .favorites-nav-container:has([class*="link-"],[class*="isActive-"]):before {
	content: "❤️";
	position: absolute;
    display: inline-block ;
    width: 10% ;
	margin: 0vh 0 0px 0 ;
	right: -10% ;
	padding: 5px 0;
	border-radius: 0 5px 5px 0;
	font-size: 13px;
	z-index: 5000000 !important;
background-color: red ;
}
/* HOVER */
.user-page.user-videos-page.my-uploads-page .user-content-section .user-content-body:has(.favorites-nav-container) .favorites-nav-container:focus-within ,
.main-wrap:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) .favorites-nav-container:has([class*="link-"],[class*="isActive-"]):focus-within ,

.user-page.user-videos-page.my-uploads-page .user-content-section .user-content-body:has(.favorites-nav-container) .favorites-nav-container:hover ,
.main-wrap:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) .favorites-nav-container:has([class*="link-"],[class*="isActive-"]):hover {
	position: absolute;
    display: inline-block ;
    width: 10%;
	margin: 4vh 0 0px 0 ;
	left: 0%;
	z-index: 5000000;
background-color: green ;
}
.user-page.user-videos-page.my-uploads-page .user-content-section .user-content-body:has(.favorites-nav-container) .favorites-nav-container:hover:before ,
.main-wrap:has([class*="link-"],[class*="isActive-"], [class^="subnav-"]) .favorites-nav-container:has([class*="link-"],[class*="isActive-"]):hover:before {
	background-color: green ;
}


/* VIDEO PLAYLIST MENU */
.main-wrap:has([class*="link-"],[class*="isActive-"], [class^="subnav-"])  .favorites-nav-container:has([class*="link-"],[class*="isActive-"]) ul[class^="subnav-"] {
	height: 40vh;
	width: 100%;
    padding: 0 0 0 0 ;
	overflow: hidden auto !important;
background-color: #222 ;
}
.favorites-nav-container:has([class*="link-"],[class*="isActive-"]) ul[class^="subnav-"] li [class^="body-"] {
    display: inline-block ;
    width: 100%;
}
.favorites-nav-container:has([class*="link-"],[class*="isActive-"]) ul[class^="subnav-"] li [class^="body-"] a {
    display: inline-block ;
    width: 100%;
	margin: 0 0 -5px 0 ;
background-color: brown ;
}
.favorites-nav-container:has([class*="link-"],[class*="isActive-"]) ul[class^="subnav-"] li [class^="body-"] a span {
    display: inline-block ;
    width: 100%;
	margin: 0 0 0px 0 ;
	white-space: pre-wrap ;
	color: silver ;
background-color: #075b07 ;
}
.favorites-nav-container:has([class*="link-"],[class*="isActive-"]) ul[class^="subnav-"] li [class^="body-"] a:visited span {
    display: inline-block ;
    width: 100%;
	margin: 0 0 0px 0 ;
	white-space: pre-wrap ;
	color: silver ;
background-color: #931c1c ;
}
    `);
const observer = new MutationObserver(() => {
    const paginationButtons = document.querySelectorAll(`${paginationSelector} .prev-next-list .page-list-wrapper .page-list-container ol.page-list li:has(.page-button-link--active) + li .page-button-link`);

    if (paginationButtons.length > 0) {
        paginationButtons.forEach(button => {
            button.addEventListener('click', () => {
                setTimeout(() => {
                    checkForItemsToDelete();
                }, 300); // wait for 1 second
            });
        });

        observer.disconnect();
    }
});

observer.observe(document.body, {
    childList: true,
    subtree: true
});
    let deleteCount = 0;

    // Function to delete videos
    async function deleteVideos(selector, menuSelector, deleteButtonSelector, saveSelector) {
        const videos = document.querySelectorAll(selector);
        if (videos.length === 0) {
            return 0;
        }

        let deleted = 0;
        for (const video of videos) {
            const menu = video.querySelector(menuSelector);
            if (menu) {
                menu.click();
                await new Promise(resolve => setTimeout(resolve, 10)); // wait for 1 second
                const deleteButton = video.querySelector(deleteButtonSelector);
                if (deleteButton) {
                    deleteButton.click();
                    await new Promise(resolve => setTimeout(resolve, 10)); // wait for 1 second
                    const saveButton = document.querySelector(saveSelector);
                    if (saveButton) {
                        saveButton.click();
                        deleted++;
                    }
                }
            }
        }
        return deleted;
    }

    // Function to auto clean
    let processing = false;
    async function autoClean() {
    if (processing) return;
    processing = true;

    console.log('Auto Clean button clicked');
// OLD .desktop-dialog.desktop-dialog--small.desktop-dialog--fixed-footer:has(.desktop-dialog__header-new) button[class*="color-brand-"]
// NEW [data-role="dialog-manager"] [class*="dialog-"][class*="fixedFooter-"] button[class*="color-brand-"]
    let deleted = 0;
    deleted += await deleteVideos(deletedVideoSelector, '.video-thumb__trigger', '.dropdown.position-right.v-position-down.open .xh-dropdown-item', '[data-role="dialog-manager"] [class*="dialog-"][class*="fixedFooter-"] button[class*="color-brand-"]');
    for (const selector of privateVideoSelectors) {
        deleted += await deleteVideos(selector, '.video-thumb__trigger', '.xh-dropdown:has(.video-thumb__trigger) span', '[data-role="dialog-manager"] [class*="dialog-"][class*="fixedFooter-"] button[class*="color-brand-"]');
    }

    deleteCount += deleted;
    const autoCleanButton = document.querySelector('.xhamster-auto-clean-button');
    autoCleanButton.textContent = `Auto Clean (${deleteCount})`;

    // Check if there are items to delete
    checkForItemsToDelete();

    // Check for pagination and proceed
    const pagination = document.querySelector(paginationSelector);
    if (pagination) {
        const nextButton = document.querySelector(nextButtonSelector);
        if (nextButton) {
            console.log('Checking next page...');
            nextButton.click();
            setTimeout(() => {
                processing = false;
                autoClean();
            }, PAGINATION_DELAY);
        } else {
            console.log('No more pages to check.');
            processing = false;
        }
    } else {
        console.log('Pagination not found.');
        processing = false;
    }
}

// Add Auto Clean button
const targetElement = document.querySelector('body');
if (targetElement) {
    setTimeout(() => {
        const autoCleanButton = document.createElement('button');
        autoCleanButton.textContent = 'Auto Clean (0)';
        autoCleanButton.className = 'xhamster-auto-clean-button';
        autoCleanButton.onclick = autoClean;
        targetElement.appendChild(autoCleanButton);

        console.log('Auto Clean button added');

        // Call checkForItemsToDelete after adding the button
        checkForItemsToDelete();

        // Create a MutationObserver to observe changes to the page
        const observer = new MutationObserver(() => {
            checkForItemsToDelete();
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    }, DELAY); // Wait for 1 second before adding the button
}


// Function to check for items to delete
function checkForItemsToDelete() {
    console.log('Checking for items to delete...');
    const autoCleanButton = document.querySelector('.xhamster-auto-clean-button');
    if (!autoCleanButton) {
        console.log('Auto clean button not found. Retrying in 1 second...');
        setTimeout(checkForItemsToDelete, 10);
        return;
    }

    const videosToDelete = document.querySelectorAll(deletedVideoSelector);
    console.log(`Found ${videosToDelete.length} videos to delete using selector: ${deletedVideoSelector}`);

    let privateVideosToDelete = 0;
    for (const selector of privateVideoSelectors) {
        const privateVideos = document.querySelectorAll(selector);
        console.log(`Found ${privateVideos.length} private videos to delete using selector: ${selector}`);
        privateVideosToDelete += privateVideos.length;
    }

    const hasItemsToDelete = videosToDelete.length + privateVideosToDelete > 0;

    console.log(`Total items to delete: ${videosToDelete.length + privateVideosToDelete}`);

    if (hasItemsToDelete) {
        console.log('Changing button color to red');
        autoCleanButton.classList.add('has-items-to-delete');
        autoCleanButton.style.background = 'linear-gradient(to bottom, #ff0000, #cc0000)';
    } else {
        console.log('Changing button color to green');
        autoCleanButton.classList.remove('has-items-to-delete');
        autoCleanButton.style.background = 'linear-gradient(to bottom, #33cc33, #009900)';
    }
}



    // Run checkForItemsToDelete on page changes
    document.addEventListener('DOMContentLoaded', function() {
    checkForItemsToDelete();
});
observer.observe(document.body, {
    childList: true,
    subtree: true
});
    setTimeout(() => {
        checkForItemsToDelete();
    }, 10); // Call checkForItemsToDelete after 2 seconds

    console.log('Userscript loaded');
})();