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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==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;
        };
    });
})();