상세 컨텐츠

본문 제목

대충 이미지 검색 왕창 다운로띵 ajax 2

자바스크립트

by e7e 2023. 7. 17. 20:39

본문

불현듯 갑자기 어처구니없겡 뜬금없잉

2023.07.16 - [자바스크립트] - 대충 이미지 검색 왕창 다운로띵 ajax 1

글의 기능 확장 요구가 들어왔당.

미리보기가 된 상태에서 원하는 이미지만 원하는 이름으로 다운받을 수 있게 해 달라

어처구니 있는 합리적이고 생각있는 아이디어 베이스의  논리적 요구사항이라 그냥 받았당.

 

요구사항을 추가하는데는 역시 항상 그렇진 않지만 그리 별로 쉽당.

미리보기용 img태그와 ,체크박스랑, 원하는 파일명을 쓸 텍스트박스, 그리고

체크된 것만 다운로드 기능을 클릭 이벤트로 걸어줄 버튼.. 이 정도면 충분 할 거시당.

 

기능의 Core 핵심은 이전 글에서 설명했으므롱, 추가된 전체 소스를 먼저 리스트하고.

일부 추가된 부분에 대해 간략히 억지롱 설명을 하도록 하장.

아래 소스를 카.복으로 실행하고, 기능을 먼저 누느로 화긴해서 의지를 올려랑.

(조금 기럭지 기러 보이지만, 나중에 알고보면 다 그게 그거당!, 그래 그거당!)

 

imgSchDownload2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>E7E 안메롱</title>
<style>
#wrapper {
    margin:10px auto;
    width:70%;
    /*min-width: 540px;*/
    border:1px solid black;
    text-align: center;
}

#disp {
    max-height:70vh;
    border:1px solid black;
    text-align: center;
    overflow:auto;
    resize: both;
}
/* 스크롤바 잘 안 보이겡 */
#disp::-webkit-scrollbar {
    /*display: none; */ 
    width: 5px;
}

h1{
    background-color: orange;
}

input[type="checkbox"] {
    position: absolute;
    left:-15%;top:40%; /* 쪼메 왼쪽 & 아래쪽으로 */
    transform: scale(2); /* 2배 크겡*/
}

#downBtn {
    width: 40%;
    color:orange;
    font-weight: bolder;
    background-color: black;
}
</style>
</head>
<body>
<div id="wrapper">
    <h1>&copy; E7E JPG 검색 다운로덩</h1>
    <input type="text" id="schWord" value="" placeholder="검색할 이미지 적어주삼" autofocus >
    <input type="button" id="schBtn" value="검색"><br>
    <input type="button" id="downBtn" value="체크 한 것만 일괄 다운로드"><br><br>
    <div id="disp"></div>
</div>
<script>
// 전역변수...
const myDisp = document.querySelector("#disp");
const mySchWord = document.querySelector("#schWord");
const mySchBtn = document.querySelector("#schBtn");
const myDownBtn = document.querySelector("#downBtn");
const preSchURL = "https://www.google.com/search?q=";
const postSchURL = "&tbm=isch";   // 이미지 서치

// 그냥 랜덤 수, 칼라, 재미?
function f_ranNum(p_startNum,p_endNum){
    var v_gap = p_endNum - p_startNum;
    
    return  p_startNum + Math.round(Math.random()*v_gap);
 }

function f_ranColor(){
    let v_red = f_ranNum(0,255);
    let v_green = f_ranNum(0,255);
    let v_blue = f_ranNum(0,255);
    let v_alpha = "0."+ f_ranNum(0,9);
    if(v_alpha <=0) v_alpha =1;        // 0은 완전투명 -> 불투명으로 바꿔줌

    return `rgba(${v_red},${v_green},${v_blue},${v_alpha})`; 
}

// 이벤토....
mySchBtn.onclick = fSch;
myDownBtn.onclick = fDown;

mySchWord.onkeydown = function(){
    if(event.keyCode == 13){
        fSch();
    }
}


// 구글검색한 이미지 URL 긁거 글거
function fSch(){
    let schURL = `${preSchURL}${mySchWord.value}${postSchURL}`;

    let xhr = new XMLHttpRequest();
    xhr.open("get",schURL,true);

    xhr.onreadystatechange = ()=>{
        if(xhr.readyState == 4 && xhr.status == 200){
            let cont = xhr.responseText;

            // sIndex는 찾기시작 index값으로 대략 튜닝값(찾을 문자열이 실제 더 뒤에 나옴,내맘!)
            let sIndex = 50000;         
            let fIndex =1;

            myDisp.innerHTML ="";
            while( (startIndex = cont.indexOf("[\"https://",sIndex)) != -1){
                sIndex = startIndex+2;
                let eIndex = cont.indexOf("\"",sIndex);
                let imgURL = cont.substring(sIndex,eIndex);
                if(imgURL.includes(".jpg")){              //난  .jpg파일만 좋앙
                    console.log("이미지URL",imgURL)
                    fileDownload(imgURL,fIndex);
                    fIndex++;
                }
            }

        }
    }
    xhr.send();
}

// URL 하나마다 해당 파일 blob로 다운로드
function fileDownload(pImgURL,pIndex){
    let xhr = new XMLHttpRequest();
    xhr.responseType="blob";
    xhr.open("get",pImgURL,true);
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                console.log("체킁:",xhr.response);  // BLOB(Binary Large OBject)

                let imgBlobURL = URL.createObjectURL(xhr.response);
                
                let outterDiv = document.createElement("div");
                outterDiv.style.border="3px solid black";
                outterDiv.style.marginBottom="5px";
                outterDiv.style.marginLeft="2px";
                let innerLeftDiv = document.createElement("div");
                innerLeftDiv.style.display="inline-block";
                innerLeftDiv.style.position="relative";
                innerLeftDiv.innerHTML += "<input type=checkbox name=myCheck value=e7e >";

                let innerRightDiv = document.createElement("div");
                innerRightDiv.style.display="inline-block";
                innerRightDiv.innerHTML = "<h2>&copy E7E 메롱</h2>";
                innerRightDiv.style.color=f_ranColor();
                innerRightDiv.style.width="50%";

                let sImg = document.createElement("img");
                sImg.src = imgBlobURL;
                sImg.width=200; sImg.height=200;
                sImg.style.borderTopRightRadius = "50%";
                sImg.style.borderBottomLeftRadius = "50%";
                innerLeftDiv.appendChild(sImg);

                let aTag = document.createElement("a"); 
                aTag.href= imgBlobURL;
                aTag.innerHTML=`${mySchWord.value}${pIndex}.jpg`; 
                aTag.target="_blank";
                innerRightDiv.appendChild(aTag);
                innerRightDiv.innerHTML +="<br>";

                let tValue = `${mySchWord.value}${pIndex}.jpg`;
                
                /*
                   input type=text를 createElement로 넣으면 value가 안보이는 버그가 발견됨
                */
                innerRightDiv.innerHTML += "원츄 파일명: ";
                innerRightDiv.innerHTML += `<input type=text value="${tValue}" size=12 ><br>`;

                let sBtn = document.createElement("button");
                sBtn.style.fontWeight="bolder";
                sBtn.style.color = f_ranColor();
                sBtn.style.backgroundColor = f_ranColor();
                sBtn.innerHTML = "요거만 다운로띵";
                /*
                  sBtn.onclick=function(){} 이 먹지 않음.... 비동기 시간차로 그리기 바쁨?
                */
                sBtn.setAttribute("onclick","fDownClick(this)");

                innerRightDiv.appendChild(sBtn);
                innerRightDiv.innerHTML +="<br><br><br><br>";

                outterDiv.appendChild(innerLeftDiv);
                outterDiv.appendChild(innerRightDiv);
                myDisp.appendChild(outterDiv);

                setTimeout(()=>{
                    myDisp.scrollTo(0,myDisp.scrollHeight);
                },100)

            }else {
                console.log("서버에서 거부코드:",xhr.status);
            }
        }
    }
    xhr.send();
}

// 텍스트박스에 쓴 파일명으로 다운로딩
function fDownClick(pThis){
    let parentDiv = pThis.parentElement;
    let inAtag= parentDiv.querySelector("a");
    let inText = parentDiv.querySelector("input");

    inAtag.download = inText.value;
    inAtag.click();
    //a 링크가 계속 새창에 이미지를 열도록 남겨두기 위해성
    inAtag.removeAttribute("download");
}

// 체크박스 체크한 것만 다운로드
function fDown(){
    let checks = document.querySelectorAll("[name=myCheck]:checked");
    for(let i=0; i<checks.length; i++){
        let rightDiv = checks[i].parentElement.parentElement;
        let downBtn = rightDiv.querySelector("button");
        console.log(downBtn);
        fDownClick(downBtn);
    }
}
</script>    
</body>
</html>

 

나의 경우 아래 그림과 같은 결과가 손에 잡혔당.(Cross-origin 플러그인을 켜는걸 잊지말장!)

마우스 휠 스크롤을 이용 필요한 이미지 파일 앞의 체크박스를 체크하공,

텍스트박스에 원하는 이름을 넣은 다음, 체크한 것만 일괄 다운로드 버튼을 누르면 된당.

 

대량 추가된 코드는 fileDownload함수 안에서  AJAX성공시에 checkbox,img,input, button등을 

div에 담아서 myDisp에 넣어주는 GUI기능 업그레이드  부분이당.(딴생각만 안하면 그냥 보인당)

일부러 style태그에 css로 안하고, 자바스크립트를 이용해서 넣어보았당.

이 과정에서 버그를 1개 발견했는뎅, input type=text 를 createElement롱 맹글어성 

value를 주면 이 value값이 크롬 브라우져에서 안 보일 수도 있당.(힘들었당~~)

 

기본적으로 요거만 다운로딩 버튼을 클릭하면 fDownClick 함수가 실행되어 

텍스트박스에 있는 이름으로 이미지를 다운로드해준당.(이전 글에서 본 코드라 보면 안당)

 

체크한 것만 텍스트박스에 입력한 이름으로 바꾸어 다운받기 위해서,  fDown함수를 추가했는뎅,

역시, 보면 안당, 먼저 체크된 체크박스를 다 가지고 와서  갯수 만큼 뺑뺑 반복 돌리는뎅,

체크박스의  부모의 부모가 a, input, button 태그를 가진 div 태그여서

그 안에서  요거만 다운로드 버튼을 찾아서  fDownClick에 해당 버튼을 매개변수로 넘기면

요거만 다운로드 버튼을 누른 것과 똑같은 동작을 하게된당. 그냥 그거뿐이당.

 

참고로 fDownClick함수는 아래 형태로도 구현할 수 있을 거시당.

마지막에 inAtag= null 은 언제 할지는 모르지만, Garbage Collector가 동작할 수 있도록

의도적으로 inAtag를 null값으로 강제로 세팅하는 척, 멋진 척 해 보았당.

// 텍스트박스에 쓴 파일명으로 다운로딩
function fDownClick(pThis){
    let parentDiv = pThis.parentElement;
    let inAtag= parentDiv.querySelector("a").cloneNode(true);
    let inText = parentDiv.querySelector("input");

    inAtag.download = inText.value;
    inAtag.click();
    inAtag= null; 
}

참고로 한가지 더 이야기 하자면 console.log를 보면 이미지파일에 서버에러가 403(forbidden)을

비롯해서 이런저런 서버사이드 거부 코드가 나온당.

만약 해당 서버가 스프링을 사용한다면, 이미지URL이 실제 정적폴더 서비스URL이 아니고

컨트롤러단에서 받아서 처리해주는 식으로 되어 있다고 추측해 볼 수 있당.

어떤 이미지URL은 추가정보를 더 요청하고 있을 수도 있당.

억지로 그런 것까지 다 알아내서 받을 필요는 없어서 난 무시무시하게 무시했당

 

 

내가 널 찾기 전까징 (Until I Found You...)

버그 넌  그 무엇도 아니었으며, 존재하지도 않았당.

내가 널 찾아서 버그라 주석을 다라 다라 달아주었을 때,

그때 비로소 넌 BUG란 이름으로 존재감을 드러냈당.

 

누가 날 찾아줄깡? 

어쩌다 마주 친 그대!  현재는 미래의 과거!

시간을 되돌린다 한들 사실 크게 의미가 바뀌진 않을거당.

바뀌면 바뀌는대로 얻는 것만큼 잃는 것이 생길지니..

 

그시절 빗속의 날구지도  그리움 스텝으로 

추억의 무대위에 동심의 댄스를 거듭 올린당.

 

Until I Found Null .... You are Not Null

 

 

https://www.youtube.com/watch?v=qyD2iNE-80Y 

 

관련글 더보기