Greasy Fork

Greasy Fork is available in English.

dav

Henry Toys dav api

当前为 2025-06-12 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/539094/1606390/dav.js

// ==UserScript==
// @name         dav
// @namespace    dav
// @version      0.0.2
// @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 = {
    get_login_data: function () {
        let dav_login_data = JSON.parse(GM_getValue("dav_login_data", null))
        // 检查数据是否存在或已过期
        if (!dav_login_data ||
            !dav_login_data.baseURL ||
            !dav_login_data.username ||
            !dav_login_data.password ||
            dav_login_data.expires < new Date().getTime()) {
            GM_deleteValue('dav_login_data')
            const login = function () {
                const baseURL = prompt("请输入地址")
                const username = prompt("请输入用户名")
                const password = prompt("请输入密码")
                const updated_dav_login_data = {
                    "baseURL": baseURL,
                    "username": username,
                    "password": password,
                    "expires": new Date().getTime() + 1000 * 60 * 1 * 1 * 1 // 7天后过期
                }
                GM_setValue("dav_login_data", JSON.stringify(updated_dav_login_data))
            }
            GM_registerMenuCommand("登录", login)
        }
        return JSON.parse(GM_getValue("dav_login_data", null))
    },

    request: async function (method, path, callback, responseType = 'text', data = null) {
        const login_data = JSON.parse(GM_getValue("dav_login_data", null))
        if (!login_data || !login_data.baseURL || !login_data.username || !login_data.password) {
            this.get_login_data()
            throw new Error('Invalid or missing login credentials')
        } else {
            const updated_dav_login_data = {
                "baseURL": login_data.baseURL,
                "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.baseURL + 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.error('Request error:', error)
                        GM_deleteValue('dav_login_data')
                        reject(new Error(`Network request failed: ${error.error || error.statusText}`))
                    },
                    ontimeout: () => {
                        console.error('Request timed out')
                        reject(new Error('Request timed out'))
                    }
                })
            } catch (requestError) {
                console.error('GM_xmlhttpRequest error:', requestError)
                reject(requestError)
            }
        })
    },

    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', '')
    }
}