├── .gitignore
├── 0화
├── README.MD
├── node_js.md
└── vsc.md
├── 1화
├── README.MD
└── bot.js
├── 2화
├── README.MD
├── bot.js
├── docs.md
└── webhook.MD
├── 3화
├── Commands
│ ├── Bot
│ │ ├── embed.js
│ │ ├── ping.js
│ │ └── webhook.js
│ └── moderator
│ │ ├── ban.js
│ │ ├── clear.js
│ │ └── kick.js
├── README.MD
├── bot.js
├── example.config.json
└── module_install.md
├── 4화
├── Commands
│ ├── Bot
│ │ ├── embed.js
│ │ ├── ping.js
│ │ └── webhook.js
│ ├── crawling
│ │ └── docs.js
│ └── moderator
│ │ ├── ban.js
│ │ ├── clear.js
│ │ └── kick.js
├── README.MD
├── bot.js
└── example.config.json
├── 5화
├── Commands
│ ├── Bot
│ │ ├── embed.js
│ │ ├── help.js
│ │ ├── ping.js
│ │ └── webhook.js
│ ├── Owner
│ │ └── eval.js
│ ├── crawling
│ │ ├── NaverRanking.js
│ │ └── docs.js
│ └── moderator
│ │ ├── ban.js
│ │ ├── clear.js
│ │ └── kick.js
├── README.MD
├── bot.js
└── example.config.json
├── 6화
├── Commands
│ ├── Bot
│ │ ├── embed.js
│ │ ├── help.js
│ │ ├── ping.js
│ │ └── webhook.js
│ ├── Owner
│ │ └── eval.js
│ ├── crawling
│ │ ├── NaverRanking.js
│ │ └── docs.js
│ ├── database
│ │ ├── gamble.js
│ │ ├── money.js
│ │ ├── registerGuild.js
│ │ └── settings.js
│ └── moderator
│ │ ├── ban.js
│ │ ├── clear.js
│ │ └── kick.js
├── README.MD
├── bot.js
├── example.config.json
└── json
│ ├── server.json
│ └── user.json
├── LICENSE
├── README.md
└── 읽어보면 좋은것들
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | /log
5 | npm-debug.log*
6 | yarn-debug.log*
7 | yarn-error.log*
8 | lerna-debug.log*
9 |
10 | # Diagnostic reports (https://nodejs.org/api/report.html)
11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12 |
13 | # Runtime data
14 | pids
15 | *.pid
16 | *.seed
17 | *.pid.lock
18 |
19 | # Directory for instrumented libs generated by jscoverage/JSCover
20 | lib-cov
21 |
22 | # Coverage directory used by tools like istanbul
23 | coverage
24 | *.lcov
25 |
26 | # nyc test coverage
27 | .nyc_output
28 |
29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30 | .grunt
31 |
32 | # Bower dependency directory (https://bower.io/)
33 | bower_components
34 |
35 | # node-waf configuration
36 | .lock-wscript
37 |
38 | # Compiled binary addons (https://nodejs.org/api/addons.html)
39 | build/Release
40 |
41 | # Dependency directories
42 | node_modules/
43 | node_modules
44 | jspm_packages/
45 |
46 | # TypeScript v1 declaration files
47 | typings/
48 |
49 | # TypeScript cache
50 | *.tsbuildinfo
51 |
52 | # Optional npm cache directory
53 | .npm
54 |
55 | # Optional eslint cache
56 | .eslintcache
57 |
58 | # Microbundle cache
59 | .rpt2_cache/
60 | .rts2_cache_cjs/
61 | .rts2_cache_es/
62 | .rts2_cache_umd/
63 |
64 | # Optional REPL history
65 | .node_repl_history
66 |
67 | # Output of 'npm pack'
68 | *.tgz
69 |
70 | # Yarn Integrity file
71 | .yarn-integrity
72 |
73 | # dotenv environment variables file
74 | .env
75 | .env.test
76 |
77 | # parcel-bundler cache (https://parceljs.org/)
78 | .cache
79 |
80 | # Next.js build output
81 | .next
82 |
83 | # Nuxt.js build / generate output
84 | .nuxt
85 | dist
86 |
87 | # Gatsby files
88 | .cache/
89 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
90 | # https://nextjs.org/blog/next-9-1#public-directory-support
91 | # public
92 |
93 | # vuepress build output
94 | .vuepress/dist
95 |
96 | # Serverless directories
97 | .serverless/
98 |
99 | # FuseBox cache
100 | .fusebox/
101 |
102 | # DynamoDB Local files
103 | .dynamodb/
104 |
105 | # TernJS port file
106 | .tern-port
107 | *.txt
108 |
109 | package-lock.json
110 | package.json
111 | config.json
112 |
--------------------------------------------------------------------------------
/0화/README.MD:
--------------------------------------------------------------------------------
1 | ### 이번 튜토리얼은 초보분들을 대상으로 제작하였습니다!
2 |
3 | 0화는 node.js 설치하는 방법과 vsc(Visual Studio Code) 설치 방법에 대한 설명을 적을 예정입니다.
4 | 잘 따라오셔서 성공하셨으면 좋겠어요!!
5 |
6 | Node_js.md 와 VSC.md로 나누었으니 각각 확인해주세요.
--------------------------------------------------------------------------------
/0화/node_js.md:
--------------------------------------------------------------------------------
1 | ### Node.js 설치 하는 방법
2 |
3 | 1. Node.js 공식 사이트를 들어가주세요. [여기를 눌러주세요!](https://nodejs.org/en/)
4 |
5 | 
6 |
7 | 2. 여기서 12.16.3 LTS 버전을 클릭하여 다운 받아주세요.
8 | > **LTS버전**은 장기적으로 node.js 팀에서 지원해주는 버전이기에 사용합니다.
9 |
10 | 
11 |
12 | *혹시나 윈도우 이외에 다른 운영체제를 사용하신다면 아래에 Other Downloads를 눌러서 자신에게 맞는 운영체제를 다운받아주세요.*
13 |
14 | 3. 다운을 다 하셨다면 실행 해주세요.
15 |
16 | 
17 |
18 | 4. 계속 next 누르시고 설치하시면 됩니다!
19 |
20 | 5. 그러고 설치를 다 하시고 finish 버튼을 누르면 끝!
21 |
--------------------------------------------------------------------------------
/0화/vsc.md:
--------------------------------------------------------------------------------
1 | ### VSC (Visual Studio Code) 설치 하는 방법
2 |
3 | 1. VSC 공식 사이트를 들어가주세요. [여기를 눌러주세요!](https://code.visualstudio.com/)
4 |
5 | 2. 들어가셨다면 다운로드 버튼을 눌러 다운해주세요.
6 | 
7 |
8 | 3. 누르셨으면 아래의 이미지처럼 나오셨을텐데 맞는 OS를 찾아 다운로드 해주세요.
9 | 
10 |
11 | 4. 다 다운로드 하시고 실행하시면 아래의 사진처럼 보일꺼에요!
12 | 
13 |
14 | 계약을 동의해주시고 다음 버튼을 계속 누르고 설치하시면 끄읕!
15 |
16 | 5. VSC 한글 버전으로 바꾸는 방법을 알려드릴꺼에요!
17 | 1) 왼쪽에 여러개의 아이콘이 있는데 그중에 아래것을 눌러주세요!
18 | 
19 |
20 | 2) 거기에 검색창이 있을텐데 **Korean Language Pack for Visual Studio Code**라고 적어주세요.
21 | 3) 거기서 맨 첫번째줄에 Korean Language 머시기 있을꺼에요 그거 install 해주세요.
22 | 
23 | 4) 그러고 오른쪽 아래에 밑에 사진처럼 보이실 꺼에요 **Restart Now**를 눌러주세요!
24 | 
25 | 5) 짜잔 그러면 한글로 바뀐것을 확인하실 수 있어요!
26 | 
27 |
--------------------------------------------------------------------------------
/1화/README.MD:
--------------------------------------------------------------------------------
1 | ## 먼저 [여기](https://discord.com/developers/applications)를 클릭하여 웹사이트에 들어가주세요.
2 |
3 | 
4 |
5 | 여기서 오른쪽 위에 보시면 New Application을 클릭해주세요.
6 |
7 | 
8 |
9 | 자신이 원하는 이름을 적어주시고 Create 버튼을 눌러주세요.
10 | (팀은 Discord Developer Teams에 어느 팀의 소속이라면 뜨는 라인입니다.)
11 |
12 | 저는 Discord JS Tutorial로 이름을 작성하였습니다.
13 |
14 | 
15 |
16 | 여기서 왼쪽에 Settings 보시면 Bot라고 있는데 클릭해주세요.
17 |
18 | 
19 |
20 | 그리고 여기서 Add Bot을 누르고 Yes, do it! 버튼을 눌러주세요.
21 |
22 | 그러면 Bot 라인에 아래의 사진처럼 보이실겁니다!
23 | 
24 |
25 | 여기서 봇의 아이콘이나 유저닉네임을 수정할 수 있습니다.
26 |
27 | 우리가 사용할 것은 토큰이니 토큰라인에 Copy를 눌러주시고 봇 소스에 "토큰" 이라고 적혀있는 곳을 지워주시고 붙여넣기 해주세요.
28 |
29 |
30 | # **※ 주의사항 ※**
31 | 1. **Regenerate**를 눌러주시면 봇 토큰이 바뀌고 로그인 되어있던 모든 수단들은 연결이 끊깁니다.
32 | 2. 토큰은 **자신만이 알아야 하고 절때로 누군가에게 도움을 받기 위해서 소스코드를 전체 복사하여 보낼 때 각별히 주의**를 해주셔야 합니다.
33 |
34 | ### Discord.js 모듈 설치하는 방법
35 |
36 | 1. 코딩을 할 폴더를 하나 생성하시고 그 폴더에 들어가주세요.
37 | 2. 그 폴더에서 경로 부분에 클릭하시고 cmd라고 적으신 후 엔터를 쳐주세요!
38 | 
39 | 3. 엔터를 치시고 cmd창이 하나 생성되었을겁니다. 거기서 **npm i discord.js --save** 라고 적으신 후 엔터를 쳐주세요.
40 | 
41 | 4. 그러고 설치가 다 완료되었으면 아래의 사진처럼 되었을겁니다!
42 | 
43 |
44 |
45 |
46 | ### node package 생성하는 방법
47 |
48 | 1. 위에서 작업했던 cmd 창을에서 **npm init**를 해주세요.
49 | 2. 거기서 이제 여러가지 머 적으라고 할텐데 양식에 맞게 적어주세요!
50 | 3. 그러면 아래의 사진처럼 되어있을텐데 거기서 엔터를 눌러서 마무리 해주세요!
51 |
52 | 
53 | 우리는 그러면 Discord.js 라는 모듈을 정상적으로 설치한 것을 알 수 있습니다!
54 | 나머지는 봇 파일에서 뵙도록 합시다!
55 |
56 | #### Made By [Jasper](https://github.com/Ukong0324)
--------------------------------------------------------------------------------
/1화/bot.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js"); // Node Module Package 에서 우리가 사용할 Discord.js 모듈을 불러옵시다.
2 | const client = new Discord.Client(); // Discord.js 에서 핵심적으로 쓰이는 아이는 Client 라는 친구를 사용하게 됩니다.
3 | // client 라는 친구를 bot으로 수정하여 사용해도 되긴 해요! 하지만 이후에 작성되는 모든 코드에 client가 들어갈 예정이니 참고해주세요!
4 |
5 | client.on("ready", () => { // client에 이벤트 함수인 ready를 사용하였습니다.
6 | console.log(`${client.user.tag} 봇에 로그인 하였습니다!`); // console.log는 콘솔에 메세지를 보내는 의미에요, 우리가 보낼 메세지는 "USER#1234 봇에 로그인 하였습니다." 라고 보낼겁니다.
7 | }); // 세미콜론(;)은 사용해도 상관 없어요 하지만 세미콜론 뒤에는 아무것도 사용하실 수 없으니 참고해주세요!
8 | // 그리고 괄호 잘 닫았나 잘 확인하면서 코드를 작성해야해요! 안그러면 에러를 뿜게 되거든요 ㅡㅅㅡ...
9 | // Tip! on과 once는 차이가 큽니다! "계속 들을 것이냐" 아니면 "한번만 들을 것이냐" 의 큰 차이니 조심하여 사용해주세요.
10 | client.on("message", msg => { // client에 이벤트 함수인 Message를 사용하였습니다.
11 | if (msg.content === "핑") { // 만약에 message를 사용하는 곳의 내용이 "핑" 이라고 적었다면
12 | msg.reply("퐁!"); // 우리는 "퐁!" 이라고 답변을 해줍시다!
13 | }
14 | });
15 |
16 | client.login("토큰"); // Client를 로그인 하기 위해서는 토큰이라는 것이 필요해요!
17 | /**
18 | * 토큰은 자신만이 알아야 하고 절때로 누군가에게 도움을 받기 위해서 소스코드를 전체 복사하여 보낼 때 각별히 주의를 해주셔야 합니다.
19 | * 1. https://discord.com/developers/applications 사이트를 들어가주세요.
20 | * 2. 자신이 만들려 한 봇의 애플리케이션을 클릭하여 접속해주세요.
21 | * 3. SETTINGS 라인에 BOT이라는 곳을 들어가주세요.
22 | * 4. Build-A-Bot에 Add Bot이라고 있습니다 클릭하여 봇을 추가해주세요.
23 | * 5. Token이라는 곳에서 Copy 버튼을 눌러주세요
24 | * 6. 해당 토큰을 로그인 할려는 공간에 붙어 넣어주시면 됩니다.
25 | * 7. 해당 토큰은 유포하시면 "위험"하오니 조심하여 다뤄주시길 바랍니다.
26 | */
--------------------------------------------------------------------------------
/2화/README.MD:
--------------------------------------------------------------------------------
1 | ## 개발하시기 전에 잠깐 읽어주세요!
2 |
3 | 1. 1화에서 알려드리지 못한 도큐들을 아래에 설명해놓을테니 확인해주시고 개발해주세요.
4 | 영문(공식):
5 | > 업데이트 될 때마다 최신으로 업데이트 되오니 영어를 혐오하지 않으시면 최대한 공식링크를 이용해주시면 좋을거 같습니다.
6 |
7 | 한글(비공식, 번역진행중):
8 | > [Discord.js Korea](https://github.com/discordjs-kr) 팀에서 번역하고 있는 비공식 라이브러리 입니다.
9 |
10 | 2. 현재 튜토리얼은 초보분들을 대상으로 작성되고 있는 소스입니다.
11 | 너무 쉽다고 혼자서 자만하지 말아주세요..
12 | 코드 설명중에 미숙한 점이나 버그가 발견되면 **Issues, Pull Requests**를 넣어주시면 감사합니다.
13 |
14 | 3. 오류는 [Google](https://www.google.co.kr/?gws_rd=ssl) 에서 검색하시면 왠만한 에러에 대한 피드백이 적혀있습니다.
15 | 대표적인 오류에 대한 설명들을 미리 적어놓을게요.
16 | ```js
17 | 1. "Error: Cannot find module"
18 | -> 해당 에러는 모듈이 설치되어 있지 않거나 해당 디렉토리에 없는 경우를 말합니다.
19 | 2. "ReferenceError: Content is not defined"
20 | -> 해당 에러는 코드를 작성하실 때에 선언되지 않은 구문을 작성하여 나오는 문제이니 수정해주시면 됩니다.
21 | 3. "TypeError: Cannot read property 'id' of null"
22 | -> 만약에 test.id 라는 것이 있는데 id의 값이 null 이면 나오는 에러입니다.
23 | ```
24 |
25 | 4. 웹훅에 대한 설명은 **webhook.MD**에 적혀있습니다.
26 | **웹훅(WebHook)에 대해서 잘 모르시는 분들은 꼭 읽어주세요.**
27 |
28 | 5. Discord.js 라이브러리 읽는 방법은 **docs.md**에 적혀있습니다.
29 | **라이브러리를 읽으실 줄 모르시는 분들은 꼭 읽어주세요..**
--------------------------------------------------------------------------------
/2화/bot.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js");
2 | const client = new Discord.Client();
3 | const prefix = "튜토야 " // 우리는 이제 접두사를 추가할꺼에요! (저는 튜토야 라고 했습니다!) 접두사가 붙어야 커맨드가 실행이 될 수 있습니다!
4 |
5 | client.on("ready", () => {
6 | console.log(`${client.user.tag} 봇에 로그인 하였습니다!`);
7 | });
8 | client.on("message", msg => {
9 | if (!msg.guild) return; // 만약에 길드 이외 다른곳이라면 return을 사용을 해줍시다. 아래도 마찬가지이지만 return을 해주어 반응을 해주지 않는 반응을 해주는 것이에요!
10 | if (msg.author.bot) return; // 여기도 마찬가지로 만약에 메세지 사용자가 봇이라면 return을 사용합시다.
11 | if (msg.content.indexOf(prefix) !== 0) return; //메세지가 prefix로 시작되지 않을시 return을 사용을 해줍시다
12 | var args = msg.content.slice(prefix.length).trim().split(/ +/g); // argument(args) 이 부분은 args를 원하는 방식으로 만들기 위한 과정이라고만 아시면 됩니다!
13 | var command = args.shift().toLowerCase(); //명령어를 가져올꺼에요 args의 어레이중 가장 앞부분을 가져옵니다 toLowerCase()는 대문자를 소문자로 변경시켜줍니다. Kick같은 실수를 방지할수 있죠
14 | if (command === `핑`) { // 이전에 핑을 퐁으로 답변했다면 웹소켓 지연시간을 알려주는 코드로 해봅시다!
15 | msg.reply(`${client.ws.ping}ms`); // CLIENT에 WS(WEBSOCKET)이라는 곳에서 PING을 구해오는 값입니다.
16 | }
17 | if (command === `임베드`) {
18 | var embed = new Discord.MessageEmbed()
19 | .setTitle("여기는 대표 타이틀!") // 여기는 임베드에서 타이틀로 사용됩니다!
20 | .setDescription("여기는 대표 설명!") // 여기는 타이틀을 설명해주는 걸로 사용됩니다!
21 | .setColor("RED") // 여기는 색상을 설정하는 공간인데 HEX값을 넣으셔도 됩니다! (#7239DA) "RED" 말고 다른것들도 있어요! 맨 밑에다가 적어놓을테니 확인해주세요!
22 | .setFooter("여기는 말머리?") // 여기는 임베드의 밑부분에서 말머리로 사용됩니다!
23 | .setThumbnail("http://blogfiles.naver.net/20151023_23/shin_0305_1445573936921jrPRT_JPEG/%BD%E6%B3%D7%C0%CF%BF%B9%BD%C3.jpg") // 여기는 임베드에서 썸네일로 불려옵니다! (URL를 넣어가 경로를 기입하면 그 경로에 있는 이미지를 불러와 썸네일로 이용되요!)
24 | .setImage("http://blogfiles.naver.net/MjAxODA4MjNfMjQ0/MDAxNTM1MDE5ODk1Njc3.c5p_E9tLPEXGnXPAkpOuhpEOm7VLqopETMTfJ9C8CWYg.6FCsIDtjWnd19lSzmw_z1oHm9E7fd39s1RmRPeBOF3Ag.JPEG.dlawldbs20/VD-poem-20150915-01.jpg") // 여기는 임베드에서 이미지로 사용되는 곳입니다. // 위에 설명이랑 같아요
25 |
26 | .setTimestamp() // 여기는 타임스탬프를 설정하는 공간인데 비워두면 현재시각, 여기에 타임스탬프를 넣으시면 그 값에 맞는 시간으로 변환됩니다!
27 | .addField("여기는 소제목", "여기는 소설명(??)") // 첫번째 칸은 임베드의 소제목, 두번째 칸은 임베드의 소제목의 설명하는 공간입니다! 세번째 칸은 INLINE으로 사용되는데 TRUE 하면 라인에 들어가는거고 FALSE 하면 밑라인으로 내려가게 됩니다.
28 | msg.reply(embed) // EMBED를 REPLY로 답변합시다!
29 | }
30 | if (command === `웹훅`) {
31 | const hook = new Discord.WebhookClient('WebHook ID', 'WebHook Token'); // https://discordapp.com/api/webhooks/{WebHook ID}/{WebHook Token} // 웹훅 생성하는 방법은 README.MD에서 설명해드릴꺼에요!
32 | hook.send("Hello, new World!") // 웹훅이 채널이 지정되어 있는 곳에다가 우리는 "Hello, new World" 라고 보내주는거에요!
33 | }
34 |
35 | /**
36 | * Moderator (관리자 기능!)
37 | * 여기 부분은 관리자 기능을 추가할려고 해요!
38 | * 코드를 꼭 이해를 하시고 복붙만 하여 사용하여 문의를 안해주셨으면 좋겠어용..
39 | * ※ 주의사항 ※
40 | * 주석으로 설명하는 라인을 잘 확인하시고 403 (permissions denial) 안뜨게 봇의 권한을 잘 사용해주세요.
41 | */
42 |
43 | if (command === `추방`) { // 만약에 메세지 내용이 추방이라면 ?
44 | var user = msg.mentions.users.first(); // var로 user를 선언을 해줍시다. (맨션을 먼저 언급을 해주라 라는 의미에용, 맨션을 안하면 undefined가 뜹니다)
45 | if (!user) { // 그래서 만약에 user가 안된다면
46 | msg.reply("추방하시기 전에 맨션을 먼저 해주세요!") // 맨션을 먼저 해달라고 문구를 전송해줍시다!
47 | } else { // 아니라면?
48 | var member = msg.guild.member(user); // var로 member를 선언을 해줍니다
49 | if (member) { // 만약에 member가 있다면
50 | member.kick(`${msg.author.username}님의 의해 서버에서 추방됨.`).then(member => { // 해당 유저를 추방하고, audit log에 추방을 당했다고 로그를 남겨줍시다.
51 | msg.reply(`성공적으로 ${member.user.tag}님을 추방하였습니다.`) // 그리고 채팅 친 곳에서 해당 유저를 추방 당했다고 알려줍시다.
52 | })
53 | } else { // member가 없다면
54 | msg.reply("이 서버에 존재하지 않은 유저입니다!") // 서버에 없는 존재를 맨션하였다고 알려줍시다!
55 | }
56 | }
57 | }
58 |
59 | if (command === `차단`) { // 만약에 메세지 내용이 차단이라면?
60 | var user = msg.mentions.users.first(); // var로 user를 선언을 해줍시다. (맨션을 먼저 언급을 해주라 라는 의미에용, 맨션을 안하면 undefined가 뜹니다)
61 | if (!user) { // 그래서 만약에 user가 안된다면
62 | msg.reply("차단하시기 전에 맨션을 먼저 해주세요!") // 맨션을 먼저 해달라고 문구를 전송해줍시다!
63 | } else {
64 | var member = msg.guild.member(user); // var로 member를 선언을 해줍니다
65 | if (member) { // 만약에 member가 있다면
66 | member.ban(`${msg.author.username}님의 의해 서버에서 추방됨.`).then(member => { // 해당 유저를 추방하고, audit log에 차단을 당했다고 로그를 남겨줍시다.
67 | msg.reply(`성공적으로 ${member.user.tag}님을 추방하였습니다.`) // 그리고 채팅 친 곳에서 해당 유저를 차단당했다고 알려줍시다.
68 | })
69 | } else { // member가 없다면
70 | msg.reply("이 서버에 존재하지 않은 유저입니다!") // 서버에 없는 존재를 맨션한걸로 전송해줍시다!
71 | }
72 | }
73 | }
74 |
75 | if (command === `청소`) { // 만약에 메세지 내용이 청소라면?
76 | if (!args[0]) return msg.reply("청소할 만큼의 값을 정수로 적어주세요!") // 만약에 argument가 비어있다면? 값을 적어달라고 메세지를 답변해줍시다.
77 | if (!Number(args[0])) return msg.reply("메세지를 지울 값이 숫자가 아니면 안되요!") // 만약에 argument가 숫자가 아니라면 숫자로 적어달라고 답변해줍시다.
78 | if (args[0] < 1) return msg.reply("메세지를 지울 값을 1보다 작게 하시면 안되요!") // 만약에 argument가 1보다 작으면 그렇게 못한다고 답변해줍시다.
79 | if (args[0] > 100) return msg.reply("메세지를 지울 값이 100보다 크면 메세지가 안지워져요!") // 만약에 argument가 100보다 크면 그렇게 못한다고 답변해줍시다 (최대 100개 삭제가능.)
80 |
81 | msg.channel.bulkDelete(args[0]).then(msg.reply(`성공적으로 ${args[0]}개 만큼 메세지를 삭제하였습니다!`)) // message.channel 에서 bulkDelete 라는 것을 사용하여 수 만큼 삭제한 후 then으로 "몇개를 삭제하였다"라고 답변해줍시다.
82 | }
83 | });
84 |
85 | client.login("토큰")
86 |
87 | /**
88 | * 그리고 제가 1화에서 설명하지 못한 부분이 있었어요 ㅠㅠ
89 | * 그리고 저희가 하고 있는 과정은 Discord.JS라는 라이브러리를 사용하여 코딩을 진행하였는데, 문서를 제가 따로 안알려드렸더라고요!
90 | * 그래서 제가 아래에 링크 2개를 적어놓을테니 확인해주세요!
91 | * 영문판 (공식): https://discord.js.org/
92 | * 한글판 (번역중, 비공식): https://discord-kr.js.org/
93 | */
94 |
95 | /**
96 | * Discord MessageEmbed Color List
97 | * - `DEFAULT`
98 | * - `WHITE`
99 | * - `AQUA`
100 | * - `GREEN`
101 | * - `BLUE`
102 | * - `YELLOW`
103 | * - `PURPLE`
104 | * - `LUMINOUS_VIVID_PINK`
105 | * - `GOLD`
106 | * - `ORANGE`
107 | * - `RED`
108 | * - `GREY`
109 | * - `DARKER_GREY`
110 | * - `NAVY`
111 | * - `DARK_AQUA`
112 | * - `DARK_GREEN`
113 | * - `DARK_BLUE`
114 | * - `DARK_PURPLE`
115 | * - `DARK_VIVID_PINK`
116 | * - `DARK_GOLD`
117 | * - `DARK_ORANGE`
118 | * - `DARK_RED`
119 | * - `DARK_GREY`
120 | * - `LIGHT_GREY`
121 | * - `DARK_NAVY`
122 | * - `RANDOM`
123 | */
124 |
--------------------------------------------------------------------------------
/2화/docs.md:
--------------------------------------------------------------------------------
1 | ### 라이브러리를 쉽게 읽는 방법!
2 |
3 | 1. 일단은 **라이브러리를 먼저 들어가**볼까요?
4 | [Offcial Docs](https://discord.js.org/#/) | [Unoffical Korean Docs](https://discord-kr.js.org/#/)
5 |
6 | 
7 |
8 | 2. 우리는 docs를 읽으러 왔으니 **오른쪽 위에 Documentation를 눌러**줍시다!
9 |
10 | 
11 |
12 | 3. 음.. 일단은 **검색을 할려면 오른쪽 위에 Search**라고 있어요! 거기서 한번 **Message** 라는걸 찾아봅시다!
13 |
14 | 
15 |
16 | 4. 으아... 엄청나게 결과 값이 나오죠?
17 | 일단은 제가 찾을려는 것이 **클래스 문이니 🇨 라고 되어있는 곳에 Message를 클릭**해줍시다!
18 |
19 | 
20 |
21 | 5. 그러면 위에 사진처럼 보일거에요!
22 |
23 | 그러면 질문이 있을꺼에요!
24 |
25 | Q: 제작자님 여기서 **Properties, Methods**가 무엇인가요?
26 | A: Properties: **괄호를 사용하지 않고 결과값을 표출**을 해줍니다.
27 | Methods: **괄호를 사용하여 괄호 안에 값을 기입하여 결과값을 표출**을 해줍니다.
28 |
29 | 우리가 늘 사용하게 될 **message에서 한번 content 찾아**볼까요?
30 |
31 | 
32 |
33 | 6. 클릭을 해보니 해당 라인에 자동으로 이동되면서 **설명이 적혀**있네요!
34 | The content of the message (해석하면 메세지 내용 이라고 되겠네요)
35 |
36 | 7. 그러면 우리가 **메인 파일에서 if (message.content) 를 쓰는것이 어떤 의미였는지 알게 되었어**요!
37 | 그러면... **마지막으로 하나 더** 해볼까요?
38 |
39 | - - -
40 |
41 | 8. 한번 guildMember를 찾아봅시다!
42 |
43 | 
44 |
45 | 9. 여기서 이제 질문이 하나 올라올꺼에요.
46 | Q: 제작자님! **guildMember**가 머에요..?
47 | A: 설명을 드리자면 **우리가 흔히들 말하는 서버가 여기서는 guild(길드)**로 표현하고 있는데
48 | 그 안에서 **우리는 유저라고 표현하긴 하지면 member(멤버)**로 표현하고 있어요!
49 | 약간 코드 형식으로 말씀 드리자면
50 |
51 | ```js
52 | message.member
53 | ```
54 |
55 | 이렇게 쓰시면 저기서 **member가 GuildMember로 표현**이 되요!
56 |
57 | 10. 나머지는 알아서 충분히 하실 수 있다고 봐요!
58 | ***정말로 모르겠으면 디스코드로 연락주세요!***
59 |
60 | ### **라이브러리 읽는 법은 여기까지 마치도록 하겠습니다!**
61 |
62 | 나머지는 메인 파일에서 뵙도록 합시다!
63 |
--------------------------------------------------------------------------------
/2화/webhook.MD:
--------------------------------------------------------------------------------
1 | ### 웹훅을 생성하는 방법!
2 |
3 | **만약에 당신이 서버에 관리자 권한이나 따로 웹훅 권한이 있으시다면 생성하거나 관리를 하실 수 있습니다!**
4 |
5 | 
6 | 
7 |
8 | #### 1. 왼쪽 위에 서버 이름 적혀있는 곳을 누르시고 **서버 관리**를 들어가주세요.
9 |
10 | 
11 |
12 | #### 2. 왼쪽에 여러가지 있을텐데 **웹후크**를 들어가주세요.
13 |
14 | 
15 |
16 | #### 3. **웹후크 만들기**를 누르시고 편집 라인에서 **웹후크 이름을 수정하고 원하는 채널을 설정**을 해주신 후 URL를 복사해주세요..
17 | (**"저는 webhook-test로 설정하였어요"**)
18 |
19 | 
20 |
21 | #### 4. 그러면 이제 URL를 확인해봅시다.
22 |
23 | 일단 제가 만든 웹훅의 URL은 아래와 같아요!
24 | **https://discordapp.com/api/webhooks/709006707640107029/piBftlF4QTdTfZdvs6vUJGRZBtdv-GrfAC-fFNBVfncXAfFhkyyHh_xr14cBkiEhRi7j**
25 |
26 | 웹훅의 아이디: 709006707640107029
27 | 웹훅의 토큰: piBftlF4QTdTfZdvs6vUJGRZBtdv-GrfAC-fFNBVfncXAfFhkyyHh_xr14cBkiEhRi7j
28 |
29 | 이런식으로 되어있을꺼에요!
30 | 이것들을 이제 어떻게 봇 소스에 적용하나?
31 |
32 | ```js
33 | const hook = new Discord.WebhookClient('709006707640107029', 'piBftlF4QTdTfZdvs6vUJGRZBtdv-GrfAC-fFNBVfncXAfFhkyyHh_xr14cBkiEhRi7j')
34 |
35 | hook.send("Hello, new World")
36 | ```
37 | 이런식으로 사용할 수 있어요!
38 |
--------------------------------------------------------------------------------
/3화/Commands/Bot/embed.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | exports.run = async (client, msg, args, prefix) => {
3 | let embed = new Discord.MessageEmbed() // var -> let으로 수정하였습니다.
4 | .setTitle("여기는 대표 타이틀!")
5 | .setDescription("여기는 대표 설명!")
6 | .setColor("RED")
7 | .setFooter("여기는 말머리?")
8 | .setThumbnail("http://blogfiles.naver.net/20151023_23/shin_0305_1445573936921jrPRT_JPEG/%BD%E6%B3%D7%C0%CF%BF%B9%BD%C3.jpg")
9 | .setImage("http://blogfiles.naver.net/MjAxODA4MjNfMjQ0/MDAxNTM1MDE5ODk1Njc3.c5p_E9tLPEXGnXPAkpOuhpEOm7VLqopETMTfJ9C8CWYg.6FCsIDtjWnd19lSzmw_z1oHm9E7fd39s1RmRPeBOF3Ag.JPEG.dlawldbs20/VD-poem-20150915-01.jpg")
10 | .setTimestamp()
11 | .addField("여기는 소제목", "여기는 소설명(??)")
12 | msg.reply(embed)
13 | }
14 |
15 | exports.config = {
16 | name: '임베드',
17 | aliases: ['embed', 'dlaqpem'],
18 | category: ['bot'],
19 | des: ['임베드에 대한 설명'],
20 | use: ['튜토야 임베드']
21 | }
--------------------------------------------------------------------------------
/3화/Commands/Bot/ping.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | msg.channel.send(`${client.user.username}의 핑은 ${client.ws.ping}ms 입니다!`)
3 | }
4 |
5 | exports.config = {
6 | name: '핑',
7 | aliases: ['vld', 'botping'],
8 | category: ['bot'],
9 | des: ['봇의 디스코드 웹소켓 지연시간을 알려드립니다'],
10 | use: ['튜토야 핑']
11 | }
--------------------------------------------------------------------------------
/3화/Commands/Bot/webhook.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | exports.run = async (client, msg, args, prefix) => {
3 | const hook = new Discord.WebhookClient('WebHook ID', 'WebHook Token');
4 | hook.send("Hello, new World!")
5 | }
6 |
7 | exports.config = {
8 | name: '웹훅',
9 | aliases: ['vld', 'botping'],
10 | category: ['bot'],
11 | des: ['웹훅에 대한 사용방법'],
12 | use: ['튜토야 웹훅']
13 | }
--------------------------------------------------------------------------------
/3화/Commands/moderator/ban.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | var user = msg.mentions.users.first();
3 | if (!user) {
4 | msg.reply("차단하시기 전에 맨션을 먼저 해주세요!")
5 | } else {
6 | var member = msg.guild.member(user);
7 | if (member) {
8 | member.ban(`${msg.author.username}님의 의해 서버에서 추방됨.`).then(member => {
9 | msg.reply(`성공적으로 ${member.user.tag}님을 추방하였습니다.`)
10 | }).catch(msg.reply("해당 유저를 차단 할 권한이 없습니다."))
11 | } else {
12 | msg.reply("이 서버에 존재하지 않은 유저입니다!")
13 | }
14 | }
15 | }
16 |
17 | exports.config = {
18 | name: '차단',
19 | aliases: ['ban', '벤'],
20 | category: ['moderator'],
21 | des: ['유저를 해당 서버에서 차단 시킵니다.'],
22 | use: ['튜토야 차단 <유저 맨션>']
23 | }
--------------------------------------------------------------------------------
/3화/Commands/moderator/clear.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | if (!args[0]) return msg.reply("청소할 만큼의 값을 정수로 적어주세요!")
3 | if (!Number(args[0])) return msg.reply("메세지를 지울 값이 숫자가 아니면 안되요!")
4 | if (args[0] < 1) return msg.reply("메세지를 지울 값을 1보다 작게 하시면 안되요!")
5 | if (args[0] > 100) return msg.reply("메세지를 지울 값이 100보다 크면 메세지가 안지워져요!")
6 |
7 | msg.channel.bulkDelete(args[0]).then(msg.reply(`성공적으로 ${args[0]}개 만큼 메세지를 삭제하였습니다!`))
8 | }
9 |
10 | exports.config = {
11 | name: '청소',
12 | aliases: ['clear', 'clean'],
13 | category: ['moderator'],
14 | des: ['bulkdelete'],
15 | use: ['튜토야 청소 <청소 할 메세지의 수>']
16 | }
--------------------------------------------------------------------------------
/3화/Commands/moderator/kick.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | var user = msg.mentions.users.first();
3 | if (!user) {
4 | msg.reply("추방하시기 전에 맨션을 먼저 해주세요!")
5 | } else {
6 | var member = msg.guild.member(user);
7 | if (member) {
8 | member.kick(`${msg.author.username}님의 의해 서버에서 추방됨.`).then(member => {
9 | msg.reply(`성공적으로 ${member.user.tag}님을 추방하였습니다.`)
10 | }).catch(msg.reply("해당 유저를 킥 할 권한이 없습니다."))
11 | } else {
12 | msg.reply("이 서버에 존재하지 않은 유저입니다!")
13 | }
14 | }
15 | }
16 |
17 | exports.config = {
18 | name: '추방',
19 | aliases: ['킥', 'kick'],
20 | category: ['moderator'],
21 | des: ['유저를 강제퇴장 시킵니다.'],
22 | use: ['튜토야 추방 <유저 맨션>']
23 | }
--------------------------------------------------------------------------------
/3화/README.MD:
--------------------------------------------------------------------------------
1 | ### 잠시 튜토리얼을 보시기 전 읽어주세요.
2 |
3 | 이번 3화 튜토리얼은 커맨드 핸들링에 관련하여 제작한 겁니다.
4 | 소스 코드를 사용하시는 것은 좋으시나 꼭 소스를 이해하셨으면 바램을 가져봅니다...
5 | 봇 소스만 복붙하여 사용하는 행위는 절대로 좋은 행위가 아닙니다.
6 | 튜토리얼을 제작하는 목적은 봇을 입문하시는 분들을 위하여 공부하시라고 제작하는거지 복붙 하라고 만든 용도가 아닙니다..
7 |
8 |
9 | ### Docs (라이브러리)
10 |
11 | 영문(공식):
12 | > 업데이트 될 때마다 버전에 맞게 업데이트되니 영어를 혐오하지 않으시면 최대한 공식링크를 이용해주시면 좋을거 같습니다.
13 |
14 | 한글(비공식, 번역진행중):
15 | > [Discord.js Korea](https://github.com/discordjs-kr) 팀에서 번역하고 있는 비공식 라이브러리 입니다.
16 |
--------------------------------------------------------------------------------
/3화/bot.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js");
2 | const client = new Discord.Client();
3 | const fs = require('fs')
4 | const config = require("./config.json") // config를 선언하여 config.json이 필요하다고 선언하였습니다.
5 | client.on("ready", () => {
6 | console.log(`${client.user.tag} 봇에 로그인 하였습니다!`);
7 | });
8 | client.commands = new Discord.Collection() // commands를 discord.collection을 사용하였습니다.
9 | client.aliases = new Discord.Collection()// aliases를 discord.collection을 사용하였습니다.
10 |
11 | fs.readdirSync("./Commands/").forEach(dir => { // fs 모듈을 이용하여 ./Commands/ 폴더 안에 내용을 불러와 forEach를 합니다 이후에 선언되는 것은 dir로 합시다.
12 | const Filter = fs.readdirSync(`./Commands/${dir}`).filter(f => f.endsWith(".js")); // Filter를 선언하여 Commands/여러 폴더들을 안에 .js로 끝나는 것들로 필터링 합시다.
13 | Filter.forEach(file => { // 안에 .js 파일들을 forEach하여 이후에 선언되는 것은 file로 합시다
14 | const cmd = require(`./Commands/${dir}/${file}`); // cmd를 선언하여 ./Commands/${dir}/${file}가 필요하다고 합시다
15 | client.commands.set(cmd.config.name, cmd) // 우리가 콜랙션으로 지정한 것들을 지정해줍시다 (안에 괄호는 그 안에 있는 config에 name을 지정하고 명령어에 이름을 저장합니다.)
16 | for (let alias of cmd.config.aliases) { // alias를 선언하고 cmd안에 있는 config.aliases가 여러개 있을텐데 그것들을 for로 반복합시다
17 | client.aliases.set(alias, cmd.config.name) // 콜렉션으로 지정한 것들을 다 넣어줍시다
18 | }
19 | })
20 | })
21 |
22 |
23 | function runCommand(command, message, args, prefix) { // 명령어를 실행할 때 쓸 함수입니다!
24 | if (client.commands.get(command) || client.aliases.get(command)) { // 만약에 command가 있는가 이후 true
25 | const cmd = client.commands.get(command) || client.commands.get(client.aliases.get(command)) // cmd를 따로 선언합시다 (해당 명령어를 get하여 불러오고)
26 | if (cmd) cmd.run(client, message, args, prefix); return // 만약에 cmd가 있다면 그 커멘드를 실행시켜줍니다.
27 | }
28 | }
29 | client.on("message", async msg => {
30 | const prefix = "튜토야 " // 접두사(prefix)를 저는 튜토야 라고 선정하였습니다!
31 | if (!msg.content.startsWith(prefix)) return // 만약에 메세지 내용이 접두사로 시작하지 않으면 return
32 | let args = msg.content.slice(prefix.length).trim().split(/ +/g) // argument
33 | let command = args.shift().toLowerCase() // 커멘드에 대한 이름을 선언
34 | try { // 아래의 명령어를 시도합니다.
35 | runCommand(command, msg, args, prefix) // 위에서 함수로 선언한 것을 command, msg(message), args(argument), prefix를 불러와 명령어를 실행
36 | } catch (e) {
37 | console.error(e) // 명령어를 실행하는 도중 에러가 발생하였다고 알려줍시다.
38 | }
39 | })
40 |
41 | client.login(config.token) // config에 token 부분을 불러오게 합시다.}
42 |
43 | /**
44 | * 이제 Commands 폴더를 생성하고 Bot, Moderator 폴더를 생성후 명령어 소스는 아래와 같이 사용하시면 됩니다.
45 | exports.run = async (client, msg, args, prefix) => {
46 | // 여기 부분에 평소에 작성하던 코드를 이쪽에서 해주시면 되요!
47 | }
48 |
49 | exports.config = {
50 | name: 'name', // 말 그대로 봇 명령어 이름이에요
51 | aliases: ['aliases', 'aliases1', 'aliases2'], // 여기는 위에 봇 명령어 이름을 aliases, aliases1, aliases2 처럼 적은거대로 명령어를 실행하면 위에 코드가 작동해요
52 | category: ['bot'], // 여기는 카테고리에요. 자신이 원하는데로 카테고리를 분류해주시면 될꺼 같아요.
53 | des: ['config 설정방법'], // 여기는 해당 명령어에 대한 설명입니다.
54 | use: ['튜토야 exports 사용법'] // 당신이 원한다면 사용 방법을 적어주시면 다른 유저분들께 도움이 될꺼에요 (추후에 help 명령어 만들예정)
55 | }
56 | */
57 |
--------------------------------------------------------------------------------
/3화/example.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "token": "your bot token!"
3 | }
--------------------------------------------------------------------------------
/3화/module_install.md:
--------------------------------------------------------------------------------
1 | ### 모듈을 설치하실 줄 모르신 분들을 위해서 작성하였습니다.
2 |
3 | 1. 먼저 설치하시기 전 개발하시던 폴더에 들어가주세요.
4 |
5 | 
6 |
7 | 2. 파일들이 쭈르르륵 있으실 텐데 그 위에 경로가 있을겁니다 그것을 클릭하고 cmd라고 적으신 후 엔터 눌러주세요.
8 |
9 | 
10 |
11 | 3. 그러면 해당 경로에 cmd가 켜졌을겁니다.
12 |
13 | 
14 |
15 | 4. 거기에 **npm i fs --save**라고 적어주세요.
16 |
17 | 
18 |
19 | 5. 그러고 엔터를 누르시면 아래의 사진처럼 바뀌었을겁니다!
20 |
21 | 
22 | 6. 모듈은 성공적으로 설치되었습니다!
23 | 이번 튜토리얼은 커멘드 핸들러 관련으로 제작되었습니다!
24 | 좀 어려운 과정이오니 천천히 설명을 잘 확인하며 따라와주세요!
25 |
26 |
--------------------------------------------------------------------------------
/4화/Commands/Bot/embed.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | exports.run = async (client, msg, args, prefix) => {
3 | let embed = new Discord.MessageEmbed() // var -> let으로 수정하였습니다.
4 | .setTitle("여기는 대표 타이틀!")
5 | .setDescription("여기는 대표 설명!")
6 | .setColor("RED")
7 | .setFooter("여기는 말머리?")
8 | .setThumbnail("http://blogfiles.naver.net/20151023_23/shin_0305_1445573936921jrPRT_JPEG/%BD%E6%B3%D7%C0%CF%BF%B9%BD%C3.jpg")
9 | .setImage("http://blogfiles.naver.net/MjAxODA4MjNfMjQ0/MDAxNTM1MDE5ODk1Njc3.c5p_E9tLPEXGnXPAkpOuhpEOm7VLqopETMTfJ9C8CWYg.6FCsIDtjWnd19lSzmw_z1oHm9E7fd39s1RmRPeBOF3Ag.JPEG.dlawldbs20/VD-poem-20150915-01.jpg")
10 | .setTimestamp()
11 | .addField("여기는 소제목", "여기는 소설명(??)")
12 | msg.reply(embed)
13 | }
14 |
15 | exports.config = {
16 | name: '임베드',
17 | aliases: ['embed', 'dlaqpem'],
18 | category: ['bot'],
19 | des: ['임베드에 대한 설명'],
20 | use: ['튜토야 임베드']
21 | }
--------------------------------------------------------------------------------
/4화/Commands/Bot/ping.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | msg.channel.send(`${client.user.username}의 핑은 ${client.ws.ping}ms 입니다!`)
3 | }
4 |
5 | exports.config = {
6 | name: '핑',
7 | aliases: ['vld', 'botping'],
8 | category: ['bot'],
9 | des: ['봇의 디스코드 웹소켓 지연시간을 알려드립니다'],
10 | use: ['튜토야 핑']
11 | }
--------------------------------------------------------------------------------
/4화/Commands/Bot/webhook.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | exports.run = async (client, msg, args, prefix) => {
3 | const hook = new Discord.WebhookClient('WebHook ID', 'WebHook Token');
4 | hook.send("Hello, new World!")
5 | }
6 |
7 | exports.config = {
8 | name: '웹훅',
9 | aliases: ['vld', 'botping'],
10 | category: ['bot'],
11 | des: ['웹훅에 대한 사용방법'],
12 | use: ['튜토야 웹훅']
13 | }
--------------------------------------------------------------------------------
/4화/Commands/crawling/docs.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | const fetch = require("node-fetch")
3 | exports.run = async (client, msg, args, prefix) => {
4 | /**
5 | * 이것은 번외로 Discord.js 문서 api로 크롤링하여 임베드로 표현한 코드입니다.
6 | * Discord.js 라이브러리 읽는것이 익숙하지 않을 경우 이것을 사용하여 참고하시면 좋을거 같습니다 (실제로 저도 많이 사용하고 있습니다 ㅎㅎ)
7 | * 그러나 라이브러리를 읽는것이 익숙해지는 것을 권장합니다!
8 | * API URL: https://djsdocs.sorta.moe
9 | */
10 | if (!args[0]) return msg.reply("❎ 쿼리를 입력해주세요.") // argument가 없다면 쿼리를 입력해달라고 전해줍시다.
11 | let query = encodeURI(args.join(" ")) // 쿼리를 선언하였고 검색에 사용할 것이오니 인코드를 해줍시다.
12 | fetch(`https://djsdocs.sorta.moe/v1/main/stable/embed?q=${query}`).then(a => a.json().then((r) => { // 해당 api를 fetch 합시다 a = fetch한 값들, 그걸 json화 하고 그 값들을 불러오기 위해서는 다시 then을 사용하여 r로 선언합니다.
13 | if (!r) return msg.reply("❎ 해당 쿼리는 존재하지 않습니다.")
14 | const docs = new Discord.MessageEmbed(r) // docs를 const로 선언을 해줍시다.
15 | docs.setFooter(msg.author.tag, msg.author.displayAvatarURL())
16 | msg.reply(docs)
17 | }))
18 | }
19 |
20 | exports.config = {
21 | name: 'docs',
22 | aliases: ['djsdocs'],
23 | category: ['Crawling'],
24 | des: ['Discord.js 문서 api를 활용한 명령어 입니다'],
25 | use: ['튜토야 docs ']
26 | }
--------------------------------------------------------------------------------
/4화/Commands/moderator/ban.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | var user = msg.mentions.users.first();
3 | if (!user) {
4 | msg.reply("차단하시기 전에 맨션을 먼저 해주세요!")
5 | } else {
6 | var member = msg.guild.member(user);
7 | if (member) {
8 | member.ban(`${msg.author.username}님의 의해 서버에서 추방됨.`).then(member => {
9 | msg.reply(`성공적으로 ${member.user.tag}님을 추방하였습니다.`)
10 | }).catch(msg.reply("해당 유저를 차단 할 권한이 없습니다."))
11 | } else {
12 | msg.reply("이 서버에 존재하지 않은 유저입니다!")
13 | }
14 | }
15 | }
16 |
17 | exports.config = {
18 | name: '차단',
19 | aliases: ['ban', '벤'],
20 | category: ['moderator'],
21 | des: ['유저를 해당 서버에서 차단 시킵니다.'],
22 | use: ['튜토야 차단 <유저 맨션>']
23 | }
--------------------------------------------------------------------------------
/4화/Commands/moderator/clear.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | if (!args[0]) return msg.reply("청소할 만큼의 값을 정수로 적어주세요!")
3 | if (!Number(args[0])) return msg.reply("메세지를 지울 값이 숫자가 아니면 안되요!")
4 | if (args[0] < 1) return msg.reply("메세지를 지울 값을 1보다 작게 하시면 안되요!")
5 | if (args[0] > 100) return msg.reply("메세지를 지울 값이 100보다 크면 메세지가 안지워져요!")
6 |
7 | msg.channel.bulkDelete(args[0]).then(msg.reply(`성공적으로 ${args[0]}개 만큼 메세지를 삭제하였습니다!`))
8 | }
9 |
10 | exports.config = {
11 | name: '청소',
12 | aliases: ['clear', 'clean'],
13 | category: ['moderator'],
14 | des: ['bulkdelete'],
15 | use: ['튜토야 청소 <청소 할 메세지의 수>']
16 | }
--------------------------------------------------------------------------------
/4화/Commands/moderator/kick.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | var user = msg.mentions.users.first();
3 | if (!user) {
4 | msg.reply("추방하시기 전에 맨션을 먼저 해주세요!")
5 | } else {
6 | var member = msg.guild.member(user);
7 | if (member) {
8 | member.kick(`${msg.author.username}님의 의해 서버에서 추방됨.`).then(member => {
9 | msg.reply(`성공적으로 ${member.user.tag}님을 추방하였습니다.`)
10 | }).catch(msg.reply("해당 유저를 킥 할 권한이 없습니다."))
11 | } else {
12 | msg.reply("이 서버에 존재하지 않은 유저입니다!")
13 | }
14 | }
15 | }
16 |
17 | exports.config = {
18 | name: '추방',
19 | aliases: ['킥', 'kick'],
20 | category: ['moderator'],
21 | des: ['유저를 강제퇴장 시킵니다.'],
22 | use: ['튜토야 추방 <유저 맨션>']
23 | }
--------------------------------------------------------------------------------
/4화/README.MD:
--------------------------------------------------------------------------------
1 | ### 잠시 튜토리얼을 보시기 전 읽어주세요.
2 |
3 | 이번 4화는 **웹에 있는 json을 불러와 사용하는 방법**에 대한 튜토리얼을 적었습니다.
4 | 이번에 필요한 모듈은 [**node-fetch**](https://www.npmjs.com/package/node-fetch), [**Moment-Timezone**](https://www.npmjs.com/package/moment-timezone) 모듈이 필요하며
5 | 이전과 **동일한 방법으로 모듈을 설치**해주시면 됩니다.
6 |
7 | 3화에서 많은 이슈들이 나왔는데
8 | **튜토리얼을 보고 계신분들을 생각하며 튜토리얼을 작성히지 못한 점에 대해서는 매우 죄송**하다고 생각합니다...
9 |
10 | 이슈가 안나오게끔 **열심히 튜토리얼을 제작할테니 많은 관심**을 주시면 감사하겠습니다!
11 |
--------------------------------------------------------------------------------
/4화/bot.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js");
2 | const client = new Discord.Client();
3 | const fs = require('fs')
4 | const config = require("./config.json")
5 | client.on("ready", () => {
6 | console.log(`${client.user.tag} 봇에 로그인 하였습니다!`);
7 | });
8 | client.commands = new Discord.Collection()
9 | client.aliases = new Discord.Collection()
10 |
11 | fs.readdirSync("./Commands/").forEach(dir => {
12 | const Filter = fs.readdirSync(`./Commands/${dir}`).filter(f => f.endsWith(".js"));
13 | Filter.forEach(file => {
14 | const cmd = require(`./Commands/${dir}/${file}`);
15 | client.commands.set(cmd.config.name, cmd)
16 | for (let alias of cmd.config.aliases) {
17 | client.aliases.set(alias, cmd.config.name)
18 | }
19 | })
20 | })
21 |
22 |
23 | function runCommand(command, message, args, prefix) {
24 | if (client.commands.get(command) || client.aliases.get(command)) {
25 | const cmd = client.commands.get(command) || client.commands.get(client.aliases.get(command))
26 | if (cmd) cmd.run(client, message, args, prefix); return
27 | }
28 | }
29 | client.on("message", async msg => {
30 | const prefix = "튜토야 "
31 | if(!msg.content.startsWith(prefix)) return
32 | let args = msg.content.slice(prefix.length).trim().split(/ +/g)
33 | let command = args.shift().toLowerCase()
34 | try {
35 | runCommand(command, msg, args, prefix)
36 | } catch (e) {
37 | console.error(e)
38 | }
39 | })
40 |
41 | client.login(config.token)
42 |
--------------------------------------------------------------------------------
/4화/example.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "token": "your bot token!"
3 | }
--------------------------------------------------------------------------------
/5화/Commands/Bot/embed.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | exports.run = async (client, msg, args, prefix) => {
3 | let embed = new Discord.MessageEmbed() // var -> let으로 수정하였습니다.
4 | .setTitle("여기는 대표 타이틀!")
5 | .setDescription("여기는 대표 설명!")
6 | .setColor("RED")
7 | .setFooter("여기는 말머리?")
8 | .setThumbnail("http://blogfiles.naver.net/20151023_23/shin_0305_1445573936921jrPRT_JPEG/%BD%E6%B3%D7%C0%CF%BF%B9%BD%C3.jpg")
9 | .setImage("http://blogfiles.naver.net/MjAxODA4MjNfMjQ0/MDAxNTM1MDE5ODk1Njc3.c5p_E9tLPEXGnXPAkpOuhpEOm7VLqopETMTfJ9C8CWYg.6FCsIDtjWnd19lSzmw_z1oHm9E7fd39s1RmRPeBOF3Ag.JPEG.dlawldbs20/VD-poem-20150915-01.jpg")
10 | .setTimestamp()
11 | .addField("여기는 소제목", "여기는 소설명(??)")
12 | msg.reply(embed)
13 | }
14 |
15 | exports.config = {
16 | name: '임베드',
17 | aliases: ['embed', 'dlaqpem'],
18 | category: ['bot'],
19 | des: ['임베드에 대한 설명'],
20 | use: ['튜토야 임베드']
21 | }
--------------------------------------------------------------------------------
/5화/Commands/Bot/help.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | exports.run = async (client, msg, args, prefix) => {
3 | if (!args[0]) {
4 | const categorys = client.category // bot.js에 있는 client.category 를 categorys로 선언하였습니다.
5 | let Commands = new Discord.MessageEmbed()
6 | .setAuthor(client.user.username + " 봇 명령어", client.user.displayAvatarURL())
7 | .setColor("7289DA")
8 | .setFooter(`${prefix}도움 <명령어> 를 통하여 해당 명령어를 자세히 확인해보세요.`)
9 | for (const category of categorys) { // 위에서 선언한 것을 for문으로 category로 선언하였습니다. (반복문)
10 | /**
11 | * 위에 for문을 잠시 설명해드리자면
12 | * categorys가 있는 만큼 반복을 하여
13 | * categorys중에 하나를 category로 선언하여 아래의 코드를 작성한 것입니다.
14 | */
15 | Commands.addField(category, `> **\`${client.commands.filter(el => el.config.category == category).keyArray().join('`, `')}\`**`)
16 | /**
17 | * 소제목에는 카테고리 이름을 넣고
18 | * 소 설명에는 이전에 client.commands를 컬랙션으로 지정한 것들을 불러와 필터를 시켜줍니다.
19 | * el로 선언하여 el이 어떤식으로 되어있냐면
20 | * 이전에 명령어들에게 exports를 사용하여 모듈화 하였는데 그것들을 불러오게 됩니다.
21 | * 여러가지 있는데 그중에 하나만 뜯어서 보여드렸습니다.
22 | * {
23 | * run: [AsyncFunction],
24 | * config: {
25 | * name: "asd",
26 | * aliases: ["asd1", "asd2", "123"],
27 | * category: ["example"],
28 | * des: ["config 설명"],
29 | * use: ["튜토야 도움 <명령어>"]
30 | * }
31 | * }
32 | * 그러고 이제 config.category가 const로 선언한 category와 맞는지 확인 후 Array화 시킨 후 안에 있는 명령어들을 불러온 것입니다.
33 | */
34 | }
35 | msg.reply(Commands)
36 | } else {
37 | if (client.commands.get(args[0])) { // 만약에 client.commands안에 args[0] 라는게 있다면
38 | var command = client.commands.get(args[0]) // command 는 client.commands.get(args[0])로 선언해줍시다.
39 | } else if (client.aliases.get(args[0])) { // 만약에 client.aliases 안에 args[0] 라는게 있다면
40 | let aliases = client.aliases.get(args[0]) // aliases 를 client.aliases.get(args[0])로 선언해주고 (왜냐하면 저기서 aliases를 불러오면 command 이름이 나오기 때문입니다.)
41 | var command = client.commands.get(aliases) // commands는 client.commands.get(aliases)으로 선언해줍시다.
42 | } else return msg.reply(`${args[0]} 명령어라는 것을 찾을 수 없어요...`)
43 |
44 | let config = command.config
45 | let name = config.name
46 | let aliases = config.aliases
47 | let category = config.category
48 | let description = config.des
49 | let use = config.use
50 |
51 | let Command = new Discord.MessageEmbed()
52 | .setTitle(`${name} 명령어`)
53 | .setColor("7289DA")
54 | .setDescription(`\`\`\`fix\n사용법: ${use}\`\`\``)
55 | .addField("명령어 설명", `**${description}**`, false)
56 | .addField("카테고리", `**${category}**`, true)
57 | .addField("공유하는 명령어", `**${aliases}**`, true)
58 | msg.reply(Command)
59 | }
60 | }
61 |
62 | exports.config = {
63 | name: '도움말',
64 | aliases: ['도움', '명령어', 'commands', 'help'],
65 | category: ['bot'],
66 | des: ['봇에 대한 명령어 리스트들을 불러와드립니다.'],
67 | use: ['튜토야 도움말 <명령어>']
68 | }
--------------------------------------------------------------------------------
/5화/Commands/Bot/ping.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | msg.channel.send(`${client.user.username}의 핑은 ${client.ws.ping}ms 입니다!`)
3 | }
4 |
5 | exports.config = {
6 | name: '핑',
7 | aliases: ['vld', 'botping'],
8 | category: ['bot'],
9 | des: ['봇의 디스코드 웹소켓 지연시간을 알려드립니다'],
10 | use: ['튜토야 핑']
11 | }
--------------------------------------------------------------------------------
/5화/Commands/Bot/webhook.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | exports.run = async (client, msg, args, prefix) => {
3 | const hook = new Discord.WebhookClient('WebHook ID', 'WebHook Token');
4 | hook.send("Hello, new World!")
5 | }
6 |
7 | exports.config = {
8 | name: '웹훅',
9 | aliases: ['vld', 'botping'],
10 | category: ['bot'],
11 | des: ['웹훅에 대한 사용방법'],
12 | use: ['튜토야 웹훅']
13 | }
--------------------------------------------------------------------------------
/5화/Commands/Owner/eval.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | exports.run = async (client, msg, args, prefix) => {
3 | if (!client.devs.includes(msg.author.id)) return msg.reply("이 명령어는 봇 관리자만 사용할 수 있습니다.") // bot.js에서 client.devs를 저장한 것을 불러와 포함하지 않으면 해당 메세지로 답변해줍시다.
4 |
5 | const coode = args.join(" ")
6 | const module = "const Discord = require(\"discord.js\")"
7 | if (!coode) return msg.reply("실행할 코드를 입력해주세요.")
8 | new Promise(res => res(eval(coode))).then(code => { // Promise를 생성하여 eval(coode)를 해준 후 then을 사용하여 그것들을 code로 선언해줍시다.
9 | if (typeof code !== 'string') code = require('util').inspect(code, { depth: 0 }) // 해당 코드가 스트링이 아니라면 code는 util 이라는 모듈 안에 있는 inspect라는 함수를 이용하여 정리 해줍시다.
10 | /**
11 | * util.inspect에 대해 자세히 알고 싶다면 아래의 링크를 클릭해주세요.
12 | * https://nodejs.org/api/util.html#util_util_inspect_object_options
13 | * */
14 | let evaled = new Discord.MessageEmbed()
15 | .setTitle("✅ Code Execution")
16 | .setColor("7289DA")
17 | .addField("📥 **Input**", `\`\`\`js\n${module}\n\n${coode}\`\`\``, false)
18 | .addField("📤 **Output**", `\`\`\`js\n${code}\`\`\``, false)
19 | msg.reply(evaled)
20 | /**
21 | * 이제 튜토야 이블 msg를 실행 시켜주면 아래와 같은 결과 값이 나와요!
22 | * Message {
23 | channel: [TextChannel],
24 | deleted: false,
25 | id: '717685629969891369',
26 | type: 'DEFAULT',
27 | content: '튜토야 이블 msg',
28 | author: [User],
29 | pinned: false,
30 | tts: false,
31 | nonce: '717685619970539520',
32 | system: false,
33 | embeds: [],
34 | attachments: Collection [Map] {},
35 | createdTimestamp: 1591179988139,
36 | editedTimestamp: null,
37 | reactions: [ReactionManager],
38 | mentions: [MessageMentions],
39 | webhookID: null,
40 | application: null,
41 | activity: null,
42 | _edits: [],
43 | flags: [MessageFlags],
44 | reference: null
45 | }
46 | */
47 | }).catch(e => { // 해당 코드에서 에러가 발생하면 캐치를 하고 그 에러 값을 e로 선언해줍시다.
48 | let evaled = new Discord.MessageEmbed()
49 | .setTitle("❎ Code Execution")
50 | .setColor("RED")
51 | .setDescription(`\`\`\`js\n${e}\`\`\``)
52 | msg.reply(evaled)
53 | })
54 | }
55 |
56 | exports.config = {
57 | name: '이블',
58 | aliases: ['eval'],
59 | category: ['owner'],
60 | des: ['코드 실행기'],
61 | use: ['튜토야 이블 <코드>']
62 | }
--------------------------------------------------------------------------------
/5화/Commands/crawling/NaverRanking.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | const fetch = require("node-fetch")
3 | const moment = require('moment-timezone')
4 | exports.run = async (client, msg, args, prefix) => {
5 | fetch("http://rank.search.naver.com/rank.js").then(r => r.json().then((r) => {
6 | let updated = moment(new Date(r.ts)).locale("ko").format("llll")
7 | console.log(r.data[0].data)
8 | let data = r.data[0].data
9 | let NaverRanking = new Discord.MessageEmbed()
10 | .setTitle("네이버 실시간 검색어 순위")
11 | .setColor("#83ff7b")
12 | .setFooter(updated)
13 | for (let i = 0; i < 10; i++) {
14 | NaverRanking.addField(`${data[i].rank}위`, `[${data[i].keyword}](https://search.naver.com/search.naver?where=nexearch&query=${encodeURI(data[i].keyword)}&sm=top_lve.agallgrpmamsi0en0sp0&ie=utf8)`)
15 | }
16 | msg.channel.send(NaverRanking)
17 | }))
18 | }
19 |
20 | exports.config = {
21 | name: '네이버차트',
22 | aliases: ['NaverRank', 'NaverRanking'],
23 | category: ['crawling'],
24 | des: ['네이버 랭킹 json을 크롤링하여 값을 불러왔습니다.'],
25 | use: ['튜토야 네이버차트']
26 | }
--------------------------------------------------------------------------------
/5화/Commands/crawling/docs.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | const fetch = require("node-fetch")
3 | exports.run = async (client, msg, args, prefix) => {
4 | if (!args[0]) return msg.reply("❎ 쿼리를 입력해주세요.")
5 | let query = encodeURI(args.join(" "))
6 | fetch(`https://djsdocs.sorta.moe/v1/main/stable/embed?q=${query}`).then(a => a.json().then((r) => {
7 | if (!r) return msg.reply("❎ 해당 쿼리는 존재하지 않습니다.")
8 | const docs = new Discord.MessageEmbed(r)
9 | docs.setFooter(msg.author.tag, msg.author.displayAvatarURL())
10 | msg.reply(docs)
11 | }))
12 | }
13 |
14 | exports.config = {
15 | name: 'docs',
16 | aliases: ['djsdocs'],
17 | category: ['crawling'],
18 | des: ['Discord.js 문서 api를 활용한 명령어 입니다'],
19 | use: ['튜토야 docs ']
20 | }
--------------------------------------------------------------------------------
/5화/Commands/moderator/ban.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | var user = msg.mentions.users.first();
3 | if (!user) {
4 | msg.reply("차단하시기 전에 맨션을 먼저 해주세요!")
5 | } else {
6 | var member = msg.guild.member(user);
7 | if (member) {
8 | member.ban(`${msg.author.username}님의 의해 서버에서 추방됨.`).then(member => {
9 | msg.reply(`성공적으로 ${member.user.tag}님을 추방하였습니다.`)
10 | }).catch(msg.reply("해당 유저를 차단 할 권한이 없습니다."))
11 | } else {
12 | msg.reply("이 서버에 존재하지 않은 유저입니다!")
13 | }
14 | }
15 | }
16 |
17 | exports.config = {
18 | name: '차단',
19 | aliases: ['ban', '벤'],
20 | category: ['moderator'],
21 | des: ['유저를 해당 서버에서 차단 시킵니다.'],
22 | use: ['튜토야 차단 <유저 맨션>']
23 | }
--------------------------------------------------------------------------------
/5화/Commands/moderator/clear.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | if (!args[0]) return msg.reply("청소할 만큼의 값을 정수로 적어주세요!")
3 | if (!Number(args[0])) return msg.reply("메세지를 지울 값이 숫자가 아니면 안되요!")
4 | if (args[0] < 1) return msg.reply("메세지를 지울 값을 1보다 작게 하시면 안되요!")
5 | if (args[0] > 100) return msg.reply("메세지를 지울 값이 100보다 크면 메세지가 안지워져요!")
6 |
7 | msg.channel.bulkDelete(args[0]).then(msg.reply(`성공적으로 ${args[0]}개 만큼 메세지를 삭제하였습니다!`))
8 | }
9 |
10 | exports.config = {
11 | name: '청소',
12 | aliases: ['clear', 'clean'],
13 | category: ['moderator'],
14 | des: ['bulkdelete'],
15 | use: ['튜토야 청소 <청소 할 메세지의 수>']
16 | }
--------------------------------------------------------------------------------
/5화/Commands/moderator/kick.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | var user = msg.mentions.users.first();
3 | if (!user) {
4 | msg.reply("추방하시기 전에 맨션을 먼저 해주세요!")
5 | } else {
6 | var member = msg.guild.member(user);
7 | if (member) {
8 | member.kick(`${msg.author.username}님의 의해 서버에서 추방됨.`).then(member => {
9 | msg.reply(`성공적으로 ${member.user.tag}님을 추방하였습니다.`)
10 | }).catch(msg.reply("해당 유저를 킥 할 권한이 없습니다."))
11 | } else {
12 | msg.reply("이 서버에 존재하지 않은 유저입니다!")
13 | }
14 | }
15 | }
16 |
17 | exports.config = {
18 | name: '추방',
19 | aliases: ['킥', 'kick'],
20 | category: ['moderator'],
21 | des: ['유저를 강제퇴장 시킵니다.'],
22 | use: ['튜토야 추방 <유저 맨션>']
23 | }
--------------------------------------------------------------------------------
/5화/README.MD:
--------------------------------------------------------------------------------
1 | ### 잠시 튜토리얼을 보시기 전 읽어주세요.
2 |
3 | 이번 5화는 도움말, eval (이블)을 만드는 방법에 대해 튜토리얼을 적어볼려고 합니다!
4 | 폴더랑 파일 명은 제대로 작업해주시고 오늘도 화이팅해서 5화를 진행해보도록 합시다:)
5 |
6 | 이번에 필요한 모듈은 [fs](https://www.npmjs.com/package/fs) 입니다.
7 |
8 | 메인 파일에 여러가지 추가하였으니 확인해주세요!
9 |
10 | 이번에도 코드 작성하시다가 에러가 발생하신다면 Issue, PR를 넣어주세요.
--------------------------------------------------------------------------------
/5화/bot.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js");
2 | const client = new Discord.Client();
3 | const fs = require('fs')
4 | const config = require("./config.json")
5 | client.on("ready", () => {
6 | console.log(`${client.user.tag} 봇에 로그인 하였습니다!`);
7 | });
8 | client.commands = new Discord.Collection()
9 | client.aliases = new Discord.Collection()
10 | client.devs = ['570617337691111444', "1234567890"] // devs에 제 고유 아이디를 넣어놨습니다! 그리고 이런식으로 아이디를 넣으면 그 사람들도 공유가 됩니다! (eval에서 권한 체크용으로 쓰일 예정)
11 | client.category = ['bot', 'crawling', 'moderator', 'owner'] // help 명령어에서 카테고리들을 쉽게 불러오도록 이미 Array(어레이)를 만들었습니다.
12 | fs.readdirSync("./Commands/").forEach(dir => {
13 | const Filter = fs.readdirSync(`./Commands/${dir}`).filter(f => f.endsWith(".js"));
14 | Filter.forEach(file => {
15 | const cmd = require(`./Commands/${dir}/${file}`);
16 | client.commands.set(cmd.config.name, cmd)
17 | for (let alias of cmd.config.aliases) {
18 | client.aliases.set(alias, cmd.config.name)
19 | }
20 | })
21 | })
22 |
23 |
24 | function runCommand(command, message, args, prefix) {
25 | if (client.commands.get(command) || client.aliases.get(command)) {
26 | const cmd = client.commands.get(command) || client.commands.get(client.aliases.get(command))
27 | if (cmd) cmd.run(client, message, args, prefix); return
28 | }
29 | }
30 | client.on("message", async msg => {
31 | const prefix = "튜토야 "
32 | if (!msg.content.startsWith(prefix)) return
33 | let args = msg.content.slice(prefix.length).trim().split(/ +/g)
34 | let command = args.shift().toLowerCase()
35 | try {
36 | runCommand(command, msg, args, prefix)
37 | } catch (e) {
38 | console.error(e)
39 | }
40 | })
41 |
42 | client.login(config.token)
43 |
--------------------------------------------------------------------------------
/5화/example.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "token": "your bot token!"
3 | }
--------------------------------------------------------------------------------
/6화/Commands/Bot/embed.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | exports.run = async (client, msg, args, prefix) => {
3 | let embed = new Discord.MessageEmbed() // var -> let으로 수정하였습니다.
4 | .setTitle("여기는 대표 타이틀!")
5 | .setDescription("여기는 대표 설명!")
6 | .setColor("RED")
7 | .setFooter("여기는 말머리?")
8 | .setThumbnail("http://blogfiles.naver.net/20151023_23/shin_0305_1445573936921jrPRT_JPEG/%BD%E6%B3%D7%C0%CF%BF%B9%BD%C3.jpg")
9 | .setImage("http://blogfiles.naver.net/MjAxODA4MjNfMjQ0/MDAxNTM1MDE5ODk1Njc3.c5p_E9tLPEXGnXPAkpOuhpEOm7VLqopETMTfJ9C8CWYg.6FCsIDtjWnd19lSzmw_z1oHm9E7fd39s1RmRPeBOF3Ag.JPEG.dlawldbs20/VD-poem-20150915-01.jpg")
10 | .setTimestamp()
11 | .addField("여기는 소제목", "여기는 소설명(??)")
12 | msg.reply(embed)
13 | }
14 |
15 | exports.config = {
16 | name: '임베드',
17 | aliases: ['embed', 'dlaqpem'],
18 | category: ['bot'],
19 | des: ['임베드에 대한 설명'],
20 | use: ['튜토야 임베드']
21 | }
--------------------------------------------------------------------------------
/6화/Commands/Bot/help.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | exports.run = async(client, msg, args, prefix) => {
3 | if (!args[0]) {
4 | const categorys = client.category
5 | let Commands = new Discord.MessageEmbed()
6 | .setAuthor(client.user.username + " 봇 명령어", client.user.displayAvatarURL())
7 | .setColor("7289DA")
8 | .setFooter(`${prefix}도움 <명령어> 를 통하여 해당 명령어를 자세히 확인해보세요.`)
9 | for (const category of categorys) {
10 | Commands.addField(category, `> **\`${client.commands.filter(el => el.config.category == category).keyArray().join('`, `')}\`**`)
11 |
12 | }
13 | msg.reply(Commands)
14 | } else {
15 | if (client.commands.get(args[0])) {
16 | var command = client.commands.get(args[0])
17 | } else if (client.aliases.get(args[0])) {
18 | let aliases = client.aliases.get(args[0])
19 | var command = client.commands.get(aliases)
20 | } else return msg.reply(`${args[0]} 명령어라는 것을 찾을 수 없어요...`)
21 |
22 | let config = command.config
23 | let name = config.name
24 | let aliases = config.aliases
25 | let category = config.category
26 | let description = config.des
27 | let use = config.use
28 |
29 | let Command = new Discord.MessageEmbed()
30 | .setTitle(`${name} 명령어`)
31 | .setColor("7289DA")
32 | .setDescription(`\`\`\`fix\n사용법: ${use}\`\`\``)
33 | .addField("명령어 설명", `**${description}**`, false)
34 | .addField("카테고리", `**${category}**`, true)
35 | .addField("공유하는 명령어", `**${aliases}**`, true)
36 | msg.reply(Command)
37 | }
38 | }
39 |
40 | exports.config = {
41 | name: '도움말',
42 | aliases: ['도움', '명령어', 'commands', 'help'],
43 | category: ['bot'],
44 | des: ['봇에 대한 명령어 리스트들을 불러와드립니다.'],
45 | use: ['튜토야 도움말 <명령어>']
46 | }
--------------------------------------------------------------------------------
/6화/Commands/Bot/ping.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | msg.channel.send(`${client.user.username}의 핑은 ${client.ws.ping}ms 입니다!`)
3 | }
4 |
5 | exports.config = {
6 | name: '핑',
7 | aliases: ['vld', 'botping'],
8 | category: ['bot'],
9 | des: ['봇의 디스코드 웹소켓 지연시간을 알려드립니다'],
10 | use: ['튜토야 핑']
11 | }
--------------------------------------------------------------------------------
/6화/Commands/Bot/webhook.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | exports.run = async (client, msg, args, prefix) => {
3 | const hook = new Discord.WebhookClient('WebHook ID', 'WebHook Token');
4 | hook.send("Hello, new World!")
5 | }
6 |
7 | exports.config = {
8 | name: '웹훅',
9 | aliases: ['vld', 'botping'],
10 | category: ['bot'],
11 | des: ['웹훅에 대한 사용방법'],
12 | use: ['튜토야 웹훅']
13 | }
--------------------------------------------------------------------------------
/6화/Commands/Owner/eval.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | exports.run = async(client, msg, args, prefix) => {
3 | if (!client.devs.includes(msg.author.id)) return msg.reply("이 명령어는 봇 관리자만 사용할 수 있습니다.")
4 |
5 | const coode = args.join(" ")
6 | const module = "const Discord = require(\"discord.js\")"
7 | if (!coode) return msg.reply("실행할 코드를 입력해주세요.")
8 | new Promise(res => res(eval(coode))).then(code => {
9 | if (typeof code !== 'string') code = require('util').inspect(code, { depth: 0 })
10 | let evaled = new Discord.MessageEmbed()
11 | .setTitle("✅ Code Execution")
12 | .setColor("7289DA")
13 | .addField("📥 **Input**", `\`\`\`js\n${module}\n\n${coode}\`\`\``, false)
14 | .addField("📤 **Output**", `\`\`\`js\n${code}\`\`\``, false)
15 | msg.reply(evaled)
16 |
17 | }).catch(e => {
18 | let evaled = new Discord.MessageEmbed()
19 | .setTitle("❎ Code Execution")
20 | .setColor("RED")
21 | .setDescription(`\`\`\`js\n${e}\`\`\``)
22 | msg.reply(evaled)
23 | })
24 | }
25 |
26 | exports.config = {
27 | name: '이블',
28 | aliases: ['eval'],
29 | category: ['owner'],
30 | des: ['코드 실행기'],
31 | use: ['튜토야 이블 <코드>']
32 | }
--------------------------------------------------------------------------------
/6화/Commands/crawling/NaverRanking.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | const fetch = require("node-fetch")
3 | const moment = require('moment-timezone')
4 | exports.run = async (client, msg, args, prefix) => {
5 | fetch("http://rank.search.naver.com/rank.js").then(r => r.json().then((r) => {
6 | let updated = moment(new Date(r.ts)).locale("ko").format("llll")
7 | console.log(r.data[0].data)
8 | let data = r.data[0].data
9 | let NaverRanking = new Discord.MessageEmbed()
10 | .setTitle("네이버 실시간 검색어 순위")
11 | .setColor("#83ff7b")
12 | .setFooter(updated)
13 | for (let i = 0; i < 10; i++) {
14 | NaverRanking.addField(`${data[i].rank}위`, `[${data[i].keyword}](https://search.naver.com/search.naver?where=nexearch&query=${encodeURI(data[i].keyword)}&sm=top_lve.agallgrpmamsi0en0sp0&ie=utf8)`)
15 | }
16 | msg.channel.send(NaverRanking)
17 | }))
18 | }
19 |
20 | exports.config = {
21 | name: '네이버차트',
22 | aliases: ['NaverRank', 'NaverRanking'],
23 | category: ['crawling'],
24 | des: ['네이버 랭킹 json을 크롤링하여 값을 불러왔습니다.'],
25 | use: ['튜토야 네이버차트']
26 | }
--------------------------------------------------------------------------------
/6화/Commands/crawling/docs.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | const fetch = require("node-fetch")
3 | exports.run = async (client, msg, args, prefix) => {
4 | if (!args[0]) return msg.reply("❎ 쿼리를 입력해주세요.")
5 | let query = encodeURI(args.join(" "))
6 | fetch(`https://djsdocs.sorta.moe/v1/main/stable/embed?q=${query}`).then(a => a.json().then((r) => {
7 | if (!r) return msg.reply("❎ 해당 쿼리는 존재하지 않습니다.")
8 | const docs = new Discord.MessageEmbed(r)
9 | docs.setFooter(msg.author.tag, msg.author.displayAvatarURL())
10 | msg.reply(docs)
11 | }))
12 | }
13 |
14 | exports.config = {
15 | name: 'docs',
16 | aliases: ['djsdocs'],
17 | category: ['crawling'],
18 | des: ['Discord.js 문서 api를 활용한 명령어 입니다'],
19 | use: ['튜토야 docs ']
20 | }
--------------------------------------------------------------------------------
/6화/Commands/database/gamble.js:
--------------------------------------------------------------------------------
1 | // 모듈 불러오기
2 | const Discord = require("discord.js")
3 | const reload = require("self-reload-json")
4 | const User = new reload("./json/user.json")
5 |
6 | exports.run = async(client, msg, args, prefix) => {
7 | // 무작위숫자 함수
8 | function getRandomInt(min, max) {
9 | return Math.floor(Math.random() * (max - min)) + min;
10 | }
11 | // user[msg.author.id].money가 0보다 작거나 같을 경우
12 | if (User[msg.author.id].money <= 0) {
13 | let nomoney = new Discord.MessageEmbed()
14 | .setDescription("❎ 당신은 도박을 할 돈이 없습니다..")
15 | .setColor("RED")
16 | return msg.reply(nomoney)
17 | }
18 |
19 | let help = new Discord.MessageEmbed()
20 | .setDescription(`${prefix}도박 <돈>`)
21 | .setColor("7289DA")
22 | .setFooter("돈 부분은 무조건 정수로 적어주세요.")
23 |
24 | // args[0]이 비어있을 경우
25 | if (!args[0]) return msg.reply(help)
26 |
27 | // args[0]이 숫자가 아닐경우
28 | if (!Number(args[0])) return msg.reply(help)
29 |
30 | let gamble = new Discord.MessageEmbed()
31 | .setDescription(`정말로 \`${args[0]}₩\` 만큼 도박을 진행하시겠습니까?`)
32 | .setColor("7289DA")
33 |
34 | msg.reply(gamble).then(async message => {
35 | // 반응 추가 (✅, ❎)
36 | await message.react("✅")
37 | await message.react("❎")
38 |
39 | // 필터 생성
40 | let filterYes = (reaction, user) => reaction.emoji.name === '✅' && user.id == msg.author.id
41 |
42 | // 반응 콜랙터 생성
43 | let collectorYes = message.createReactionCollector(filterYes, { max: 1, time: 60000 }) // max: 1 -> 반응은 한번만, time: 60000 -> 제한시간 60초
44 |
45 | // 위에 콜랙터 이벤트 생성
46 | collectorYes.on('collect', () => { // 반응을 할 경우
47 | message.delete()
48 |
49 | // 배율 설정
50 | let multiplication = getRandomInt(2, 10)
51 |
52 | // 성공하면 받을 금액
53 | let money = args[0] * multiplication
54 |
55 | // 성공과 실패를 나눌 숫자
56 | let boolean = getRandomInt(1, 3)
57 |
58 | // boolean 변수가 1일 경우
59 | if (boolean == 1) {
60 | let yourmoney = User[msg.author.id].money + money
61 | let success = new Discord.MessageEmbed()
62 | .setDescription(`당신은 도박을 성공하여 ${multiplication}배 만큼 거신 금액을 얻으셨습니다.\n\n 보유하고 있는 돈: ||${yourmoney}₩||`)
63 | .setColor("7289DA")
64 | msg.reply(success)
65 |
66 | // user의 money는 money + money <- (위에 선언한 money)
67 | User[msg.author.id].money = User[msg.author.id].money + money
68 |
69 | // user 저장
70 | User.save()
71 |
72 | // 아닐경우
73 | } else {
74 | // 임베드에 표기할 숫자
75 | let yourmoney = User[msg.author.id].money - args[0]
76 | let fail = new Discord.MessageEmbed()
77 | .setDescription(`당신은 도박을 실패하여 거신 금액을 모두 잃었습니다.\n\n 보유하고 있는 돈: ||${yourmoney}₩||`)
78 | .setColor("7289DA")
79 | msg.reply(fail)
80 |
81 | // user의 money는 money - args[0] (건 금액)
82 | User[msg.author.id].money = User[msg.author.id].money - args[0]
83 |
84 | // user의 json을 저장
85 | User.save()
86 | }
87 | })
88 |
89 | // 위의 콜랙터의 이벤트 생성
90 | collectorYes.on('end', (_, reason) => { // 이벤트가 끝날 경우
91 | if (reason === "time") { // 이벤트가 끝난 사유가 time일 경우
92 | message.delete()
93 | let timeover = new Discord.MessageEmbed()
94 | .setDescription("시간이 초과가 되었으니 다시 시도해주세요.")
95 | .setColor("RED")
96 | msg.reply(timeover)
97 | }
98 | })
99 |
100 | // 필터 생성
101 | let filterNo = (reaction, user) => reaction.emoji.name === '❎' && user.id === msg.author.id
102 |
103 | // 콜랙터 생성
104 | let collectorNo = message.createReactionCollector(filterNo, { max: 1, time: 60000 })
105 | // 콜랙터 이벤트 생성
106 | collectorNo.on('collect', () => { // 반응을 할 경우
107 | message.delete()
108 | let cancel = new Discord.MessageEmbed()
109 | .setDescription("도박 진행을 취소하였습니다.")
110 | .setColor("RED")
111 | msg.reply(cancel)
112 | })
113 | })
114 | }
115 |
116 | exports.config = {
117 | name: '도박',
118 | aliases: ['gamble'],
119 | category: ['database'],
120 | des: ['당신이 돈을 걸어 반반의 확률로 게임을 진행합니다.'],
121 | use: ['튜토야 도박 <돈>']
122 | }
--------------------------------------------------------------------------------
/6화/Commands/database/money.js:
--------------------------------------------------------------------------------
1 | // 모듈 불러오기
2 | const Discord = require("discord.js")
3 | const reload = require("self-reload-json")
4 | const User = new reload("./json/user.json")
5 |
6 | exports.run = async(client, msg, args, prefix) => {
7 | let money = new Discord.MessageEmbed()
8 | // user.money를 아래와 같이 불러옴.
9 | .setDescription(`보유하고 있는 금액: ${User[msg.author.id].money}₩`)
10 | .setColor("7289DA")
11 | msg.reply(money)
12 | }
13 |
14 | exports.config = {
15 | name: '돈',
16 | aliases: ['내돈', 'money', 'mymoney'],
17 | category: ['database'],
18 | des: ['당신이 보유하고 있는 금액을 알려드립니다.'],
19 | use: ['튜토야 돈']
20 | }
--------------------------------------------------------------------------------
/6화/Commands/database/registerGuild.js:
--------------------------------------------------------------------------------
1 | // 모듈 불러오기
2 | const Discord = require("discord.js")
3 | const reload = require("self-reload-json")
4 | const Guild = new reload("./json/server.json")
5 |
6 | exports.run = async(client, msg, args, prefix) => {
7 | let already = new Discord.MessageEmbed()
8 | .setDescription("❎ 이 서버는 이미 가입되어 있습니다.")
9 | .setColor("RED")
10 |
11 | // guild[msg.guild.id]가 있을 경우
12 | if (Guild[msg.guild.id]) return msg.reply(already)
13 | else {
14 |
15 | // guild[msg.guild.id] 값을 아래의 오브젝트로 저장
16 | Guild[msg.guild.id] = {
17 | leveling: true,
18 | gambling: true
19 | }
20 | let registered = new Discord.MessageEmbed()
21 | .setDescription("✅ 성공적으로 해당 길드의 데이터베이스가 생성되었습니다.")
22 | .setColor("7289DA")
23 |
24 | // Guild 저장
25 | Guild.save()
26 | msg.reply(registered)
27 | }
28 | }
29 |
30 | exports.config = {
31 | name: '서버가입',
32 | aliases: ['registerGuild'],
33 | category: ['database'],
34 | des: ['튜토봇에 이 서버만의 데이터베이스를 생성합니다.'],
35 | use: ['튜토야 서버가입']
36 | }
--------------------------------------------------------------------------------
/6화/Commands/database/settings.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js")
2 | const reload = require("self-reload-json")
3 | const guild = new reload("./json/server.json")
4 |
5 | exports.run = async(client, msg, args, prefix) => {
6 | let noperm = new Discord.MessageEmbed()
7 | .setDescription("❎ 당신은 관리자 권한이 없습니다.")
8 | .setColor("RED")
9 | if (!msg.member.hasPermission("ADMINISTRATOR")) return msg.reply(noperm)
10 | let empty = new Discord.MessageEmbed()
11 | .setTitle("⚙️ 현재 설정되어 있는 것들")
12 | .setColor("7289DA")
13 | .setDescription(`레벨링: ${guild[msg.guild.id].leveling ? "✅" : "❎"}\n도박: ${guild[msg.guild.id].gambling ? "✅" : "❎"}`)
14 | .setFooter(`기능들을 온오프 하고 싶으시면 "${prefix}설정 <기능>"으로 해주세요.`)
15 | switch (args[0]) { // args[0]에 대한 여러가지 변수가 있을때 사용함
16 | case "레벨링": // args[0] == 레벨링 일 경우
17 | let emptyGuild = new Discord.MessageEmbed()
18 | .setDescription("❎ 현재 이 길드는 데이터베이스에 저장되어 있지 않습니다.")
19 | .setFooter(`데이터베이스에 가입하고 싶으시면\n서버 관리자중"${prefix} 서버가입" 명령어를 사용해주세요.`)
20 | .setColor("RED")
21 |
22 | // guild[msg.guild.id] 가 없을 경우
23 | if (!guild[msg.guild.id]) return msg.reply(emptyGuild)
24 |
25 | // guild[msg.guild.id].leveling이 true일 경우
26 | if (guild[msg.guild.id].leveling === true) {
27 | let question = new Discord.MessageEmbed()
28 | .setDescription("정말로 이 서버에서 레벨링을 비활성화 하시겠습니까?")
29 | .setColor("7289DA")
30 | msg.reply(question).then(async message => {
31 | await message.react("✅")
32 | await message.react("❎")
33 |
34 | // 필터 생성
35 | let filterYes = (reaction, user) => reaction.emoji.name === '✅' && user.id == msg.author.id
36 |
37 | // 콜랙터 생성
38 | let collectorYes = message.createReactionCollector(filterYes, { max: 1, time: 60000 })
39 |
40 | // 콜랙터 이벤트 생성
41 | collectorYes.on('collect', () => { // 반응을 할 경우
42 | message.delete()
43 | let success = new Discord.MessageEmbed()
44 | .setDescription("성공적으로 이 서버에 레벨링 기능을 비활성화 하였습니다.")
45 | .setColor("7289DA")
46 | msg.reply(success)
47 |
48 | // guild.leveling = false
49 | guild[msg.guild.id].leveling = false
50 |
51 | // guild 저장
52 | guild.save()
53 | })
54 | // 콜랙터 이벤트 생성
55 | collectorYes.on('end', (_, reason) => { // 이벤트가 종료되었을 경우
56 | if (reason === "time") { // 종료된 사유가 time일 경우
57 | message.delete()
58 | let timeover = new Discord.MessageEmbed()
59 | .setDescription("시간이 초과가 되었으니 다시 시도해주세요.")
60 | .setColor("RED")
61 | msg.reply(timeover)
62 | }
63 | })
64 |
65 | // 필터 생성
66 | let filterNo = (reaction, user) => reaction.emoji.name === '❎' && user.id === msg.author.id
67 |
68 | // 콜랙터 생성
69 | let collectorNo = message.createReactionCollector(filterNo, { max: 1, time: 60000 })
70 |
71 | // 콜랙터 이벤트 생성
72 | collectorNo.on('collect', () => { // 반응을 할 경우
73 | message.delete()
74 | let cancel = new Discord.MessageEmbed()
75 | .setDescription("레벨링 비활성화를 취소하였습니다.")
76 | .setColor("RED")
77 | msg.reply(cancel)
78 | })
79 | })
80 |
81 | // guild[msg.guild.id].leveling이 false일 경우
82 | } else if (guild[msg.guild.id].leveling === false) {
83 | let question = new Discord.MessageEmbed()
84 | .setDescription("정말로 이 서버에서 레벨링을 활성화 하시겠습니까?")
85 | .setColor("7289DA")
86 | msg.reply(question).then(async message => {
87 | await message.react("✅")
88 | await message.react("❎")
89 |
90 | // 필터 생성
91 | let filterYes = (reaction, user) => reaction.emoji.name === '✅' && user.id == msg.author.id
92 |
93 | // 콜랙터 생성
94 | let collectorYes = message.createReactionCollector(filterYes, { max: 1, time: 60000 })
95 |
96 | // 콜랙터 이벤트 생성
97 | collectorYes.on('collect', () => { // 반응을 할 경우
98 | message.delete()
99 | let success = new Discord.MessageEmbed()
100 | .setDescription("성공적으로 이 서버에 레벨링 기능을 활성화 하였습니다.")
101 | .setColor("7289DA")
102 | msg.reply(success)
103 |
104 | // guild.leveling = true
105 | guild[msg.guild.id].leveling = true
106 |
107 | // guild 저장
108 | guild.save()
109 |
110 | })
111 |
112 | // 콜랙터 이벤트 생성
113 | collectorYes.on('end', (_, reason) => { // 이벤트가 종료할 경우
114 | if (reason === "time") { // 종료 사유가 time일 경우
115 | message.delete()
116 | let timeover = new Discord.MessageEmbed()
117 | .setDescription("시간이 초과가 되었으니 다시 시도해주세요.")
118 | .setColor("RED")
119 | msg.reply(timeover)
120 | }
121 | })
122 |
123 | // 필터 생성
124 | let filterNo = (reaction, user) => reaction.emoji.name === '❎' && user.id === msg.author.id
125 |
126 | // 콜랙터 생성
127 | let collectorNo = message.createReactionCollector(filterNo, { max: 1, time: 60000 })
128 |
129 | // 콜랙터 이벤트 생성
130 | collectorNo.on('collect', () => { // 반응을 할 경우
131 | message.delete()
132 | let cancel = new Discord.MessageEmbed()
133 | .setDescription("레벨링 활성화를 취소하였습니다.")
134 | .setColor("RED")
135 | msg.reply(cancel)
136 | })
137 | })
138 | }
139 | break;
140 | case "도박": // args[0] == 도박 일 경우
141 | /**
142 | * 밑에는 위와 설명이 같습니다.
143 | */
144 | if (!guild[msg.guild.id]) return msg.reply(emptyGuild)
145 | if (guild[msg.guild.id].gambling === true) {
146 | let question = new Discord.MessageEmbed()
147 | .setDescription("정말로 이 서버에서 도박을 비활성화 하시겠습니까?")
148 | .setColor("7289DA")
149 | msg.reply(question).then(async message => {
150 | await message.react("✅")
151 | await message.react("❎")
152 | let filterYes = (reaction, user) => reaction.emoji.name === '✅' && user.id == msg.author.id
153 | let collectorYes = message.createReactionCollector(filterYes, { max: 1, time: 60000 })
154 | collectorYes.on('collect', () => {
155 | message.delete()
156 | let success = new Discord.MessageEmbed()
157 | .setDescription("성공적으로 이 서버에 도박 기능을 비활성화 하였습니다.")
158 | .setColor("7289DA")
159 | msg.reply(success)
160 | guild[msg.guild.id].gambling = false
161 | guild.save()
162 | })
163 | collectorYes.on('end', (_, reason) => {
164 | if (reason === "time") {
165 | message.delete()
166 | let timeover = new Discord.MessageEmbed()
167 | .setDescription("시간이 초과가 되었으니 다시 시도해주세요.")
168 | .setColor("RED")
169 | msg.reply(timeover)
170 | }
171 | })
172 | let filterNo = (reaction, user) => reaction.emoji.name === '❎' && user.id === msg.author.id
173 | let collectorNo = message.createReactionCollector(filterNo, { max: 1, time: 60000 })
174 |
175 | collectorNo.on('collect', () => {
176 | message.delete()
177 | let cancel = new Discord.MessageEmbed()
178 | .setDescription("도박 비활성화를 취소하였습니다.")
179 | .setColor("RED")
180 | msg.reply(cancel)
181 | })
182 | })
183 | } else if (guild[msg.guild.id].gambling === false) {
184 | let question = new Discord.MessageEmbed()
185 | .setDescription("정말로 이 서버에서 도박을 활성화 하시겠습니까?")
186 | .setColor("7289DA")
187 | msg.reply(question).then(async message => {
188 | await message.react("✅")
189 | await message.react("❎")
190 | let filterYes = (reaction, user) => reaction.emoji.name === '✅' && user.id == msg.author.id
191 | let collectorYes = message.createReactionCollector(filterYes, { max: 1, time: 60000 })
192 | collectorYes.on('collect', () => {
193 | message.delete()
194 | let success = new Discord.MessageEmbed()
195 | .setDescription("성공적으로 이 서버에 도박 기능을 활성화 하였습니다.")
196 | .setColor("7289DA")
197 | msg.reply(success)
198 | guild[msg.guild.id].gambling = true
199 | guild.save()
200 |
201 | })
202 | collectorYes.on('end', (_, reason) => {
203 | if (reason === "time") {
204 | message.delete()
205 | let timeover = new Discord.MessageEmbed()
206 | .setDescription("시간이 초과가 되었으니 다시 시도해주세요.")
207 | .setColor("RED")
208 | msg.reply(timeover)
209 | }
210 | })
211 | let filterNo = (reaction, user) => reaction.emoji.name === '❎' && user.id === msg.author.id
212 | let collectorNo = message.createReactionCollector(filterNo, { max: 1, time: 60000 })
213 |
214 | collectorNo.on('collect', () => {
215 | message.delete()
216 | let cancel = new Discord.MessageEmbed()
217 | .setDescription("도박 활성화를 취소하였습니다.")
218 | .setColor("RED")
219 | msg.reply(cancel)
220 | })
221 | })
222 | }
223 | break;
224 | default:
225 | msg.reply(empty)
226 | break;
227 | }
228 |
229 | }
230 |
231 | exports.config = {
232 | name: '설정',
233 | aliases: ['settings', ],
234 | category: ['database'],
235 | des: ['데이터베이스에 대한 설정을 합니다.'],
236 | use: ['튜토야 설정 <항목들>']
237 | }
--------------------------------------------------------------------------------
/6화/Commands/moderator/ban.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | var user = msg.mentions.users.first();
3 | if (!user) {
4 | msg.reply("차단하시기 전에 맨션을 먼저 해주세요!")
5 | } else {
6 | var member = msg.guild.member(user);
7 | if (member) {
8 | member.ban(`${msg.author.username}님의 의해 서버에서 추방됨.`).then(member => {
9 | msg.reply(`성공적으로 ${member.user.tag}님을 추방하였습니다.`)
10 | }).catch(msg.reply("해당 유저를 차단 할 권한이 없습니다."))
11 | } else {
12 | msg.reply("이 서버에 존재하지 않은 유저입니다!")
13 | }
14 | }
15 | }
16 |
17 | exports.config = {
18 | name: '차단',
19 | aliases: ['ban', '벤'],
20 | category: ['moderator'],
21 | des: ['유저를 해당 서버에서 차단 시킵니다.'],
22 | use: ['튜토야 차단 <유저 맨션>']
23 | }
--------------------------------------------------------------------------------
/6화/Commands/moderator/clear.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | if (!args[0]) return msg.reply("청소할 만큼의 값을 정수로 적어주세요!")
3 | if (!Number(args[0])) return msg.reply("메세지를 지울 값이 숫자가 아니면 안되요!")
4 | if (args[0] < 1) return msg.reply("메세지를 지울 값을 1보다 작게 하시면 안되요!")
5 | if (args[0] > 100) return msg.reply("메세지를 지울 값이 100보다 크면 메세지가 안지워져요!")
6 |
7 | msg.channel.bulkDelete(args[0]).then(msg.reply(`성공적으로 ${args[0]}개 만큼 메세지를 삭제하였습니다!`))
8 | }
9 |
10 | exports.config = {
11 | name: '청소',
12 | aliases: ['clear', 'clean'],
13 | category: ['moderator'],
14 | des: ['bulkdelete'],
15 | use: ['튜토야 청소 <청소 할 메세지의 수>']
16 | }
--------------------------------------------------------------------------------
/6화/Commands/moderator/kick.js:
--------------------------------------------------------------------------------
1 | exports.run = async (client, msg, args, prefix) => {
2 | var user = msg.mentions.users.first();
3 | if (!user) {
4 | msg.reply("추방하시기 전에 맨션을 먼저 해주세요!")
5 | } else {
6 | var member = msg.guild.member(user);
7 | if (member) {
8 | member.kick(`${msg.author.username}님의 의해 서버에서 추방됨.`).then(member => {
9 | msg.reply(`성공적으로 ${member.user.tag}님을 추방하였습니다.`)
10 | }).catch(msg.reply("해당 유저를 킥 할 권한이 없습니다."))
11 | } else {
12 | msg.reply("이 서버에 존재하지 않은 유저입니다!")
13 | }
14 | }
15 | }
16 |
17 | exports.config = {
18 | name: '추방',
19 | aliases: ['킥', 'kick'],
20 | category: ['moderator'],
21 | des: ['유저를 강제퇴장 시킵니다.'],
22 | use: ['튜토야 추방 <유저 맨션>']
23 | }
--------------------------------------------------------------------------------
/6화/README.MD:
--------------------------------------------------------------------------------
1 | ### 잠시 튜토리얼을 보시기 전 읽어주세요.
2 |
3 | 이번 6화 튜토리얼은 json을 활용하여 레벨링, 도박기능을 만들어볼려고 합니다!
4 | 이번에 필요한 모듈은 [self-reload-json](https://www.npmjs.com/package/self-reload-json) 입니다!
5 |
6 | 이번 설명이 약간 딱딱할 수 있습니다.
7 | 그래도 자세하게 설명해놨으니 꼭 주석처리 된 부분을 읽으셔서 해당 코드들을 이해해주시면 좋을꺼 같습니다!
8 |
9 | 살짝 알고리즘 관련으로 진행하는거니 참고하여 잘 따라와주시길 바랍니다 :D
10 |
11 |
12 | ### 추가 된 파일
13 |
14 | ./Commands/database (folder)
15 | ㄴ settings.js
16 | ㄴ registerGuild.js
17 | ㄴ gamble.js
18 | ㄴ money.js
19 |
20 | ./json (folder)
21 | ㄴ server.json
22 | ㄴ user.json
23 |
24 | ### 수정 된 파일
25 |
26 | main(bot).js
27 |
28 |
29 |
--------------------------------------------------------------------------------
/6화/bot.js:
--------------------------------------------------------------------------------
1 | const Discord = require("discord.js");
2 | const client = new Discord.Client();
3 | const fs = require('fs')
4 | const config = require("./config.json")
5 | const reload = require("self-reload-json")
6 | const guild = new reload("./json/server.json")
7 | const User = new reload("./json/user.json")
8 | client.on("ready", () => {
9 | console.log(`${client.user.tag} 봇에 로그인 하였습니다!`);
10 | });
11 | client.commands = new Discord.Collection()
12 | client.aliases = new Discord.Collection()
13 | client.devs = ['570617337691111444', "1234567890"]
14 | client.category = ['bot', 'crawling', 'moderator', 'owner', 'database']
15 | fs.readdirSync("./Commands/").forEach(dir => {
16 | const Filter = fs.readdirSync(`./Commands/${dir}`).filter(f => f.endsWith(".js"));
17 | Filter.forEach(file => {
18 | const cmd = require(`./Commands/${dir}/${file}`);
19 | client.commands.set(cmd.config.name, cmd)
20 | for (let alias of cmd.config.aliases) {
21 | client.aliases.set(alias, cmd.config.name)
22 | }
23 | })
24 | })
25 |
26 |
27 | function runCommand(command, msg, args, prefix) {
28 | if (client.commands.get(command) || client.aliases.get(command)) {
29 | const cmd = client.commands.get(command) || client.commands.get(client.aliases.get(command))
30 | if (cmd) cmd.run(client, msg, args, prefix);
31 | return
32 | }
33 | }
34 | client.on("message", async msg => {
35 | const prefix = "튜토야 "
36 | if (msg.author.bot) return;
37 | if (!msg.content.startsWith(prefix)) return;
38 | let args = msg.content.slice(prefix.length).trim().split(/ +/g)
39 | let command = args.shift().toLowerCase()
40 | try {
41 | runCommand(command, msg, args, prefix)
42 | } catch (e) {
43 | console.error(e)
44 | }
45 |
46 | })
47 |
48 | // 레벨링을 위하여 message 이벤트를 하나 더 생성함.
49 | client.on("message", async msg => {
50 | // User[msg.author.id]가 없을 경우
51 | if (!User[msg.author.id]) {
52 | User[msg.author.id] = {
53 | level: 1,
54 | money: 0,
55 | xp: 0
56 | }
57 | // User 저장
58 | User.save()
59 | }
60 |
61 | // 무작위숫자 함수
62 | function getRandomInt(min, max) {
63 | return Math.floor(Math.random() * (max - min)) + min;
64 | }
65 |
66 | // guild[msg.guild.id]가 없을 경우 return;
67 | if (!guild[msg.guild.id]) return;
68 |
69 | // guild[msg.guild.id].leveling == false일 경우 return;
70 | if (guild[msg.guild.id].leveling == false) return;
71 |
72 | // 유저의 경험치는 1,10까지 랜덤으로 획득
73 | User[msg.author.id].xp += getRandomInt(1, 10)
74 |
75 | // User 저장
76 | User.save()
77 |
78 | // 만약에 xp가 level * 75보다 클 경우
79 | if (User[msg.author.id].xp > User[msg.author.id].level * 75) {
80 |
81 | // xp = 0
82 | User[msg.author.id].xp = 0
83 |
84 | /**
85 | * level = level + 1
86 | *
87 | * level이 2였다면 3으로 오름.
88 | */
89 | User[msg.author.id].level = User[msg.author.id].level + 1
90 |
91 | // 랜덤으로 지급할 돈을 변수로 선언
92 | let money = getRandomInt(100, 500)
93 |
94 | // money = money + money <- 위에서 선언한 money
95 | User[msg.author.id].money = User[msg.author.id].money + money
96 | let levelup = new Discord.MessageEmbed()
97 | .setDescription(`당신은 ${User[msg.author.id].level}레벨로 레벨업 하였습니다!\n레벨업 보상으로 ${money}원을 지급하였습니다.`)
98 | .setColor("7289DA")
99 | msg.reply(levelup)
100 |
101 | // User 저장
102 | User.save()
103 | }
104 | })
105 |
106 | client.login(config.token)
--------------------------------------------------------------------------------
/6화/example.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "token": "your bot token!"
3 | }
--------------------------------------------------------------------------------
/6화/json/server.json:
--------------------------------------------------------------------------------
1 | {"620871538920521728":{"leveling":true,"gambling":true}}
--------------------------------------------------------------------------------
/6화/json/user.json:
--------------------------------------------------------------------------------
1 | {"708327173689442305":{"level":2,"money":443,"xp":121},"518729656749522956":{"level":4,"money":784,"xp":133},"570617337691111444":{"level":3,"money":1791,"xp":217},"578499535471378432":{"level":1,"money":0,"xp":9}}
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 제스퍼
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 디스코드 자바스크립트 튜토리얼에 오신 것을 환영합니다!
2 |
3 | [](https://www.codefactor.io/repository/github/ukong0324/discord-js-tutorial) [](https://app.codacy.com/manual/Ukong0324/Discord-JS-Tutorial?utm_source=github.com&utm_medium=referral&utm_content=Ukong0324/Discord-JS-Tutorial&utm_campaign=Badge_Grade_Dashboard)
4 |
5 | ## 튜토리얼 제작자
6 |
7 | **Discord: 제스퍼#0001**
8 | **Github: [UKong0324](https://github.com/Ukong0324)**
9 |
10 | 봇 개발에 쉬운 접근을 위해 제작하였으니 참고 바랍니다!
11 |
12 | ## 오타나 소스코드 지적은 언제나 환영합니다!
13 |
14 | DM이나 저를 맨션하는 것보다는 **Issues, Pull Requests**를 사용해주시면 감사합니다.
15 |
16 | **Pull Requests를 넣어주시면 제가 검토 후 "프로젝트에 도움을 주신 분들" 이라는 라인에 적어드리도록 하겠습니다.**
17 | ## 튜토리얼 방식에 대해 설명하겠습니다.
18 |
19 | ```
20 | 1화 2화 이런식으로 폴더별로 정리하여 올릴 예정입니다.
21 | 그리고 튜토리얼을 어디까지 진행할지 고민을 많이 하고 있습니다.
22 | 하지만 제가 가능한 선에서 알려드릴 수 있는 것들은 최대한 알려드릴테니 기대해주세요!
23 |
24 | 폴더 안에 MD 파일이 따로 있다면 꼭 읽어주세요!
25 | 초보분들이 쉽게 접근하실 수 있게 이미지들을 포함하여 올릴 예정입니다.
26 | ```
27 |
28 | Q: **튜토리얼은 어디까지 제작하시려나요?**
29 | A: **가능하면 웬만한 봇들이 가지고 있을법한 명령어들을 제작하고 이해하실 수 있도록 제작 해보려고 합니다.**
30 |
31 | Q: **혹시 지금까지 생각하신 부분은 어디까지 인가요?**
32 | A: **모듈을 활용하는 방법, 기초적인 크롤링, 데이터베이스 활용법, 뮤직 (Lavalink) 정도로 생각하고 있습니다.**
33 |
34 | ## 튜토리얼을 시작하시기 전에 잠깐 읽어주세요!
35 |
36 | 이 강의에서 초보분들을 중심으로 튜토리얼을 하는건 맞습니다.
37 | 하지만 이 강의에서는 디스코드 모듈 안에서 만들 수 있는 명령어들은 만들지 않으려고 합니다.
38 | 이외의 명령어 만드는 것에서는 많은 주석처리로 설명을 해놓을테니 잘 읽고 따라와주시면 좋을 것 같습니다.
39 |
40 | ## 이 강의는 GITHUB에도 있지만 구름 EDU에도 있습니다!
41 |
42 | [구름 EDU](https://edu.goorm.io/)에서도 강의를 하고 있으니 Github이 불편하시다면 [여기](https://edu.goorm.io/learn/lecture/20853/%EB%94%94%EC%8A%A4%EC%BD%94%EB%93%9C-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC)를 누르셔서 강의를 들으셔도 됩니다!
43 |
44 |
45 | ## 해당 프로젝트에 ⭐️을 눌러주신다면 저에게 큰 도움이 됩니다!
46 | **혹시나 튜토리얼을 같이 제작하고 싶으신 분들은 저에게 따로 디스코드 DM(PM)을 주시면 영광입니다!**
47 | [[서포트 채널]](https://discord.gg/WVKSnJr) | [[StayCute]](https://discord.gg/2UxaNp8)
48 |
49 | ## 프로젝트에 도움을 주신 분들
50 |
51 | [sannoob](https://github.com/sannoob) | [SaidBySolo](https://github.com/SaidBySolo) | [vendetta-team](https://github.com/vendetta-team) | [제로 | Brazil](https://github.com/zero734kr) | [AkiaCode](https://github.com/AkiaCode) | [Goolgae](https://github.com/Goolgae) | [MintyU](https://github.com/MintyU) | [MadeGOD](https://github.com/MadeGOD)
52 |
--------------------------------------------------------------------------------
/읽어보면 좋은것들/README.md:
--------------------------------------------------------------------------------
1 | # 이 문서는 자바스크립트 개발을 하면서 궁금했던 점이나, 유용한 것들을 정리해 놓은 문서입니다
2 |
3 | ## 자바스크립트 const, let, var 차이점
4 | [LeoHeo 님의 문서](https://gist.github.com/LeoHeo/7c2a2a6dbcf80becaaa1e61e90091e5d)
5 | [bathingape 님의 문서](https://velog.io/@bathingape/JavaScript-var-let-const-%EC%B0%A8%EC%9D%B4%EC%A0%90)
6 |
7 | ## 자바스크립트 개발자라면 알아야 할 33가지의 개념 (번역본)
8 | [33concepts-of-javascript](https://velog.io/@jakeseo_me/series/33conceptsofjavascript)
9 |
10 | ## 클린한 코드
11 |
12 | [[번역판] CLEAN CODE JAVASCRIPT](https://edu.goorm.io/learn/lecture/20119/%EB%B2%88%EC%97%AD%ED%8C%90-clean-code-javascript)
13 |
14 | ## 노드 사용에 좋은 습관들
15 | - [원문](https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md)
16 | - [부분 번역판](https://github.com/goldbergyoni/nodebestpractices/blob/master/README.korean.md)
17 |
18 | 대부분 사이트 쪽과 관련된 내용을 담고 있으나 필요한 부분만 참고하시면 좋습니다
19 |
20 | ## 문제 검색
21 | [Stackoverflow](https://stackoverflow.com)
22 |
23 | * 추후 더 다양한 문서들이 추가될 예정입니다
24 |
--------------------------------------------------------------------------------