Greasy Fork is available in English.

dav

Henry Toys dav api

Tento skript by nemal byť nainštalovaný priamo. Je to knižnica pre ďalšie skripty, ktorú by mali používať cez meta príkaz // @require https://update.greasyfork.ip-ddns.com/scripts/539094/1608444/dav.js

// ==UserScript==
// @name         dav
// @namespace    dav
// @version      3.0.1
// @description  Henry Toys dav api
// @author       Henry

// @grant        unsafeWindow

// @grant        GM_download
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_xmlhttpRequest
// @grant        GM_registerMenuCommand

// @license      CC-BY-4.0
// ==/UserScript==

const dav = {
    login: async function () {
        const validate_url = function (url) {
            try {
                new URL(url)
                return true
            } catch {
                return false
            }
        }
        const validate_login = function (loginurl, username, password) {
            return new Promise((resolve) => {
                try {
                    GM_xmlhttpRequest({
                        method: "PROPFIND",
                        url: loginurl,
                        headers: { 'Authorization': 'Basic ' + btoa(username + ':' + password), 'Depth': '0' },
                        timeout: 10000,
                        onload: (response) => {
                            if (response.status == 207) {
                                const dav_login_data = {
                                    "loginurl": loginurl,
                                    "username": username,
                                    "password": password,
                                    "expires": new Date().getTime() + 1000 * 60 * 60 * 24 * 7
                                }
                                GM_setValue("dav_login_data", JSON.stringify(dav_login_data))
                                resolve(true)
                            } else {
                                GM_deleteValue('dav_login_data')
                                resolve(false)
                            }
                        },
                        onerror: () => {
                            GM_deleteValue('dav_login_data')
                            resolve(false)
                        },
                        ontimeout: () => {
                            GM_deleteValue('dav_login_data')
                            resolve(false)
                        }
                    });
                } catch (requestError) {
                    GM_deleteValue('dav_login_data')
                    resolve(false)
                }
            })
        }
        const login_promot = async function () {
            let loginurl, username, password
            let is_valid = false
            while (!is_valid) {
                // 获取并验证登录网址
                do {
                    loginurl = prompt("请输入登录网址:")
                    if (loginurl === null) return null // 用户点击取消
                    loginurl = loginurl.trim()
                    if (!loginurl) {
                        alert("登录网址不能为空!")
                    } else if (!validate_url(loginurl)) {
                        alert("请输入有效的URL地址!")
                    }
                } while (!loginurl || !validate_url(loginurl))

                // 获取并验证用户名
                do {
                    username = prompt("请输入用户名:")
                    if (username === null) return null // 用户点击取消
                    username = username.trim()
                    if (!username) {
                        alert("用户名不能为空!")
                    }
                } while (!username)

                // 获取并验证密码
                do {
                    password = prompt("请输入密码")
                    if (password === null) return null // 用户点击取消
                    password = password.trim()
                    if (!password) {
                        alert("密码不能为空!")
                    }
                } while (!password)
                is_valid = await validate_login(loginurl, username, password)
                console.log("验证登录信息:", is_valid)
                location.reload() // 刷新页面
                if (!is_valid) {
                    alert("登录信息不正确,请重新输入!")
                }
            }

            const login_details = { loginurl, username, password }
            if (login_details) {
                console.log("登录信息已收集")
                // 这里可以添加登录逻辑
            } else {
                console.log("用户取消了登录操作")
            }
        }
        // 使用示例
        GM_registerMenuCommand("登录", login_promot)
    },

    logout: function () {
        const confirm = window.confirm('确定要退出登录吗?')
        if (!confirm) { return }
        // 如果用户确认退出登录,则删除登录数据
        GM_deleteValue('dav_login_data')
        alert('已退出登录')
        location.reload() // 刷新页面        
    },

    get_login_data: function () {
        let dav_login_data = JSON.parse(GM_getValue("dav_login_data", null))
        const self = this
        // 检查数据是否存在或已过期
        if (!dav_login_data ||
            !dav_login_data.loginurl ||
            !dav_login_data.username ||
            !dav_login_data.password ||
            dav_login_data.expires < new Date().getTime()) {
            GM_deleteValue('dav_login_data')
            self.login()
        } else {
            GM_registerMenuCommand("退出登录", self.logout)
        }
        return JSON.parse(GM_getValue("dav_login_data", null))
    },

    request: async function (method, path, callback, responseType = 'text', data = null) {
        const login_data = this.get_login_data()
        if (!login_data ||
            !login_data.loginurl ||
            !login_data.username ||
            !login_data.password ||
            login_data.expires < new Date().getTime()) {
            GM_deleteValue('dav_login_data')
            this.get_login_data()
            throw new Error('Invalid or missing login credentials')
        } else {
            const updated_dav_login_data = {
                "loginurl": login_data.loginurl,
                "username": login_data.username,
                "password": login_data.password,
                "expires": new Date().getTime() + 1000 * 60 * 60 * 24 * 7 // 7天后过期
            }
            GM_setValue("dav_login_data", JSON.stringify(updated_dav_login_data))
        }
        return new Promise((resolve) => {
            try {
                GM_xmlhttpRequest({
                    method: method,
                    data: data,
                    url: login_data.loginurl + path,
                    headers: { 'Authorization': 'Basic ' + btoa(login_data.username + ':' + login_data.password), },
                    responseType: responseType,
                    timeout: 30000, // 设置默认超时时间为30秒
                    onload: async (response) => { await callback(response, resolve) },
                    onerror: (error) => {
                        console.log('Request error:', error)
                        GM_deleteValue('dav_login_data')
                        this.get_login_data()
                    },
                    ontimeout: () => {
                        console.log('Request timed out')
                        GM_deleteValue('dav_login_data')
                        this.get_login_data()
                    }
                })
            } catch (requestError) {
                console.log('GM_xmlhttpRequest error:', requestError)
                GM_deleteValue('dav_login_data')
                this.get_login_data()
            }
        })
    },

    get_file_data: function (file_path) {
        let callback = function (response, resolve) { resolve(response.responseText) }
        return this.request('GET', file_path, callback, 'text')
    },

    get_file_last_modified_time: function (file_path) {
        let callback = function (response, resolve) { resolve(response.responseXML.getElementsByTagName('d:getlastmodified')[0].textContent) }
        return this.request('PROPFIND', file_path, callback, 'document', '')
    },

    upload_file_through_file_data: function (file_path, file_data) {
        let callback = function () { }
        this.request('PUT', file_path, callback, 'text', file_data)
    },

    upload_file_through_url: async function (file_path, url) {
        function get_url_file_data(url) {
            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: "GET",
                    url: url,
                    responseType: "arraybuffer",
                    onload: (response) => { resolve(new Blob([response.response])) },
                    onerror: () => { reject('error'); }
                })
            })
        }
        let file_data = await get_url_file_data(url)
        this.upload_file_through_file_data(file_path, file_data)
    },

    check_path_exists: function (path) {
        let callback = function (response, resolve) {
            if (response.status === 404) { resolve(false) }
            else { resolve(true) }
        }
        return this.request('PROPFIND', path, callback, 'text', '')
    },

    create_dir_path: async function (dir_path) {
        let callback = function () { }
        try {
            let dir_exits = await this.check_path_exists(dir_path)
            if (dir_exits) { return }
            let currentPath = dir_path
            while (currentPath) {
                dir_exits = await this.check_path_exists(currentPath);
                if (dir_exits) { break }
                // 尝试创建目录
                await this.request('MKCOL', currentPath, callback, 'text', '');
                // 截取到上一级目录
                const lastIndex = currentPath.lastIndexOf('/');
                if (lastIndex === -1) { break }
                currentPath = currentPath.slice(0, lastIndex)
            }
        } catch (error) {
            console.error(`Error creating directory ${dir_path}:`, error);
        }
    },

    get_latest_modified_file: async function (dir_path) {
        let callback = function (response, resolve) {
            if (response.status === 404) { resolve("error") }
            else { resolve(response.responseXML.firstChild.lastChild.firstElementChild.innerHTML) }
        }
        return this.request('PROPFIND', dir_path, callback, 'text', '')
    }
}