Greasy Fork

Greasy Fork is available in English.

SmartStrm助手 - 转存触发任务

监听天翼云盘、夸克网盘和115网盘转存成功事件,根据转存路径触发 SmartStrm 任务,支持设置延时触发。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         SmartStrm助手 - 转存触发任务
// @namespace    https://github.com/Cp0204/SmartStrm
// @license      AGPL
// @icon         https://raw.githubusercontent.com/Cp0204/SmartStrm/refs/heads/main/img/icon.svg
// @version      1.2
// @description  监听天翼云盘、夸克网盘和115网盘转存成功事件,根据转存路径触发 SmartStrm 任务,支持设置延时触发。
// @author       Cp0204
// @match        https://cloud.189.cn/web/share?code=*
// @match        https://pan.quark.cn/s/*
// @match        https://115cdn.com/s/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        unsafeWindow
// @connect      *
// @require      https://cdn.jsdelivr.net/npm/sweetalert2@11
// ==/UserScript==

(function () {
    'use strict';

    let webhook = GM_getValue('webhook', '');
    let delay = parseInt(GM_getValue('delay', 0), 10);

    // 设置
    async function setWebhookUrl() {
        Swal.fire({
            title: 'SmartStrm助手设置',
            html: `
                <label for="webhook-input">Webhook 地址:</label>
                <input id="webhook-input" class="swal2-input" placeholder="http://192.168.8.8:8024/webhook/9dfb573e83" value="${webhook || ''}"><br>
                <label for="delay-input">执行延时:</label>
                <input id="delay-input" class="swal2-input" type="number" min="0" title="0为不延时" value="${delay}"> 秒
            `,
            focusConfirm: false,
            showCancelButton: true,
            preConfirm: () => {
                const webhookInput = document.getElementById('webhook-input').value;
                const delayInput = document.getElementById('delay-input').value;
                if (!webhookInput) {
                    Swal.showValidationMessage('Webhook 地址不能为空!');
                    return false;
                }
                if (delayInput === '' || isNaN(parseInt(delayInput, 10)) || parseInt(delayInput, 10) < 0) {
                    Swal.showValidationMessage('延时应为非负整数!');
                    return false;
                }
                return { webhook: webhookInput, delay: parseInt(delayInput, 10) };
            }
        }).then((result) => {
            if (result.isConfirmed) {
                webhook = result.value.webhook;
                delay = result.value.delay;
                GM_setValue('webhook', webhook);
                GM_setValue('delay', delay);
                Swal.fire({
                    title: '设置已保存',
                    icon: 'success',
                    html: `Webhook 地址: ${webhook}<br><br>转存延时: ${delay} 秒<br><br>可在油猴菜单中重新设置`,
                    confirmButtonText: '好的'
                });
            }
        });;
    }

    // 注册菜单命令
    GM_registerMenuCommand('参数设置', setWebhookUrl);


    // 页面加载完成后再检查
    window.addEventListener('load', async () => {
        if (!webhook) {
            await setWebhookUrl();
        }
        // 根据当前域名判断处理逻辑
        if (window.location.hostname === 'cloud.189.cn') {
            initCloud189();
        } else if (window.location.hostname === 'pan.quark.cn') {
            initQuark();
        } else if (window.location.hostname === '115cdn.com') {
            init115();
        }
        console.log('SmartStrm助手已启动');
    });


    // 天翼云盘处理逻辑
    function initCloud189() {
        let saveSuccess = false;
        const originalOpen = XMLHttpRequest.prototype.open;
        const originalSend = XMLHttpRequest.prototype.send;
        XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
            this._url = url;
            originalOpen.apply(this, arguments);
        };
        XMLHttpRequest.prototype.send = function (body) {
            this.addEventListener('load', function () {
                try {
                    if (this._url.includes('api/open/batch/checkBatchTask.action')) {
                        const response = JSON.parse(this.responseText);
                        // taskStatus=4 任务成功
                        if (response.taskStatus === 4) {
                            saveSuccess = true;
                            console.log('检测到天翼云盘转存成功');
                        }
                    }
                    // 监听系统发出的 getLastSavePath.action 请求,但仅在转存成功后才处理
                    else if (this._url.includes('api/open/getLastSavePath.action') && saveSuccess) {
                        const response = JSON.parse(this.responseText);
                        if (response.code === 'success') {
                            const savepath = response.data.filePath;
                            sendWebhook(savepath, 'cloud189');
                            saveSuccess = false;
                        }
                    }
                } catch (e) {
                    console.error('SmartStrm助手解析响应出错:', e);
                }
            });
            originalSend.apply(this, arguments);
        };
    }

    // 夸克网盘处理逻辑
    function initQuark() {
        const originalOpen = XMLHttpRequest.prototype.open;
        const originalSend = XMLHttpRequest.prototype.send;
        XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
            this._url = url;
            originalOpen.apply(this, arguments);
        };
        XMLHttpRequest.prototype.send = function (body) {
            this.addEventListener('load', function () {
                try {
                    if (this._url.includes('drive-pc.quark.cn/1/clouddrive/task')) {
                        const response = JSON.parse(this.responseText);
                        // status=2 任务成功
                        if (response.data && response.data.status === 2) {
                            console.log('检测到夸克网盘转存成功');
                            let pathElement = document.querySelector('.path-name');
                            const savepath = pathElement ? pathElement.title.replace('全部文件', '').trim() : "";
                            sendWebhook(savepath, 'quark');
                        }
                    }
                } catch (e) {
                    console.error('SmartStrm助手解析响应出错:', e);
                }
            });
            originalSend.apply(this, arguments);
        };
    }

    // 115网盘处理逻辑
    function init115() {
        const originalFetch = unsafeWindow.fetch;
        unsafeWindow.fetch = async function (input, init) {
            const url = typeof input === 'string' ? input : input.url;
            const response = await originalFetch(input, init);
            const clonedResponse = response.clone();
            try {
                if (url.includes('webapi/share/receive')) {
                    const responseJson = await clonedResponse.json();
                    if (responseJson.state === true) {
                        // 等待1秒,确保最近路径更新完成
                        setTimeout(() => {
                            console.log('检测到115网盘转存成功');
                            // 1. 获取当前用户的 uid
                            let currentUserJson = unsafeWindow.sessionStorage.getItem('current_user');
                            let user = JSON.parse(currentUserJson);
                            let uid = user.id;
                            // 2. 获取文件保存路径
                            let lastSavePathJson = unsafeWindow.localStorage.getItem('file_picker_last_save_path_' + uid);
                            let lastSavePath = JSON.parse(lastSavePathJson);
                            let savepath = lastSavePath.name;
                            // 3. 发送 webhook 通知
                            sendWebhook(savepath, 'open115');
                        }, 500);
                    }
                }
            } catch (e) {
                console.error('SmartStrm助手解析Fetch响应出错:', e);
            }
            return response;
        };
    }

    // 发送webhook通知
    function sendWebhook(savepath, driver) {
        const currentWebhook = GM_getValue('webhook', '');
        const currentDelay = parseInt(GM_getValue('delay', '0'), 10);
        if (isNaN(currentDelay)) currentDelay = 0;

        if (!currentWebhook) {
            console.error('Webhook地址未设置');
            return;
        }
        GM_xmlhttpRequest({
            method: 'POST',
            url: currentWebhook,
            headers: {
                'Content-Type': 'application/json'
            },
            data: JSON.stringify({
                event: 'web_save',
                delay: currentDelay,
                data: {
                    driver: driver,
                    savepath: savepath
                },
            }),
            onload: function (response) {
                const data = JSON.parse(response.responseText);
                if (data.success) {
                    console.log('Webhook发送成功:', data.message, data.task);
                    showFloatingTip(`Webhook发送成功: ${data.message || ''} [${data.task.name}] ${data.task.storage_path}`, 'success');
                } else {
                    console.error('Webhook发送成功,但触发失败:', data.message);
                    showFloatingTip(`Webhook发送成功,但触发失败: ${data.message || ''}`, 'error');
                }
            },
            onerror: function (error) {
                console.error('Webhook发送失败:', error);
                showFloatingTip(`Webhook发送失败: ${error.responseText || error.statusText || '未知错误'}`, 'error');
            }
        });
    }

    // 显示 SweetAlert2 悬浮提示
    function showFloatingTip(message, type) {
        Swal.fire({
            text: message,
            icon: type,
            toast: true,
            position: 'top',
            showConfirmButton: false,
            timer: 5000,
            timerProgressBar: true,
            customClass: { container: 'swal2-always-on-top' },
            didOpen: (toast) => {
                toast.addEventListener('mouseenter', Swal.stopTimer);
                toast.addEventListener('mouseleave', Swal.resumeTimer);
            }
        });
    }

    // 确保 SweetAlert2 提示框始终在顶部
    const style = document.createElement('style');
    style.textContent = `.swal2-always-on-top {z-index: 999999 !important;}`;
    document.head.appendChild(style);
})();