이번에는 얼마전에 GitHub에 올려놓았던 Discord 이미지 서버 주소를 media.discordapp.net
에서 cdn.discordapp.com
으로 변경하는 스크립트의 개발 로그를 써볼 예정입니다.
완성품은 Seia-Soto/switch-discord-desktop-image-source에서 볼 수 있습니다.
HTTP 503: Service Unavailable
네, media.discordapp.net
의 자기소개입니다. 사실 약간 어이가 없었습니다. 옛날에는 속도가 느리더라도 결과가 나오기는 했거든요. 물론 거의 1분을 기다려야 했습니다. 그리고 샬며시 봐달라는 듯 나오는 이미지입니다.

Discord에서 이미지를 제공해주는 도메인은 2가지 종류가 있습니다.
- media.discordapp.net: 이미지의 썸네일과 orientation을 설정
- cdn.discordapp.com: 이미지 자체를 전송
이 때 Discord의 썸네일은 media.discordapp.net
에서 로드되는데 썸네일을 처리하는 로직이 병목 현상에 발이 묶인 건지 그 당시에 cdn.discordapp.com
쪽에서 오는 데이터는 빠르게 잘 넘어오고 있더라고요. 그래서 media.discordapp.net
으로 가는 요청을 cdn.discordapp.com
으로 프록시 등을 사용해서 대신 데이터를 넘겨주면 어떨까 싶었습니다. 사실 스크립트로 결과물이 나오게 된 이유는 제가 안드로이드나 iOS 등 네이티브 스택이 아닌 웹 스택만 줄줄이 쌓고 있었기 때문입니다. 아쉽게도 지금은 어떻게 만들 줄을 모르기 때문에 일단은 스크립트로 작성해보기로 했습니다.
코딩하기
가장 먼저 할 것은 현재 이미지를 모두 가져오는 것입니다. (그 전에 jQuery를 import하지 않도록 하세요, 반드시)
const images = document.querySelector('img')
다음 할 일은 재사용 가능한 함수를 만들어주는 것입니다. 그 이후에 업로드되는 이미지의 주소도 변경해야 하기 때문이죠. DOM 노드 리스트를 받고 src
속성 값을 변경해줍니다.
const updateImageSource = images => {
for (let i = 0, l = images.length; i < l; i++) {
const image = images[i]
image.src = image.src.replace(/media\.discordapp\.net/i, 'cdn.discordapp.com')
image.style['image-orientation'] = 'from-image'
}
}
마지막으로 추후에 올라오는 이미지를 가져오는데에 MutationObserver
API를 사용할 수 있습니다. Mutation Observer
는 실시간으로 변경(추가 그리고 제거를 포함함)되는 DOM 노드의 리스트를 반환합니다. 길이가 굳이 길 필요는 없기 때문에 Mutation Observer
의 Constructor와 함께 반환된 객체를 바로 사용하면 됩니다. 여기에서 추가된 노드들은 i
번째 mutation list의 addedNodes
DOM 객체 리스트에 포함되어 있습니다. 그러므로 나머지는 간단히 tagName
속성을 사용하여 이미지 태그만 가져온 다음 마지막 observe
메서드를 통해 document.body
에 대해 subtree 변경 사항을 확인합니다.
new MutationObserver(mutations => {
const newImages = []
for (let i = 0, l = mutations.length; i < l; i++) {
const addedNodes = mutations[i].addedNodes
for (let k = 0, s = addedNodes.length; k < s; k++) {
const addedNode = addedNodes[k]
if (addedNode.tagName === 'IMG') {
newImages.push(addedNode)
}
}
}
updateImageSource(newImages)
})
.observe(document.body, {
childList: true,
subtree: true
})
테스트하기
아래는 완성된 코드를 Minify한 것입니다. 숏코딩 자체는 평소에 하지 않아 어떤 요소를 중점적으로 해야 하는지는 모르겠지만 최대한 그 당시에는 최선이라고 생각하고 있습니다...
d=document;g='image';p='discordapp';a=c=>c.forEach(e=>{e.src=e.src.replace('media.'+p+'.net','cdn.'+p+'.com');e.style[g+'-orientation']='from-'+g});a(d.querySelectorAll('img'));new MutationObserver(m=>{x=[];m.forEach(z=>{n=z.addedNodes;n.forEach(k=>{if(k.tagName=='IMG'){x.push(k)}})});a(x)}).observe(d.body,{childList:true,subtree:true})
위 코드를 복사해서 Discord 클라이언트의 개발자도구 콘솔에 붙여넣어줍니다. (Ctrl Shift I를 통해 Chrome 개발자 도구를 열 수 있습니다) 아래 서버는 제가 개인적으로 Discord 봇 개발 중 사용하는 테스트 서버입니다. img
태그의 src
값이 cdn.discordapp.com
으로 대체되는 것을 확인할 수 있습니다.

감사합니다. 끝이예요.