bilibili 收藏夹批量复制

批量复制bilibili收藏夹!

// ==UserScript==
// @name         bilibili 收藏夹批量复制
// @namespace    http://tampermonkey.net/
// @version      2024-02-15 v0.5
// @description  批量复制bilibili收藏夹!
// @author       You
// @match        https://space.bilibili.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bilibili.com
// @license      MIT
// @grant        none
// ==/UserScript==

(function() {
    'use strict';


class EventListeners {

    static toggleSelectAll() {
        if (this.selectAllButton.textContent === "点我全选") {
            for (const chkbocItem of this.favCheckboxItemList) {
                chkbocItem.checkbox.checked = true;
            }
            this.selectAllButton.textContent = "点我全部取消";
        } else {
            for (const chkbocItem of this.favCheckboxItemList) {
                chkbocItem.checkbox.checked = false;
            }
            this.selectAllButton.textContent = "点我全选";
        }
    }
    static toggleSelectAll(selectAllButton, favCheckboxItemList) {
        if (selectAllButton.textContent === "点我全选") {
            for (const chkbocItem of favCheckboxItemList) {
                chkbocItem.checkbox.checked = true;
            }
            selectAllButton.textContent = "点我全部取消";
        } else {
            for (const chkbocItem of favCheckboxItemList) {
                chkbocItem.checkbox.checked = false;
            }
            selectAllButton.textContent = "点我全选";
        }
    }

    static toggleMinimize() {
        const floP = this.floatingPanel;
        if (this.minimizeButton.textContent === "点我最小化") {

            this.recordHiddenPanelSize(); 
            this.minimizeButton.textContent = "点我打开面板";
            floP.style.width = this.minW + "px";
            floP.style.height = this.minH + "px";

        } else {
            this.minimizeButton.textContent = "点我最小化";

            floP.style.width = Math.max(this.hiddenWidth, floP.offsetWidth, this.originFPW) + "px";
            floP.style.height = Math.max(this.hiddenHeight, floP.offsetHeight, this.originFPH) + "px";

        }
    }


    static stopResizeOnBody() {
        this.resizeable = false
    }
    static stopDragOnPanel() {
        this.isDragging = false;
    }



    static mouseDown(e) {
        const floP = this.floatingPanel;
        let d = this.getDirection(e)

        if (d !== '') {
            this.resizeable = true
            this.isDragging = false
            this.direction = d

        } else {
            
            

            if (e.target.tagName === 'BUTTON' || e.target.tagName === 'INPUT' || e.target.classList.contains('output-text-box')) {
                
            }
            else {
                this.isDragging = true;
                this.offsetX = e.clientX - floP.getBoundingClientRect().left;
                this.offsetY = e.clientY - floP.getBoundingClientRect().top;
            }
        }
    }

    
    static mouseMove(e) {
        let floP = this.floatingPanel;
        
        let d = this.getDirection(e)

        
        let cursor
        if (d === '') cursor = 'default';
        else cursor = d + '-resize';
        floP.style.cursor = cursor;

        if (this.resizeable) {
            
            const direc = this.direction;
            let newWidth = floP.offsetWidth;
            let newHeight = floP.offsetHeight;
            

            let originTop = floP.offsetTop;
            let originLeft = floP.offsetLeft;
            let newTop = originTop;
            let newLeft = originLeft;

            
            
            if (direc.indexOf('w') !== -1) {
                newWidth -= e.movementX;
                newLeft += e.movementX;
            }
            
            if (direc.indexOf('n') !== -1) {
                newHeight -= e.movementY;
                newTop += e.movementY;
            }

            
            if (direc.indexOf('e') !== -1) {
                newWidth += e.movementX;

            }

            
            if (direc.indexOf('s') !== -1) {
                newHeight += e.movementY;
            }


            this.judgePanelSizeAndUpdate(newLeft, newTop, newWidth, newHeight, originTop, originLeft);



        }
    }


    static dragOnPanel(e) {
        if (this.isDragging) {
            const floP = this.floatingPanel;
            
            let newLeft = e.clientX - this.offsetX;
            let newTop = e.clientY - this.offsetY;

            this.judgePanelPosAndUpdate(newLeft, newTop);
        }
    }




}


class CreateElemClass {
    constructor() {
        this.name = "CreateElemClass";
    }
    getName() {
        return this.name;
    }
    static createButton(text, clickHandler, className = "btn") {
        const button = document.createElement("button");
        button.textContent = text;

        button.classList.add("btn");
        
        button.style.margin = "0px";
        button.style.padding = '0px 0px';
        button.style.fontSize = '14px';
        
        button.style.width = '150px';
        button.style.height = '40px';

        
        button.style.marginTop = '5px';
        button.style.marginLeft = '5px';

        if (clickHandler)
            button.addEventListener("click", clickHandler);

        return button;
    }

    static createOutputTextBox() {

        
        const editableArea = document.createElement('div');

        
        editableArea.classList.add('output-text-box');
        
        
        editableArea.style.border = '1px solid #ccc'; 
        editableArea.style.padding = '5px'; 
        editableArea.style.boxSizing = 'border-box'; 
        editableArea.style.whiteSpace = 'nowrap'; 
        editableArea.style.minWidth = "400px";
        editableArea.contentEditable = true; 
        editableArea.style.flexGrow = "1";
        
        

        editableArea.style.overflow = 'auto'; 
        
        
        
        
        

        
        editableArea.addEventListener('scroll', function () {
            this.scrollTopEnabled = false;
        });
        return editableArea;
    }



    static createSubDiv(className, floatPos, width, height) {
        const subPanel = document.createElement("div");
        subPanel.style.flexGrow = "1";
        subPanel.style.display = 'flex';
        subPanel.style.border = "1px solid #ccc"; 
        if (className)
            subPanel.classList.add(className);
        if (floatPos)
            subPanel.style.float = floatPos;
        if (width)
            subPanel.style.width = width;

        if (height) {
            subPanel.style.height = height;
        }


        return subPanel;
    }
}
class CheckboxItem {
    constructor(favName) {
        this.checkboxContainer = this.createCheckboxContainer(favName);
        this.checkbox = this.checkboxContainer.querySelector("input[type='checkbox']");
        this.label = this.checkboxContainer.querySelector("label");
        this.inputText = this.checkboxContainer.querySelector("input[type='text']");
    }

    createCheckboxContainer(favName) {
        const checkboxContainer = document.createElement("div");
        const checkboxDiv = CreateElemClass.createSubDiv("signal-panel");
        checkboxDiv.style.justifyContent = "space-between";

        const checkbox = document.createElement("input");
        checkbox.type = "checkbox";
        checkbox.id = `checkbox-${favName}`;

        
        const label = document.createElement("label");
        label.textContent = favName;
        label.setAttribute("for", `checkbox-${favName}`);

        
        const inputText = document.createElement("input");
        inputText.type = "text";
        inputText.value = favName;
        
        inputText.style.textAlign = "center";

        
        checkboxDiv.appendChild(checkbox);
        checkboxDiv.appendChild(label);
        checkboxDiv.appendChild(inputText);

        
        checkboxContainer.appendChild(checkboxDiv);

        return checkboxContainer;
    }

    getLabelValue() {
        return this.label.textContent;
    }

    getInputTextValue() {
        return this.inputText.value;
    }

    getCheckboxValue() {
        return this.checkbox.checked;
    }
}


class ControlPanel {
    constructor(favBtns, favulList) {
        this.createMembers(favBtns, favulList);
        this.leftPanel = this.createLeftPanel();
        this.rightPanel = this.createRightPanel();
        this.floatingPanel = this.createFloatingPanel();


    }

    createMembers(favBtns, favulList) {
        this.delayTimeShort = 500;
        this.delayTimeMiddle = 1000;
        
        this.errorCode = 0;
        this.normalCode = 1;
        this.startBatchCode = 2;
        this.startSingleCode = 3;
        this.endSingleCode = 4;
        this.endBatchCode = 5;
        this.onePageCode = 6;

        this.leftWidth = "35%";
        this.rightWidth = "63%";


        this.isDragging = false;
        this.resizeable = false; 
        this.scrollTopEnabled = true;

        this.favBtns = favBtns;
        this.favulList = favulList;
        this.favCheckboxItemList = this.createFavCheckboxItems();
    }

    createLeftPanel() {
        this.btnContainer = this.cretaeButtonContainer();
        
        this.favContainer = this.createFavPanel();
        
        
        const leftPanel = CreateElemClass.createSubDiv("left-panel", "left");
        leftPanel.appendChild(this.btnContainer);
        leftPanel.appendChild(this.favContainer);
        leftPanel.style.flexGrow = "0"; 

        
        

        
        leftPanel.style.backgroundColor = "green";

        return leftPanel;
    }

    createRightPanel() {

        const textContainer = document.createElement("div");
        const textDiv = CreateElemClass.createSubDiv("div");
        

        const hintText = document.createElement("h3");
        
        hintText.style.fontWeight = "bold";
        hintText.textContent = "输出信息";

        textDiv.appendChild(hintText);
        textContainer.appendChild(textDiv);


        this.outputTextBox = CreateElemClass.createOutputTextBox();
        this.outputTextBox.style.backgroundColor = "pink";

        const rightPanel = CreateElemClass.createSubDiv("right-panel", "right");
        rightPanel.style.backgroundColor = "yellow";
        rightPanel.style.overflowX = "hidden";
        
        rightPanel.style.flexDirection = 'column';
        rightPanel.appendChild(textContainer);
        rightPanel.appendChild(this.outputTextBox);

        
        



        
        

        
        return rightPanel;
    }

    cretaeButtonContainer() {
        const btnContainer = document.createElement("div");
        this.btnPanel = this.createButtonPanel();
        btnContainer.appendChild(this.btnPanel);
        return btnContainer;
    }

    createButtonPanel() {
        const btnPanel = document.createElement("div");
        btnPanel.className = "btn-panel";
        
        btnPanel.style.display = 'flex';
        btnPanel.style.border = "1px solid #ccc"; 

        
        btnPanel.style.backgroundColor = "purple";
        btnPanel.style.flexDirection = 'column';

        const selectAllButton = CreateElemClass.createButton("点我全选");
        selectAllButton.addEventListener("click", () => {
            EventListeners.toggleSelectAll(selectAllButton, this.favCheckboxItemList);
        });
        

        const startBatchTransferButton = CreateElemClass.createButton("开始批量复制");
        const startTransferCurrentButton = CreateElemClass.createButton("开始复制当前收藏夹");
        const minimizeButton = CreateElemClass.createButton("点我最小化", EventListeners.toggleMinimize.bind(this), "minimize-btn");
        const destroyButton = CreateElemClass.createButton('点我销毁', () => {
            this.floatingPanel.remove();
            
            delete this;



        });

        btnPanel.appendChild(selectAllButton);
        btnPanel.appendChild(startBatchTransferButton);
        let showAll = false;
        if (showAll) {
            btnPanel.appendChild(startTransferCurrentButton); 
        }
        btnPanel.appendChild(minimizeButton);
        btnPanel.appendChild(destroyButton);

        this.selectAllButton = selectAllButton;
        this.minimizeButton = minimizeButton;
        this.startBatchTransferButton = startBatchTransferButton;
        this.startTransferCurrentButton = startTransferCurrentButton;

        

        return btnPanel;
    }

    createFavContainer() {
        const favContainer = document.createElement("div");
        this.favPanel = this.createFavPanel();
        favContainer.appendChild(this.favPanel);
        return favContainer;
    }

    createFavPanel() {
        const favPanel = CreateElemClass.createSubDiv("fav-panel");
        
        favPanel.style.backgroundColor = "red";
        
        
        favPanel.style.overflow = "auto";
        favPanel.style.flexDirection = 'column';

        
        const textContainer = document.createElement("div");

        const textDiv = CreateElemClass.createSubDiv("div");
        
        textDiv.style.justifyContent = "space-between";

        const srcText = document.createElement("h3");
        
        srcText.style.fontWeight = "bold";
        srcText.textContent = "源收藏夹";

        const dstText = document.createElement("h3");
        
        dstText.style.fontWeight = "bold";
        dstText.textContent = "目标收藏夹";

        
        textDiv.appendChild(srcText);
        textDiv.appendChild(dstText);

        
        textContainer.appendChild(textDiv);
        favPanel.appendChild(textContainer);

        for (const chkboxItem of this.favCheckboxItemList) {
            favPanel.appendChild(chkboxItem.checkboxContainer);
        }
        return favPanel;
    }

    createFavCheckboxItems() {
        let favCheckboxItemList = [];
        for (const ul of this.favulList) {
            const chkboxItem = new CheckboxItem(ul.textContent);
            favCheckboxItemList.push(chkboxItem);
        }
        return favCheckboxItemList;
    }

    getSelectedItems() {
        let selectedItems = [];
        for (const chkboxItem of this.favCheckboxItemList) {
            if (chkboxItem.getCheckboxValue()) {
                selectedItems.push(chkboxItem);
            }
        }
        return selectedItems;
    }

    recordPanelSize() {

        const fPW = this.floatingPanel.offsetWidth;
        const fPH = this.floatingPanel.offsetHeight;

        if (this.originRPW === undefined) {

            this.originRPW = this.rightPanel.offsetWidth;
            this.originRPH = this.rightPanel.offsetHeight;

            this.originBtnContainerW = this.btnContainer.offsetWidth;
            this.originBtnContainerH = this.btnContainer.offsetHeight;

            this.originFavContainerW = this.favContainer.offsetWidth;
            this.originFavContainerH = this.favContainer.offsetHeight;

            this.originFPW = fPW;
            this.originFPH = fPH;

            this.minW = this.originFPW;
            this.minW = this.leftPanel.offsetWidth;
            this.minH = this.originFPH;
            this.minH = this.btnPanel.offsetHeight;
            
            
        }


        
        

        
        this.floatingPanel.style.width = fPW + "px";
        this.floatingPanel.style.height = fPH + "px";

    }

    recordHiddenPanelSize() {
        this.hiddenWidth = this.floatingPanel.offsetWidth;
        this.hiddenHeight = this.floatingPanel.offsetHeight;
    }




    judgePanelSizeAndUpdate(newLeft, newTop, newWidth, newHeight, originTop, originLeft) {

        const floP = this.floatingPanel;
        


        


        
        let viewportWidth = window.innerWidth || document.documentElement.clientWidth;
        let viewportHeight = window.innerHeight || document.documentElement.clientHeight;

        if (newLeft < 0 || newLeft + newWidth > viewportWidth) {
            return
        }
        if (newTop < 0 || newTop + newHeight > viewportHeight) {
            return
        }


        
        if (newWidth < this.minW) {
            newWidth = this.minW;
            newLeft = originLeft;
        }

        

        if (newHeight < this.minH) {
            newHeight = this.minH;
            newTop = originTop;
        }
        
        
        

        
        
        



        floP.style.width = newWidth + "px";
        floP.style.height = newHeight + "px";

        floP.style.top = newTop + "px";
        floP.style.left = newLeft + "px";


    }
    judgePanelPosAndUpdate(newLeft, newTop) {

        const floP = this.floatingPanel;
        
        let viewportWidth = window.innerWidth || document.documentElement.clientWidth;
        let viewportHeight = window.innerHeight || document.documentElement.clientHeight;


        
        newLeft = Math.max(0, Math.min(newLeft, viewportWidth - floP.offsetWidth));
        newTop = Math.max(0, Math.min(newTop, viewportHeight - floP.offsetHeight));


        
        floP.style.left = newLeft + "px";
        floP.style.top = newTop + "px";

        
    }

    createFloatingPanel() {
        
        const floP = document.createElement("div");
        
        floP.style.backgroundColor = "blue";
        floP.classList.add("floating-panel");
        floP.style.position = "fixed";
        floP.style.top = "50px";
        floP.style.left = "50px";
        floP.style.backgroundColor = "#ffffff";
        floP.style.border = "0px solid #ccc";
        floP.style.borderRadius = "5px";
        floP.style.padding = "0px";
        floP.style.boxShadow = "0 2px 5px rgba(0, 0, 0, 0.1)";
        floP.style.zIndex = "99999";

        
        

        floP.style.display = "flex";



        floP.addEventListener('mousedown', EventListeners.mouseDown.bind(this));
        floP.addEventListener("mouseup", EventListeners.stopDragOnPanel.bind(this));
        floP.addEventListener("mousemove", EventListeners.dragOnPanel.bind(this));

        
        document.body.addEventListener('mousemove', EventListeners.mouseMove.bind(this))
        document.body.addEventListener('mouseup', EventListeners.stopResizeOnBody.bind(this));



        floP.appendChild(this.leftPanel);
        floP.appendChild(this.rightPanel);
        return floP;
    }

    
    getDirection(ev) {
        const floP = this.floatingPanel;
        let dir = '';
        if (ev.clientX - floP.getBoundingClientRect().left < 15)
            dir += 'w';
        else if (floP.getBoundingClientRect().right - ev.clientX < 15)
            dir += 'e';

        if (ev.clientY - floP.getBoundingClientRect().top < 15)
            dir += 'n';
        else if (floP.getBoundingClientRect().bottom - ev.clientY < 15)
            dir += 's';
        return dir;

    }

    appendInfo(info, type = this.normalCode) {
        this.appendInfoToTextarea(this.outputTextBox, info, type);
    }

    appendInfoToTextarea(textarea, info, type = this.normalCode) {
        
        
        let currentDate = new Date();
        let timezoneOffset = currentDate.getTimezoneOffset();
        let timezoneOffsetMilliseconds = timezoneOffset * 60 * 1000;
        let userCurrentDate = new Date(currentDate.getTime() - timezoneOffsetMilliseconds);
        let formattedDate = userCurrentDate.toISOString().replace(/T/, ' ').replace(/\..+/, '');
        
        let textColor;
        let brCnt = 1;
        switch (type) {
            case this.errorCode:
                textColor = 'red';
                break;
            case this.normalCode:
                textColor = 'black';
                break;
            case this.endBatchCode:
                brCnt++;
            case this.startBatchCode:
                brCnt++;
                textColor = 'blue';
                break;
            case this.endSingleCode:
                brCnt++;
            case this.startSingleCode:
                textColor = 'green';
                break;
            case this.onePageCode:
                textColor = 'purple';
                info+="--------------";
                break;
            default:
                textColor = 'black'; 
                break;
        }

        
        const span = document.createElement('span');
        span.style.color = textColor;
        span.textContent = formattedDate + ':' + info; 

        
        textarea.appendChild(span);
        for (let i = 0; i < brCnt; i++) {
            textarea.appendChild(document.createElement('br'));
        }


        
        if (this.scrollTopEnabled) {
            textarea.scrollTop = textarea.scrollHeight;
        }
    }



}
class BatchTransfer {

    constructor() {
        this.usage = "Hi,这是一个Bilibili 收藏夹管理工具,可以批量复制保存其他人的收藏夹视频,也可以批量复制自己的收藏夹视频(还未实现)。";
        this.delayTimeShort = 500;
        this.delayTimeMiddle = 1000;
        
        this.errorCode = 0;
        this.normalCode = 1;
        this.startBatchCode = 2;
        this.startSingleCode = 3;
        this.endSingleCode = 4;
        this.endBatchCode = 5;
        this.onePageCode = 6;

        
        this.favBtns = this.getAllFavBtns(); 
        this.favulList = this.iterateFavs(); 

        this.selectedItems = []
        
        this.ctl = new ControlPanel(this.favBtns, this.favulList);
        this.floatingPanel = this.ctl.floatingPanel;

        this.ctl.startBatchTransferButton.addEventListener("click", this.initiateBatchOperation.bind(this));
        this.ctl.startTransferCurrentButton.addEventListener("click", this.transferOneFav.bind(this));


        document.body.insertBefore(this.floatingPanel, document.body.firstChild);
        this.ctl.recordPanelSize();
    }



    getAllFavLinks() {
        
        let parentElement = document.getElementById('fav-createdList-container');
        
        let links = parentElement.querySelectorAll('a[href]');
        return links;
    }

    getAllFavBtns() {
        let buttons = document.querySelectorAll('#fav-createdList-container .fav-item a');
        return buttons;
        
        buttons.forEach(function (button) {
            button.click(); 
        });
    }
    iterateFavs() {
        
        let favulList = []
        for (const btn of this.favBtns) {
            const ul = document.createElement("ul");
            ul.innerHTML = "<input type='checkbox' id='checkBox' name='checkBox' value='" + btn.title + "' />" + btn.title;
            favulList.push(ul);
        }
        return favulList;
    }


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

        
        this.selectedItems = this.ctl.getSelectedItems();

        await this.delay(this.delayTimeShort);
        this.ctl.appendInfo("开始批量复制", this.startBatchCode);

        for (const item of this.selectedItems) {
            let srcFav = item.getLabelValue();
            let dstFav = item.getInputTextValue();

            
            let btn = null;
            this.favBtns.forEach(function (button) {
                if (button.title === srcFav) {
                    btn = button;
                    return;
                }
            });
            btn.click();
            await this.delay(this.delayTimeShort);
            await this.transferOneFav(srcFav, dstFav);
        }

        this.ctl.appendInfo("批量复制结束", this.endBatchCode);

    }

    async transferOneFav(sourceFavName, targetFavName) {

        if (sourceFavName === undefined) {
            const sourceFavName = document.querySelector('.favInfo-details .fav-name').textContent.trim();
        }
        if (targetFavName === undefined) {
            const targetFavName = sourceFavName;
        }

        const totalPagesElement = document.querySelector('.be-pager-item[title^="最后一页"]');
        const totalPages = totalPagesElement ? parseInt(totalPagesElement.textContent.trim().split(':')[0]) : 1; 

        this.ctl.appendInfo("开始复制收藏夹[" + sourceFavName + "]到[" + targetFavName + "],一共" + totalPages + "页", this.startSingleCode);

        
        let batchOperationButton = document.querySelector('.filter-item.do-batch .text');
        if (batchOperationButton && batchOperationButton.textContent.trim() === "批量操作") {
            batchOperationButton.click();
        } else {
            this.ctl.appendInfo("Error!!! 找不到[批量操作]按钮或按钮文本不匹配", this.errorCode);

        }
        await this.delay(this.delayTimeShort);
        await this.saveCollection(1, totalPages, sourceFavName, targetFavName); 
    }

    async saveCollection(currentPage, totalPages, sourceFavName, targetFavName) {
        if (sourceFavName === undefined) {
            const sourceFavName = document.querySelector('.favInfo-details .fav-name').textContent.trim();
        }
        if (targetFavName === undefined) {
            const targetFavName = sourceFavName;
        }

        if (currentPage > totalPages || totalPages == 0) {
            this.ctl.appendInfo("收藏夹[" + sourceFavName + "]复制到[" + targetFavName + "]结束", this.endSingleCode);
            return;
        }

        this.ctl.appendInfo("正在保存第" + currentPage + "页", this.onePageCode);

        this.ctl.appendInfo("点击[全选]按钮");
        document.querySelector('.icon-selece-all').parentNode.click();
        await this.delay(this.delayTimeShort);

        this.ctl.appendInfo("点击[复制到]按钮");
        document.querySelector('.icon-copy').parentNode.click();
        await this.delay(this.delayTimeShort);

        const targetFavList = document.querySelectorAll('.target-favlist-container .fav-name');
        let hasSameNameFav = false;

        targetFavList.forEach(function (targetFav) {
            if (targetFav.textContent.trim() === targetFavName) {
                hasSameNameFav = true;
                return;
            }
        });

        if (!hasSameNameFav) {
            this.ctl.appendInfo("创建新的收藏夹:[" + targetFavName + "]");
            this.ctl.appendInfo("点击[新建收藏夹]按钮");
            document.querySelector('.fake-fav-input').click();
            await this.delay(this.delayTimeMiddle);

            this.ctl.appendInfo("输入新收藏夹名称:[" + targetFavName + "]");
            const inputText = document.querySelector('.add-fav-input');
            inputText.value = targetFavName;
            inputText.dispatchEvent(new Event('input', { bubbles: true }));
            await this.delay(this.delayTimeShort);

            this.ctl.appendInfo("点击[新建]按钮");
            document.querySelector('.fav-add-btn').click();
        }

        await this.delay(this.delayTimeShort);

        this.ctl.appendInfo("点击目标收藏夹:[" + targetFavName + "]");
        const favListContainer = document.querySelector('.target-favlist-container');
        const favItems = favListContainer.querySelectorAll('.target-favitem');

        favItems.forEach(function (item) {
            const folderNameElement = item.querySelector('.fav-name');
            if (folderNameElement && folderNameElement.textContent.trim() === targetFavName) {
                folderNameElement.click();
                return;
            }
        });

        await this.delay(this.delayTimeShort);

        this.ctl.appendInfo("点击[确定]");
        const panel = document.querySelector('.edit-video-modal');
        const confirmBtn = panel.querySelector('.btn-content');
        confirmBtn.click();
        await this.delay(this.delayTimeShort);

        this.ctl.appendInfo("点击[下一页]按钮");
        const nextPageBtn = document.querySelector('.be-pager-next');
        if(!nextPageBtn){
            this.ctl.appendInfo("Error!!! 找不到[下一页]按钮,判断为单页收藏夹.", this.errorCode);
            this.ctl.appendInfo("收藏夹[" + sourceFavName + "]复制到[" + targetFavName + "]结束", this.endSingleCode);
            return;
        }
        nextPageBtn.click();
        await this.delay(this.delayTimeMiddle);
        await this.saveCollection(currentPage + 1, totalPages, sourceFavName, targetFavName);
    }
}


setTimeout(function () {
    let bt = new BatchTransfer()
}, 2000);



    // Your code here...
})();