Melon Ticket API Logger

Log 'summary' with realSeatCntlk >= 1 in formatted output or display '잔여 좌석이 없습니다' message from Melon Ticket API calls after the page is fully loaded

// ==UserScript==
// @name         Melon Ticket API Logger
// @namespace    http://tampermonkey.net/
// @version      1.22
// @description  Log 'summary' with realSeatCntlk >= 1 in formatted output or display '잔여 좌석이 없습니다' message from Melon Ticket API calls after the page is fully loaded
// @author       Your Name
// @match        https://ticket.melon.com/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    console.log('Melon Ticket API Logger Script Initialized');

    window.addEventListener('load', function() {
        console.log('Page fully loaded');

        // 기존 fetch를 백업
        const originalFetch = window.fetch;

        // fetch 함수를 오버라이드하여 요청을 감시
        window.fetch = async function() {
            const response = await originalFetch.apply(this, arguments);
            const url = arguments[0];

            // 특정 API 호출을 감지
            if (url.includes('/tktapi/product/block/summary.json')) {
                // 응답 데이터 처리
                const clonedResponse = response.clone();
                const responseData = await clonedResponse.text(); // 응답을 텍스트로 변환

                console.log("API Response:", responseData.interlockTypeCode); // 응답 데이터 확인

                // JSONP 콜백 함수 처리
                const jsonpCallbackMatch = /getBlockSummaryCountCallBack\(([^)]+)\)/.exec(responseData);
                if (jsonpCallbackMatch) {
                    const jsonData = jsonpCallbackMatch[1];
                    try {
                        // JSON 데이터의 양 끝에 불필요한 문자 제거
                        const cleanedJsonData = jsonData.trim();
                        // JSON 데이터가 너무 클 경우를 대비하여
                        if (cleanedJsonData.endsWith(';')) {
                            cleanedJsonData = cleanedJsonData.slice(0, -1); // ; 제거
                        }
                        // JSON 데이터가 유효한지 확인
                        if (/^[\[{]/.test(cleanedJsonData)) {
                            const parsedData = JSON.parse(cleanedJsonData);

                            // `summary` 배열이 있는지 확인
                            if (Array.isArray(parsedData.summary)) {
                                const filteredData = parsedData.summary.filter(item => item.realSeatCntlk > 0);

                                // 결과를 포맷팅하여 단일 console.log로 출력
                                if (filteredData.length > 0) {
                                    const result = filteredData.map(item => `${item.floorNo} ${item.floorName} ${item.areaNo} ${item.areaName} ${item.realSeatCntlk} 석`).join('\n');
                                    console.log(`잔여 좌석:\n${result}`);
                                } else {
                                    console.log('잔여 좌석이 없습니다');
                                }
                            } else {
                                console.error('응답 데이터에 summary 배열이 없습니다.');
                            }
                        } else {
                            console.error('응답 데이터가 유효한 JSON이 아닙니다.');
                        }
                    } catch (e) {
                        console.error('Failed to parse JSON data:', e);
                    }
                } else {
                    console.error('Failed to extract JSONP callback data.');
                }
            }

            return response;
        };

        // XMLHttpRequest 감시
        const originalXHR = window.XMLHttpRequest;
        window.XMLHttpRequest = function() {
            const xhr = new originalXHR();
            xhr.addEventListener('readystatechange', function() {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    const url = xhr.responseURL;
                    if (url.includes('/tktapi/product/block/summary.json')) {
                        // 응답 데이터 처리
                        const responseData = xhr.responseText;

                        console.log("API Response:", responseData.interlockTypeCode); // 응답 데이터 확인

                        // JSONP 콜백 함수 처리
                        const jsonpCallbackMatch = /getBlockSummaryCountCallBack\(([^)]+)\)/.exec(responseData);
                        if (jsonpCallbackMatch) {
                            const jsonData = jsonpCallbackMatch[1];
                            try {
                                // JSON 데이터의 양 끝에 불필요한 문자 제거
                                const cleanedJsonData = jsonData.trim();
                                // JSON 데이터가 너무 클 경우를 대비하여
                                if (cleanedJsonData.endsWith(';')) {
                                    cleanedJsonData = cleanedJsonData.slice(0, -1); // ; 제거
                                }
                                // JSON 데이터가 유효한지 확인
                                if (/^[\[{]/.test(cleanedJsonData)) {
                                    const parsedData = JSON.parse(cleanedJsonData);

                                    // `summary` 배열이 있는지 확인
                                    if (Array.isArray(parsedData.summary)) {
                                        const filteredData = parsedData.summary.filter(item => item.realSeatCntlk > 0);

                                        // 결과를 포맷팅하여 단일 console.log로 출력
                                        if (filteredData.length > 0) {
                                            const result = filteredData.map(item => `${item.floorNo} ${item.floorName} ${item.areaNo} ${item.areaName} ${item.realSeatCntlk} 석`).join('\n');
                                            console.log(`잔여 좌석:\n${result}`);
                                        } else {
                                            console.log('잔여 좌석이 없습니다');
                                        }
                                    } else {
                                        console.error('응답 데이터에 summary 배열이 없습니다.');
                                    }
                                } else {
                                    console.error('응답 데이터가 유효한 JSON이 아닙니다.');
                                }
                            } catch (e) {
                                console.error('Failed to parse JSON data:', e);
                            }
                        } else {
                            console.error('Failed to extract JSONP callback data.');
                        }
                    }
                }
            });
            return xhr;
        };
    });
})();