绳网跨域助手

none

目前為 2025-06-07 提交的版本,檢視 最新版本

// ==UserScript==
// @name         绳网跨域助手
// @namespace    http://tampermonkey.net/
// @version      1.4.5
// @description  none
// @author       claxmo
// @license      MIT
// @run-at       document-start
// @match        http://localhost:*/inter-knot/*
// @match        https://claxmo.github.io/inter-knot/*
// @connect      github.com
// @connect      api.github.com
// @grant        unsafeWindow
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function () {
    'use strict';
    unsafeWindow.version = '1.4.5';
    const CLIENT_ID = "Ov23lifQzV3VA2p4vEmL";
    const CLIENT_SECRET = "b9cab7872c74d1958582676e4393bc112cacee24";
    const OWNER = "claxmo";
    const REPO = "inter-knot";
    let accessToken = localStorage.getItem('access_token');

    const request = async (method, url, data = null, timeout = 5000) => {        
         return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method,
                url,
                headers: {
                    "Authorization": `Bearer ${accessToken}`,
                    "Accept": "application/json"
                },
                ...(data && { data: JSON.stringify(data) }),
                timeout,
                onload: (res) => {
                    if (res.status === 401){
                        localStorage.removeItem("access_token");
                        accessToken = null;
                        return authLogin();
                    }else{
                        resolve(JSON.parse(res.responseText));
                    }
                },
                ontimeout: () => reject(new Error('request timeout.')),
                onerror: () => reject(new Error('request error.'))
            });
        });
    };

    const getAccessToken = async (code) => {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "POST",
                url: "https://github.com/login/oauth/access_token",
                headers: {
                    "Content-Type": "application/json",
                    "Accept": "application/json"
                },
                data: JSON.stringify({
                    client_id: CLIENT_ID,
                    client_secret: CLIENT_SECRET,
                    code,
                }),
                onload: (res) => {
                    resolve(JSON.parse(res.responseText).access_token);
                },
                onerror: () => reject(new Error('get access_token error.'))
            });
        });
    };

    const authLogin = () => {
        window.location.href =`https://github.com/login/oauth/authorize?client_id=${CLIENT_ID}&scope=public_repo`;
    };

    const graphql = async (query, variables) => {
        return await request("POST","https://api.github.com/graphql",{query,variables});
    };

    unsafeWindow.addDiscussionComment = async (discussion_id, body) => {
        return (await graphql(`
          mutation($discussionId: ID!, $body: String!) {
            addDiscussionComment(input: {discussionId: $discussionId, body: $body}) {
              comment {
                 id
                 bodyHTML
                 bodyText
                 createdAt
                 updatedAt
                 url
                 author {
                     login
                     avatarUrl
                  }
                }
              }
            }
          }`, { discussionId: discussion_id, body })).data.addDiscussionComment.comment;
    };


    unsafeWindow.getUserProfile = async () => {
        return await request("GET","https://api.github.com/user");
    };

    unsafeWindow.getDiscussions = async (cursor, searchQuery = "") => {
        return (await graphql(`
          query($queryString: String!, $cursor: String) {
            search(type: DISCUSSION, query: $queryString, first: 20, after: $cursor) {
              pageInfo {
                endCursor
                hasNextPage
              }
              nodes {
                ... on Discussion {
                  number
                  id
                  title
                  bodyHTML
                  bodyText
                  createdAt
                  updatedAt
                  upvoteCount
                  url
                  author {
                    login
                    avatarUrl
                  }
                 category {
                    id
                    name
                    emoji
                  }
                }
              }
            }
          }`, {
            queryString: `repo:${OWNER}/${REPO} ${searchQuery}`.trim(),
            cursor
        })).data.search;
    };

    unsafeWindow.getComments = async (discussion_id, cursor = null) => {
        return (await graphql(`
          query($id: ID!, $cursor: String) {
              node(id: $id) {
                  ... on Discussion {
                      comments(first: 20, after: $cursor) {
                          nodes {
                              id
                              bodyHTML
                              bodyText
                              createdAt
                              updatedAt
                              url
                              author {
                                  login
                                  avatarUrl
                              }
                          }
                          totalCount
                          pageInfo {
                              endCursor
                              hasNextPage
                          }
                      }
                  }
              }
          }`, { id: discussion_id, cursor })).data.node.comments;
    };

    const urlParams = new URLSearchParams(window.location.search);
    const code = urlParams.get("code");
    if (code) {
        history.replaceState(null, '', window.location.origin + window.location.pathname);
        getAccessToken(code).then((token) => {
            accessToken = token;
            localStorage.setItem('access_token', accessToken);
            // console.log("Access Token:",accessToken);
        });
    }else if(!accessToken){
        authLogin();
    }
})();