My Collection to CC98 QMD

同步CC98抽卡游戏的收藏至CC98签名档

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         My Collection to CC98 QMD
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  同步CC98抽卡游戏的收藏至CC98签名档
// @author       Q&A
// @match        https://card.cc98.org/Home/Collection
// @match        https://www.cc98.org
// @icon         https://www.google.com/s2/favicons?sz=64&domain=cc98.org
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.4/toastr.min.js
// @resource     toastrCSS https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.4/toastr.min.css
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_getResourceText
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @license MIT

// ==/UserScript==
/* globals html2canvas, toastr */
(function() {
    'use strict';
    GM_addStyle(GM_getResourceText("toastrCSS"));
    let toastr_title = "My Collection to CC98 QMD";
    toastr.options.timeOut = 5000;
    toastr.options.extendedTimeOut = 5000;
    toastr.options.newestOnTop = false;
    toastr.options.progressBar = true;
    toastr.options.positionClass = "toast-top-center";

    // 从 www.cc98.org 的 localStorage 获取 accessToken
    if ("www.cc98.org" === location.host) {
        if(!GM_getValue("update_token", false)) return;
        let access_token = localStorage.getItem("accessToken");
        if(null !== access_token) {
            GM_setValue("access_token", access_token.slice(4));
            toastr.success("获取accessToken成功!",toastr_title);
            GM_setValue("update_token", false);
        } else {
            toastr.error("获取accessToken失败!",toastr_title);
        }
        return;
    }
    // 日期格式化字符串
    Date.prototype.format = function(fmt) {
        var o = {
            "M+" : this.getMonth()+1,
            "d+" : this.getDate(),
            "h+" : this.getHours(),
            "m+" : this.getMinutes(),
            "s+" : this.getSeconds(),
            "q+" : Math.floor((this.getMonth()+3)/3),
            "S"  : this.getMilliseconds()
        };
        if(/(y+)/.test(fmt)) {
            fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
        }
        for(var k in o) {
            if(new RegExp("("+ k +")").test(fmt)){
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
            }
        }
        return fmt;
    }
    // base64转文件
    function dataURLtoFile(base64Str, fileName) {
        var arr = base64Str.split(','),
            mime = arr[0].match(/:(.*?);/)[1], //base64解析出来的图片类型
            bstr = atob(arr[1]), //对base64串进行操作,去掉url头,并转换为byte   atob为window内置方法
            len = bstr.length,
            ab = new ArrayBuffer(len), //将ASCII码小于0的转换为大于0
            u8arr = new Uint8Array(ab); //
        while (len--) {
            u8arr[len] = bstr.charCodeAt(len)
        }
        // 创建新的 File 对象实例[utf-8内容,文件名称或者路径,[可选参数,type:文件中的内容mime类型]]
        return new File([u8arr], fileName, {
            type: mime
        })
    }

    // 添加按钮
    document.getElementsByClassName("alert alert-info")[0].innerHTML += "<a href=\"javascript:myCollection2CC98()\" class=\"alert-link\">单击这里</a>同步我的收藏至CC98签名档。"
    unsafeWindow.myCollection2CC98 = function() {
        console.log("My Collection to CC98 QMD!");
        let card_group = document.getElementsByClassName("card-group")[0];
        html2canvas(card_group).then(canvas => {
            // 生成图片
            var image = new Image();
            image.src = canvas.toDataURL("image/png");
            let image_file = dataURLtoFile(image.src, "card-group.png");
            // 获取accessToken
            let access_token = GM_getValue("access_token", "");
            if("" === access_token) {
                GM_setValue("update_token", true);
                toastr.error("【0/3】请<button onclick=\"window.open('https://www.cc98.org')\">点我打开cc98.org</button>获取accessToken!",toastr_title);
                return;
            }
            toastr.success("【1/3】已成功获取accessToken!(token: "+access_token.slice(0,5) + "……" + access_token.slice(-5)+")",toastr_title);
            // 上传文件至cc98服务器,获取图片URL
            var form = new FormData();
            form.append("files", image_file, "card-group.png");
            GM_xmlhttpRequest({
                method: "POST",
                url: "https://api.cc98.org/file",
                headers: {
                    Authorization: access_token
                },
                data: form,
                onload: function(res){
                    if(res.status === 200){
                        let img_url = JSON.parse(res.response)[0];
                        toastr.success("【2/3】已成功上传图片至98服务器!(URL: " + img_url +")",toastr_title);
                        // 更新签名档
                        GM_xmlhttpRequest({
                            method: "GET",
                            url: "https://api.cc98.org/me",
                            headers:  {
                                Authorization: access_token
                            },
                            onload: function(res){
                                if(res.status == 200) {
                                    let me = JSON.parse(res.response);
                                    let birthday = new Date(me.birthday);
                                    let update_me = {
                                        Birthday: birthday.format("yyyy-MM-dd"),
                                        DisplayTitleId: me.displatTitleId?me.displatTitleId:0,
                                        EmailAddress: me.emailAddress,
                                        Gender: me.gender,
                                        Introduction: me.introduction,
                                        QQ: me.qq,
                                        SignatureCode: "[img]" + img_url + "[/img]\n[right]Updated at " + new Date().format("yy-MM-dd hh:mm:ss")+" | Powered by [url=https://greasyfork.org/zh-CN/scripts/449683][b][u]My Collection to CC98 QMD[/u][/b][/url][/right]",
                                        birthdayDay: birthday.getDate(),
                                        birthdayMonth: birthday.getMonth()+1,
                                        birthdayYear: birthday.getFullYear(),
                                        userTitleIds: me.userTitleIds
                                    }
                                    GM_xmlhttpRequest({
                                        method: "PUT",
                                        url: "https://api.cc98.org/me",
                                        headers:  {
                                            Authorization: access_token,
                                            "Content-Type": "application/json"
                                        },
                                        data: JSON.stringify(update_me),
                                        onload: function(res) {
                                            if(res.status == 200) {
                                                toastr.success("【3/3】已成功更新个人资料,请<button onclick=\"window.open('https://www.cc98.org/usercenter')\">点我打开cc98.org</button>查看!",toastr_title)
                                            } else {
                                                console.log(res);
                                                toastr.error("【2/3】更新个人资料失败,请重试!",toastr_title);
                                            }
                                        }
                                    });
                                } else {
                                    console.log(res);
                                    toastr.error("【2/3】获取个人资料失败,请重试!",toastr_title);
                                }
                            }
                        });
                    }else{
                        console.log(res);
                        GM_setValue("update_token", true);
                        toastr.error("【1/3】上传失败,请<button onclick=\"window.open('https://www.cc98.org')\">点我打开cc98.org</button>重新获取accessToken!",toastr_title);
                    }
                },
                onerror : function(err){
                    console.log(err);
                }
            });
        });
    }
})();