<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>건유1019</title>
    <link>https://coding-y.tistory.com/</link>
    <description>디스코드봇과 카카오톡봇을 개발하고 있는 &amp;quot;YBOT(?)&amp;quot;이라고 합니다.</description>
    <language>ko</language>
    <pubDate>Sun, 5 Jul 2026 16:25:05 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>건유1019</managingEditor>
    <image>
      <title>건유1019</title>
      <url>https://tistory1.daumcdn.net/tistory/3782335/attach/2b2d1af57fcf4d37a2294cfb210194db</url>
      <link>https://coding-y.tistory.com</link>
    </image>
    <item>
      <title>갤럭시 워치로 실시간 버스도착 정보를?!</title>
      <link>https://coding-y.tistory.com/56</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;MyBUS&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;갤럭시워치를 통하여 대중교통 정보를 보다 쉽게 알아볼 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;시연 사진&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zoKyl/btrzkznp0tt/ziwDoNfrGT1DK3YKa5awFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zoKyl/btrzkznp0tt/ziwDoNfrGT1DK3YKa5awFk/img.png&quot; data-origin-width=&quot;957&quot; data-origin-height=&quot;957&quot; data-filename=&quot;20220402_112059.png&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zoKyl/btrzkznp0tt/ziwDoNfrGT1DK3YKa5awFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzoKyl%2Fbtrzkznp0tt%2FziwDoNfrGT1DK3YKa5awFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;957&quot; height=&quot;957&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TIN99/btrzigioOX8/HnyOuHxVH71cX8r1Lomlk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TIN99/btrzigioOX8/HnyOuHxVH71cX8r1Lomlk0/img.png&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;1220&quot; data-filename=&quot;20220409_110743.png&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TIN99/btrzigioOX8/HnyOuHxVH71cX8r1Lomlk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTIN99%2FbtrzigioOX8%2FHnyOuHxVH71cX8r1Lomlk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1220&quot; height=&quot;1220&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bi35K6/btrzhrdmu1A/kRaAXUegY46VoI4n6T0BGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bi35K6/btrzhrdmu1A/kRaAXUegY46VoI4n6T0BGk/img.png&quot; data-origin-width=&quot;651&quot; data-origin-height=&quot;651&quot; data-filename=&quot;20220409_113015.png&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bi35K6/btrzhrdmu1A/kRaAXUegY46VoI4n6T0BGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbi35K6%2Fbtrzhrdmu1A%2FkRaAXUegY46VoI4n6T0BGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;651&quot; height=&quot;651&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLF7TH/btryDkeas8d/J8OBCk3pdA0fCRtQPpZDV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLF7TH/btryDkeas8d/J8OBCk3pdA0fCRtQPpZDV0/img.png&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;1321&quot; data-is-animation=&quot;false&quot; data-filename=&quot;20220409_113134.png&quot; style=&quot;width: 49.4186%; margin-top: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLF7TH/btryDkeas8d/J8OBCk3pdA0fCRtQPpZDV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLF7TH%2FbtryDkeas8d%2FJ8OBCk3pdA0fCRtQPpZDV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1321&quot; height=&quot;1321&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20220403_150828 복사.png&quot; data-origin-width=&quot;1993&quot; data-origin-height=&quot;1122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Okiy5/btrzjZs92Pj/KuCj1bLK7KlbOHVAQtLkT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Okiy5/btrzjZs92Pj/KuCj1bLK7KlbOHVAQtLkT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Okiy5/btrzjZs92Pj/KuCj1bLK7KlbOHVAQtLkT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOkiy5%2FbtrzjZs92Pj%2FKuCj1bLK7KlbOHVAQtLkT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1993&quot; height=&quot;1122&quot; data-filename=&quot;20220403_150828 복사.png&quot; data-origin-width=&quot;1993&quot; data-origin-height=&quot;1122&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p id=&quot;SE-f9b427ca-c527-463e-8fdb-b05c72968e93&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;1. 청량리 (주변정류소)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bc41e4b2-2f68-46e6-8b8c-832b20ab48e8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;2. 잠실역 (실시간 버스 도착정보)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-01a4aad5-b40f-49ae-a50b-55985b2bf6c8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;3. 잠실역 (실시간 버스 도착정보)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3227138a-2ea9-44c4-819e-f29749de7cc5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;4. 어린이대공원.세종대학교 (실시간 버스 도착정보)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e28f606c-eff5-4885-9f9e-8145eb869fb9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;5. 은행사거리 (주변정류소)&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div id=&quot;SE-faff8106-5d51-4ef2-ab1c-02a8c05dfa25&quot; data-compid=&quot;SE-faff8106-5d51-4ef2-ab1c-02a8c05dfa25&quot; data-a11y-title=&quot;본문&quot;&gt;
&lt;div&gt;
&lt;div data-unitid=&quot;&quot; data-compid=&quot;SE-faff8106-5d51-4ef2-ab1c-02a8c05dfa25&quot; data-direction=&quot;top&quot;&gt;
&lt;div&gt;
&lt;div id=&quot;SE-b6a20384-6541-492a-8123-5578bb6770a0&quot;&gt;
&lt;h3 id=&quot;SE-278a4be2-00fa-4d14-90bd-c7fa91d7024d&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;기능 소개&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;주변 정류소 검색&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;정류소 검색&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;실시간 버스 도착정보&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 id=&quot;SE-e28fa32f-ac5c-4c54-8a45-6ba3ec974558&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;지원하는 지역 &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-2eaeab09-7cb1-40d1-a352-dc7fffa3452f&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;수도권&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt; (서울특별시, 경기도, 인천광역시)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8857316a-b548-446b-81ac-dcb745731536&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #c2c2c2;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;s&gt;&lt;b&gt;부울권&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;&lt;span style=&quot;color: #c2c2c2;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;s&gt; (부산광역시, 울산광역시, 창원시, 양산시, 김해시)&lt;/s&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4ccfe16a-b8a5-47b2-b40c-af9a9bc72196&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #c2c2c2;&quot; data-darkreader-inline-color=&quot;&quot;&gt;목표는 전국 지원입니다!&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 id=&quot;SE-233f6d3e-b0e9-4a46-88a9-ee53a4358b25&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;&amp;lt; 링크 &amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-534da252-7b03-4b14-8035-ffcc7f2c0f1d&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;플레이스토어: &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot; data-href=&quot;https://play.google.com/store/apps/details?id=kr.yhs.traffic&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=kr.yhs.traffic&quot;&gt;https://play.google.com/store/apps/details?id=kr.yhs.traffic&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1463dd56-3a0e-4aa0-a65a-e7cae47cbd85&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;소스코드: &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot; data-href=&quot;https://github.com/gunyu1019/TrafficApplication&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/gunyu1019/TrafficApplication&quot;&gt;https://github.com/gunyu1019/TrafficApplication&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 id=&quot;SE-828deb4a-a30a-495a-84b6-e9ef5f3299ae&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;&amp;lt; 주의사항 &amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-37b57ba7-2cb2-48e5-b03a-2c8e70419ae2&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;플레이스토어 버그로 인하여 조건에 충족한 웨어러블 디바이스에서 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;u&gt;페어링된 모바일 디바이스&lt;/u&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;으로 호환성 버그로 다운로드 버튼이 비활성화되는 문제가 계속 발생하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-16fb3c78-810e-42cd-a02e-a23be07943b2&quot; data-compid=&quot;SE-16fb3c78-810e-42cd-a02e-a23be07943b2&quot; data-a11y-title=&quot;사진&quot;&gt;
&lt;div&gt;
&lt;div data-unitid=&quot;&quot; data-compid=&quot;SE-16fb3c78-810e-42cd-a02e-a23be07943b2&quot; data-direction=&quot;top&quot;&gt;
&lt;div&gt;
&lt;div id=&quot;SE-16fb3c78-810e-42cd-a02e-a23be07943b2&quot;&gt;
&lt;div data-unitid=&quot;SE-16fb3c78-810e-42cd-a02e-a23be07943b2&quot; data-compid=&quot;&quot; data-direction=&quot;top&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1035&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDkxsB/btrzjoGIn33/D5B0PO3MU3kTjtixKvNXnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDkxsB/btrzjoGIn33/D5B0PO3MU3kTjtixKvNXnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDkxsB/btrzjoGIn33/D5B0PO3MU3kTjtixKvNXnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDkxsB%2FbtrzjoGIn33%2FD5B0PO3MU3kTjtixKvNXnK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;1035&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1035&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;SE-ed2e2d81-f8d6-4464-8e85-7840ff9416e7&quot;&gt;
&lt;p id=&quot;SE-6abbd1f7-a477-4e54-8284-9863e152fecc&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&quot;기기가 이 버전과 호환되지 않습니다.&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;따라서 웹사이트에서 &quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;u&gt;다른 기기에 설치&lt;/u&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&quot;를 통해 어플을 설치해주시거나, &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;SE-8474557a-2445-4576-b9ff-dae228fe6295&quot; data-compid=&quot;SE-8474557a-2445-4576-b9ff-dae228fe6295&quot; data-a11y-title=&quot;본문&quot;&gt;
&lt;div&gt;
&lt;div data-unitid=&quot;&quot; data-compid=&quot;SE-8474557a-2445-4576-b9ff-dae228fe6295&quot; data-direction=&quot;top&quot;&gt;
&lt;div&gt;
&lt;div id=&quot;SE-c290a88a-b41f-4b88-b7b8-aae81f2455b9&quot;&gt;
&lt;p id=&quot;SE-3bfec296-8713-4e5f-bed5-3313f1e00221&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;u&gt;WearOS 기기의 플레이스토어&lt;/u&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot; data-darkreader-inline-color=&quot;&quot;&gt;에서 &quot;MyBUS&quot;를 검색해서 다운로드 해주셔야합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e9d28e81-b65f-4a6a-be4b-5d9a161de968&quot; data-compid=&quot;SE-e9d28e81-b65f-4a6a-be4b-5d9a161de968&quot; data-a11y-title=&quot;사진&quot;&gt;
&lt;div&gt;
&lt;div data-unitid=&quot;&quot; data-compid=&quot;SE-e9d28e81-b65f-4a6a-be4b-5d9a161de968&quot; data-direction=&quot;top&quot;&gt;
&lt;div&gt;
&lt;div id=&quot;SE-e9d28e81-b65f-4a6a-be4b-5d9a161de968&quot;&gt;
&lt;div data-unitid=&quot;SE-e9d28e81-b65f-4a6a-be4b-5d9a161de968&quot; data-compid=&quot;&quot; data-direction=&quot;top&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;672&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GgxZG/btrzmjj5qXk/8KZ8zp6EitQjDBGwr5KRh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GgxZG/btrzmjj5qXk/8KZ8zp6EitQjDBGwr5KRh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GgxZG/btrzmjj5qXk/8KZ8zp6EitQjDBGwr5KRh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGgxZG%2Fbtrzmjj5qXk%2F8KZ8zp6EitQjDBGwr5KRh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;672&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;672&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-23acec7a-3277-4bba-a9cb-66d0756e659a&quot; data-compid=&quot;SE-23acec7a-3277-4bba-a9cb-66d0756e659a&quot; data-a11y-title=&quot;본문&quot;&gt;
&lt;div&gt;
&lt;div data-unitid=&quot;&quot; data-compid=&quot;SE-23acec7a-3277-4bba-a9cb-66d0756e659a&quot; data-direction=&quot;top&quot;&gt;
&lt;div&gt;
&lt;div id=&quot;SE-e5e54097-b0a6-4005-a9bd-3967e578a4d4&quot;&gt;
&lt;p id=&quot;SE-4bd110ab-5322-4e08-a631-3b8c8b050564&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;아직&amp;nbsp;원인을&amp;nbsp;찾고&amp;nbsp;있으며,&amp;nbsp;빠른&amp;nbsp;시일내에&amp;nbsp;해결하도록&amp;nbsp;하겠습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;불편을 드려 대단히 죄송합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로젝트/WearOS 어플 (MyBUS)</category>
      <author>건유1019</author>
      <guid isPermaLink="true">https://coding-y.tistory.com/56</guid>
      <comments>https://coding-y.tistory.com/56#entry56comment</comments>
      <pubDate>Thu, 14 Apr 2022 01:37:10 +0900</pubDate>
    </item>
    <item>
      <title>PUBG BOT v2.0 패치노트 &amp;amp; 공지사항</title>
      <link>https://coding-y.tistory.com/55</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. PUBG BOT으로는 오랜만으로 찾아뵙게 되었습니다. 10월 27일에 v1.1을 패치하고 나서 약 10개월이 지난 지금 패치노트를 써보게 되었습니다. PUBG BOT은 2020년에 봇 인증 관련 문제가 장기적으로 이어지면서, 개발에 대한 차질도 피하지 못했습니다. 그러나 10개월이 지난 지금 200개 이상의 서버가 PUBG BOT을 지지해주고 있으며, PUBG BOT의 많은 부분을 개선하였습니다. PUBG BOT이 업그레이드되기까지 기다려주신 분들 많은 감사드립니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 PUBG BOT의 v2.0 패치노트에 대하여 알아보고자 합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;421&quot; width=&quot;289&quot; height=&quot;352&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bv4TsI/btraSZSqNRu/j0vcVKoxas1v5lz0YpAtXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bv4TsI/btraSZSqNRu/j0vcVKoxas1v5lz0YpAtXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bv4TsI/btraSZSqNRu/j0vcVKoxas1v5lz0YpAtXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbv4TsI%2FbtraSZSqNRu%2Fj0vcVKoxas1v5lz0YpAtXK%2Fimg.png&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;421&quot; width=&quot;289&quot; height=&quot;352&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;PUBG BOT이 드디어 빗금 명령어을 지원 합니다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금으로부터 약 한 달 전, PUBG BOT에 빗금 명령어가 지원한다는 많은 떡밥을 뿌리고 다녔었습니다. 정작 명령어는 추가되었지만 작동되지 않는다는 점에서 많은 유저분들이 의문을 품기도 했을 것입니다. 이토록 오랜 시간 동안 떡밥만 뿌리고 정식으로 패치 못하였던 이유는 이 기능을 준비하기 위해 많은 시간을 투자하였습니다. 빗금 명령어는 약 1년 전에 디스코드에 추가되었지만, 메시지를 보내는 방법과 구조가 다른 바람에 시간이 좀 걸렸습니다. 어쨌든 PUBG BOT의 명령어가 드디어 빗금 명령어와 호환됩니다. 아무래도 빗금 명령어가 대세가 되고 있는 지금 PUBG BOT이 선제적으로 지원합니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4yfIg/btraSYlAn4a/FK253hW99RBB3pLiDeLDRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4yfIg/btraSYlAn4a/FK253hW99RBB3pLiDeLDRK/img.png&quot; data-origin-width=&quot;598&quot; data-origin-height=&quot;256&quot; style=&quot;width: 55.935%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4yfIg/btraSYlAn4a/FK253hW99RBB3pLiDeLDRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4yfIg%2FbtraSYlAn4a%2FFK253hW99RBB3pLiDeLDRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;598&quot; height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfICm3/btraRkhz41d/kQjhvsb1SsXZOLJPM4eB1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfICm3/btraRkhz41d/kQjhvsb1SsXZOLJPM4eB1k/img.png&quot; data-origin-width=&quot;473&quot; data-origin-height=&quot;264&quot; style=&quot;width: 42.9022%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfICm3/btraRkhz41d/kQjhvsb1SsXZOLJPM4eB1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfICm3%2FbtraRkhz41d%2FkQjhvsb1SsXZOLJPM4eB1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;473&quot; height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;(좌) 기존 전적 기능 / (우) 새로운 전적 기능&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전적 기능에 버튼이 도입되었습니다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 전적 기능을 사용하면 아래의 반응을 통하여 자세한 정보를 확인할 수 있었습니다. 그러나 반응을 사용하기 위해서는 &quot;메시지 관리 권한&quot;이라는 것이 필요했고, 반응이 모두 생성되기까지 시간이 걸렸다는 점에서 걸림돌이 되기도 하였습니다. 이제부터는 아래에 버튼과 더 세련된 이모지를 통하여 빠르고 편리하게 상호작용할 수 있도록 업데이트하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;매치 로그 기능에 많은 부분을 개선하였습니다.&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kQoOK/btra8zc9uMU/42xw1WZ5nRWmvgnEoZOqB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kQoOK/btra8zc9uMU/42xw1WZ5nRWmvgnEoZOqB1/img.png&quot; data-origin-width=&quot;349&quot; data-origin-height=&quot;147&quot; style=&quot;width: 49.8617%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kQoOK/btra8zc9uMU/42xw1WZ5nRWmvgnEoZOqB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkQoOK%2Fbtra8zc9uMU%2F42xw1WZ5nRWmvgnEoZOqB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;349&quot; height=&quot;147&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2S8tF/btra8AC62Vt/qtMjeQqYJBhyCXVC6JipYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2S8tF/btra8AC62Vt/qtMjeQqYJBhyCXVC6JipYK/img.png&quot; data-origin-width=&quot;562&quot; data-origin-height=&quot;241&quot; style=&quot;width: 48.9755%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2S8tF/btra8AC62Vt/qtMjeQqYJBhyCXVC6JipYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2S8tF%2Fbtra8AC62Vt%2FqtMjeQqYJBhyCXVC6JipYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;562&quot; height=&quot;241&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;(좌) 기존 매치 선택 / (우) 새로운 매치 선택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 매치 로그 기능 전부분인 매치 선택 부분부터 확인해보자면, 위 사진과 같이 반응에서 선택하는 방식으로 변경되었습니다. 그리고 기존 5개까지 밖에 확인할 수밖에 없었던 매치 로그가 24개로 늘어났습니다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/esY6vz/btra33zqmLX/rLElMsk2QJbSHWtESx5Pt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/esY6vz/btra33zqmLX/rLElMsk2QJbSHWtESx5Pt0/img.png&quot; data-origin-width=&quot;421&quot; data-origin-height=&quot;257&quot; style=&quot;width: 46.1939%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/esY6vz/btra33zqmLX/rLElMsk2QJbSHWtESx5Pt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FesY6vz%2Fbtra33zqmLX%2FrLElMsk2QJbSHWtESx5Pt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;421&quot; height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bloIZj/btraXXzZfO3/LHb5n8Tot03H6dk7KYAN21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bloIZj/btraXXzZfO3/LHb5n8Tot03H6dk7KYAN21/img.png&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;321&quot; style=&quot;width: 31.4495%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bloIZj/btraXXzZfO3/LHb5n8Tot03H6dk7KYAN21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbloIZj%2FbtraXXzZfO3%2FLHb5n8Tot03H6dk7KYAN21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;358&quot; height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k2GJ8/btrbbSKmXUg/WD9XUU7F8ZUry7qeKXkJu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k2GJ8/btrbbSKmXUg/WD9XUU7F8ZUry7qeKXkJu1/img.png&quot; data-origin-width=&quot;412&quot; data-origin-height=&quot;580&quot; style=&quot;width: 20.0311%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k2GJ8/btrbbSKmXUg/WD9XUU7F8ZUry7qeKXkJu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk2GJ8%2FbtrbbSKmXUg%2FWD9XUU7F8ZUry7qeKXkJu1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;412&quot; height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;(좌) 팀원 매치 전적 / (중) 개편된 매치 전적(종합창) / (우) 매치 전적 요약 지도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 매치 전적을 더 보기 좋게, 다양한 정보를 담아보았습니다. 플레이어가 보급 상자를 오픈한 위치, 타 플레이어를 길한 위치, 팀원에게 회복하는 위치까지 다양한 위치를 표시하도록 업데이트하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서버 상태 기능을 개선하였습니다.&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;442&quot; width=&quot;341&quot; height=&quot;294&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxV8N0/btra09Gjeuc/9YWYaRXVDo5Lmp8b0tbtm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxV8N0/btra09Gjeuc/9YWYaRXVDo5Lmp8b0tbtm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxV8N0/btra09Gjeuc/9YWYaRXVDo5Lmp8b0tbtm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxV8N0%2Fbtra09Gjeuc%2F9YWYaRXVDo5Lmp8b0tbtm0%2Fimg.png&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;442&quot; width=&quot;341&quot; height=&quot;294&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 스팀 서버의 상태 기능은 디스코드 봇을 점검하거나 일시적으로 중지되었을 때 데이터가 날아가버리는 문제가 있었습니다. 이제부터는 디스코드 봇이 갑작스럽게 중지되거나, 일시 정지되어도 데이터가 정상적으로 불러와집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 PUBG BOT v2.0의 업데이트 내역을 알아보았습니다. PUBG BOT은 오는 8월 9일에 정식 패치를 진행합니다! 또한, 오늘 8월 3일부터 Pre-Launch-Test를 통하여 미리 체험해보실 수 있습니다. 꼭 새로운 PUBG BOT을 이용해 보세요! 감사합니다.&lt;/p&gt;</description>
      <category>프로젝트/디스코드 봇 (PUBG BOT)</category>
      <author>건유1019</author>
      <guid isPermaLink="true">https://coding-y.tistory.com/55</guid>
      <comments>https://coding-y.tistory.com/55#entry55comment</comments>
      <pubDate>Tue, 3 Aug 2021 02:20:35 +0900</pubDate>
    </item>
    <item>
      <title>디스코드봇(Components) - 03ㅣComponents를 상호작용해보자.</title>
      <link>https://coding-y.tistory.com/54</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 지난 강의에서는 디스코드 봇(Components)을 통하여 버튼을 만들어 보도록 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번 강의가 생각보다 내용이 많았던 것 같았어요. 사실 이번 강의는 2편에 넣으려고 했던 내용이었지만, 내용이 길어지다 보니 어쩔 수 없이 분리하게 됐습니다. 그래서 그렇게 저번처럼 매우 길어지지는 않을 거라고 봅니다. 저번 강의에서는 디스코드 봇(Componnents)을 통하여 버튼을 만들어 보았더라면, 이번 강의에서는 버튼을 클릭한 여부, 즉 상호작용을 해보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 강의는 discord.py(Python)을 기준으로 강의를 진행할 예정이며, discord.py(v1.7 기준) 내에는 기본적으로 지원하지 않기 때문에, 저희는 discord.py 내에 있는 웹소켓을 받아서 직접 상호작용을 진행할 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;우리는 디스코드의 통신 방법을 알아야 합니다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 지금까지 on_message 등의 다양한 이벤트 핸들러와, cogs를 통하여 메시지를 받고자 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 우리는 지금까지 on_message와 cogs의 수신 방법을 아시는 분들도 있겠지만, 모르는 사람이 대부분 일 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;discord.py 내에서는 사실 간단한 코드 일지라도 많은 처리 프로세스가 동작하고 있는 것 다들 알고 계셨나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Discord API에서는 어떠한 이벤트가 발생했을 때, 웹소켓 통신 방법을 활용하여 아래와 비슷한 코드를 리턴합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1623213825056&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  t: 'GUILD_MEMBERS_CHUNK',
  s: 3,
  op: 0,
  d: {
    not_found: [ 123123 ],
    members: [],
    guild_id: '308994132968210433'
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 저 위 내용과 관련된 내용은 아래의 Discord API 문서에서 확인하실 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://discord.com/developers/docs/topics/gateway&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://discord.com/developers/docs/topics/gateway&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1375&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EuToX/btq6RHIkCVV/YZXua9mA2p0gtIVDvZsXe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EuToX/btq6RHIkCVV/YZXua9mA2p0gtIVDvZsXe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EuToX/btq6RHIkCVV/YZXua9mA2p0gtIVDvZsXe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEuToX%2Fbtq6RHIkCVV%2FYZXua9mA2p0gtIVDvZsXe1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1375&quot; height=&quot;301&quot; data-origin-width=&quot;1375&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;필드(키)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;타입&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;op&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;int(정수형)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;a href=&quot;https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway-opcodes&quot;&gt;&lt;span&gt;opcode&lt;/span&gt;&lt;/a&gt;에 대한 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;d&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;mixed(혼합형, JSON)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;이벤트 데이터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;s&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;int(정수형)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;세션&amp;nbsp;및&amp;nbsp;하트&amp;nbsp;비트&amp;nbsp;재개에&amp;nbsp;사용되는&amp;nbsp;시퀀스&amp;nbsp;번호&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;t&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;string(문자열)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;페이로드의&amp;nbsp;이벤트&amp;nbsp;이름&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 정보를 파악한다면, 't'라는 곳에는 이벤트 이름이 들어가 있으며, 'd'에는 관련된 데이터 값이 들어 있다는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로써 discord.py가 처리하기 전에 받는 데이터를 대하여 분석해보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;discord.py 안에서는 socket_response라는 이벤트 함수를 통하여 Discord API와 서로 간 상호작용하는 내용 중 Discord API가 발신하는 되는 모든 정보를 읽어올 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1623258954942&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async def on_socket_response(payload):
	print(payload)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 함수를 추가한다면, 웹소켓을 통하여 받는 모든 내용을 읽을 수 있습니다. 위 소스를 통하여 불러온 payload를 중에서 우리가 익숙한 두 가지를 분석해보고자 합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;+ 추가 (2022-02-18)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;discord.py v2.0 이상의 버전에서는 더 이상 &quot;on_socket_response&quot; 이벤트를 통하여 상호작용하는 내역을 수집할 수 없습니다. 따라서 아래의 과정을 추가함으로써, discord.py v2.0 이상의 버전에서도 디스코드와 상호작용한 값을 수집할 수 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. Client에 enable_debug_events 인자를 True 값으로 설정합니다.&lt;/b&gt;&lt;br /&gt;
&lt;pre id=&quot;code_1645153995919&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;client = discord.Client(enable_debug_events=True)​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법은 discord.AutoShardedClient, command.Bot, command.AutoShardedBot에도 동일하게 사용됩니다.&lt;/p&gt;
&lt;br /&gt;&lt;b&gt;2. &quot;on_socket_response&quot; 대신 &quot;on_socket_raw_receive&quot;를 사용합니다.&lt;/b&gt;&lt;br /&gt;대신 해당 함수를 사용하게 되면, 압축 상태의 값이 들어오기 때문에, 압축 해체(decompress) 과정이 필요합니다.&lt;br /&gt;Discord 공식 문서(&lt;a href=&quot;https://discord.com/developers/docs/topics/gateway&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;#&lt;/a&gt;)에서도 서술되어 있으며, 아래의 소스 코드를 통해 동일한 값을 얻으실 수 있습니다.
&lt;pre id=&quot;code_1645154180325&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Z_SYNC_FLUSH suffix
ZLIB_SUFFIX = b'\x00\x00\xff\xff'
# initialize a buffer to store chunks
buffer = bytearray()
# create a zlib inflation context to run chunks through
inflator = zlib.decompressobj()

# ...
@client.event()
def on_socket_raw_receive(msg):
  # always push the message data to your cache
  buffer.extend(msg)

  # check if the last four bytes are equal to ZLIB_SUFFIX
  if len(msg) &amp;lt; 4 or msg[-4:] != ZLIB_SUFFIX:
    return

  # if the message *does* end with ZLIB_SUFFIX,
  # get the full message by decompressing the buffers
  # NOTE: the message is utf-8 encoded.
  msg = inflator.decompress(buffer)
  buffer = bytearray()

  # here you can treat `msg` as either JSON or ETF encoded,
  # depending on your `encoding` param​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 소스코드를 다소 보기좋게 수정한다면 아래의 소스코드를 대신 적용해도 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1645154301958&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;_zlib = zlib.decompressobj()
_buffer = bytearray()

@client.event()
def on_socket_raw_receive(msg):
	if type(msg) is bytes:
		_buffer.extend(msg)
		if len(msg) &amp;lt; 4 or msg[-4:] != b'\x00\x00\xff\xff':
			return
		msg = _zlib.decompress(self.__buffer)
		msg = msg.decode('utf-8')
		_buffer = bytearray()
	msg = json.loads(msg)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 discord.py v2.0 에서부터는 컴포넌트 수신을 지원하기 때문에, 꼭 이 방법을 적용하실 필요는 없지만, 혹시나 필요하신 분을 위해 작성해드렸습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 설명한 것을 기반으로 아래의 두 가지 데이터를 분석해보도록 하겠습니다. 두 데이터는 우리가 디스코드 봇을 운영한다면 무조건 받은 payload입니다. 한번 차근차근 분석해보도록 하겠습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;on_ready (READY)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1623260098453&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  't': 'READY',
  's': 1,
  'op': 0,
  'd': {
    'v': 6,
    'user_settings': {},
    'user': {
      'verified': True,
      'username': '&amp;lt;name&amp;gt;',
      'mfa_enabled': True,
      'id': '&amp;lt;ID&amp;gt;',
      'flags': 0,
      'email': None,
      'discriminator': '&amp;lt;tag&amp;gt;',
      'bot': True,
      'avatar': '&amp;lt;avatar&amp;gt;'
    },
    'session_id': '&amp;lt;Session ID&amp;gt;',
    'relationships': [],
    'private_channels': [],
    'presences': [],
    'guilds': ['guild'],
    'guild_join_requests': [],
    'geo_ordered_rtc_regions': ['south-korea', 'japan', 'hongkong', 'singapore', 'india'],
    'application': {
      'id': '&amp;lt;ID&amp;gt;',
      'flags': 303104
    },
    '_trace': []
    'shard_id': None
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 기능은 't'값에 READY라는 내용이 있는 것을 보아, 준비되었다는 것을 알리기 위한 이벤트라고 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 해당 payload가 들어오고 나서 on_ready() 이벤트 함수가 작동하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 이때, 성공적으로 실행됐다는 것만 알 수 있지만, 사실은 들어가 있는 길드 정보, 서버 정보, 앱 정보, 봇 사용자 정보 등 다양한 정보가 들어가 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;on_message (MESSAGE CREATE)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1623260265626&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  't': 'MESSAGE_CREATE',
  's': 4,
  'op': 0,
  'd': {
    'type': 0,
    'tts': False,
    'timestamp': '&amp;lt;time&amp;gt;',
    'referenced_message': None,
    'pinned': False,
    'nonce': '&amp;lt;nonce ID&amp;gt;',
    'mentions': [],
    'mention_roles': [],
    'mention_everyone': False,
    'member': {
      'roles': ['&amp;lt;role ID&amp;gt;'],
      'premium_since': None,
      'pending': False,
      'nick': None,
      'mute': False,
      'joined_at': '&amp;lt;joined_at&amp;gt;',
      'is_pending': False,
      'hoisted_role': '&amp;lt;role&amp;gt;',
      'deaf': False,
      'avatar': None,
      'user': {
        'username': '&amp;lt;name&amp;gt;',
        'id': &amp;lt;User ID&amp;gt;,
        'avatar': '&amp;lt;avatar&amp;gt;',
        'discriminator': '&amp;lt;tag&amp;gt;',
        'bot': False
      }
    },
    'id': '&amp;lt;message ID&amp;gt;',
    'flags': 0,
    'embeds': [],
    'edited_timestamp': None,
    'content': '.',
    'components': [],
    'channel_id': '&amp;lt;channel ID&amp;gt;',
    'author': {
      'username': '&amp;lt;name&amp;gt;',
      'public_flags': 131136,
      'id': '&amp;lt;User ID&amp;gt;',
      'discriminator': '&amp;lt;tag&amp;gt;',
      'avatar': '&amp;lt;avatar&amp;gt;'
    },
    'attachments': [],
    'guild_id': '&amp;lt;guild ID&amp;gt;'
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 위에 있는 예제를 분석해보도록 하겠습니다. 't'의 값이 &quot;MESSAGE CREATE&quot;라는 것을 보아, 메시지가 만들어졌을 때 발생하는 이벤트 함수인 것을 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'d'라는 키값에 데이터 값이 상당히 많다는 것을 알 수 있는데요. 수신받은 메시지, 임베드, 자료(attachments), 서버 정보, 채널 정보, 유저 정보, 맨션 유무 등의 상당한 많은 양에 데이터가 들어 있음을 알 수 있습니다. 이 데이터들이 discord.py에서는 message라는 데이터 모델(Data Model) 안에 들어가게 되어, 보다 쉽게 수집할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 버튼을 눌렀을 때도 이벤트가 발생한다는 것을 대충 눈치채셨을까요? 맞습니다. 버튼을 만들었을 때에도, &quot;&lt;b&gt;&lt;span style=&quot;background-color: #9feec3; color: #009a87;&quot;&gt;INTERACTION_CREATE&lt;/span&gt;&lt;/b&gt;&quot;라는 이벤트가 발생합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1623344085793&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  't': 'INTERACTION_CREATE',
  's': 7,
  'op': 0,
  'd': {
    'version': 1,
    'type': 3,
    'token': '&amp;lt;token&amp;gt;',
    'message': '&amp;lt;message&amp;gt;',
    'member': {
      'user': {
        'username': '&amp;lt;name&amp;gt;',
        'public_flags': 131136,
        'id': '&amp;lt;id&amp;gt;',
        'discriminator': '&amp;lt;tag&amp;gt;',
        'avatar': '&amp;lt;avatar&amp;gt;'
      },
      'roles': ['&amp;lt;role&amp;gt;'],
      'premium_since': None,
      'permissions': '&amp;lt;permissions&amp;gt;',
      'pending': False,
      'nick': None,
      'mute': False,
      'joined_at': '&amp;lt;joined_at&amp;gt;',
      'is_pending': False,
      'deaf': False,
      'avatar': None
    },
    'id': '&amp;lt;id&amp;gt;',
    'guild_id': '&amp;lt;guild_id&amp;gt;',
    'data': {
      'custom_id': 'python',
      'component_type': 2
    },
    'channel_id': '&amp;lt;channel_id&amp;gt;',
    'application_id': '&amp;lt;application_id&amp;gt;'
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 생긴 payload가 들어오며, 사실 상당히 긴 내용의 데이터지만 일부 중복되는 데이터를 축약하여 알려드리겠습니다. 우선 member에는 버튼을 누른 사용자의 데이터가 들어가 있었습니다. 그리고, message에는 INTERACTION(상호작용)이 발생한 메시지 데이터가 들어 있었습니다. data 값에는 사용자가 누른 버튼의 데이터와 ID값이 들어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 ID 값은 저번 2편에서 다루었던 'custom_id'라는 것을 알 수 있었습니다. 즉, 우리는 'custom_id'값이 버튼을 찾기 위한 고유의 키값이라는 것을 또 알 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;버튼을 받아볼까요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 한번 사용자가 택한 버튼을 읽어보고 분석해보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 강의는 저번 편에 이어서 진행할 예정입니다. 저번 편에 있던 마지막 소스를 이어서 나갈 예정이니 지난 강의를 보지 못한 분들은 지난 강의를 보고 오시는 것이 편할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.yonghyeon.com/53&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2021.06.01 - [개발 강좌/기타 강좌] - 디스코드봇(Components) - 02ㅣComponents를 통하여 버튼을 만들어보자!&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 위에 말했듯 discord.py에서는 기본적으로 상호작용에 대한 이벤트가 존재하지 않기 때문에 직접 만들어야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1623345332467&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@client.event
async def on_socket_response(payload):
	if payload.get(&quot;t&quot;, &quot;&quot;) == &quot;INTERACTION_CREATE&quot;:
		return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그다음은 &lt;b&gt;&lt;span style=&quot;background-color: #9feec3; color: #409d00;&quot;&gt;INTERACTION_CREATE&lt;/span&gt;&lt;/b&gt;이라는 이벤트만 받아야 하기 때문에 위 조건문을 추가해야 합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;+ 추가 (2021-06-13)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;해당 이벤트는 버튼을 누르는 경우 외에도, &quot;/&quot; 명령어라는 빗금 명령어를 사용해도 발생합니다. 따라서 type를 통하여 구분을 할 필요가 있습니다.&lt;br /&gt;&lt;br /&gt;상호작용 이벤트가 발생하는 타입(type)에는 총 3가지가 있으며, 아래의 표와 같습니다.&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFClcK/btq65fqSF8o/ynOlKeKDKq3mHEJ0mtU5J0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFClcK/btq65fqSF8o/ynOlKeKDKq3mHEJ0mtU5J0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFClcK/btq65fqSF8o/ynOlKeKDKq3mHEJ0mtU5J0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFClcK%2Fbtq65fqSF8o%2FynOlKeKDKq3mHEJ0mtU5J0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1378&quot; height=&quot;200&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;br /&gt;해당 내용을 아래의 표에 추가로 정리해두겠습니다.&lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style9&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;이름&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;값&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;핑&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;빗금 명령어('/')&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;메시지 컴포넌트&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
따라서 data 값내에 있는 type 에서 &quot;3&quot; 값일 경우에만 작동하도록 만들어야 합니다.&lt;br /&gt;&lt;br /&gt;
&lt;pre id=&quot;code_1623581718505&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@client.event
async def on_socket_response(payload):
	if payload.get(&quot;t&quot;, &quot;&quot;) == &quot;INTERACTION_CREATE&quot; and payload.get(&quot;d&quot;, {}).get(&quot;type&quot;) == 3:
		return​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 해당 이벤트를 통하여, 상호작용이라는 이벤트뿐만 아닌, 다른 다양한 이벤트가 발생하기 때문에 우리는 우리가 필요한 이벤트만 잡아줄 필요가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'t에 이벤트 이름이 들어 있으니, 't' 값을 통하여 이벤트를 필터링해줍니다. 그다음 우리는 해당 이벤트에서 제공하는 데이터 값을 수집해야 합니다. 우선 사용자가 무엇을 선택했는지에 대한 정보와, 메시지 정보를 직접 수집해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로, discord.py에서는 해당 값들이 모두 Data Class안에 내장되어 보다 쉽게 불러올 수 있지만, 직접 수집할 때에는 payload라는 변수 안에 dict형태의 데이터가 들어 있으므로 직접 수집해줘야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1623429693093&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;d = payload.get(&quot;d&quot;, {})
message = d.get(&quot;message&quot;, {})
custom_id = d.get(&quot;data&quot;, {}).get(&quot;custom_id&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data 값을 불러오지 않고, custom_id를 바로 불러왔냐면, 굳이 Button 인 것을 아는데, 불러올 필요가 있을 까라는 생각이 들어서였습니다. 물론 data라는 변수가 없어서는 안 되겠지만, 만약에 없을 경우 None값을 불러오기 때문에 에러를 유발할 수 있습니다. 따라서, 우리는 dict의 기본값을 넣어주어서 값을 확인합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 &lt;span style=&quot;background-color: #99cefa; color: #006dd7;&quot;&gt;&lt;b&gt;print()&lt;/b&gt;&lt;/span&gt;를 사용하여, 사용자가 선택받은 값을 읽어보도록 합시다.&lt;/p&gt;
&lt;pre id=&quot;code_1623431361871&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@client.event
async def on_socket_response(payload):
	if payload.get(&quot;t&quot;, &quot;&quot;) == &quot;INTERACTION_CREATE&quot;:
		d = payload.get(&quot;d&quot;, {})
		message = d.get(&quot;message&quot;, {})
		custom_id = d.get(&quot;data&quot;, {}).get(&quot;custom_id&quot;)
		print(custom_id)
	return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 말입니다. 어찌 버튼을 눌러도 이상한 점을 발견하지 않으셨나요? 분명히 값은 잘 불러와지는데, 아래 사진과 같은 현상이 발생합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;274&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chtt5d/btq64SPv1aP/misCTJEvqNLKR6j61riX90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chtt5d/btq64SPv1aP/misCTJEvqNLKR6j61riX90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chtt5d/btq64SPv1aP/misCTJEvqNLKR6j61riX90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fchtt5d%2Fbtq64SPv1aP%2FmisCTJEvqNLKR6j61riX90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;469&quot; height=&quot;274&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;274&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상호작용 실패? 분명히 잘 받았는데, 왜 상호작용에 실패하였다는 메시지가 뜰까요? 그것은 디스코드 봇이 올바르게 버튼을 수신받았는지 알 수 없기 때문입니다. 따라서, 상호작용을 성공적으로 맞추었다는 내용을 Discord API에 발신해야 합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;상호작용(&lt;span style=&quot;color: #ef5369;&quot;&gt;Ineraction Callback&lt;/span&gt;) 성공해보자!&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 올바르게 수신받았다! 를 전달하기 위해선 메시지를 보내는 것처럼 HTTP 클래스를 활용해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용방법은 아래의 디스코드 API 공식 문서에 작성돼 있긴 하지만, 이 강의에서 차근차근 다루어볼 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://discord.com/developers/docs/interactions/slash-commands#create-interaction-response&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://discord.com/developers/docs/interactions/slash-commands#create-interaction-response&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9TQZ2/btq64z3LwXo/3LUOU2gN5VEEmFXkwUzCn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9TQZ2/btq64z3LwXo/3LUOU2gN5VEEmFXkwUzCn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9TQZ2/btq64z3LwXo/3LUOU2gN5VEEmFXkwUzCn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9TQZ2%2Fbtq64z3LwXo%2F3LUOU2gN5VEEmFXkwUzCn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;659&quot; height=&quot;64&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내용을 참조하자면 /interactions/{상호작용 ID}/{상호작용 token}/callback에 POST를 보내야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방식은 2편에서 다루었던 메시지를 보내는 방법과 동일합니다. 근데 의문점이 발생합니다. 도대체 어디서 상호작용 ID와 토큰 값을 얻어오는 걸까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 위 이벤트에서 받았던 데이터 안에 포함되어 있습니다. 따라서 ID값과 토큰 값도 불러와야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1623431779094&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interaction_id = d.get(&quot;id&quot;)
interaction_token = d.get(&quot;token&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 무슨 데이터를 보내야 할까요? 상호작용 ID 만과 토큰으로는 충분하지 않을 텐데 무엇이 더 필요할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상호작용 유형(Type)과 그에 알맞은 데이터가 필요합니다. 우선 유형을 지정해볼까요?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1371&quot; data-origin-height=&quot;514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5sYiv/btq64z3Lydv/QxDdc0QTVFrW4UZFHYAag0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5sYiv/btq64z3Lydv/QxDdc0QTVFrW4UZFHYAag0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5sYiv/btq64z3Lydv/QxDdc0QTVFrW4UZFHYAag0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5sYiv%2Fbtq64z3Lydv%2FQxDdc0QTVFrW4UZFHYAag0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1371&quot; height=&quot;514&quot; data-origin-width=&quot;1371&quot; data-origin-height=&quot;514&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 위 사진을 참조해보면 총 5가지의 콜백 유형이 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 표를 아래에 번역해보도록 하겠습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 119px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style9&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;이름&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;값&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;퐁(Pong)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;ACK 핑(아직 무슨 기능인지는 잘 모릅니다. ㅎㅎ)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;ChannelMessageWithSource&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;새로운 메시지를 전송합니다. 이 메시지가 사용자만 볼 수 있는 메시지 인지 선택할 수도 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;DeferredChannelMessageWithSource&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&quot;생각 중 입니다.&quot;라는 메시지를 보냅니다. 만약에 처리하는데 시간이 걸리는 상호작용이라면 해당 값을 리턴시키는 것을 추천드립니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;DeferredUpdateMessage&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;6&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;우선 성공적으로 상호작용에 성공했다는 메시지를 보냅니다. 그러나 추후 메시지 수정이 필요합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;UpdateMessage&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;data 내에 첨부된 내용을 기반으로 메시지를 수정합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6번과 7번은 특히 컴포넌트(Components)를 사용했을 때만 사용이 가능한 기능인 점도 아래에 서술되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5번과 6번을 리턴할 경우에는 추가적으로 데이터를 제공할 필요는 없지만, 4번과 7번을 보냈을 경우에는 리턴되는 데이터가 data라는 값 안에 포함되어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data에 전송해야 되는 값은 2편에서 다루었던 메시지를 출력하는 방식과 방식이 동일하지만 Message 안에 있는 flag값이 0일 경우 그리고 64 일 경우에 따라, 메시지를 공개할 것인지, 본인만 볼 수 있는지를 고를 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;387&quot; data-origin-height=&quot;104&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bozJYu/btq69RPEBmM/pk0CKqoaeZI762IcRTdENk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bozJYu/btq69RPEBmM/pk0CKqoaeZI762IcRTdENk/img.png&quot; data-alt=&quot;flag값이 64일 경우 이렇게 리턴됩니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bozJYu/btq69RPEBmM/pk0CKqoaeZI762IcRTdENk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbozJYu%2Fbtq69RPEBmM%2Fpk0CKqoaeZI762IcRTdENk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;387&quot; height=&quot;104&quot; data-origin-width=&quot;387&quot; data-origin-height=&quot;104&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;flag값이 64일 경우 이렇게 리턴됩니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 우리가 개발하고 있었던 소스코드에 돌아와서 위 문서를 참조해준 뒤, 저는 사용자에게 ㅇㅇ을 골랐다고 알려주는 메시지를 추가하였습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1623478583541&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;await bot.http.request(
	Route(&quot;POST&quot;, f&quot;/interactions/{interaction_id}/{interaction_token}/callback&quot;),
	json={&quot;type&quot;: 4, &quot;data&quot;: {
		&quot;content&quot;: &quot;당신은 {}를 고르셨군요!&quot;.format(custom_id),
		&quot;flags&quot;: 64
	}},
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 상호작용을 하는 방법까지 알아보았습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;지금까지&amp;nbsp;배운&amp;nbsp;것을&amp;nbsp;응용해봅시다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 강의에서 배운 상호작용(콜백)과 상호작용 수신을 토대로 어제 다루었던 프로젝트를 이어서 나가보도록 하겠습니다. 해당 내용은 이전 강의 글을 이어서 나가기 때문에 이전에 다루었던 코드가 필요합니다!&lt;/p&gt;
&lt;pre id=&quot;code_1623509033376&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import discord
from discord.http import Route

bot = discord.Client()
http = bot.http

default_components = [
    {
        &quot;type&quot;: 1,
        &quot;components&quot;: [
            {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;Python&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;python&quot;,
                &quot;emoji&quot;: {
                    &quot;id&quot;: &quot;847876880257908757&quot;,
                    &quot;name&quot;: &quot;python&quot;
                }
            }, {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;Kotlin&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;kotlin&quot;,
                &quot;emoji&quot;: {
                    &quot;id&quot;: &quot;847876848662216714&quot;,
                    &quot;name&quot;: &quot;kotlin&quot;
                }
            }, {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;C언어&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;c&quot;
            }, {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;C++&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;cpp&quot;,
                &quot;emoji&quot;: {
                    &quot;id&quot;: &quot;847876987778629722&quot;,
                    &quot;name&quot;: &quot;cpp&quot;
                }
            }, {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;Java&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;java&quot;,
                &quot;emoji&quot;: {
                    &quot;id&quot;: &quot;847876915619954708&quot;,
                    &quot;name&quot;: &quot;java&quot;
                }
            }
        ]

    }
]

@bot.event
async def on_message(msg: discord.Message):
	if msg.content == &quot;!프로그래밍&quot;:
		embed = discord.Embed(
			title=&quot;최고의 프로그래밍 언어&quot;,
			description=&quot;&quot;&quot;&amp;lt;:python:847876880257908757&amp;gt; Python: 0표
				&amp;lt;:kotlin:847876848662216714&amp;gt; Kotlin: 0표
				C언어: 0표
				&amp;lt;:cpp:847876987778629722&amp;gt; C++: 0표
				&amp;lt;:java:847876915619954708&amp;gt; Java: 0표&quot;&quot;&quot;,
			colour=0x0080ff
		)
        
		r = Route('POST', '/channels/{channel_id}/messages', channel_id=msg.channel.id)
		payload = {
			&quot;embed&quot;: embed.to_dict()
			&quot;components&quot;: default_components
		}
		http.request(r, json=payload)
		return
       
bot.run(&quot;&amp;lt;토큰&amp;gt;&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2편에서 다루었던 코드)를 편의상 가져와보았습니다. 이곳에 오늘 배운 소스를 모두 추가해줄 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, 위에서 말했듯이 이벤트를 저희가 직접 받아서 만들어 줘야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1623521115928&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@bot.event
async def on_socket_response(payload: dict):
	return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그다음 우리는 특정 이벤트 일 경우에만 작동할 수 있도록 필터링을 해준 뒤, 데이터 값과 이벤트 이름을 변수에 저장해둡니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1623521184698&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@bot.event
async def on_socket_response(payload: dict):
	d = payload.get(&quot;d&quot;, {})
	t = payload.get(&quot;t&quot;)
	if t == &quot;INTERACTION_CREATE&quot; and d.get(&quot;type&quot;) == 3:
		return
	return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그다음, 사용자가 선택한 값을 불러옵니다. 그리고 메시지 값 또한, payload 데이터에서 꺼낸 뒤 변수에 저장해 둡니다. 해당 값은 추후 사용할 필요가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1623521785287&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# + custom_id = d.get(&quot;data&quot;, {}).get(&quot;custom_id&quot;)
# + message = d.get(&quot;message&quot;)
@bot.event
async def on_socket_response(payload: dict):
	d = payload.get(&quot;d&quot;, {})
	t = payload.get(&quot;t&quot;)
	if t == &quot;INTERACTION_CREATE&quot; and d.get(&quot;type&quot;) == 3:
		custom_id = d.get(&quot;data&quot;, {}).get(&quot;custom_id&quot;)
		message = d.get(&quot;message&quot;)
	return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 저희는 최고의 프로그래밍 언어를 선택하는 프로그램을 만들 예정이기 때문에, 투표한 데이터 값을 저장해야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1623521883113&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;voted_data = {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 위에 해당 변수를 선언하여 전역 변수를 만들어 주고 나서, 아래처럼 메시지를 보내고 난 뒤에도 데이터를 저장할 수 있도록 값을 저장해 둡니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1623521992381&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;voted_data[response.get(&quot;id&quot;)] = {
	&quot;python&quot;: 0, &quot;kotlin&quot;: 0, &quot;java&quot;: 0, &quot;cpp&quot;: 0, &quot;c&quot;: 0
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1623522081340&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@bot.event
async def on_message(msg: discord.Message):
	if msg.content == &quot;!프로그래밍&quot;:
		embed = discord.Embed(
			title=&quot;최고의 프로그래밍 언어&quot;,
			description=&quot;&quot;&quot;&amp;lt;:python:847876880257908757&amp;gt; Python: 0표
				&amp;lt;:kotlin:847876848662216714&amp;gt; Kotlin: 0표
				C언어: 0표
				&amp;lt;:cpp:847876987778629722&amp;gt; C++: 0표
				&amp;lt;:java:847876915619954708&amp;gt; Java: 0표&quot;&quot;&quot;,
			colour=0x0080ff
		)

		component1 = {
			&quot;embed&quot;: embed.to_dict(),
			&quot;components&quot;: default_components
		}

		response = await http.request(
			Route('POST', '/channels/{channel_id}/messages', channel_id=msg.channel.id), json=component1
		)
		voted_data[response.get(&quot;id&quot;)] = {
			&quot;python&quot;: 0, &quot;kotlin&quot;: 0, &quot;java&quot;: 0, &quot;cpp&quot;: 0, &quot;c&quot;: 0
		}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러고 나서, 사용자가 선택한 값을 변수에 저장해둔 뒤에 embed를 재생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1623522372022&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;embed = discord.Embed(
	title=&quot;최고의 프로그래밍 언어&quot;,
	description=&quot;&quot;&quot;&amp;lt;:python:847876880257908757&amp;gt; Python: {}표
				&amp;lt;:kotlin:847876848662216714&amp;gt; Kotlin: {}표
				C언어: {}표
				&amp;lt;:cpp:847876987778629722&amp;gt; C++: {}표
				&amp;lt;:java:847876915619954708&amp;gt; Java: {}표&quot;&quot;&quot;.format(
		voted_data[message.get(&quot;id&quot;, 0)]['python'], voted_data[message.get(&quot;id&quot;, 0)]['kotlin'],
		voted_data[message.get(&quot;id&quot;, 0)]['c'], voted_data[message.get(&quot;id&quot;, 0)]['cpp'],
		voted_data[message.get(&quot;id&quot;, 0)]['java']),
	colour=0x0080ff
)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1623522182288&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@bot.event
async def on_socket_response(payload: dict):
	d = payload.get(&quot;d&quot;, {})
	t = payload.get(&quot;t&quot;)
	if t == &quot;INTERACTION_CREATE&quot; and d.get(&quot;type&quot;) == 3:
		custom_id = d.get(&quot;data&quot;, {}).get(&quot;custom_id&quot;)
		message = d.get(&quot;message&quot;)
		
		embed = discord.Embed(
			title=&quot;최고의 프로그래밍 언어&quot;,
			description=&quot;&quot;&quot;&amp;lt;:python:847876880257908757&amp;gt; Python: {}표
						&amp;lt;:kotlin:847876848662216714&amp;gt; Kotlin: {}표
						C언어: {}표
						&amp;lt;:cpp:847876987778629722&amp;gt; C++: {}표
						&amp;lt;:java:847876915619954708&amp;gt; Java: {}표&quot;&quot;&quot;.format(
				voted_data[message.get(&quot;id&quot;, 0)]['python'], voted_data[message.get(&quot;id&quot;, 0)]['kotlin'],
				voted_data[message.get(&quot;id&quot;, 0)]['c'], voted_data[message.get(&quot;id&quot;, 0)]['cpp'],
				voted_data[message.get(&quot;id&quot;, 0)]['java']),
			colour=0x0080ff
		)
	return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러고 나서 변경한 메시지를 사용자에게 전달해 주어야 합니다. 투표 후 수정된 값을 전송해 줍니다. 이 방법 역시 메시지를 송신할 때와 방법이 동일합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1623522401764&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;component2 = {
	&quot;embed&quot;: embed.to_dict(),
	&quot;components&quot;: default_components
}

await http.request(
	Route('PATCH', '/channels/{channel_id}/messages/{message_id}',
	channel_id=message.get(&quot;channel_id&quot;), message_id=message.get('id')), json=component2
)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1623522298122&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@bot.event
async def on_socket_response(payload: dict):
	d = payload.get(&quot;d&quot;, {})
	t = payload.get(&quot;t&quot;)
	if t == &quot;INTERACTION_CREATE&quot; and d.get(&quot;type&quot;) == 3:
		custom_id = d.get(&quot;data&quot;, {}).get(&quot;custom_id&quot;)
		message = d.get(&quot;message&quot;)
		
		embed = discord.Embed(
			title=&quot;최고의 프로그래밍 언어&quot;,
			description=&quot;&quot;&quot;&amp;lt;:python:847876880257908757&amp;gt; Python: {}표
						&amp;lt;:kotlin:847876848662216714&amp;gt; Kotlin: {}표
						C언어: {}표
						&amp;lt;:cpp:847876987778629722&amp;gt; C++: {}표
						&amp;lt;:java:847876915619954708&amp;gt; Java: {}표&quot;&quot;&quot;.format(
				voted_data[message.get(&quot;id&quot;, 0)]['python'], voted_data[message.get(&quot;id&quot;, 0)]['kotlin'],
				voted_data[message.get(&quot;id&quot;, 0)]['c'], voted_data[message.get(&quot;id&quot;, 0)]['cpp'],
				voted_data[message.get(&quot;id&quot;, 0)]['java']),
			colour=0x0080ff
		)

		component2 = {
			&quot;embed&quot;: embed.to_dict(),
			&quot;components&quot;: default_components
		}

		await http.request(
			Route('PATCH', '/channels/{channel_id}/messages/{message_id}',
			channel_id=message.get(&quot;channel_id&quot;), message_id=message.get('id')), json=component2
		)
	return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 메시지는 &quot;PATCH&quot;라는 method와 &quot;/channels/{채널 ID}/messages/{메시지 ID}&quot;(https://discord.com/api/v9/channels/{채널 ID}/messages/{메시지 ID})로 수정할 수 있음을 알 수 있습니다. 채널 ID, 메시지 ID는 위에서 불러온 message 변수에서 꺼내왔습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이제 다 왔습니다. 이제 사용자가 정상적으로 수신했다는 메시지만 얻어오면 됩니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1623522682387&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interaction_id = d.get(&quot;id&quot;)
interaction_token = d.get(&quot;token&quot;)
		
await bot.http.request(
	Route(&quot;POST&quot;, f&quot;/interactions/{interaction_id}/{interaction_token}/callback&quot;),
	json={&quot;type&quot;: 4, &quot;data&quot;: {
		&quot;content&quot;: &quot;당신은 {}를 고르셨군요!&quot;.format(custom_id),
		&quot;flags&quot;: 64
	}},
)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1623522619249&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@bot.event
async def on_socket_response(payload: dict):
	d = payload.get(&quot;d&quot;, {})
	t = payload.get(&quot;t&quot;)
	if t == &quot;INTERACTION_CREATE&quot; and d.get(&quot;type&quot;) == 3:
		custom_id = d.get(&quot;data&quot;, {}).get(&quot;custom_id&quot;)
		message = d.get(&quot;message&quot;)
		
		embed = discord.Embed(
			title=&quot;최고의 프로그래밍 언어&quot;,
			description=&quot;&quot;&quot;&amp;lt;:python:847876880257908757&amp;gt; Python: {}표
						&amp;lt;:kotlin:847876848662216714&amp;gt; Kotlin: {}표
						C언어: {}표
						&amp;lt;:cpp:847876987778629722&amp;gt; C++: {}표
						&amp;lt;:java:847876915619954708&amp;gt; Java: {}표&quot;&quot;&quot;.format(
				voted_data[message.get(&quot;id&quot;, 0)]['python'], voted_data[message.get(&quot;id&quot;, 0)]['kotlin'],
				voted_data[message.get(&quot;id&quot;, 0)]['c'], voted_data[message.get(&quot;id&quot;, 0)]['cpp'],
				voted_data[message.get(&quot;id&quot;, 0)]['java']),
			colour=0x0080ff
		)

		component2 = {
			&quot;embed&quot;: embed.to_dict(),
			&quot;components&quot;: default_components
		}

		await http.request(
			Route('PATCH', '/channels/{channel_id}/messages/{message_id}',
			channel_id=message.get(&quot;channel_id&quot;), message_id=message.get('id')), json=component2
		)
        
		interaction_id = d.get(&quot;id&quot;)
		interaction_token = d.get(&quot;token&quot;)
		
		await bot.http.request(
			Route(&quot;POST&quot;, f&quot;/interactions/{interaction_id}/{interaction_token}/callback&quot;),
			json={&quot;type&quot;: 4, &quot;data&quot;: {
				&quot;content&quot;: &quot;당신은 {}를 고르셨군요!&quot;.format(custom_id),
				&quot;flags&quot;: 64
			}},
		)
	return&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이 중에 사용자만 무엇을 택했는지 확인할 수 있도록 flags 값을 64로 제공하였습니다. 위에서 설명했듯이 0을 주면 전부 다 메시지를 볼 수 있지만, 64를 주면 버튼을 누른 사용자만 메시지를 확인하게 만들 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 사용자가 버튼을 누른 값을 확인하고 이에 알맞은 값을 보내는 방법까지 알아보았습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;앞서 말한 코드는 Github Gist를 통하여 배포하고 있습니다. 저 위에 있는 코드가 잘보이지 않는다면 아래의 소스코드를 써보는 것도 나쁘지 않다고 생각합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gist.github.com/gunyu1019/39bb26eccd23da99f2d8f7c6d5f22308&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://gist.github.com/gunyu1019/39bb26eccd23da99f2d8f7c6d5f22308&lt;/a&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 이번 강의에서는 사용자가 버튼을 누른 값을 확인하고, 정상적으로 상호작용을 했다는 콜백 부분에 대하여 알아보았습니다. 사실은 이렇게 하면 디스코드 봇 버튼 만드는 과정은 마스터하신 거지만, 강의의 내용이 아직 하나 남아 있습니다. 다음 마지막 편에서는 아직 배포되지 않은 숨겨진 기능, Select에 대하여 다루어 보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 강의도 길이가 만만치 않은 편인데, 끝까지 읽어주신 분들께 감사인사를 드립니다. 모두들 수고하셨습니다!&lt;/p&gt;</description>
      <category>개발 강좌/기타 강좌</category>
      <author>건유1019</author>
      <guid isPermaLink="true">https://coding-y.tistory.com/54</guid>
      <comments>https://coding-y.tistory.com/54#entry54comment</comments>
      <pubDate>Sun, 13 Jun 2021 03:40:19 +0900</pubDate>
    </item>
    <item>
      <title>디스코드봇(Components) - 02ㅣComponents를 통하여 버튼을 만들어보자!</title>
      <link>https://coding-y.tistory.com/53</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 이번 강의에서는 디스코드 봇(Components)을 통하여 버튼을 만들어 보도록 하겠습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 오늘 배우는 것은 discord.py를 사용할 거지만, discord.py를 굳이 사용하지 않고, aiohttp나 requests 등을 통하여 HTTP 세션을 보낼 수 있다면, 충분히 가능합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 이번 강좌도 저번 강좌에 예고했듯이 난이도가 있는 편입니다. 본인이 &quot;네트워크에 대한 지식이 없다&quot;, &quot;프로그래밍 언어에 대한 기초 지식이 없다.&quot;, &quot;디스코드 봇을 모른다&quot; 그러면 많은 어려움이 따를 수 있습니다. 최소한 네트워크 지식을 알고 하시는 것을 추천합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Components를 활용한 버튼을 만드는 작업은 정식적으로 discord.py에서 지원해주지 않기 때문에 API를 통해야 합니다. 우선 Discord API 사용법에 대하여 알아봅시다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Discord API 사용법?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 우리가 알아야 할 부분에 대해서만 집중적으로 다루겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Discord API를 다루기 위해선 HTTP 세션을 Discord에 보내주어야만 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Discord API 주소는 &lt;span style=&quot;background-color: #ffc1c8; color: #ee2323;&quot;&gt;&lt;b&gt;&amp;lt;BASE URL&amp;gt;/v &amp;lt;버전&amp;gt;/&amp;lt;path&amp;gt;&lt;/b&gt;&lt;/span&gt;로 구성되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Discord API의 BASE URL는 &quot;https://discord.com/api&quot;입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;357&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5GvdX/btq59NngxGA/33a9hpDkuDKH1ohuHo2V4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5GvdX/btq59NngxGA/33a9hpDkuDKH1ohuHo2V4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5GvdX/btq59NngxGA/33a9hpDkuDKH1ohuHo2V4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5GvdX%2Fbtq59NngxGA%2F33a9hpDkuDKH1ohuHo2V4K%2Fimg.png&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;357&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버전은 Components는 최근에 추가되었기 때문에 9 버전을 택하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 디스코드 API를 사용하기 위해선 앞에 &quot;&lt;a href=&quot;https://discord.com/api&quot;&gt;h&lt;/a&gt;&lt;a href=&quot;https://discord.com/api/v9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ttps://discord.com/api/v9&lt;/a&gt;&quot;을 입력해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 우리는 무슨 path를 보낼지 정해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 메시지를 보낼 것이기 때문에 &lt;a href=&quot;https://discord.com/developers/docs/resources/channel#create-message&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://discord.com/developers/docs/resources/channel#create-message를&lt;/a&gt; 참고해서 사용해야만 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1370&quot; data-origin-height=&quot;854&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cz8Hly/btq57qfwETd/AEhXNszmKTWXFDgu64kJhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cz8Hly/btq57qfwETd/AEhXNszmKTWXFDgu64kJhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cz8Hly/btq57qfwETd/AEhXNszmKTWXFDgu64kJhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcz8Hly%2Fbtq57qfwETd%2FAEhXNszmKTWXFDgu64kJhK%2Fimg.png&quot; data-origin-width=&quot;1370&quot; data-origin-height=&quot;854&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내용이 많이 복잡하지만 천천히 읽으면 모두 이해할 수 있는 사항입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;method는 POST 형태로, path는 &quot;/channels/{채널 ID}/messages&quot;를 통하여 메시지를 보낼 수 있다고 기재되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Limitations(한계)에서는 아래와 같이 분석할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보낼 봇이 &quot;메시지 보내기&quot; 권한이 필요합니다.&lt;/li&gt;
&lt;li&gt;TTS 메시지를 보낼 경우에는 &quot;TTS 메시지 보내기&quot; 권한이 필요합니다.&lt;/li&gt;
&lt;li&gt;회신(답변)을 하기 위해서는 &quot;메시지 역사 보기&quot; 권한이 필요합니다.&lt;/li&gt;
&lt;li&gt;메시지의 최대 전송 크기는 8MB로 제한됩니다.&lt;/li&gt;
&lt;li&gt;임베드를 설정할 때에는 type에 rich 값을 안 주어도 rich 값으로 자동으로 설정합니다.&lt;/li&gt;
&lt;li&gt;파일은 &quot;multipart/form-data&quot; 형태의 데이터 타입만 수신할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 최소 파일, 메시지, 임베드(embed)를 하나 이상 제공해야 한다고도 하네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1374&quot; data-origin-height=&quot;577&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQ6ZMq/btq54N25AH6/PiTB7oqlS6rSDGhNkh2IJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQ6ZMq/btq54N25AH6/PiTB7oqlS6rSDGhNkh2IJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ6ZMq/btq54N25AH6/PiTB7oqlS6rSDGhNkh2IJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ6ZMq%2Fbtq54N25AH6%2FPiTB7oqlS6rSDGhNkh2IJK%2Fimg.png&quot; data-origin-width=&quot;1374&quot; data-origin-height=&quot;577&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 필요한 Params를 알아보도록 합시다. 위에 있는 표를 참고하면 됩니다. 위에 있는 표를 아래에 번역해 두도록 하겠습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 180px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style9&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;&lt;b&gt;필드(키)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;&lt;b&gt;타입&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;&lt;b&gt;필수 여부&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;content&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;string(문자열)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;메시지&amp;nbsp;내용&amp;nbsp;(최대&amp;nbsp;2000&amp;nbsp;자)&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 25%;&quot;&gt;content, tts, file 중 하나는 필수로 작성해야합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;tts&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;boolean&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;TTS 활성화 여부&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;기본값이 True로 설정되며, 필수가 아닙니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;file&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;file contents&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;파일 콘텐츠&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 40px;&quot; rowspan=&quot;2&quot;&gt;content, tts, file 중 하나는 필수로 작성해야합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;embed&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;embed 모델&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;임베드 콘텐츠&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;payload_json&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;string (문자열)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;파일이 아닌 매개 변수의 json 인코딩 본문&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;multipart/form-data만 받을 수 있습니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;allowed_mentions&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;allowed_mentions 모델&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;맨션 허가 여부&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;필수가 아닙니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;message_reference&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;message_reference 모델&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;답장(회신)을 하기위한 메시지 콘텐츠&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;필수가 아닙니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;components&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;components 모델&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;components 내용&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;필수가 아닙니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서 내에 일부 누락되어 있지만, &quot;components&quot;에 대한 내용을 추가하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, Postman 등을 통하여 직접 보낼 때에는 아래처럼 보내야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;211&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brHG3y/btq580npnCU/7TxSTi4oJhua36IOyEYon1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brHG3y/btq580npnCU/7TxSTi4oJhua36IOyEYon1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brHG3y/btq580npnCU/7TxSTi4oJhua36IOyEYon1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrHG3y%2Fbtq580npnCU%2F7TxSTi4oJhua36IOyEYon1%2Fimg.png&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;211&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 그대로 보내게 된다면, 아래의 에러가 리턴될 겁니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622437358085&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;message&quot;: &quot;401: Unauthorized&quot;,
    &quot;code&quot;: 0
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 토큰 값이 저장되어 있지 않기 때문에 사용자가 누군지 확인할 수 없어서 발생한 현상입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 우리는 우리가 누구인지 증명을 해줘야 합니다. 따라서 Headers 값에 &quot;&lt;span style=&quot;color: #505050;&quot;&gt;authorization&quot;를 추가해줘야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;75&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R8Nb9/btq6esQXZQV/xB5DgSUNCsDsGKipkeytlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R8Nb9/btq6esQXZQV/xB5DgSUNCsDsGKipkeytlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R8Nb9/btq6esQXZQV/xB5DgSUNCsDsGKipkeytlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR8Nb9%2Fbtq6esQXZQV%2FxB5DgSUNCsDsGKipkeytlk%2Fimg.png&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;75&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 봇을 통하여 사용할 때에는 저렇게 작성해주시고 &amp;lt;token&amp;gt; 값에는 디스코드 봇의 토큰 값을 작성해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;(저기에 들어가는 값에 따라 유저 봇이라는 사용자가 봇이 되는 것도 가능하지만, 이용약관에 위배되는 사항이므로 다루지는 않겠습니다)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 과정은 discord.py가 없어도, 충분히 가능한 사항입니다. 다음은 discord.py를 통하여 메시지를 출력하는 방법을 알려드리겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;discord.py를 통하여 &quot;직접 메시지&quot;를 보내기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;discord.py를 통하여 메시지를 보낸다고 하신 다면 어떤 사람들은 아래처럼 보내면 될 거라고도 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622437732725&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@bot.event
async def on_message(msg):
	await msg.channel.send(&quot;블라블라~&quot;)
    
@command.commands(name=&quot;명령어&quot;)
async def command(ctx):
	await ctx.send(&quot;블라블라~~&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 최근에 지원을 하기 시작한 Components는 위 방법을 통하여 보내 줄 수 없기 때문에 &quot;직접&quot; 보내줘야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 이 과정을 알기 위해서는 discord.py를 뜯어볼 필요가 있다고 봅니다. 우리는 우리의 목표를 충족하기 위해서 우리가 사용하는 코드의 일부를 보고 분석해야 할 능력이 있어야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 discord.py가 배포 중인 &quot;&lt;a href=&quot;https://github.com/Rapptz/discord.py&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/Rapptz/discord.py&lt;/a&gt;&quot;를 가 보록 합시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 저렇게 &lt;span style=&quot;background-color: #ffc9af; color: #ef6f53;&quot;&gt;~. send()&lt;/span&gt;를 통하여 보낼 때 discord.py에는 아래의 함수가 실행되어 보내집니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;964&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvRimj/btq6eqZX4px/7bH9EcYr8KnezPOXqKjBc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvRimj/btq6eqZX4px/7bH9EcYr8KnezPOXqKjBc0/img.png&quot; data-alt=&quot;discord/abc.py의 1172줄&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvRimj/btq6eqZX4px/7bH9EcYr8KnezPOXqKjBc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvRimj%2Fbtq6eqZX4px%2F7bH9EcYr8KnezPOXqKjBc0%2Fimg.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;964&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;discord/abc.py의 1172줄&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 함수를 집중적으로 분석해 봅시다. 참고로 views라는 매개변수는 아직 정식으로 추가된 것은 아니지만 Components와 관련된 매개변수라는 점을 또 알 수 있습니다. (아직 discord.py v1.7을 사용하는 개발자는 사용할 수 없습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 분석해보자면 아래의 부분을 발견하게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;69&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fa0Ur/btq57qmo1Iw/2r8GyBX01e3ERbjcGffz4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fa0Ur/btq57qmo1Iw/2r8GyBX01e3ERbjcGffz4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fa0Ur/btq57qmo1Iw/2r8GyBX01e3ERbjcGffz4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFa0Ur%2Fbtq57qmo1Iw%2F2r8GyBX01e3ERbjcGffz4k%2Fimg.png&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;69&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 파일을 제외한 tts, content, embed 등이 이곳을 통하여 보내진 다는 것을 알 수 있습니다. 저 함수의 위치를 다시 찾게 된다면 아래에 있다는 것을 알게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;742&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDcBlY/btq56c2Z6QS/5nfKDwk0zWkjLvN398n5r0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDcBlY/btq56c2Z6QS/5nfKDwk0zWkjLvN398n5r0/img.png&quot; data-alt=&quot;discord/http.py의 349줄&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDcBlY/btq56c2Z6QS/5nfKDwk0zWkjLvN398n5r0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDcBlY%2Fbtq56c2Z6QS%2F5nfKDwk0zWkjLvN398n5r0%2Fimg.png&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;742&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;discord/http.py의 349줄&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 Route라는 함수에 위에 다루었던 method와 path를 볼 수 있습니다. 그렇습니다. 사실 discord.py도 Discord API를 거치고 있는 겁니다. 따라서 우리는 http.py에 있는 Route를 꺼내서, path와 method를 지정한 뒤에 HTTP 클래스에 있는 request 함수를 통하여 보내야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 클래스는 Client 또는 Cog(Bot)을 사용하든 아래의 방법으로 꺼낼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622438463478&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http = Client.http # Client를 사용할 때, 대부분 Client이라는 변수를 사용한다는 전재
http = Bot.http # Cog를 사용할 때, 대부분 Bot이라는 변수를 사용한다는 전재&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 서술한 헤더(Headers)와 Base URI, 버전은 discord.py에서 자동으로 설정해주기 때문에, 굳이 신경을 쓰실 필요는 없습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622438795259&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import discord
from discord.http import Route

bot = discord.Client()
http = bot.http

@bot.event
async def on_message(msg: discord.Message):
    if msg.content == &quot;!프로그래밍&quot;:
    	return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 저는 discord.py에 있는 Client를 기준으로 서술해보겠습니다. cog도 이번에는 과정이 동일하기 때문에 충분히 따라오시면 가능할 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 discord를 불러옵니다. 그리고 Route 클래스는 discord에 기본 모듈에는 없기 때문에 &quot;직접&quot; 불러와야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 우리는 Route를 불러와야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622438996989&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;r = Route('POST', '/channels/{channel_id}/messages', channel_id=msg.channel.id)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1622438987086&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import discord
from discord.http import Route

bot = discord.Client()
http = bot.http

@bot.event
async def on_message(msg: discord.Message):
    if msg.content == &quot;!프로그래밍&quot;:
    	r = Route('POST', '/channels/{channel_id}/messages', channel_id=msg.channel.id)
    	return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;r값에 Route에서 불러온 클래스를 넣어 주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 시험 삼아 &quot;파이썬 최고!&quot;라는 메시지를 보내도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 설명했던 content라는 키를 사용하여 보내게 됩니다. 파이썬에서는 params 데이터는 대부분 dict를 통하여 전송할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622439119203&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;payload = {
	&quot;content&quot;: &quot;파이썬 최고!&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1622439126392&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import discord
from discord.http import Route

bot = discord.Client()
http = bot.http

@bot.event
async def on_message(msg: discord.Message):
    if msg.content == &quot;!프로그래밍&quot;:
    	r = Route('POST', '/channels/{channel_id}/messages', channel_id=msg.channel.id)
        payload = {
			&quot;content&quot;: &quot;파이썬 최고!&quot;
		}
    	return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 우리는 이 메시지를 보내주어야만 합니다. 위에서 불러온 http 변수에 있는 request 함수를 통하여 가능하다고 했기 때문에 아래의 코드를 추가해주면, 우리는 &lt;span style=&quot;background-color: #ffc9af; color: #ef6f53;&quot;&gt;~. send()&lt;/span&gt;를 직접 구현한 것입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622439235718&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http.request(r, json=payload)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1622439224711&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import discord
from discord.http import Route

bot = discord.Client()
http = bot.http

@bot.event
async def on_message(msg: discord.Message):
    if msg.content == &quot;!프로그래밍&quot;:
    	r = Route('POST', '/channels/{channel_id}/messages', channel_id=msg.channel.id)
        payload = {
			&quot;content&quot;: &quot;파이썬 최고!&quot;
		}
        http.request(r, json=payload)
    	return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 discord.py를 통하여 메시지를 &quot;직접&quot; 보내는 방법에 대하여 알아보았습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Components 사용법에 대하여 알아보자&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Components를 보내보도록 합시다. 위 코드를 이어서 설명해보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 Components를 사용하기 전에 사용 방법을 알아야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://discord.com/developers/docs/interactions/message-components&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://discord.com/developers/docs/interactions/message-components를&lt;/a&gt; 통하여 Components 사용법을 알 수 있으며, (영어를 잘해야 되는 이유) 영어를 하실 줄 아신다면 충분히 저 내용만으로 만 이해하실 수 있을 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 위에 있던 components라는 키값 안에 저 내용이 들어가야 하는 것이며, content에 있던 것처럼 넣어주시면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622439964170&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;content&quot;: &quot;This is a message with components&quot;,
    &quot;components&quot;: [
        {
            &quot;type&quot;: 1,
            &quot;components&quot;: []
        }
    ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서 내에 있는 예제 문처럼 보내면 됩니다. 이렇게 하시면 components는 성공적으로 불러왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 버튼을 만들어봐야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼은 components안에 있는 components에 만들어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 우리는 아래 서술되어 있는 components 모델에 대하여 확인해보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;368&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAte7O/btq59OndnFP/Ho5xtgek571RGgdfoanrL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAte7O/btq59OndnFP/Ho5xtgek571RGgdfoanrL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAte7O/btq59OndnFP/Ho5xtgek571RGgdfoanrL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAte7O%2Fbtq59OndnFP%2FHo5xtgek571RGgdfoanrL0%2Fimg.png&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;368&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 내용은 영어로 되어 있기 때문에, 아래에 표로 번역해두겠습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 160px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style9&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;필드(키)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;타입&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;type&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;int(정수형)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;컴포넌트 타입(아래 서술)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;style&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;int(정수형)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;스타일 타입(아래 서술)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;lable&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;string(문자열)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;내용(아래 서술)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;emoji&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;이모지 모델&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;이모지 콘텐츠&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;custom_id&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;string(문자열)&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;url&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;string(문자열)&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;주소(아래 서술)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;disabled&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;boolean&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;비활성화 여부&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 type은 필수로 사용해야 하며, style, label, custom_id는 버튼을 생성하기 위해 필수로 사용해야 하는 것들입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;181&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s8S76/btq6htPoBtq/Q62riWenVg3PLek40WXqnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s8S76/btq6htPoBtq/Q62riWenVg3PLek40WXqnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s8S76/btq6htPoBtq/Q62riWenVg3PLek40WXqnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs8S76%2Fbtq6htPoBtq%2FQ62riWenVg3PLek40WXqnk%2Fimg.png&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;181&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 위에 작성되어 있는 컴포넌트 타입은 위와 같습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.5333%; height: 113px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style9&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;필드(키)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;이름&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;ActionRow&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;컴포넌트 가로 줄&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;버튼&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;버튼&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 type값을 2로 지정하셔야 버튼을 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 style에 대하여 서술해보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;508&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjmMEi/btq59MXgNiy/mKEPLYkjPV9iO59bXOz1n1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjmMEi/btq59MXgNiy/mKEPLYkjPV9iO59bXOz1n1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjmMEi/btq59MXgNiy/mKEPLYkjPV9iO59bXOz1n1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjmMEi%2Fbtq59MXgNiy%2FmKEPLYkjPV9iO59bXOz1n1%2Fimg.png&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;508&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타일은 아래와 같이 Primary-CTA(&lt;span style=&quot;color: #0593d3;&quot;&gt;파란색&lt;/span&gt;), Primary-success(&lt;span style=&quot;color: #409d00;&quot;&gt;초록색&lt;/span&gt;), Secondary, Destructve(&lt;span style=&quot;color: #ef5369;&quot;&gt;빨간색&lt;/span&gt;), Link로 구성할 수 있으며, 1~5의 값을 대입합니다. 따라서 Primary-CTA(파란색) 버튼을 만들고 싶다면, 1이란 값을 style에 넣어주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 5번(Link 버튼)을 만들 때에는 위에 서술되어 있는 url 값을 무조건 넣어줘야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;disabled 키값에 True(참)을 넣게 될 경우 위 사진에 있는 것처럼 되며, 버튼을 누를 수 없도록 설정됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼을 넣어주게 된다면, 아래의 예시 코드가 구성될 것입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622454362076&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;content&quot;: &quot;This is a message with components&quot;,
    &quot;components&quot;: [
        {
            &quot;type&quot;: 1,
            &quot;components&quot;: [
                {
                    &quot;type&quot;: 2,
                    &quot;label&quot;: &quot;버튼&quot;,
                    &quot;style&quot;: 1,
                    &quot;custom_id&quot;: &quot;&amp;lt;찾을 버튼의 ID&amp;gt;&quot;
                }
            ]

        }
    ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 버튼을 여러 개 만드신다면, components라는 리스트('[]') 안에 계속해서 넣어주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의하실 점은 저 리스트 안에는 최대 5개의 버튼밖에 들어갈 수 없습니다. 따라서 버튼을 6개 이상을 한 줄에 넣을 수는 없다는 소리입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;지금까지 배운 것을 응용해봅시다!&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 우리가 지금까지 알아온 위 내용을 토대로 1편에 있는 버튼을 만들어 보도록 합시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;254&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mUEE0/btq6hdGan3c/KuzvOk473GcGKe5E4DUHwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mUEE0/btq6hdGan3c/KuzvOk473GcGKe5E4DUHwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mUEE0/btq6hdGan3c/KuzvOk473GcGKe5E4DUHwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmUEE0%2Fbtq6hdGan3c%2FKuzvOk473GcGKe5E4DUHwK%2Fimg.png&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;254&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 만들어 볼 디스코드 봇은 이렇습니다. embed안에 Python, Kotlin, C언어, C++, Java 중 최고의 프로그래밍 언어를 선정하는 프로그램입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;embed(임베드)의 title(주제) 값은 &quot;최고의 프로그래밍 언어&quot;라는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622481321603&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import discord
from discord.http import Route

bot = discord.Client()
http = bot.http

@bot.event
async def on_message(msg: discord.Message):
	if msg.content == &quot;!프로그래밍&quot;:
		return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 위에 있는 코드가 있는 상태에서 다시 시작해보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 Route와 http.requests를 설정해주신 뒤에, 위에서 서술했듯이 content, embed, file값은 무조건 하나 이상 포함하고 있어야 한다고 했기 때문에 우리는 embed값을 만들 어 줄 예정입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622481610405&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import discord
from discord.http import Route

bot = discord.Client()
http = bot.http

@bot.event
async def on_message(msg: discord.Message):
	if msg.content == &quot;!프로그래밍&quot;:
		r = Route('POST', '/channels/{channel_id}/messages', channel_id=msg.channel.id)
		payload = {}
		http.request(r, json=payload)
		return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 위에서 다루었던, Route와 payload, http.requests를 모두 사용한다는 것을 알 수 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;embed는 discord.py에서 이미 지원하는 기능이기 때문에, 이미 지원하고 있는 embed를 통하여 만들어 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622481736038&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;embed = discord.Embed(
	title=&quot;최고의 프로그래밍 언어&quot;,
	description=&quot;&quot;&quot;&amp;lt;:python:847876880257908757&amp;gt; Python: 0표
		&amp;lt;:kotlin:847876848662216714&amp;gt; Kotlin: 0표
		C언어: 0표
		&amp;lt;:cpp:847876987778629722&amp;gt; C++: 0표
		:java:847876915619954708&amp;gt; Java: 0표&quot;&quot;&quot;,
	colour=0x0080ff
)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1622481709248&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import discord
from discord.http import Route

bot = discord.Client()
http = bot.http

@bot.event
async def on_message(msg: discord.Message):
	if msg.content == &quot;!프로그래밍&quot;:
		embed = discord.Embed(
			title=&quot;최고의 프로그래밍 언어&quot;,
			description=&quot;&quot;&quot;&amp;lt;:python:847876880257908757&amp;gt; Python: 0표
				&amp;lt;:kotlin:847876848662216714&amp;gt; Kotlin: 0표
				C언어: 0표
				&amp;lt;:cpp:847876987778629722&amp;gt; C++: 0표
				&amp;lt;:java:847876915619954708&amp;gt; Java: 0표&quot;&quot;&quot;,
			colour=0x0080ff
		)
        
		r = Route('POST', '/channels/{channel_id}/messages', channel_id=msg.channel.id)
		payload = {}
		http.request(r, json=payload)
		return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;embed라는 이름에 저장된 embed 값은. to_dict()를 통하여 dict형태의 embed 문을 불러올 수 있습니다. 따라서 payload에 &quot;embed&quot;라는 키값으로 embed.to_dict()라는 값을 넣어줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622481854163&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import discord
from discord.http import Route

bot = discord.Client()
http = bot.http

@bot.event
async def on_message(msg: discord.Message):
	if msg.content == &quot;!프로그래밍&quot;:
		embed = discord.Embed(
			title=&quot;최고의 프로그래밍 언어&quot;,
			description=&quot;&quot;&quot;&amp;lt;:python:847876880257908757&amp;gt; Python: 0표
				&amp;lt;:kotlin:847876848662216714&amp;gt; Kotlin: 0표
				C언어: 0표
				&amp;lt;:cpp:847876987778629722&amp;gt; C++: 0표
				&amp;lt;:java:847876915619954708&amp;gt; Java: 0표&quot;&quot;&quot;,
			colour=0x0080ff
		)
        
		r = Route('POST', '/channels/{channel_id}/messages', channel_id=msg.channel.id)
		payload = {
			&quot;embed&quot;: embed.to_dict()
		}
		http.request(r, json=payload)
		return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;embed를 이렇게 해서 payload라는 곳에 성공적으로 넣을 수 있습니다. 다음은 components 작업을 이어서 하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622482055461&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import discord
from discord.http import Route

bot = discord.Client()
http = bot.http

@bot.event
async def on_message(msg: discord.Message):
	if msg.content == &quot;!프로그래밍&quot;:
		embed = discord.Embed(
			title=&quot;최고의 프로그래밍 언어&quot;,
			description=&quot;&quot;&quot;&amp;lt;:python:847876880257908757&amp;gt; Python: 0표
				&amp;lt;:kotlin:847876848662216714&amp;gt; Kotlin: 0표
				C언어: 0표
				&amp;lt;:cpp:847876987778629722&amp;gt; C++: 0표
				&amp;lt;:java:847876915619954708&amp;gt; Java: 0표&quot;&quot;&quot;,
			colour=0x0080ff
		)
        
		r = Route('POST', '/channels/{channel_id}/messages', channel_id=msg.channel.id)
		payload = {
			&quot;embed&quot;: embed.to_dict()
			&quot;components&quot;: default_components
		}
		http.request(r, json=payload)
		return&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트의 내용은 사실상 매우 길어질 수 있기 때문에 따로 default_components라는 변수 안에 만들어 넣겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;default_components 에는 우선 우리가 위해서 서술했듯 Action Raw형태의 컴포넌트를 미리 넣어줘야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622482166275&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;default_components = [
	{
		&quot;type&quot;: 1,
		&quot;components&quot;: []
	}
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그다음은 components안에 버튼을 넣어줘야 합니다. 하나하나 차근식 넣어주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622482233666&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;type&quot;: 2,
	&quot;label&quot;: &quot;Python&quot;,
	&quot;style&quot;: 2,
	&quot;custom_id&quot;: &quot;python&quot;,
	&quot;emoji&quot;: {
		&quot;id&quot;: &quot;847876880257908757&quot;,
		&quot;name&quot;: &quot;python&quot;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 생긴 것을 총 5개 넣어주시면 됩니다. custom_id는 추후 우리가 식별한 id값을 넣어주시면 되고, label 값 안에는 디스코드 버튼의 이름을 넣어 주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 우리가 강의 중에서 서술되지 않은 &quot;emoji&quot;부분이 있는데요, emoji 모델은 id와 name으로 구성되어 있으며, 이모지의 ID값과 이모지의 이름을 통하여 불러올 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 문장을 반복해서 총 5개의 버튼을 만들어주면 아래의 코드가 탄생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622482133679&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;default_components = [
    {
        &quot;type&quot;: 1,
        &quot;components&quot;: [
            {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;Python&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;python&quot;,
                &quot;emoji&quot;: {
                    &quot;id&quot;: &quot;847876880257908757&quot;,
                    &quot;name&quot;: &quot;python&quot;
                }
            }, {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;Kotlin&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;kotlin&quot;,
                &quot;emoji&quot;: {
                    &quot;id&quot;: &quot;847876848662216714&quot;,
                    &quot;name&quot;: &quot;kotlin&quot;
                }
            }, {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;C언어&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;c&quot;
            }, {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;C++&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;cpp&quot;,
                &quot;emoji&quot;: {
                    &quot;id&quot;: &quot;847876987778629722&quot;,
                    &quot;name&quot;: &quot;cpp&quot;
                }
            }, {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;Java&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;java&quot;,
                &quot;emoji&quot;: {
                    &quot;id&quot;: &quot;847876915619954708&quot;,
                    &quot;name&quot;: &quot;java&quot;
                }
            }
        ]

    }
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 default_components의 변수를 만들어 주었습니다. 이제 메인코드에 삽입해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622482408566&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import discord
from discord.http import Route

bot = discord.Client()
http = bot.http

default_components = [
    {
        &quot;type&quot;: 1,
        &quot;components&quot;: [
            {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;Python&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;python&quot;,
                &quot;emoji&quot;: {
                    &quot;id&quot;: &quot;847876880257908757&quot;,
                    &quot;name&quot;: &quot;python&quot;
                }
            }, {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;Kotlin&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;kotlin&quot;,
                &quot;emoji&quot;: {
                    &quot;id&quot;: &quot;847876848662216714&quot;,
                    &quot;name&quot;: &quot;kotlin&quot;
                }
            }, {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;C언어&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;c&quot;
            }, {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;C++&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;cpp&quot;,
                &quot;emoji&quot;: {
                    &quot;id&quot;: &quot;847876987778629722&quot;,
                    &quot;name&quot;: &quot;cpp&quot;
                }
            }, {
                &quot;type&quot;: 2,
                &quot;label&quot;: &quot;Java&quot;,
                &quot;style&quot;: 2,
                &quot;custom_id&quot;: &quot;java&quot;,
                &quot;emoji&quot;: {
                    &quot;id&quot;: &quot;847876915619954708&quot;,
                    &quot;name&quot;: &quot;java&quot;
                }
            }
        ]

    }
]

@bot.event
async def on_message(msg: discord.Message):
	if msg.content == &quot;!프로그래밍&quot;:
		embed = discord.Embed(
			title=&quot;최고의 프로그래밍 언어&quot;,
			description=&quot;&quot;&quot;&amp;lt;:python:847876880257908757&amp;gt; Python: 0표
				&amp;lt;:kotlin:847876848662216714&amp;gt; Kotlin: 0표
				C언어: 0표
				&amp;lt;:cpp:847876987778629722&amp;gt; C++: 0표
				&amp;lt;:java:847876915619954708&amp;gt; Java: 0표&quot;&quot;&quot;,
			colour=0x0080ff
		)
        
		r = Route('POST', '/channels/{channel_id}/messages', channel_id=msg.channel.id)
		payload = {
			&quot;embed&quot;: embed.to_dict()
			&quot;components&quot;: default_components
		}
		http.request(r, json=payload)
		return
       
bot.run(&quot;&amp;lt;토큰&amp;gt;&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 코드를 완성하였습니다. 아무래도 discord.py에서는 공식적으로 지원하는 것도 아니고, 직접 구현하다 보니 생각보다 난이도가 있었을 거라고 생각합니다.&amp;nbsp; 그럼에도 불구하고 여기까지 따라오셨다면 나중에 discord.py를 안 써보고도 디스코드 봇을 만들 수 있다는 사람입니다. discord.py를 사용하지 않고, 디스코드 봇 만들기 꼭 한번 해보시는 것을 추천드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 2편을 끝내게 되었습니다. 사실은 총 3편의 구성으로 알차게 작성하려 했지만, 아직 다루어야 할 부분이 조금 남아있어서 4편으로 끝내게 될 것 같다고 봅니다. 이번 강의 내용이 많이 길었지만 잘 따라와 주셔서 감사합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 강의에서는 Components에 있는 버튼을 클릭하면 반응하도록 하는 부분에 대하여 작성해보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 한 번 긴 글을 읽어주신 여러분들 진심으로 감사합니다.&lt;/p&gt;</description>
      <category>개발 강좌/기타 강좌</category>
      <author>건유1019</author>
      <guid isPermaLink="true">https://coding-y.tistory.com/53</guid>
      <comments>https://coding-y.tistory.com/53#entry53comment</comments>
      <pubDate>Tue, 1 Jun 2021 02:42:25 +0900</pubDate>
    </item>
    <item>
      <title>디스코드봇(Components) - 01ㅣComponents에 대하여 알아보자.</title>
      <link>https://coding-y.tistory.com/52</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 이번 강의에서는 디스코드 봇(Components)에 대하여 알아보도록 할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Components에 대한 강의는 총 3편으로 구성될 예정이며, 이번 편에서는 Components에 대한 개념을 알려드릴 껍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;여러분들은 동적(반응형) 디스코드 보라고 들어보신 적 있나요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적(반응형) 디스코드 보란 사용자와 디스코드 봇을 서로 상호작용하는 것을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 사용자는 특정 명령어를 요구한다면, 봇은 그것에 대한 정보를 반환합니다. 사용자는 그 정보를 기반으로 다시 특정 명령어를 요구하게 되고, 봇은 또 새롭게 들어온 특정 요구에 대하여 정보를 반환하는 것이라고 보면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;620&quot; data-filename=&quot;제목 없음-1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RcDnW/btq53QLosFs/Vntk80kJ9tvSZ2fNTZ8Sv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RcDnW/btq53QLosFs/Vntk80kJ9tvSZ2fNTZ8Sv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RcDnW/btq53QLosFs/Vntk80kJ9tvSZ2fNTZ8Sv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRcDnW%2Fbtq53QLosFs%2FVntk80kJ9tvSZ2fNTZ8Sv1%2Fimg.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;620&quot; data-filename=&quot;제목 없음-1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Components는 &quot;동적(반응형) 디스코드 봇&quot;을 만들기 위해선 필수 요소라고 생각합니다. 기존에는 &quot;반응(Reaction)&quot;을 기반으로 꼼수를 사용하였다면, &quot;컴포넌트(Components)&quot;는 공식적으로 디스코드가 만들어 준 서로 간 상호작용하는 길이라고 봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;처음 들어보는데, Components가 뭐예요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Components는 슬래시 커맨드(빗금 명령어)의 기능 중 하나로, 2021년 5월 28일에 정식 추가된 기능입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;450&quot; data-filename=&quot;discord_interactions.gif&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l3j0V/btq52qfRmyZ/5BpCLAOtnGTmL97VAQo0e0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l3j0V/btq52qfRmyZ/5BpCLAOtnGTmL97VAQo0e0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l3j0V/btq52qfRmyZ/5BpCLAOtnGTmL97VAQo0e0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/l3j0V/btq52qfRmyZ/5BpCLAOtnGTmL97VAQo0e0/img.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;450&quot; data-filename=&quot;discord_interactions.gif&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 GIF와 같이, 메시지 아래에 버튼을 만들어 주어서, 봇과 사용자 간 서로 상호작용을 수월하게 해 주기 위하여 만들어진 기능입니다. 버튼뿐만 아닌, 드롭다운 등의 더욱 다양한 Components가 추가될 것이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Components에 대한 여러 예시를 설명해보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kzjKm/btq52zDBfAk/VMhnyHO9P06UNr0Po9Suh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kzjKm/btq52zDBfAk/VMhnyHO9P06UNr0Po9Suh0/img.png&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;188&quot; style=&quot;width: 43.1827%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kzjKm/btq52zDBfAk/VMhnyHO9P06UNr0Po9Suh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkzjKm%2Fbtq52zDBfAk%2FVMhnyHO9P06UNr0Po9Suh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;457&quot; height=&quot;188&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FOrim/btq53vOgneG/YG2f16c9B1H6TKMzAIDhU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FOrim/btq53vOgneG/YG2f16c9B1H6TKMzAIDhU1/img.png&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;158&quot; style=&quot;width: 55.6545%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FOrim/btq53vOgneG/YG2f16c9B1H6TKMzAIDhU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFOrim%2Fbtq53vOgneG%2FYG2f16c9B1H6TKMzAIDhU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;495&quot; height=&quot;158&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 사진을 비교해봅시다. 우리는 가위바위보라는 명령어를 만들었다고 가정하였을 때, 왼쪽은 직접 입력하는 방식이고 오른쪽은 버튼 하나로 해결됩니다. 이런 면에서는 사용자가 직접 작성하는 것보다는 버튼을 누르는 것이 효과적이며, 이런 점에서 유용하다고 봅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;438&quot; data-origin-height=&quot;301&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oXxaK/btq52T2VIGl/ZaVe92Xnm0Mg3FkqlIkBg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oXxaK/btq52T2VIGl/ZaVe92Xnm0Mg3FkqlIkBg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oXxaK/btq52T2VIGl/ZaVe92Xnm0Mg3FkqlIkBg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoXxaK%2Fbtq52T2VIGl%2FZaVe92Xnm0Mg3FkqlIkBg1%2Fimg.png&quot; data-origin-width=&quot;438&quot; data-origin-height=&quot;301&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 예시는 디스코드 봇을 활용한 계산기입니다. 디스코드 봇 계산기의 경우 유저가 직접 입력할 수도 있으나, Code Injection 등의 보안 위협이 따르며, 보안면에서는 유저가 직접 입력하게 하는 것보다는 특정 값을 입력할 수 있도록 제한을 두어야만 합니다. 계산기의 경우도 우리는 특정 값만 요구하는 &quot;화이트 리스트&quot; 개념을 충족합니다. 만약에 Components를 사용하신 다면 이런 것도 만들어 볼 수 있다고 보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 discord.py를 응용하여, &quot;직접&quot; 버튼을 만들어 보고자 합니다. 아직 discord.py에서도 해당 기능은 정식적으로 지원하지 않으나, discord.py를 통하여 Discord API와 통신하여 Components를 구현해볼 것입니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;본 강의는 Discord Bot의 기초를 모를 경우, 많은 어려움이 따를 수 있습니다. 만약 디스코드 봇에 대하여 기초 지식이 부족할 경우, 디스코드 강의를 먼저 보시고 오시기 바랍니다.&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상 1편을 마치도록 하겠습니다. 2편에서는 위에 있는 사진 처럼 버튼을 불러오고 리턴된 값을 불러오는 방법까지 세세히 다루도록 하겠습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발 강좌/기타 강좌</category>
      <author>건유1019</author>
      <guid isPermaLink="true">https://coding-y.tistory.com/52</guid>
      <comments>https://coding-y.tistory.com/52#entry52comment</comments>
      <pubDate>Sat, 29 May 2021 03:18:17 +0900</pubDate>
    </item>
  </channel>
</rss>