

// 임의 복사 저장을 허용하지 않습니다 2025-03-21(금)



/*=================================================================================================
 * MARI HOME   ---------------"--<@
 *-------------------------------------------------------------------------------------------------
 * @코드 명칭 : 마리 멀티 업로더 ( 가제 ) 
 * @요약 정보 : 업로더에 필요한 작은 기능 함수들 모음
 * @파일 이름 : multi_uploader_util.js
 * @웹용 주소 : 글쓰기등 업로드가 필요한 곳, 파일 탐색기와 같이 파일 미리보기가 필요한 곳에서 외부 파일(js파일)로 호출됨 
 * @호출 파일 : multi_uploader_code.js에 스프레드 연산자로 등록되어 각 요소에서 호출됨
 * @서버 위치 : 마리홈 ( ),  그누보드 ( plugin/multi_uploader/ )
 * @소스 제작 : repter ( 예뜨락 ), 홈페이지 ( https://marihome.net ) 
 * @제작 날짜 : 2023.08.01 ( 최초 제작 시작일 )
 * @소스 설명 : mp3에 대한 정보를 가져온다
 * @기타 사항 : 당분간 필요한 업그레이드를 통해서 소스 변경이 자주 일어날 수 있습니다 
 *           자바스크립트 형태 : 객체 리터럴 ( Object Literal )
 *           변수 => 프로퍼티 (Property)   : 프로퍼티 값
 *           함수 => 메서드 (Method)
 * @최종 수정 : 2024.11.21
 * @버전 명시 : 0.8
 *-------------------------------------------------------------------------------------------------
 * Copyright 2023. repter All Rights Reserved.
**===============================================================================================*/ 


 
/*================================
** 사용하는 펑션
**------------------------------*/
function syncSafeInteger(size) {
    return (
        ((size & 0x7f000000) >> 3) |
        ((size & 0x007f0000) >> 2) |
        ((size & 0x00007f00) >> 1) |
        (size & 0x0000007f)
    );
}


/*================================
** 디코딩에 사용하는 펑션
**------------------------------*/
function decodeString(arrayBuffer) {
    // ISO-8859-1로 시도한 후, 한글이 깨지면 EUC-KR로 다시 시도
    const iso88591Decoder = new TextDecoder("ISO-8859-1");
    let decodedString = iso88591Decoder.decode(arrayBuffer);

    // ISO-8859-1로 디코딩했는데 한글이 깨지는 경우에 EUC-KR로 재디코딩
    if (/[\u0080-\uFFFF]/.test(decodedString)) { 
        try {
            const eucKrDecoder = new TextDecoder("euc-kr");
            decodedString = eucKrDecoder.decode(arrayBuffer);
        } catch (error) {
            console.error("EUC-KR 디코딩 실패:", error);
        }
    }

    return decodedString.trim();

}
 
 
/*================================
** 타입1
**------------------------------*/ 
function parseID3v1Tags(arrayBuffer) {
    const dataView = new DataView(arrayBuffer);
    const TAG_OFFSET = arrayBuffer.byteLength - 128;
    const tag = String.fromCharCode(...new Uint8Array(arrayBuffer.slice(TAG_OFFSET, TAG_OFFSET + 3)));

    if (tag === 'TAG') {
        const title = decodeString(arrayBuffer.slice(TAG_OFFSET + 3, TAG_OFFSET + 33)).trim();
        const artist = decodeString(arrayBuffer.slice(TAG_OFFSET + 33, TAG_OFFSET + 63)).trim();
        const album = decodeString(arrayBuffer.slice(TAG_OFFSET + 63, TAG_OFFSET + 93)).trim();
        const year = decodeString(arrayBuffer.slice(TAG_OFFSET + 93, TAG_OFFSET + 97)).trim();
        const comment = decodeString(arrayBuffer.slice(TAG_OFFSET + 97, TAG_OFFSET + 127)).trim();
        const genreByte = dataView.getUint8(TAG_OFFSET + 127);

		const genres5 = [
			"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz",
			// Add more genres as needed
		];

        const genre = genreByte < genres5.length ? genres5[genreByte] : 'Unknown';

        return { title, artist, album, year, comment, genre };
    }

    return null;

}


/*================================
** 버전명 타입이 무엇인지 확인하는 함수
**------------------------------*/ 
function detectID3Version22(arrayBuffer) {
    const dataView = new DataView(arrayBuffer);

    // Check for ID3v2.2, ID3v2.3, ID3v2.4 header
    const tag = String.fromCharCode(dataView.getUint8(0), dataView.getUint8(1), dataView.getUint8(2));

    if (tag === 'ID3') {
        const versionMajor = dataView.getUint8(3);
        const versionMinor = dataView.getUint8(4);
        return `ID3v2.${versionMajor}.${versionMinor}`;
    }

    // Check for ID3v1 or ID3v1.1
    const id3v1TagOffset = arrayBuffer.byteLength - 128;
    const id3v1Tag = String.fromCharCode(
        dataView.getUint8(id3v1TagOffset),
        dataView.getUint8(id3v1TagOffset + 1),
        dataView.getUint8(id3v1TagOffset + 2)
    );

    if (id3v1Tag === 'TAG') {
        const version = dataView.getUint8(id3v1TagOffset + 125) === 1 ? 'ID3v1.1' : 'ID3v1';
        return version;
    }

    return 'Unknown or No ID3 Tag';

}


/*================================
** 버전명 타입이 무엇인지 확인하는 함수
**------------------------------*/ 
function detectID3Version(arrayBuffer) { 
/* ID3v1, ID3v1.1      ID3v2.2, ID3v2.3, ID3v2.4 */
    const dataView = new DataView(arrayBuffer);
    // ID3v2 검사
	if (String.fromCharCode(dataView.getUint8(0), dataView.getUint8(1), dataView.getUint8(2)) === 'ID3') {
		const versionMajor = dataView.getUint8(3); // 예: 3 (ID3v2.3)
		const versionMinor = dataView.getUint8(4); // 예: 0 (ID3v2.3.0)
		return`ID3v2.${versionMajor}.${versionMinor}`;
	}
    // ID3v1 검사const 
	id3v1TagOffset = arrayBuffer.byteLength - 128;
    if (String.fromCharCode(dataView.getUint8(id3v1TagOffset), dataView.getUint8(id3v1TagOffset + 1), dataView.getUint8(id3v1TagOffset + 2)) === 'TAG') {
        return "ID3v1";
    }

    return"Unknown or No ID3 Tag";

}


/*================================
** 버전 체크해서 각 버전 함수로 리턴
**------------------------------*/  
function parseID3Tags(arrayBuffer) {
    const version = detectID3Version(arrayBuffer);
	
//console.log( '파싱된 현재 버전은 :: ', version);
    switch (version) {
        case 'ID3v2.2.0':
            return parseID3v2_2(arrayBuffer);
        case 'ID3v2.3.0':
            return parseID3v2_3(arrayBuffer);
        case 'ID3v2.4.0':
            return parseID3v2_4(arrayBuffer);
        case 'ID3v1'  :
        case 'ID3v1.1':
            return parseID3v1(arrayBuffer);
        default:
            return { version: null, tags: null, mimeType: null, imageData: null };
    }

}


/*================================
** 버전 호출해서 각 버전 함수로 리턴
**------------------------------*/  
function callTags(version, arrayBuffer) { 
	
	//console.log( '현재 버전은 :: ', version);
    switch (version) {
        case 'ID3v2_2_0':
            return parseID3v2_2(arrayBuffer);
        case 'ID3v2_3_0':
            return parseID3v2_3(arrayBuffer);
        case 'ID3v2_4_0':
            return parseID3v2_4(arrayBuffer);
        case 'ID3v1'  :
            return parseID3v1(arrayBuffer);
        case 'ID3v1_1':
            return parseID3v1(arrayBuffer);
        default:
            return { version: null, tags: null, mimeType: null, imageData: null };
    }

}


/*================================
** ID3v1, ID3v1.1
**------------------------------*/  
function parseID3v1(arrayBuffer) {
//console.log('aaaaaaaaaaaaaaaa');
    const dataView = new DataView(arrayBuffer);
    const id3v1TagOffset = arrayBuffer.byteLength - 128;
    const tags = {};
    
    tags['Title'] = decodeString(arrayBuffer.slice(id3v1TagOffset + 3, id3v1TagOffset + 33));
    tags['Artist'] = decodeString(arrayBuffer.slice(id3v1TagOffset + 33, id3v1TagOffset + 63));
    tags['Album'] = decodeString(arrayBuffer.slice(id3v1TagOffset + 63, id3v1TagOffset + 93));
    tags['Year'] = decodeString(arrayBuffer.slice(id3v1TagOffset + 93, id3v1TagOffset + 97));
    tags['Comment'] = decodeString(arrayBuffer.slice(id3v1TagOffset + 97, id3v1TagOffset + 127));
    tags['Genre'] = dataView.getUint8(id3v1TagOffset + 127);

    return { version: 'ID3v1' || 'ID3v1.1', tags, mimeType: null, imageData: null };

}


/*================================
** ID3v2.2
**------------------------------*/  
function parseID3v2_2(arrayBuffer) {
//console.log('bbbbbbbbbbbbbb');
    const dataView = new DataView(arrayBuffer);
    let offset = 10;
    const tags = {};
    const size = dataView.getUint8(6) << 21 | dataView.getUint8(7) << 14 | dataView.getUint8(8) << 7 | dataView.getUint8(9);

    while (offset < size + 10) {
        const frameID = String.fromCharCode(
            dataView.getUint8(offset),
            dataView.getUint8(offset + 1),
            dataView.getUint8(offset + 2)
        );
        const frameSize = dataView.getUint8(offset + 3);
        const frameData = new Uint8Array(arrayBuffer.slice(offset + 4, offset + 4 + frameSize));
        tags[frameID] = new TextDecoder("ISO-8859-1").decode(frameData).trim();
        offset += 4 + frameSize;

 //console.log(tags[frameID] );
    }

    return { version: 'ID3v2.2.0', tags, mimeType: null, imageData: null };

}


/*================================
** ID3v2.3
**------------------------------*/  
function parseID3v2_3_0(arrayBuffer) {
    const dataView = new DataView(arrayBuffer);
    let offset = 10;
    const tags = {};
    let imageData = null;
    let mimeType = null;
    const size = syncSafeInteger(dataView.getUint32(6));

    while (offset < size + 10) {
        const frameID = new TextDecoder("ISO-8859-1").decode(new Uint8Array(arrayBuffer.slice(offset, offset + 4)));
        const frameSize = syncSafeInteger(dataView.getUint32(offset + 4));
        const frameFlags = dataView.getUint16(offset + 8);
        const frameData = new Uint8Array(arrayBuffer.slice(offset + 10, offset + 10 + frameSize));

        if (frameID === 'APIC') {
            let index = 1;
            while (frameData[index] !== 0) index++;
            mimeType = new TextDecoder("ISO-8859-1").decode(frameData.slice(1, index)).trim();
            index++;
            while (frameData[index] !== 0) index++;
            index++;
            imageData = frameData.slice(index); 
        } else {
            const encoding = frameData[0];
            let decodedString = '';

            if (encoding === 0) {
                decodedString = new TextDecoder("ISO-8859-1").decode(frameData.slice(1));
            } else if (encoding === 1) {
                decodedString = new TextDecoder("utf-16").decode(frameData.slice(1));
            } else if (encoding === 3) {
                decodedString = new TextDecoder("utf-8").decode(frameData.slice(1));
            }

            tags[frameID] = decodedString.trim();
        }

        offset += 10 + frameSize;
    }

    return { version: 'ID3v2.3.0', tags, mimeType, imageData };

}


/*================================
**  ID3v2.4
** 'ID3v2_4_0' 
**------------------------------*/  
function parseID3v2_4(arrayBuffer) {
    const dataView = new DataView(arrayBuffer);
    let offset = 10;
    const tags = {};
    let imageData = null;
    let mimeType = null;
    const size = syncSafeInteger(dataView.getUint32(6));

    while (offset < size + 10) {
        const frameID = new TextDecoder("ISO-8859-1").decode(new Uint8Array(arrayBuffer.slice(offset, offset + 4)));
        const frameSize = syncSafeInteger(dataView.getUint32(offset + 4));
        const frameFlags = dataView.getUint16(offset + 8);
        const frameData = new Uint8Array(arrayBuffer.slice(offset + 10, offset + 10 + frameSize));

        if (frameID === 'APIC') {
            let index = 1;
            while (frameData[index] !== 0) index++;
            mimeType = new TextDecoder("ISO-8859-1").decode(frameData.slice(1, index)).trim();
            index++;
            while (frameData[index] !== 0) index++;
            index++;
            imageData = frameData.slice(index);
        } else {
            const encoding = frameData[0];
            let decodedString = '';

            if (encoding === 0) {
                decodedString = new TextDecoder("ISO-8859-1").decode(frameData.slice(1));
            } else if (encoding === 1) {
                decodedString = new TextDecoder("utf-16").decode(frameData.slice(1));
            } else if (encoding === 3) {
                decodedString = new TextDecoder("utf-8").decode(frameData.slice(1));
            }

            tags[frameID] = decodedString.trim();
        }

        offset += 10 + frameSize;
    }

    return { version: 'ID3v2.4.0', tags, mimeType, imageData };

}


/*================================
** ID3v2.3.0 
**------------------------------*/ 
function parseID3v2_3(arrayBuffer) {
    const dataView = new DataView(arrayBuffer);
    // Check for ID3v2.3.0 header
	const tag = String.fromCharCode(
        dataView.getUint8(0), 
        dataView.getUint8(1), 
        dataView.getUint8(2)
    );

    if (tag !== 'ID3') {
        return { tags: null, mimeType: null, imageData: null };
    }

    const versionMajor = dataView.getUint8(3);
    const versionMinor = dataView.getUint8(4);
    const flags = dataView.getUint8(5);
    const size = syncSafeInteger(dataView.getUint32(6));

    if (versionMajor !== 3) {
        return { tags: null, mimeType: null, imageData: null }; // Handle versions other than 2.3.0 if needed
    }

    let offset = 10; // ID3 header size is 10 bytes
	const tags = {};
    let imageData = null;
    let mimeType = null;

    while (offset < size + 10) {
        const frameID = String.fromCharCode(
            dataView.getUint8(offset),
            dataView.getUint8(offset + 1),
            dataView.getUint8(offset + 2),
            dataView.getUint8(offset + 3)
        );

        const frameSize  = syncSafeInteger(dataView.getUint32(offset + 4));
        const frameFlags = dataView.getUint16(offset + 8);
        const frameData  = new Uint8Array(arrayBuffer.slice(offset + 10, offset + 10 + frameSize));
        if (frameID === 'APIC') { // Album art
			let index = 1;
            // MIME type
			while (frameData[index] !== 0) index++;
            mimeType = new TextDecoder("ISO-8859-1").decode(frameData.slice(1, index)).trim();
            index++;
            // Picture type (1 byte) + description (null-terminated)
			while (frameData[index] !== 0) index++;
            index++;
            // Image data
            imageData = frameData.slice(index);

        } else {

            const encoding = frameData[0];
            let decodedString = '';  
			// Handle text encoding based on the first byte
			if (encoding === 0) {
				decodedString = new TextDecoder("ISO-8859-1").decode(frameData.slice(1));
			} else if (encoding === 1) {
				decodedString = new TextDecoder("utf-16").decode(frameData.slice(1));
			} else if (encoding === 3) {
				decodedString = new TextDecoder("utf-8").decode(frameData.slice(1));
			}

			tags[frameID] = decodedString.trim();
        }

        offset += 10 + frameSize;
    }

    return { tags, mimeType, imageData };

}






































// 바탕에 mp3이미지가 생기고 있음
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
        // mp3 커버 이미지를 썸네일로 
        function createThumbnail_mp3(imageUrl) {
            const img = new Image();
            img.src = imageUrl;
//return; 


            return new Promise((resolve, reject) => {
                img.onload = () => {
                    const originalWidth = img.width;
                    const originalHeight = img.height;

                    // 250픽셀을 초과하는지 확인
                    if (originalWidth > 250 || originalHeight > 250) {
                        const canvas = document.createElement('canvas');
                        const ctx = canvas.getContext('2d');

                        // 썸네일의 비율에 맞춰 캔버스 크기 설정
                        let thumbnailWidth = originalWidth > 250 ? 250 : originalWidth;
                        let thumbnailHeight = originalHeight > 250 ? 250 : originalHeight;

                        // 비율 맞춰 크기 조정
                        if (originalWidth > originalHeight) {
                            thumbnailHeight = (thumbnailWidth / originalWidth) * originalHeight;
                        } else {
                            thumbnailWidth = (thumbnailHeight / originalHeight) * originalWidth;
                        }

                        canvas.width = thumbnailWidth;
                        canvas.height = thumbnailHeight;

                        // 캔버스에 이미지 그리기
                        ctx.drawImage(img, 0, 0, originalWidth, originalHeight, 0, 0, thumbnailWidth, thumbnailHeight);

                        // 썸네일 URL을 Blob 형식으로 변환하여 반환
                        canvas.toBlob((blob) => {
                            const thumbnailUrl = URL.createObjectURL(blob);
                            resolve({
                                originalWidth,
                                originalHeight,
                                originalUrl: imageUrl,
                                thumbnailWidth,
                                thumbnailHeight,
                                thumbnailUrl
                            });
                        }, 'image/jpeg');
                    } else {
                        // 크기가 250픽셀 이하일 경우 원본 이미지 URL 반환
                        resolve({
                            originalWidth,
                            originalHeight,
                            originalUrl: imageUrl,
                            thumbnailWidth: originalWidth,
                            thumbnailHeight: originalHeight,
                            thumbnailUrl: imageUrl
                        });
                    }
                };

                img.onerror = (err) => reject(err);
            });
        }

        async function loadThumbnail_mp3(file_imageSrc, datas) {
            const imageUrl = file_imageSrc; // 여기에 이미지 URL을 입력하세요.

            try {
                const result = await this.createThumbnail_mp3(imageUrl);
                
                console.log('원본 이미지 크기:', result.originalWidth, 'x', result.originalHeight);
                console.log('썸네일 크기:', result.thumbnailWidth, 'x', result.thumbnailHeight);
                console.log('원본 이미지 URL:', result.originalUrl);
                console.log('썸네일 URL:', result.thumbnailUrl);
                
                // 썸네일을 이미지 요소에 적용하는 예시
                const thumbnailImg = document.createElement('img');
                thumbnailImg.style.display = 'none'; 
                thumbnailImg.src   = result.thumbnailUrl;
                document.body.appendChild(thumbnailImg);  
                let code = {
                    originalWidth   : result.originalWidth,
                    originalHeight  : result.originalHeight,
                    originalUrl     : result.originalUrl,
                    thumbnailWidth  : result.thumbnailWidth,
                    thumbnailHeight : result.thumbnailHeight,
                    thumbnailUrl    : result.thumbnailUrl
                };
                thumbnailImg.remove();

                return code;

            } catch (error) {
                console.error('이미지 처리 중 오류 발생:', error);
            }
        }
 

    // 파일을 처리하는 비동기 함수를 생성
	async function processFile(event, objType, eq_idx2, list_idx, info_Ary){
 
        let obj_util    = MARI.file_uploder.util; 
        let obj_this    = MARI.file_uploder.code;
        let eq_idx      = (objType === 'New') ? obj_this.event_eq(event) : eq_idx2;    //사용 가능하게 설정된 업로더에서의 인덱스
        let li_obj      = obj_this.li_obj(eq_idx);  
        let datas       = obj_this.getFileInfo2(eq_idx, objType, list_idx, 'All', '430');
        let call_idx    = ( objType === 'New' ) ? totalCnt - 1 : list_idx;
        
        let totalcnt    = obj_this.file_count_return(eq_idx, 'totalCnt'); // 파일 업로더 전체 갯수
        let oneList     = li_obj[totalCnt - 1]; // 맨 마지막에
        let file        = datas;

        //파일화가 필요함
        console.log( datas );


        
        let loaderMain  = obj_this.loader_main_obj(eq_idx);  
		try {
			/*======================
			** 공통 버퍼   1174 line
			**---------------------*/
			const arrayBuffer = await file.arrayBuffer();
			const data        = new Uint8Array(arrayBuffer); // new Uint8Array(e.target.result)
			const headerSize  = obj_util.getID3v2Size(data);

			/*======================
			** 출력 변수 설정
			**---------------------*/
			let mp3_title       = ''; // 타이틀
			let mp3_artist      = ''; // 아티스트
			let mp3_album       = ''; // 앨범
			let mp3_albumArtist = ''; // 아티스트
			let mp3_track       = ''; // 트랙 
			let mp3_disc        = ''; // 디스크
			let mp3_genre       = ''; // 장르
			let mp3_year        = ''; // 출시년도
			let mp3_date        = ''; // 출시일
			let mp3_composer    = ''; // 작곡가 
			let mp3_comment     = ''; // 코멘트
			let mp3_lyrics      = ''; // 가사
			let mp3_albumCover  = ''; // 앨범커버
			let mp3_tagType     = ''; // 담겨진 버전 타입

			if (headerSize > 0) {
			 	const { version, tags } = parseID3Tags(arrayBuffer);
				const apicFrame = obj_util.findAPICFrame(data, headerSize);
			 	const { mimeType, imageData } = obj_util.extractImageData(apicFrame);

				// 각 프레임 ID를 통해 데이터를 추출하고 변수에 할당
			 	mp3_title       = ( tags['title']       || tags['TIT2'] || tags['TT2'] || 'Unknown'     );
			 	mp3_artist      = ( tags['artist']      || tags['TPE1'] || tags['TP1'] || 'Unknown'     );
			 	mp3_album       = ( tags['album']       || tags['TALB'] || tags['TAL'] || 'Unknown'     );
			 	mp3_albumArtist = ( tags['albumArtist'] || tags['TPE2'] || tags['TP2'] || 'Unknown'     );
			 	mp3_track       = ( tags['track']       || tags['TRCK'] || tags['TRK'] || 'Unknown'     );
			 	mp3_disc        = ( tags['disc']        || tags['TPOS'] || tags['TPA'] || 'Unknown'     );
			 	mp3_genre       = ( tags['genre']       || tags['TCON'] || tags['TCO'] || 'Unknown'     );
			 	mp3_year        = ( tags['year']        || tags['TYER'] || tags['TYE'] || 'Unknown'     );
			 	mp3_date        = ( tags['date']        || tags['TDAT'] || tags['TDA'] || 'Unknown'     );
			 	mp3_composer    = ( tags['composer']    || tags['TCOM'] || tags['TCM'] || 'Unknown'     );
			 	mp3_comment     = ( tags['comment']     || tags['COMM'] || tags['COM'] || 'No comments' );
			 	mp3_lyrics      = ( tags['lyrics']      || tags['USLT'] || tags['ULT'] || 'No lyrics'   );
			 	mp3_albumCover  = ( tags['albumCover']  || tags['APIC'] || tags['PIC'] || null          );
				mp3_tagType = tags['version'];

//				console.log('Title : ',  title);
//				console.log('Artist : ', artist);
//				console.log('Album : ',  album);
//				console.log('AlbumArtist : ',  albumArtist); 
//				console.log('Track : ',    track);
//				console.log('Disc : ',   disc); 
////		    console.log('Genre : ',  genre);
//				console.log('Year : ',    year);
//				console.log('Date : ',    date);
//				console.log('Composer : ',  composer);
//				console.log('Comment : ',  comment);
//				console.log('Lyrics : ',  lyrics);
//				console.log('AlbumCover : ',  albumCover); 

				// ID3v2_4_0
				const tagArys5   = callTags('ID3v2_4_0', arrayBuffer);
				const version5   = tagArys5['version'];
				const tags5      = tagArys5['tags'];
				const mimeType5  = tagArys5['mimeType'];
				const imageData5 = tagArys5['imageData'];

				// 각 프레임 ID를 통해 데이터를 추출하고 변수에 할당
			 	mp3_title       = ( mp3_title       === 'Unknown' ) ? ( tags5['TIT2'] || tags5['TT2'] || 'Unknown' ) : mp3_title;
			 	mp3_artist      = ( mp3_artist      === 'Unknown' ) ? ( tags5['TPE1'] || tags5['TP1'] || 'Unknown' ) : mp3_artist;
			 	mp3_album       = ( mp3_album       === 'Unknown' ) ? ( tags5['TALB'] || tags5['TAL'] || 'Unknown' ) : mp3_album;
			 	mp3_albumArtist = ( mp3_albumArtist === 'Unknown' ) ? ( tags5['TPE2'] || tags5['TP2'] || 'Unknown' ) : mp3_albumArtist;
			 	mp3_track       = ( mp3_track       === 'Unknown' ) ? ( tags5['TRCK'] || tags5['TRK'] || 'Unknown' ) : mp3_track;
			 	mp3_disc        = ( mp3_disc        === 'Unknown' ) ? ( tags5['TPOS'] || tags5['TPA'] || 'Unknown' ) : mp3_disc;
			 	mp3_genre       = ( mp3_genre       === 'Unknown' ) ? ( tags5['TCON'] || tags5['TCO'] || 'Unknown' ) : mp3_genre;
			 	mp3_year        = ( mp3_year        === 'Unknown' ) ? ( tags5['TYER'] || tags5['TYE'] || 'Unknown' ) : mp3_year;
			 	mp3_date        = ( mp3_date        === 'Unknown' ) ? ( tags5['TDAT'] || tags5['TDA'] || 'Unknown' ) : mp3_date;
			 	mp3_composer    = ( mp3_composer    === 'Unknown' ) ? ( tags5['TCOM'] || tags5['TCM'] || 'Unknown' ) : mp3_composer;
			 	mp3_comment     = ( mp3_comment     === 'Unknown' ) ? ( tags5['COMM'] || tags5['COM'] || 'Unknown' ) : mp3_comment;
			 	mp3_lyrics      = ( mp3_lyrics      === 'Unknown' ) ? ( tags5['USLT'] || tags5['ULT'] || 'Unknown' ) : mp3_lyrics;
			 	mp3_albumCover  = ( mp3_albumCover  === null      ) ? ( tags5['APIC'] || tags5['PIC'] || null      ) : mp3_albumCover;
				mp3_tagType     = 'ID3v2_4_0';
 
				// ID3v2_3_0
				const tagArys4   = callTags('ID3v2_3_0', arrayBuffer);
				const version4   = tagArys4['version'];
				const tags4      = tagArys4['tags'];
				const mimeType4  = tagArys4['mimeType'];
				const imageData4 = tagArys4['imageData'];

				// 각 프레임 ID를 통해 데이터를 추출하고 변수에 할당
			 	mp3_title       = ( mp3_title       === 'Unknown' ) ? ( tags4['TIT2'] || tags4['TT2'] || 'Unknown' ) : mp3_title;
			 	mp3_artist      = ( mp3_artist      === 'Unknown' ) ? ( tags4['TPE1'] || tags4['TP1'] || 'Unknown' ) : mp3_artist;
			 	mp3_album       = ( mp3_album       === 'Unknown' ) ? ( tags4['TALB'] || tags4['TAL'] || 'Unknown' ) : mp3_album;
			 	mp3_albumArtist = ( mp3_albumArtist === 'Unknown' ) ? ( tags4['TPE2'] || tags4['TP2'] || 'Unknown' ) : mp3_albumArtist;
			 	mp3_track       = ( mp3_track       === 'Unknown' ) ? ( tags4['TRCK'] || tags4['TRK'] || 'Unknown' ) : mp3_track;
			 	mp3_disc        = ( mp3_disc        === 'Unknown' ) ? ( tags4['TPOS'] || tags4['TPA'] || 'Unknown' ) : mp3_disc;
			 	mp3_genre       = ( mp3_genre       === 'Unknown' ) ? ( tags4['TCON'] || tags4['TCO'] || 'Unknown' ) : mp3_genre;
			 	mp3_year        = ( mp3_year        === 'Unknown' ) ? ( tags4['TYER'] || tags4['TYE'] || 'Unknown' ) : mp3_year;
			 	mp3_date        = ( mp3_date        === 'Unknown' ) ? ( tags4['TDAT'] || tags4['TDA'] || 'Unknown' ) : mp3_date;
			 	mp3_composer    = ( mp3_composer    === 'Unknown' ) ? ( tags4['TCOM'] || tags4['TCM'] || 'Unknown' ) : mp3_composer;
			 	mp3_comment     = ( mp3_comment     === 'Unknown' ) ? ( tags4['COMM'] || tags4['COM'] || 'Unknown' ) : mp3_comment;
			 	mp3_lyrics      = ( mp3_lyrics      === 'Unknown' ) ? ( tags4['USLT'] || tags4['ULT'] || 'Unknown' ) : mp3_lyrics;
			 	mp3_albumCover  = ( mp3_albumCover  === null      ) ? ( tags4['APIC'] || tags4['PIC'] || null      ) : mp3_albumCover;
				mp3_tagType     = 'ID3v2_3_0';

				// ID3v2_2_0
				const tagArys3   = callTags('ID3v2_2_0', arrayBuffer); 
				const version3   = tagArys3['version'];
				const tags3      = tagArys3['tags'];
				const mimeType3  = tagArys3['mimeType'];
				const imageData3 = tagArys3['imageData']; 

				// 각 프레임 ID를 통해 데이터를 추출하고 변수에 할당
			 	mp3_title       = ( mp3_title       === 'Unknown' ) ? ( tags3['TIT2'] || tags3['TT2'] || 'Unknown' ) : mp3_title;
			 	mp3_artist      = ( mp3_artist      === 'Unknown' ) ? ( tags3['TPE1'] || tags3['TP1'] || 'Unknown' ) : mp3_artist;
			 	mp3_album       = ( mp3_album       === 'Unknown' ) ? ( tags3['TALB'] || tags3['TAL'] || 'Unknown' ) : mp3_album;
			 	mp3_albumArtist = ( mp3_albumArtist === 'Unknown' ) ? ( tags3['TPE2'] || tags3['TP2'] || 'Unknown' ) : mp3_albumArtist;
			 	mp3_track       = ( mp3_track       === 'Unknown' ) ? ( tags3['TRCK'] || tags3['TRK'] || 'Unknown' ) : mp3_track;
			 	mp3_disc        = ( mp3_disc        === 'Unknown' ) ? ( tags3['TPOS'] || tags3['TPA'] || 'Unknown' ) : mp3_disc;
			 	mp3_genre       = ( mp3_genre       === 'Unknown' ) ? ( tags3['TCON'] || tags3['TCO'] || 'Unknown' ) : mp3_genre;
			 	mp3_year        = ( mp3_year        === 'Unknown' ) ? ( tags3['TYER'] || tags3['TYE'] || 'Unknown' ) : mp3_year;
			 	mp3_date        = ( mp3_date        === 'Unknown' ) ? ( tags3['TDAT'] || tags3['TDA'] || 'Unknown' ) : mp3_date;
			 	mp3_composer    = ( mp3_composer    === 'Unknown' ) ? ( tags3['TCOM'] || tags3['TCM'] || 'Unknown' ) : mp3_composer;
			 	mp3_comment     = ( mp3_comment     === 'Unknown' ) ? ( tags3['COMM'] || tags3['COM'] || 'Unknown' ) : mp3_comment;
			 	mp3_lyrics      = ( mp3_lyrics      === 'Unknown' ) ? ( tags3['USLT'] || tags3['ULT'] || 'Unknown' ) : mp3_lyrics;
			 	mp3_albumCover  = ( mp3_albumCover  === null      ) ? ( tags3['APIC'] || tags3['PIC'] || null      ) : mp3_albumCover;
				mp3_tagType     = 'ID3v2_2_0';

				// ID3v1_1
				const tagArys2   = callTags('ID3v1_1', arrayBuffer);
				const version2   = tagArys2['version'];
				const tags2      = tagArys2['tags'];
				const mimeType2  = tagArys2['mimeType'];
				const imageData2 = tagArys2['imageData'];
 
				// 각 프레임 ID를 통해 데이터를 추출하고 변수에 할당
			 	mp3_title       = ( mp3_title       === 'Unknown' ) ? ( tags2['title']       || 'Unknown'     ) : mp3_title;
			 	mp3_artist      = ( mp3_artist      === 'Unknown' ) ? ( tags2['artist']      || 'Unknown'     ) : mp3_artist;
			 	mp3_album       = ( mp3_album       === 'Unknown' ) ? ( tags2['album']       || 'Unknown'     ) : mp3_album;
			 	mp3_albumArtist = ( mp3_albumArtist === 'Unknown' ) ? ( tags2['albumArtist'] || 'Unknown'     ) : mp3_albumArtist;
			 	mp3_track       = ( mp3_track       === 'Unknown' ) ? ( tags2['track']       || 'Unknown'     ) : mp3_track;
			 	mp3_disc        = ( mp3_disc        === 'Unknown' ) ? ( tags2['disc']        || 'Unknown'     ) : mp3_disc;
			 	mp3_genre       = ( mp3_genre       === 'Unknown' ) ? ( tags2['genre']       || 'Unknown'     ) : mp3_genre;
			 	mp3_year        = ( mp3_year        === 'Unknown' ) ? ( tags2['Year']        || 'Unknown'     ) : mp3_year;
			 	mp3_date        = ( mp3_date        === 'Unknown' ) ? ( tags2['date']        || 'Unknown'     ) : mp3_date;
			 	mp3_composer    = ( mp3_composer    === 'Unknown' ) ? ( tags2['composer']    || 'Unknown'     ) : mp3_composer;
			 	mp3_comment     = ( mp3_comment     === 'Unknown' ) ? ( tags2['comment']     || 'No comments' ) : mp3_comment;
			 	mp3_lyrics      = ( mp3_lyrics      === 'Unknown' ) ? ( tags2['lyrics']      || 'No lyrics'   ) : mp3_lyrics;
			 	mp3_albumCover  = ( mp3_albumCover  === null      ) ? ( tags2['albumCover']  || null          ) : mp3_albumCover;
				mp3_tagType     = 'ID3v1_1';
 
				// ID3v1
				const tagArys1   = callTags('ID3v1', arrayBuffer);
				const version1   = tagArys1['version'];
				const tags1      = tagArys1['tags'];
				const mimeType1  = tagArys1['mimeType'];
				const imageData1 = tagArys1['imageData'];

				// 각 프레임 ID를 통해 데이터를 추출하고 변수에 할당
			 	mp3_title       = ( mp3_title       === 'Unknown' ) ? ( tags1['title']       || 'Unknown'     ) : mp3_title;
			 	mp3_artist      = ( mp3_artist      === 'Unknown' ) ? ( tags1['artist']      || 'Unknown'     ) : mp3_artist;
			 	mp3_album       = ( mp3_album       === 'Unknown' ) ? ( tags1['album']       || 'Unknown'     ) : mp3_album;
			 	mp3_albumArtist = ( mp3_albumArtist === 'Unknown' ) ? ( tags1['albumArtist'] || 'Unknown'     ) : mp3_albumArtist;
			 	mp3_track       = ( mp3_track       === 'Unknown' ) ? ( tags1['track']       || 'Unknown'     ) : mp3_track;
			 	mp3_disc        = ( mp3_disc        === 'Unknown' ) ? ( tags1['disc']        || 'Unknown'     ) : mp3_disc;
			 	mp3_genre       = ( mp3_genre       === 'Unknown' ) ? ( tags1['genre']       || 'Unknown'     ) : mp3_genre;
			 	mp3_year        = ( mp3_year        === 'Unknown' ) ? ( tags1['Year']        || 'Unknown'     ) : mp3_year;
			 	mp3_date        = ( mp3_date        === 'Unknown' ) ? ( tags1['date']        || 'Unknown'     ) : mp3_date;
			 	mp3_composer    = ( mp3_composer    === 'Unknown' ) ? ( tags1['composer']    || 'Unknown'     ) : mp3_composer;
			 	mp3_comment     = ( mp3_comment     === 'Unknown' ) ? ( tags1['comment']     || 'No comments' ) : mp3_comment;
			 	mp3_lyrics      = ( mp3_lyrics      === 'Unknown' ) ? ( tags1['lyrics']      || 'No lyrics'   ) : mp3_lyrics;
			 	mp3_albumCover  = ( mp3_albumCover  === null      ) ? ( tags1['albumCover']  || null          ) : mp3_albumCover;
				mp3_tagType     = 'ID3v1';

				/*======================
				** 썸네일 이미지 추출
				**---------------------*/
				//썸네일이 존재한다면
				if (apicFrame) {
					const { mimeType, imageData } = obj_util.extractImageData(apicFrame);
					const base64String = obj_util.arrayBufferToBase64(imageData);
					const base64Image  = `data:${mimeType};base64,${base64String}`;

					// 썸네일을 로드 시키면서 필요 정보를 불러온다
					let imgs = new Image(); // 이미지 객체 생성 
					let file_naturalWidth  = '';
					let file_naturalHeight = '';
					imgs.src = base64Image; // base64Image를 직접 src에 할당

					// 이미지 blob과 url생성된 주소 변수가 이 안에 있어야 함  
					const blob        = obj_util.base64ToBlob(base64String, mimeType);// base64 문자열을 Blob으로 변환 
					let file_imageSrc = URL.createObjectURL(blob);// Blob을 위한 URL 생성( 파일의 주소로 ) 

                    let thumbnailDiv = oneList.querySelector('.upload_thumb'); 
                    let fileIconDiv  = oneList.querySelector('.file_icon');
                    let fileNameDiv  = oneList.querySelector('.file_name');
                    let fileTypeDiv  = oneList.querySelector('.file_type_in > em');
                    let fileSizeDiv  = oneList.querySelector('.file_size_in > em');
                    let picSizeDiv   = oneList.querySelector('.file_pic_size_in > em');
                    let modifiedDiv  = oneList.querySelector('.modified_date_in > em');

                    if( thumbnailDiv ){
                        imgs.addEventListener('load', function() {
                            let dataImgWidth     = this.naturalWidth ; // 이미지 넓이 
                            let dataImgHeight    = this.naturalHeight; // 이미지 높이
                            
                            // mp3 데이터 관련 내용을 업데이트 한다           
                            // 이미지 관련 추가 
  		 	                // datas.dataThumbnail   = file_imageSrc;//base64Image;// file_imageSrc; // mp3의 썸네일을 넣어준다 
  		 	                // datas.dataPicture     = file_imageSrc; 
             
                            
                        // 만들어진 커버 이미지가 커서 캔버스를 이용한 썸네일을 만들려는 작업을할력 했었음
                            
                            // 추출한 mp3의 커버 이미지를 썸네일 이미지로 만듦
                            let obj_this  = MARI.file_uploder.code;  
                         //   let mp3Thumb  = obj_this.loadThumbnail_mp3(file_imageSrc, datas); 
                            let mp3Thumb  = loadThumbnail_mp3(file_imageSrc, datas); 
                            let chk_nums  = 0;
                            let checkLoad = setInterval(() => { 
                                
                                
//                let code = {
//                    originalWidth   : result.originalWidth,
//                    originalHeight  : result.originalHeight,
//                    originalUrl     : result.originalUrl,
//                    thumbnailWidth  : result.thumbnailWidth,
//                    thumbnailHeight : result.thumbnailHeight,
//                    thumbnailUrl    : result.thumbnailUrl
//                }; 
 console.log( 'mp3Thumb ==> ',mp3Thumb.thumbnailUrl );

                                
                             //   console.log(`${mp3Thumb.thumbnailUrl}chk_nums=${chk_nums} `); 
                                
                                if(chk_nums >= 50 /*|| mp3Thumb.thumbnailUrl !== 'undefined'*/){// 조건을 충족하면  
                                    console.log( 'hhhhhhhhhhhhhhhhhhh ',mp3Thumb.thumbnailUrl );

                            
                                    datas.dataThumbnail = mp3Thumb.thumbnailUrl;

                                            
                                    clearInterval(checkLoad); // 완료되면 반복 중지   
                                }

                                chk_nums++; //setInterval의 실행 횟수를 체크를 위해서 사용한다
                            }, 500); // 50ms 간격 실행하면서 캔버스에서 이미지 생성이 되어 자료가 콜백되었는지 확인한다 

                        // 만들어진 커버 이미지가 커서 캔버스를 이용한 썸네일을 만들려는 작업을할력 했었음
                        // 썸네일의 주소, 픽처의 원본주소, 넓이, 높이등을 데이터에 넘겨야 함


                            
                            //datas.dataThumbnail  = mp3Thumb.thumbnailUrl;
                            datas.dataThumbnail  = file_imageSrc;
                            datas.dataPicture    = file_imageSrc;  
  		 	                datas.dataImgWidth    = dataImgWidth;
  		 	                datas.dataImgHeight   = dataImgHeight; 

                            // mp3 관련 추가 
  		 	                datas.mp3_title       = mp3_title.replace(/\u0000/g, '');       // 타이틀
  		 	                datas.mp3_artist      = mp3_artist.replace(/\u0000/g, '');      // 아티스트
  		 	                datas.mp3_album       = mp3_album.replace(/\u0000/g, '');       // 앨범
  		 	                datas.mp3_albumArtist = mp3_albumArtist.replace(/\u0000/g, ''); // 아티스트
  		 	                datas.mp3_track       = mp3_track.replace(/\u0000/g, '');       // 트랙 
  		 	                datas.mp3_disc        = mp3_disc.replace(/\u0000/g, '');        // 디스크
  		 	                datas.mp3_genre       = mp3_genre.replace(/\u0000/g, '');       // 장르
  		 	                datas.mp3_year        = mp3_year.replace(/\u0000/g, '');        // 출시년도
  		 	                datas.mp3_date        = mp3_date.replace(/\u0000/g, '');        // 출시일
  		 	                datas.mp3_composer    = mp3_composer.replace(/\u0000/g, '');    // 작곡가 
  		 	                datas.mp3_comment     = mp3_comment.replace(/\u0000/g, '');     // 코멘트
  		 	                datas.mp3_lyrics      = mp3_lyrics.replace(/\u0000/g, '');      // 가사
  		 	                datas.mp3_albumCover  = mp3_albumCover;//.replace(/\u0000/g, '');  // 앨범커버
  		 	                datas.mp3_tagType     = mp3_tagType.replace(/\u0000/g, '');     // 담겨진 버전 타입

                            // datas에 넣어둔 것을 가져와서 html에 넣어준다
                            // html에 내용을 넣어준다
                     //     datas.dataPicture;
                            if(file_imageSrc !=='undefined')
                            thumbnailDiv.src      = datas.dataThumbnail;//file_imageSrc;           // 이미지를 넣는다

                            if(datas.dataIcon !=='undefined')
                            fileIconDiv.src       = datas.dataIcon;          // 파일 아이콘  
                            fileNameDiv.innerHTML = datas.dataFileName;      // 파일 이름 
                            fileTypeDiv.innerHTML = datas.dataFileType2;     // 파일 유형 
                            modifiedDiv.innerHTML = datas.dataModifyDate;    // 수정한 날짜 
                            fileSizeDiv.innerHTML = datas.dataFileSize;      // 파일 크기 표기 ( Mb or Kb ) 
                            picSizeDiv.innerHTML  = dataImgWidth + ' x ' + dataImgHeight; // 사진 크기 
                            obj_this.spinnerFadeOut(eq_idx, totalcnt - 1); // 스피너를 감춘다

                        });

                    } // if( thumbDiv )
 
				}// if (apicFrame)
				else{ // 썸네일 커버 이미지가 없다면
						
					// 위의 것을 참고할 것 mp3배열을 만들어 넣는 형식 디펄트 배열은 디펄트대로 넣는다
                    
                    let info_ary = [{
                        'mp3_title'        : mp3_title,       // 타이틀
                        'mp3_artist'       : mp3_artist,      // 아티스트
                        'mp3_album'        : mp3_album,       // 앨범
                        'mp3_albumArtist'  : mp3_albumArtist, // 아티스트
                        'mp3_track'        : mp3_track,       // 트랙 
                        'mp3_disc'         : mp3_disc,        // 디스크
                        'mp3_genre'        : mp3_genre,       // 장르
                        'mp3_year'         : mp3_year,        // 출시년도
                        'mp3_date'         : mp3_date,        // 출시일
                        'mp3_composer'     : mp3_composer,    // 작곡가 
                        'mp3_comment'      : mp3_comment,     // 코멘트
                        'mp3_lyrics'       : mp3_lyrics,      // 가사
                        'mp3_albumCover'   : mp3_albumCover,   // 앨범커버 
                        'mp3_tagType'      : mp3_tagType, // 태그
                    }];

                    if (document.querySelectorAll(obj_this.loader_cls)[eq_idx]) {
                        obj_this.new_list_add_dom(event, eq_idx, list_idx, 'New', ''); // 새로운 파일을 리스트에 추가한다
                        // 파일 읽기가 완료된 시점이니 스피너를 감춘다 새로운 리스트 호출은 new_file_add 루프에서 한다  
                        let spinner_cover = loaderMain.querySelector('.spinner_cover');
                        obj_util.fadeOut(spinner_cover,  100, 10);
                    }
				} 
			} // end headerSize
			else{
 
                let info_ary = [{ 
                    'mp3_title'        : mp3_title,       // 타이틀
                    'mp3_artist'       : mp3_artist,      // 아티스트
                    'mp3_album'        : mp3_album,       // 앨범
                    'mp3_albumArtist'  : mp3_albumArtist, // 아티스트
                    'mp3_track'        : mp3_track,       // 트랙 
                    'mp3_disc'         : mp3_disc,        // 디스크
                    'mp3_genre'        : mp3_genre,       // 장르
                    'mp3_year'         : mp3_year,        // 출시년도
                    'mp3_date'         : mp3_date,        // 출시일
                    'mp3_composer'     : mp3_composer,    // 작곡가 
                    'mp3_comment'      : mp3_comment,     // 코멘트
                    'mp3_lyrics'       : mp3_lyrics,      // 가사
                    'mp3_albumCover'   : mp3_albumCover,  // 앨범커버 
                    'mp3_tagType'      : mp3_tagType,     // 태그 버전
                }]; 
                    
                let spinner_cover = loaderMain.querySelector('.spinner_cover');
                obj_util.fadeOut(spinner_cover,  100, 10);
                    
                if( loaderMain ){ 
                    obj_this.newAddDom(event, list_idx); // 새로운 파일을 리스트에 추가한다

                    // 파일 읽기가 완료된 시점이니 스피너를 감춘다 새로운 리스트 호출은 new_file_add 루프에서 한다 
                    let spinner_cover = loaderMain.querySelector('.spinner_cover');
                    obj_util.fadeOut(spinner_cover,  100, 10);
                } 

			}
		} catch (error) {
			alert(error);
			console.log('Error reading file:', error);
		}

	}// async


 

/*
ID3v1.1: ID3v1의 확장판으로, 곡의 트랙 번호를 추가로 지원합니다. parseID3v1Tags에 추가적인 처리가 필요합니다.

ID3v2.3 및 ID3v2.4: ID3v2는 세부적으로 2.2, 2.3, 2.4로 나뉩니다. 이 버전들은 서로 약간 다른 형식을 사용합니다. 
예를 들어, 2.3에서는 프레임 ID가 4바이트로 고정되며, 2.4에서는 일부 프레임에 대해 다르게 처리합니다.

APEv2 Tags: APEv2 태그는 주로 MP3 파일 외에도 WAV, APE 형식에서 사용됩니다. 이 태그는 ID3와 다른 구조를 가집니다.

Vorbis Comments: 주로 Ogg Vorbis와 FLAC 같은 포맷에서 사용되며, ID3와 다른 태그 구조를 가지고 있습니다.

Lyrics3 Tags: 가사 정보를 저장하는 데 사용되며, ID3v1의 확장 태그로 사용됩니다.

추가적으로 고려할 수 있는 사항:
ID3v2.2 프레임 처리: ID3v2.2에서는 프레임 ID가 3바이트로 되어 있으므로, 이를 위해 별도의 파싱 로직이 필요합니다.

싱크 세이프 인티저: ID3v2.3 이상에서는 데이터 크기를 표현할 때 Sync-Safe Integer 방식을 사용합니다.

APEv2
Vorbis Comments
Lyrics3 Tags

// 종류
ID3v1
ID3v1.1

ID3v2.2
ID3v2.3
ID3v2.4
https://clansim.tistory.com/97
https://products.groupdocs.app/metadata/app/?lang=en&file=e37b2b83-3392-4a9c-b7fd-eaec1f57c573%2F019_%EC%A0%95%EC%8A%B9%ED%99%98___%EB%88%88%EC%82%AC%EB%9E%8C.mp3&action=&url=%2Fmetadata%2Fmp3
*/