牌譜の一括ダウンロード - majaneye/JANTAMA GitHub Wiki

牌譜の一括ダウンロードについてにゃ!

概要にゃ!

↓こちらのページを参考に牌譜を一括ダウンロードするようのスクリプトを作成しました。本当に助かりました!(このページでは語尾をにゃ!にさせていただきますにゃ!!)
雀魂 API 解析にゃ! Wiki*

牌譜をファイルに保存するにゃ  

大会の情報と牌譜一覧をファイルに保存するにゃ

注意にゃ!

あまり短い間隔でやるとBANされるかもしれないので注意するにゃ!
自己責任でお願いしますにゃ!

手順にゃ!

デベロッパーツールの起動方法については割愛しますにゃ!

1. 牌譜のリストをダウンロードするにゃ!

 1. デベロッパーツールのコンソールに以下のコードをコピペしてエンターキーを押すにゃ!

function paifulist(type) {
    let namesub = "";
    if(type==2){ namesub = "danni"; }
    else if(type==1){ namesub = "yuujin"; }
    else if(type==4){ namesub = "taikai"; }
    else if(type==0){ namesub = "all"; }
    else {return; }

    function download(data, fileName) {
        let a = document.createElement("a");
        a.href = URL.createObjectURL(
            new Blob([JSON.stringify(data, null, "  ")],
            {type: "text/plain"}));
        a.download = fileName;
        a.style.display = "none";
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    }
    function sleep(msec) {
        return new Promise(function(resolve) {setTimeout(function() {resolve();}, msec);});
    }
    async function getRecords(type,namesub) {
        let uuidArray = new Array();
        let loopEndFlag = false;
    for (let i = 0;; i += 20) {
        app.NetAgent.sendReq2Lobby(
                "Lobby",
                "fetchGameRecordList",
                // type 2 マッチング type 1 友人 type 4 大会戦 type 0 段位・友人・大会全て
                {start:i, count:20, type:type},
                function(error, Records) {
                    if (Records.record_list.length == 0) {
                        loopEndFlag = true;
                        return;
                    }
                    for (const record of Records.record_list) {
                        uuidArray.push(record.uuid);
                        console.log(i + " データ取得中 / Downloading");
                    }
                });
            if (loopEndFlag) {
                break;
            }
            await sleep(1000);
        }
        download(uuidArray, "mahjongsoul_" + namesub + "_uuid_list.txt");
    }
    getRecords(type,namesub);
}

 2. デベロッパーツールのコンソールに以下のコードを入力してエンターキーを押すにゃ!(2は段位戦、3なら友人戦、4なら大会戦にゃ!)

paifulist(2)

以上で牌譜のリストがダウンロードされるにゃ!
牌譜のリストは1000件までしかとれないっぽいにゃ!
いっぱい遊んでいるご主人はこのリストを取っておくと後で古い牌譜を確認できるかもにゃ!

2. 牌譜を一括ダウンロードするにゃ!

  1. 以下のコードをデベロッパーツールのコンソールにコピペしてエンターキーを押すにゃ!
async function paifus(array) {
    for (let index = 0; index < array.length; index++)
    {
        function sleep(msec) {
            return new Promise(function(resolve) {setTimeout(function() {resolve();}, msec);});
        }

        uuid = array[index];
        uuid = uuid.replace(/^.*=(.*)_a.*$/, '$1');
        const pbWrapper = net.ProtobufManager.lookupType(".lq.Wrapper");
        const pbGameDetailRecords = net.ProtobufManager.lookupType(".lq.GameDetailRecords");
        function parseRecords(gameDetailRecords, json) {
            try {
                if (gameDetailRecords.version == 0) {
                    for (let i in gameDetailRecords.records) {
                        const record = (pbWrapper.decode(gameDetailRecords.records[i]));
                        const pb = net.ProtobufManager.lookupType(record.name);
                        const data = JSON.parse(JSON.stringify((pb.decode(record.data))));
                        json.records[i] = {name:record.name, data:data};
                    }
                }
                else if (gameDetailRecords.version == 210715) {
                    for (let i in gameDetailRecords.actions) {
                        if (gameDetailRecords.actions[i].type == 1) {
                            const record = (pbWrapper.decode(gameDetailRecords.actions[i].result));
                            const pb = net.ProtobufManager.lookupType(record.name);
                            const data = JSON.parse(JSON.stringify((pb.decode(record.data))));
                            json.actions[i].result = {name:record.name, data:data};
                        }
                    };
                }
                else {
                    throw ("Unknown version: " + gameDetailRecords.version);
                }
            }
            catch (e) {
                console.log(e);
            }
            return json;
        }
        async function fetchData(url) {
            const response = await fetch(url);
            const arrayBuffer = await response.arrayBuffer();
            return new Uint8Array(arrayBuffer);
        }
        function download(data, uuid) {
            let a = document.createElement("a");
            a.href = URL.createObjectURL(
                new Blob([JSON.stringify(data, null, "  ")],
                {type: "text/plain"}));
            a.download = "mahjongsoul_paifu_" + uuid + ".txt";
            a.style.display = "none";
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
        }

        
        app.NetAgent.sendReq2Lobby(
            "Lobby",
            "fetchGameRecord",
            {game_uuid:uuid, client_version_string:GameMgr.Inst.getClientVersion()},
            async function(error, gameRecord) {
                if (gameRecord.data == "") {
                    gameRecord.data = await fetchData(gameRecord.data_url);
                }
                const gameDetailRecordsWrapper = pbWrapper.decode(gameRecord.data);
                const gameDetailRecords = pbGameDetailRecords.decode(gameDetailRecordsWrapper.data);
                let gameDetailRecordsJson = JSON.parse(JSON.stringify(gameDetailRecords));
                gameDetailRecordsJson = parseRecords(gameDetailRecords, gameDetailRecordsJson);
                gameRecord.data = "";
                let gameRecordJson = JSON.parse(JSON.stringify(gameRecord));
                gameRecordJson.data = {name:gameDetailRecordsWrapper.name, data:gameDetailRecordsJson};
                download(gameRecordJson, uuid);
            });

        console.log((index+1) + "/" + array.length + "(" + uuid + ")" + " データ取得中 / Downloading");

        await sleep(2000);
    }
}
  1. デベロッパーツールのコンソールに以下のコードを入力してエンターキーを押すにゃ!
paifus(["uuid0",
  "uuid1",
  "uuid2",])

uuid0,uuid1,uuid2は、さっきダウンロードしたリストからブロックでコピペすれば良いにゃ!
中頃から抜き出した場合に[]を忘れないことが大事にゃ!

以上で牌譜を一定の間隔で、連続でダウンロードできるはずにゃ!
じゃんたまの通信が途切れたりすると、ログは進むけどダウンロードに失敗しているなんてことがあるので注意するにゃ!