UNPKG

75.6 kBMarkdownView Raw
1# API
2
3 - [Introduction](#introduction)
4
5---
6
7 - [miniplug(opts)](#mp-constructor)
8 - [mp.connect({ email, password })](#mp-connect)
9 - [mp.use(plugin)](#mp-use)
10
11 - Room methods
12 - [mp.join(room)](#mp-join)
13 - [mp.room()](#mp-room)
14 - [mp.getRooms(query, page, limit)](#mp-getrooms)
15 - [mp.getFavorites(query, page, limit)](#mp-getfavorites)
16 - [mp.getMyRooms()](#mp-getmyrooms)
17 - [mp.validateRoomName(name)](#mp-validateroomname)
18 - [mp.createRoom(name, isPrivate)](#mp-createroom)
19 - [mp.favoriteRoom(id)](#mp-favoriteroom)
20 - [mp.unfavoriteRoom(id)](#mp-unfavoriteroom)
21 - [mp.getRoomState()](#mp-getroomstate)
22 - User methods
23 - [mp.me()](#mp-me)
24 - [mp.user(id)](#mp-user)
25 - [mp.userByName(name)](#mp-userbyname)
26 - [mp.users()](#mp-users)
27 - [mp.guests()](#mp-guests)
28 - [mp.getMe()](#mp-getme)
29 - [mp.getUser(id)](#mp-getuser)
30 - [mp.getUsers(...ids)](#mp-getusers)
31 - [mp.saveSettings(settings)](#mp-savesettings)
32 - [mp.setAvatar(avatar)](#mp-setavatar)
33 - [mp.setBadge(badge)](#mp-setbadge)
34 - [mp.setBlurb(blurb)](#mp-setblurb)
35 - [mp.setLanguage(lang)](#mp-setlanguage)
36 - [mp.getTransactions()](#mp-gettransactions)
37 - Booth and waitlist methods
38 - [mp.score()](#mp-score)
39 - [mp.vote(direction)](#mp-vote)
40 - [mp.woot()](#mp-woot)
41 - [mp.meh()](#mp-meh)
42 - [mp.dj()](#mp-dj)
43 - [mp.waitlist()](#mp-waitlist)
44 - [mp.joinWaitlist()](#mp-joinwaitlist)
45 - [mp.leaveWaitlist()](#mp-leavewaitlist)
46 - [mp.isCycling()](#mp-iscycling)
47 - [mp.setCycle(cycle)](#mp-setcycle)
48 - [mp.enableCycle()](#mp-enablecycle)
49 - [mp.disableCycle()](#mp-disablecycle)
50 - [mp.isLocked()](#mp-islocked)
51 - [mp.setLock(lock)](#mp-setlock)
52 - [mp.lockWaitlist()](#mp-lockwaitlist)
53 - [mp.unlockWaitlist()](#mp-unlockwaitlist)
54 - [mp.addDJ(uid)](#mp-adddj)
55 - [mp.moveDJ(uid, position)](#mp-movedj)
56 - [mp.removeDJ(uid)](#mp-removedj)
57 - [mp.getWaitlistBans()](#mp-getwaitlistbans)
58 - [mp.waitlistBan(uid, duration, reason)](#mp-waitlistban)
59 - [mp.waitlistUnban(uid)](#mp-waitlistunban)
60 - History methods
61 - [mp.historyEntry()](#mp-historyentry)
62 - [mp.getRoomHistory()](#mp-getroomhistory)
63 - [mp.getUserHistory(uid)](#mp-getuserhistory)
64 - Chat methods
65 - [mp.chat(message)](#mp-chat)
66 - [mp.emote(message)](#mp-emote)
67 - [mp.getChatHistory()](#mp-getchathistory)
68 - [mp.deleteChat(id)](#mp-deletechat)
69 - Playlist methods
70 - [mp.getPlaylists()](#mp-getplaylists)
71 - [mp.getActivePlaylist()](#mp-getactiveplaylist)
72 - [mp.createPlaylist(name)](#mp-createplaylist)
73 - [mp.deletePlaylist(id)](#mp-deleteplaylist)
74 - [mp.activatePlaylist(id)](#mp-activateplaylist)
75 - [mp.renamePlaylist(id, name)](#mp-renameplaylist)
76 - [mp.shufflePlaylist(id)](#mp-shuffleplaylist)
77 - [mp.getMedia(id)](#mp-getmedia)
78 - [mp.updateMedia(pid, mid, author, title)](#mp-updatemedia)
79 - [mp.moveMedia(pid, mids, before)](#mp-movemedia)
80 - [mp.insertMedia(id, media, append)](#mp-insertmedia)
81 - [mp.deleteMedia(pid, mids)](#mp-deletemedia)
82 - Store methods
83 - [mp.getProducts(type, category)](#mp-getproducts)
84 - [mp.getStoreAvatars(category)](#mp-getstoreavatars)
85 - [mp.getStoreBadges(category)](#mp-getstorebadges)
86 - [mp.getStoreMisc(category)](#mp-getstoremisc)
87 - [mp.getInventory(type)](#mp-getinventory)
88 - [mp.getOwnedAvatars()](#mp-getownedavatars)
89 - [mp.getOwnedBadges()](#mp-getownedbadges)
90 - [mp.purchase(product)](#mp-purchase)
91 - [mp.validateUsername(name)](#mp-validateusername)
92 - [mp.purchaseNameChange(username)](#mp-purchasenamechange)
93 - Notification methods
94 - [mp.notifications()](#mp-notifications)
95 - [mp.getNotifications()](#mp-notifications)
96 - [mp.acknowledgeNotification(id)](#mp-notifications)
97 - Classes
98 - [Room](#class-room)
99 - [User](#class-user)
100 - [Waitlist](#class-waitlist)
101 - [WaitlistBan](#class-waitlistban)
102 - [ChatMessage](#class-chatmessage)
103 - [Playlist](#class-playlist)
104 - [Media](#class-media)
105 - [HistoryEntry](#class-historyentry)
106 - [StoreProduct](#class-storeproduct)
107 - [InventoryProduct](#class-inventoryproduct)
108 - [Notification](#class-notification)
109 - [User Roles](#role)
110 - [Mute Durations](#muteduration)
111 - [Mute Reasons](#mutereason)
112 - [Ban Durations](#banduration)
113 - [Ban Reasons](#banreason)
114 - [Media Sources](#mediasource)
115 - [Product Categories](#productcategories)
116 - [REST methods](#mp-rest)
117 - [WebSocket](#mp-ws)
118 - [Events](#events)
119 - [Errors](#errors)
120
121## Introduction
122
123The miniplug API is heavily Promise-based. Most methods return Promises.
124
125miniplug uses the [Bluebirdish][] library. Bluebirdish implements methods from
126the Bluebird library on top of native Promises. That means that Promises
127returned by miniplug have many of the useful methods from Bluebird, too. See its
128[API reference][Bluebird API] for documentation, and the [Bluebirdish Readme][]
129for a list of available methods.
130
131Promises work really well with JavaScript [async functions][]. Async functions
132are available in Node.js in versions 8 and up. If you are using an older
133version, you can compile async functions to generator functions, which are
134widely supported, using [async-to-gen][], or using [Babel][] with the
135[babel-plugin-transform-async-to-generator][async-to-generator] transform. If
136you do not want a build step, you can use the [Bluebird .coroutine][coroutine]
137method to write similar-looking code with generator functions.
138
139Some miniplug methods don't return Promises, but return their result
140immediately. By convention, miniplug method names that are nouns (such as
141`room()`, or `user()`) return immediately. Method names that are verbs (like
142`getRooms()`, or `getUser()`) return Promises, and usually fetch new data from
143the plug.dj API.
144
145[Bluebirdish]: https://github.com/goto-bus-stop/bluebirdish
146[Bluebirdish Readme]: https://github.com/goto-bus-stop/bluebirdish#readme
147[Bluebird API]: http://bluebirdjs.com/docs/api-reference.html
148[async functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
149[Babel]: https://babeljs.io
150[async-to-gen]: https://github.com/leebyron/async-to-gen
151[async-to-generator]: https://babeljs.io/docs/plugins/transform-async-to-generator/
152[coroutine]: http://bluebirdjs.com/docs/api/promise.coroutine.html
153
154<a id="mp-constructor"></a>
155## mp = miniplug(opts={})
156
157Create a miniplug instance.
158
159 - `opts.host` - The plug.dj host to use, defaults to `https://plug.dj/`.
160 This can be changed for mocking or to run on a plug.dj subdomain like `stg.`.
161
162Note that a miniplug instance is not very useful until you open a
163[connection](#mp-connect) to plug.dj.
164
165```js
166const miniplug = require('miniplug')
167
168const mp = miniplug()
169```
170
171<a id="mp-connect"></a>
172## mp.connect(opts): Promise&lt;this>
173
174Connect to plug.dj. Available options:
175
176 - `opts.guest` - If true, will log in as a guest user. Defaults to false.
177 - `opts.email` and `opts.password` - Login credentials. Only email/password
178 login is supported and support for Facebook login is not currently planned.
179
180```js
181const mp = miniplug()
182mp.connect({ guest: true }).catch(() => {
183 // failed
184})
185```
186
187```js
188const mp = miniplug()
189mp.connect({
190 email: 'example@test.com',
191 password: 'hunter2'
192}).catch(() => {
193 // failed
194})
195```
196
197This method returns `this` so you can use async/await syntax to do:
198
199```js
200async function main () {
201 const mp = await miniplug().connect({ /* ... */ })
202}
203```
204
205<a id="mp-use"></a>
206## mp.use(plugin)
207
208Add a plugin to enhance miniplug's functionality. Returns the miniplug instance
209for chaining.
210
211```js
212const lotteryPlugin = require('miniplug-lottery')
213
214mp.use(lotteryPlugin())
215 .use((instance) => { /* Add other custom methods to `instance` */ })
216```
217
218<a id="mp-join"></a>
219## mp.join(room): Promise
220
221Join a room. The parameter is the room's slug. If your room URL is
222`https://plug.dj/loves-kpop`, the slug is `loves-kpop`.
223
224```js
225mp.join('loves-kpop').then(() => {
226 mp.chat('Hello!')
227})
228```
229
230It returns the Room object so you can do:
231
232```js
233const room = await mp.join('my-fav-room')
234```
235
236<a id="mp-room"></a>
237## mp.room(): [Room](#class-room)
238
239Get the current room object.
240
241```js
242console.log('I am in:', mp.room().name)
243```
244
245<a id="mp-getrooms"></a>
246## mp.getRooms(query='', page=0, limit=50): Promise&lt;Array&lt;[Room](#class-room)>>
247
248List open rooms, like on the plug.dj dashboard.
249
250`query` is a search query. `page` and `limit` can be used for pagination.
251
252```js
253mp.getRooms('reggae').then((rooms) => {
254 rooms.forEach((room) => {
255 console.log(room.name)
256 })
257})
258```
259
260<a id="mp-getfavorites"></a>
261## mp.getFavorites(query='', page=0, limit=50): Promise&lt;Array&lt;[Room](#class-room)>>
262
263List the current user's favorites.
264
265`query` is a search query. `page` and `limit` can be used for pagination.
266
267<a id="mp-getmyrooms"></a>
268## mp.getMyRooms(): Promise&lt;Array&lt;[Room](#class-room)>>
269
270List the rooms created by the current user.
271
272```js
273console.log('Your rooms:')
274mp.getMyRooms().each((room) => {
275 console.log(`https://plug.dj/${room.slug}: ${room.name}`)
276})
277```
278
279<a id="mp-validateroomname"></a>
280## mp.validateRoomName(name): Promise&lt;{slug: string}>
281
282Check if a room name is valid and available. Returns a Promise that resolves
283with an object containing the room's `slug` if the name is valid and available,
284and rejects if the name is invalid or unavailable.
285
286```js
287mp.validateRoomName('Tastycat')
288 .then((o) => console.log('Room is available with slug:', o.slug))
289 .catch((err) => console.log(err.message))
290```
291
292<a id="mp-createroom"></a>
293## mp.createRoom(name, isPrivate = false): Promise&lt;[Room](#class-room)>
294
295Create a new room. Note that plug.dj will derive an unchangeable URL slug from
296the name. This slug may collide with existing rooms.
297
298```js
299mp.createRoom('My private test room!', true).then((room) => {
300 return room.favorite()
301})
302```
303
304<a id="mp-favoriteroom"></a>
305## mp.favoriteRoom(id): Promise
306
307Add a room to the bot user's favorites.
308
309```js
310mp.favoriteRoom(123456).then(() => {
311 console.log('Added!')
312})
313```
314
315<a id="mp-unfavoriteroom"></a>
316## mp.unfavoriteRoom(id): Promise
317
318Remove a room from the bot user's favorites.
319
320```js
321mp.unfavoriteRoom(123456).then(() => {
322 console.log('Removed!')
323})
324```
325
326<a id="mp-getroomstate"></a>
327## mp.getRoomState(): Promise&lt;object>
328
329Get the current room object, but fresh from the plug.dj API and not cached. It
330returns the object from plug.dj's [`/_/rooms/state`][rooms/state] endpoint.
331
332Using other API methods like [mp.room()](#mp-room) should be preferred whenever
333possible.
334
335[rooms/state]: https://github.com/plugcommunity/documentation/blob/master/api/endpoints/rooms_state.md
336
337<hr>
338
339<a id="mp-me"></a>
340## mp.me(): [User](#class-user)
341
342Get the current logged-in user. Will be `null` when logged in as a guest user.
343
344```js
345console.log('Logged in as', mp.me().username)
346```
347
348<a id="mp-user"></a>
349## mp.user(id): [User](#class-user)
350
351Synchronously get a user object from the current room. Returns `null` if the
352requested user is not in the room.
353
354```js
355console.log('Some other user:', mp.user(123456).username)
356```
357
358<a id="mp-userbyname"></a>
359## mp.userByName(name): [User](#class-user)
360
361Synchronously get a user object from the current room, identified by the username.
362Returns `null` if the requested user is not in the room.
363
364Usernames are case sensitive.
365
366```js
367// An `!id` command that shows a user's ID
368// Usage: `!id @Username`, eg `!id @Tastybot`
369mp.on('chat', (message) => {
370 if (message.startsWith('!id @')) {
371 const name = message.slice(5)
372 const user = mp.userByName(name)
373 if (user) {
374 message.reply(`${user.mention()}'s ID is ${user.id}`)
375 } else {
376 message.reply(`I don't know the user "${name}"`)
377 }
378 }
379})
380```
381
382<a id="mp-users"></a>
383## mp.users(): Array&lt;[User](#class-user)>
384
385Synchronously get all user objects from the current room.
386
387```js
388console.log('Users:', mp.users().map((user) => user.username))
389```
390
391<a id="mp-guests"></a>
392## mp.guests(): number
393
394Get the number of guests in the current room.
395
396<a id="mp-getme"></a>
397## mp.getMe(): Promise&lt;[User](#class-user)>
398
399Get the current logged-in user from the plug.dj web API. [mp.me()](#mp-me)
400should be used instead whenever possible.
401
402<a id="mp-getuser"></a>
403## mp.getUser(id): Promise&lt;[User](#class-user)>
404
405Get a user object by ID. The user does not have to be in the same room as the
406bot.
407
408<a id="mp-getusers"></a>
409## mp.getUsers(...ids): Promise&lt;Array&lt;[User](#class-user)>>
410
411Get multiple users. User IDs can be passed in an array or as separate arguments.
412Up to 50 user objects can be requested at a time.
413
414```js
415mp.getUsers(123456, 654321).then((users) => {
416 console.log('Found:', users)
417})
418```
419
420<a id="mp-savesettings"></a>
421## mp.saveSettings(settings): Promise
422
423Save user settings. See the [PlugCommunity documentation](https://github.com/plugcommunity/documentation/blob/master/api/endpoints/users_settings.md#parameters)
424for a list of available settings.
425
426<a id="mp-setavatar"></a>
427## mp.setAvatar(avatar): Promise
428
429Set the bot user's avatar.
430
431<a id="mp-setbadge"></a>
432## mp.setBadge(badge): Promise
433
434Set the bot user's badge.
435
436<a id="mp-setblurb"></a>
437## mp.setBlurb(blurb): Promise
438
439Set the bot user's profile blurb / bio.
440
441<a id="mp-setlanguage"></a>
442## mp.setLanguage(lang): Promise
443
444Set the bot user's language preference.
445
446<a id="mp-gettransactions"></a>
447## mp.getTransactions(): Promise&lt;Array>
448
449Get the bot user's transaction history.
450
451<hr>
452
453<a id="mp-score"></a>
454## mp.score(): {positive, negative, grabs, listeners}
455
456Get the score for the currently playing media.
457
458Returns an object with properties:
459
460 - `positive` - Amount of woots.
461 - `negative` - Amount of mehs.
462 - `grabs` - Amount of grabs.
463 - `listeners` - Amount of listeners.
464
465```js
466const score = mp.score()
467mp.chat(`Score: ${score.positive} woots - ${score.negative} mehs - ${score.grabs} grabs`)
468```
469
470<a id="mp-vote"></a>
471## mp.vote(direction): Promise
472
473Vote on the currently playing media.
474
475`direction` is 1 for woot, -1 for meh.
476
477```js
478const direction = Math.random() < 0.5 ? -1 : 1
479mp.vote(direction)
480```
481
482<a id="mp-woot"></a>
483## mp.woot(): Promise
484
485Woot the currently playing media.
486
487```js
488mp.woot().then(() => {
489 mp.chat('Great track! Wooted!')
490})
491```
492
493<a id="mp-meh"></a>
494## mp.meh(): Promise
495
496Meh the currently playing media.
497
498```js
499mp.meh().then(() => {
500 mp.chat('Ew, I don\'t like this. :(')
501})
502```
503
504<hr>
505
506<a id="mp-dj"></a>
507## mp.dj(): [User](#class-user)
508
509Get the current DJ. Returns `null` if there is no DJ.
510
511```js
512mp.dj().chat('Nice play!')
513// → "@Username Nice play!"
514```
515
516<a id="mp-waitlist"></a>
517## mp.waitlist(): [Waitlist](#class-waitlist)
518
519Get the current waitlist. A [Waitlist](#class-waitlist) object is a JavaScript
520array containing [User](#class-user) objects, so the typical JavaScript array
521methods can be used:
522
523```js
524mp.waitlist().forEach((user, position) => {
525 console.log(`#${position + 1} - ${user.username}`)
526})
527```
528
529There are also some additional methods:
530
531```js
532// By user ID
533mp.waitlist().contains(762534)
534// or by user object.
535mp.waitlist().contains(mp.me())
536
537mp.waitlist().positionOf(mp.me())
538```
539
540<a id="mp-joinwaitlist"></a>
541## mp.joinWaitlist(): Promise
542
543Join the waitlist.
544
545<a id="mp-leavewaitlist"></a>
546## mp.leaveWaitlist(): Promise
547
548Leave the waitlist.
549
550<a id="mp-iscycling"></a>
551## mp.isCycling(): bool
552
553Check if waitlist cycling is enabled. If enabled, users automatically rejoin the
554waitlist after their play.
555
556<a id="mp-setcycle"></a>
557## mp.setCycle(cycle): Promise
558
559Change whether the waitlist should cycle.
560
561```js
562// Disable waitlist cycle when there are 20 or more DJs.
563mp.on('waitlistUpdate', (waitlist) => {
564 if (waitlist.length < 20) {
565 mp.setCycle(true)
566 } else {
567 mp.setCycle(false)
568 }
569})
570```
571
572<a id="mp-enablecycle"></a>
573## mp.enableCycle(): Promise
574
575Enable waitlist cycle. Shorthand to <code>[setCycle](#mp-setcycle)(true)</code>.
576
577<a id="mp-disablecycle"></a>
578## mp.disableCycle(): Promise
579
580Disable waitlist cycle. Shorthand to <code>[setCycle](#mp-setcycle)(false)</code>.
581
582<a id="mp-islocked"></a>
583## mp.isLocked(): bool
584
585Check if the waitlist is locked. If the waitlist is locked, only Resident DJs
586and up can join.
587
588<a id="mp-setlock"></a>
589## mp.setLock(lock): Promise
590
591Change whether normal users can join the waitlist. If the waitlist is locked,
592only Resident DJs and up can join.
593
594```js
595mp.setLock(true).then(() => {
596 mp.chat('Sorry! Only staff can join the waitlist at the moment.')
597})
598```
599
600<a id="mp-lockwaitlist"></a>
601## mp.lockWaitlist(): Promise
602
603Lock the waitlist, preventing users from joining.
604Shorthand to <code>[setLock](#mp-setlock)(true)</code>.
605
606<a id="mp-unlockwaitlist"></a>
607## mp.unlockWaitlist(): Promise
608
609Unlock the waitlist, allowing everyone to join.
610Shorthand to <code>[setLock](#mp-setlock)(false)</code>.
611
612<a id="mp-adddj"></a>
613## mp.addDJ(uid): Promise
614
615Add a user to the end of the waitlist. `uid` is the user's ID.
616
617<a id="mp-movedj"></a>
618## mp.moveDJ(uid, position): Promise
619
620Move a user in the waitlist. `uid` is the user's ID. `position` is the target
621position, starting at 0.
622
623```js
624// Add a user to position #2 in the waitlist.
625mp.addDJ(123456).then(() => {
626 return mp.moveDJ(123456, 1)
627})
628```
629
630<a id="mp-removedj"></a>
631## mp.removeDJ(uid): Promise
632
633Remove a user from the waitlist. `uid` is the user's ID.
634
635```js
636const user = mp.user(123456)
637mp.removeDJ(user.id).then(() => {
638 return user.chat('I removed you from the waitlist. Sorry! 🙈')
639})
640```
641
642<a id="mp-getwaitlistbans"></a>
643## mp.getWaitlistBans(): Promise&lt;Array&lt;[WaitlistBan](#class-waitlistban)>>
644
645Get a list of current Waitlist Bans.
646
647```js
648mp.getWaitlistBans().then((list) => {
649 list.forEach((ban) => {
650 console.log(`${ban.user.mention()} was banned from the waitlist by ${ban.moderatorName}`)
651 })
652})
653```
654
655<a id="mp-waitlistban"></a>
656## mp.waitlistBan(uid, duration, reason): Promise
657
658Ban a user from the waitlist.
659`uid` is the ID of the user to ban from the waitlist.
660`duration` is a [WAITLIST_BAN_DURATION](#waitlistbanduration).
661`reason` is a [WAITLIST_BAN_REASON](#waitlistbanreason).
662
663```js
664const user = mp.userByName('AnnoyingUser')
665mp.waitlistBan(user.id, WAITLIST_BAN_DURATION.PERMA, WAITLIST_BAN_REASON.GENRE).then(() => {
666 console.log('Banned', user.mention())
667})
668```
669
670<a id="mp-waitlistunban"></a>
671## mp.waitlistUnban(uid): Promise
672
673Unban a previously waitlist-banned user.
674`uid` is the ID of the user to unban.
675
676```js
677mp.getWaitlistBans().each((ban) => {
678 return mp.waitlistUnban(ban.user.id)
679}).then(() => {
680 console.log('Unbanned _everyone_! har har')
681})
682```
683
684<hr>
685
686<a id="mp-historyentry"></a>
687## mp.historyEntry(): [HistoryEntry](#class-historyentry)
688
689Get the current history entry. When no song is being played, returns `null`.
690
691```js
692const entry = mp.historyEntry()
693if (/nightcore/i.test(entry.title)) {
694 entry.skip()
695}
696```
697
698<a id="mp-getroomhistory"></a>
699## mp.getRoomHistory(): Promise&lt;Array&lt;[HistoryEntry](#class-historyentry)>>
700
701Get the 25 most recent plays in the current room.
702
703```js
704mp.on('advance', (next) => {
705 // Check the room history for recent plays.
706 mp.getRoomHistory().then((history) => {
707 // If one of the entries is the same as the currently playing song, skip it!
708 const isSameEntry = (entry) => entry.media.cid === next.media.cid
709 if (history.some(isSameEntry)) {
710 next.user.chat('This track was played recently.')
711 next.skip()
712 }
713 })
714})
715```
716
717<a id="mp-getuserhistory"></a>
718## mp.getUserHistory(uid): Promise&lt;Array&lt;[HistoryEntry](#class-historyentry)>>
719
720Get the 25 most recent plays by a user. `uid` is the user's ID.
721
722```js
723mp.on('userJoin', (user) => {
724 mp.getUserHistory(user).then((history) => {
725 if (history.some((entry) => /The Koxx/i.test(entry.media.artist))) {
726 user.chat('Welcome! You played excellent music recently!')
727 }
728 })
729})
730```
731
732<hr>
733
734<a id="mp-chat"></a>
735## mp.chat(message): Promise&lt;[ChatMessage](#class-chatmessage)>
736
737Send a chat message. Returns a Promise that will resolve with the message once
738it is sent.
739
740```js
741const delay = require('delay')
742
743// Send a temporary greeting that is deleted after 5 seconds.
744// Note that the bot user needs to have the appropriate staff permissions to be
745// able to delete its own messages.
746mp.chat('Hello!')
747 .then(delay(5000)) // Using the `delay` module from npm
748 .then((message) => message.delete())
749```
750
751<a id="mp-emote"></a>
752## mp.emote(message): Promise&lt;[ChatMessage](#class-chatmessage)>
753
754Send an emote chat message, like `/me` or `/em` on the plug.dj web client.
755
756```js
757mp.emote('does a little dance')
758 .then((message) => { /* Resolves to the message, just like mp.chat(). */ })
759```
760
761<a id="mp-getchathistory"></a>
762## mp.getChatHistory(): Promise&lt;Array&lt;[ChatMessage](#class-ChatMessage)>>
763
764Get the 30 most recent chat messages, including messages that were sent before
765the bot user joined the room.
766
767```js
768mp.getChatHistory().then((messages) => {
769 messages.forEach((message) => {
770 console.log(`<${message.un}> ${message.message}`)
771 })
772})
773```
774
775<a id="mp-deletechat"></a>
776## mp.deleteChat(id): Promise
777
778Delete a chat message by ID.
779
780```js
781// Delete all incoming chat:
782mp.on('chat', (message) => {
783 mp.deleteChat(message.cid)
784})
785```
786
787<hr>
788
789<a id="mp-getplaylists"></a>
790## mp.getPlaylists(): Promise&lt;Array&lt;[Playlist](#class-playlist)>>
791
792Get all the user's playlists.
793
794```js
795const each = require('p-each-series')
796
797each(mp.getPlaylists(), (playlist) => {
798 console.log(`${playlist.name} (${playlist.count})`)
799})
800```
801
802<a id="mp-getactiveplaylist"></a>
803## mp.getActivePlaylist(): Promise&lt;[Playlist](#class-playlist)>
804
805Get the user's active playlist.
806
807```js
808mp.getActivePlaylist().then((playlist) => {
809 return playlist.insert({
810 format: mp.MEDIA_SOURCE.YOUTUBE,
811 cid: 'UT4zZzAtWm4',
812 author: 'Ovcoco',
813 title: 'Your Ghost',
814 duration: 209,
815 image: 'https://i.ytimg.com/vi/UT4zZzAtWm4/default.jpg'
816 })
817})
818```
819
820<a id="mp-createplaylist"></a>
821## mp.createPlaylist(name): Promise&lt;[Playlist](#class-playlist)>
822
823Create a new playlist.
824
825```js
826mp.createPlaylist('Test playlist').then((playlist) => {
827 return Promise.all([
828 playlist.insert([
829 // your favourite songs
830 ]),
831 playlist.activate()
832 ])
833})
834```
835
836<a id="mp-deleteplaylist"></a>
837## mp.deletePlaylist(id): Promise
838
839Permanently delete a playlist by ID.
840
841Alias: [`playlist.delete()`](#playlist-delete)
842
843<a id="mp-activateplaylist"></a>
844## mp.activatePlaylist(id): Promise
845
846Set a playlist to active by ID.
847
848Alias: [`playlist.activate()`](#playlist-activate)
849
850<a id="mp-renameplaylist"></a>
851## mp.renamePlaylist(id, name): Promise
852
853Rename a playlist.
854
855Alias: [`playlist.rename(name)`](#playlist-rename)
856
857<a id="mp-shuffleplaylist"></a>
858## mp.shufflePlaylist(id): Promise&lt;Array&lt;[Media](#class-media)>
859
860Shuffle a playlist. Returns a Promise that resolves with the shuffled media
861items.
862
863Alias: [`playlist.shuffle()`](#playlist-shuffle)
864
865<a id="mp-getmedia"></a>
866## mp.getMedia(id): Promise&lt;Array&lt;[Media](#class-media)>
867
868Get the media items in a playlist.
869
870Alias: [`playlist.getMedia()`](#playlist-getmedia)
871
872<a id="mp-updatemedia"></a>
873## mp.updateMedia(pid, mid, author, title): Promise&lt;{author, title}>
874
875Update the author and title tags of a media item. Returns a Promise that
876resolves with the new actual author and title as used by plug.dj, with HTML
877escapes.
878
879```js
880mp.updateMedia(playlist.id, media.id, 'Test Author', '& Test Title').then(({ author, title }) => {
881 // author == "Test Author"
882 // title == "&amp; Test Title"
883})
884```
885
886Alias: [`media.update(author, title)`](#media-update)
887
888<a id="mp-movemedia"></a>
889## mp.moveMedia(pid, mids, before): Promise
890
891Move existing media items to a different position in the playlist.
892
893Alias: [`playlist.move()`](#playlist-move)
894
895<a id="mp-insertmedia"></a>
896## mp.insertMedia(id, media, append=true): Promise
897
898Insert new media items into a playlist.
899
900Alias: [`playlist.insert()`](#playlist-insert)
901
902<a id="mp-deletemedia"></a>
903## mp.deleteMedia(pid, mids): Promise&lt;Array&lt;[Media](#class-media)>
904
905Alias: [`media.delete()`](#media-delete)
906
907<hr>
908
909<a id="mp-getproducts"></a>
910## mp.getProducts(type, category='all'): Promise&lt;[StoreProduct](#class-storeproduct)>
911
912Get the product listing from a store category. `type` is one of 'avatars',
913'badges' or 'misc'. `category` selects a specific category, like a page in the
914store. See [Product Categories](#productcategories) for an overview of available
915categories for each product type.
916
917```js
918const randomItem = require('random-item')
919mp.getProducts('avatars', 'island').then((products) => {
920 return randomItem(products).purchase()
921})
922```
923
924<a id="mp-getstoreavatars"></a>
925## mp.getStoreAvatars(category='all'): Promise&lt;[StoreProduct](#class-storeproduct)>
926
927Get the avatars store listing. Shorthand to `getProducts('avatars', category)`.
928
929<a id="mp-getstorebadges"></a>
930## mp.getStoreBadges(category='all'): Promise&lt;[StoreProduct](#class-storeproduct)>
931
932Get the badges store listing. Shorthand to `getProducts('badges', category)`.
933
934<a id="mp-getstoremisc"></a>
935## mp.getStoreMisc(category='all'): Promise&lt;[StoreProduct](#class-storeproduct)>
936
937Get the miscellaneous store listing. Shorthand to `getProducts('misc', category)`.
938
939<a id="mp-getinventory"></a>
940## mp.getInventory(type): Promise&lt;[InventoryProduct](#class-inventoryproduct)>
941
942Get the products purchased by the user.
943
944<a id="mp-getownedavatars"></a>
945## mp.getOwnedAvatars(): Promise&lt;[InventoryProduct](#class-inventoryproduct)>
946
947Get the avatars purchased by the user.
948
949<a id="mp-getownedbadges"></a>
950## mp.getOwnedBadges(): Promise&lt;[InventoryProduct](#class-inventoryproduct)>
951
952Get the badges purchased by the user.
953
954<a id="mp-purchase"></a>
955## mp.purchase(product): Promise
956
957Purchase an avatar or a badge. `product` is a product ID, or a
958[StoreProduct](#class-storeproduct).
959
960<a id="mp-validateusername"></a>
961## mp.validateUsername(name): Promise&lt;{slug: string}>
962
963Check if a user name is valid and available. Returns a Promise that resolves
964with an object containing the new profile `slug` if the name is valid and
965available, and rejects if the name is invalid or unavailable.
966
967```js
968mp.validateUsername('Burkes')
969 .then((o) => console.log('Username is available with slug:', o.slug))
970 .catch((err) => console.log(err.message))
971```
972
973<a id="mp-purchasenamechange"></a>
974## mp.purchaseNameChange(username): Promise
975
976Purchase a name change.
977
978<hr>
979
980<a id="mp-notifications"></a>
981## mp.notifications(): Array&lt;[Notification](#class-notification)>
982
983Get a list of current notifications.
984
985```js
986// Acknowledge all notifications.
987const promises = mp.notifications().map((notif) => {
988 return notif.acknowledge()
989})
990
991// Wait for all acknowledgements to go through.
992Promise.all(promises).then(() => {
993 console.log('All clear!')
994})
995```
996
997<a id="mp-notifications"></a>
998## mp.getNotifications(): Promise&lt;Array&lt;[Notification](#class-notification)>>
999
1000Get current notifications from the plug.dj Web API. Normally
1001[mp.notifications()](#mp-notifications) should be preferred instead, because
1002it's instant.
1003
1004<a id="mp-notifications"></a>
1005## mp.acknowledgeNotification(id): Promise
1006
1007Acknowledge and remove a notification. `id` is the numeric unique ID of the
1008notification.
1009
1010<hr>
1011
1012<a id="class-room"></a>
1013## Room
1014
1015### Properties
1016
1017 - [room.id](#room-id)
1018 - [room.name](#room-name)
1019 - [room.slug](#room-slug)
1020 - [room.join()](#room-join)
1021 - [room.getHost()](#room-gethost)
1022 - [room.favorite()](#room-favorite)
1023 - [room.unfavorite()](#room-unfavorite)
1024
1025<a id="room-id"></a>
1026### room.id: number
1027
1028The room's unique ID.
1029
1030<a id="room-name"></a>
1031### room.name: string
1032
1033The room's name.
1034
1035<a id="room-slug"></a>
1036### room.slug: string
1037
1038The room's unique URL slug.
1039
1040```js
1041mp.chat('Visit us at https://plug.dj/' + mp.room().slug + '!')
1042```
1043
1044<a id="room-join"></a>
1045### room.join(): Promise
1046
1047Join this room. See [mp.join(room)](#mp-join).
1048
1049```js
1050// Join the most populous room.
1051mp.getRooms().then((rooms) => {
1052 const room = rooms[0]
1053 return room.join()
1054})
1055```
1056
1057<a id="room-gethost"></a>
1058### room.getHost(): Promise&lt;[User](#class-user)>
1059
1060Get this room's host.
1061
1062```js
1063// Attempt to befriend the host of the most populated room.
1064mp.getRooms().get(0).then((room) => {
1065 return room.getHost()
1066}).then((host) => {
1067 return host.befriend()
1068})
1069
1070// To get the host from the current room, use:
1071mp.room().getHost().then((host) => {
1072 // Do whatever
1073})
1074```
1075
1076<a id="room-favorite"></a>
1077### room.favorite(): Promise
1078
1079Add this room to the bot user's favorites.
1080
1081```js
1082// Add the top 50 most populous rooms to favorites.
1083mp.getRooms()
1084 .map((room) => room.favorite())
1085 .then(() => {
1086 console.log('Added lots of favorites')
1087 })
1088```
1089
1090<a id="room-unfavorite"></a>
1091### room.unfavorite(): Promise
1092
1093Remove this room from the bot user's favorites.
1094
1095```js
1096// Remove the current room from favorites.
1097mp.room().unfavorite().then(() => {
1098 console.log('Removed!')
1099})
1100```
1101
1102<a id="class-user"></a>
1103## User
1104
1105### Properties
1106
1107 - [user.id](#user-id)
1108 - [user.username](#user-username)
1109 - [user.role](#user-role)
1110 - [user.gRole](#user-grole)
1111 - [user.hasPermission(role)](#user-haspermission)
1112 - [user.hasGlobalPermission(role)](#user-hasglobalpermission)
1113 - [user.chat(text)](#user-chat)
1114 - [user.emote(text)](#user-emote)
1115 - [user.mention()](#user-mention)
1116 - [user.add()](#user-add)
1117 - [user.move(position)](#user-move)
1118 - [user.remove()](#user-remove)
1119 - [user.skip(historyId)](#user-skip)
1120 - [user.befriend()](#user-befriend)
1121 - [user.rejectRequest()](#user-rejectrequest)
1122 - [user.ignore()](#user-ignore)
1123 - [user.unignore()](#user-unignore)
1124 - [user.mute(duration, reason)](#user-mute)
1125 - [user.unmute()](#user-unmute)
1126 - [user.ban(duration, reason)](#user-ban)
1127 - [user.unban()](#user-unban)
1128 - [user.waitlistBan(duration, reason)](#user-waitlistban)
1129 - [user.waitlistUnban()](#user-waitlistunban)
1130 - [user.getHistory()](#user-gethistory)
1131
1132<a id="user-id"></a>
1133### user.id: number
1134
1135User ID.
1136
1137<a id="user-username"></a>
1138### user.username: string
1139
1140Username.
1141
1142<a id="user-role"></a>
1143### user.role: [ROLE](#role)
1144
1145The user's role in the current room. One of
1146
1147 - `ROLE.NONE`,
1148 - `ROLE.DJ`,
1149 - `ROLE.BOUNCER`,
1150 - `ROLE.MANAGER`,
1151 - `ROLE.COHOST`,
1152 - `ROLE.HOST`.
1153
1154<a id="user-grole"></a>
1155### user.gRole: [ROLE](#role)
1156
1157The user's global role. One of
1158
1159 - `ROLE.NONE`,
1160 - `ROLE.PROMOTER`,
1161 - `ROLE.PLOT`,
1162 - `ROLE.SITEMOD`,
1163 - `ROLE.AMBASSADOR`,
1164 - `ROLE.ADMIN`.
1165
1166<a id="user-haspermission"></a>
1167### user.hasPermission(role: [ROLE](#role)): bool
1168
1169Check if the user has a role in the current room.
1170
1171This function checks if either one of the role in the current room, or the
1172global role is equal to or higher than the given role.
1173
1174**Parameters**
1175
1176 - `role` - The permission to check for.
1177
1178```js
1179const { ROLE } = require('miniplug')
1180mp.me().hasPermission(ROLE.NONE) // → true
1181mp.me().hasPermission(ROLE.BOUNCER) // depends on your role in the current room
1182```
1183
1184<a id="user-hasglobalpermission"></a>
1185### user.hasGlobalPermission(role: [ROLE](#role)): bool
1186
1187Check if the user has the given global role. Returns `true` if the user's global
1188role is equal to or higher than the given role.
1189
1190**Parameters**
1191
1192 - `role` - The role to check for.
1193
1194```js
1195const { ROLE } = require('miniplug')
1196mp.me().hasGlobalPermission(ROLE.NONE) // → true
1197mp.me().hasGlobalPermission(ROLE.AMBASSADOR)
1198```
1199
1200<a id="user-chat"></a>
1201### user.chat(text): Promise&lt;[ChatMessage](#class-chatmessage)>
1202
1203Send a chat message directed at this user. Prepends `@Username` to the provided
1204text.
1205
1206```js
1207mp.user(123456).chat('Hello!')
1208// → "@Username Hello!"
1209```
1210
1211<a id="user-emote"></a>
1212### user.emote(text): Promise&lt;[ChatMessage](#class-chatmessage)>
1213
1214Send an emote chat message directed at this user.
1215
1216```js
1217mp.user(123456).emote('Hello!')
1218// → "/me @Username Hello!"
1219```
1220
1221<a id="user-mention"></a>
1222### user.mention(): string
1223
1224Get a string to mention the user in the chat.
1225
1226```js
1227const mentionStr = mp.user(123456).mention()
1228// → "@Username"
1229```
1230
1231This function is also used when stringifying a user object, for example when
1232embedding it in a template string:
1233
1234```js
1235const message = `Hello ${mp.user(123456)}!`
1236// → "Hello @Username!"
1237```
1238
1239<a id="user-add"></a>
1240### user.add(): Promise
1241
1242Add the user to the waitlist.
1243
1244<a id="user-move"></a>
1245### user.move(position): Promise
1246
1247Move the user to a different position in the waitlist.
1248
1249<a id="user-remove"></a>
1250### user.remove(): Promise
1251
1252Remove the user from the waitlist or the DJ Booth.
1253
1254<a id="user-skip"></a>
1255### user.skip(historyId): Promise
1256
1257> Please use the [historyEntry.skip](#historyentry-skip) method instead.
1258
1259Skip the user. `historyId` is the ID of the currently playing track, i.e.
1260`mp.historyEntry().id`.
1261
1262<a id="user-befriend"></a>
1263### user.befriend(): Promise
1264
1265Send or accept a friend request to/from this user.
1266
1267<a id="user-rejectrequest"></a>
1268### user.rejectRequest(): Promise
1269
1270Reject a friend request from this user.
1271
1272<a id="user-ignore"></a>
1273### user.ignore(): Promise
1274
1275Ignore the user in chat.
1276
1277<a id="user-unignore"></a>
1278### user.unignore(): Promise
1279
1280Stop ignoring the user in chat.
1281
1282<a id="user-mute"></a>
1283### user.mute(duration, reason): Promise
1284
1285Mute the user in chat. `duration` is a [MUTE_DURATION](#muteduration). `reason`
1286is a [MUTE_REASON](#mutereason).
1287
1288<a id="user-unmute"></a>
1289### user.unmute(): Promise
1290
1291Unmute the user in chat.
1292
1293<a id="user-ban"></a>
1294### user.ban(duration, reason): Promise
1295
1296Ban the user from the room. `duration` is a [BAN_DURATION](#banduration).
1297`reason` is a [BAN_REASON](#banreason).
1298
1299<a id="user-unban"></a>
1300### user.unban(): Promise
1301
1302Unban the user from the room.
1303
1304<a id="user-waitlistban"></a>
1305### user.waitlistBan(duration, reason): Promise
1306
1307Ban the user from the waitlist.
1308`duration` is a [WAITLIST_BAN_DURATION](#waitlistbanduration).
1309`reason` is a [WAITLIST_BAN_REASON](#waitlistbanreason).
1310
1311<a id="user-waitlistunban"></a>
1312### user.waitlistUnban(): Promise
1313
1314Unban the user from the waitlist.
1315
1316<a id="user-gethistory"></a>
1317### user.getHistory(): Promise&lt;Array&lt;[HistoryEntry](#class-historyentry)>>
1318
1319Get the 25 most recent plays by this user. See also [mp.getUserHistory(uid)](#mp-getuserhistory).
1320
1321<a id="class-waitlist"></a>
1322## Waitlist
1323
1324Waitlist objects are JavaScript arrays of [User](#class-user) objects. Like
1325JavaScript arrays, Waitlist objects are zero-indexed, so the user on top of the
1326waitlist (#1 on plug.dj) is `waitlist[0]`.
1327
1328```js
1329// Notify users when they're about to play.
1330mp.on('advance', () => {
1331 const waitlist = mp.waitlist()
1332 if (waitlist.length >= 1) {
1333 waitlist[0].chat('You\'re up next!')
1334 }
1335})
1336```
1337
1338Because Waitlist objects are JavaScript arrays, all the usual JavaScript array
1339methods can be used. Note that most native JavaScript array methods return plain
1340JavaScript arrays, and _not_ Waitlist objects.
1341
1342```js
1343const firstTen = mp.waitlist().slice(0, 10)
1344// firstTen is NOT a Waitlist object--just an array of the first ten users.
1345```
1346
1347### Properties
1348
1349 - [waitlist.contains(user)](#waitlist-contains)
1350 - [waitlist.positionOf(user)](#waitlist-positionof)
1351
1352<a id="waitlist-contains"></a>
1353### waitlist.contains(user): bool
1354
1355Check if a user is in the waitlist. `user` is a [User](#class-user) object or a
1356user ID.
1357
1358```js
1359if (mp.waitlist().contains(123456)) {
1360 mp.user(123456).chat('You\'re in the waitlist, Hermione!')
1361}
1362```
1363
1364This is similar to the `Array#includes` method of JavaScript arrays. However,
1365`includes` only checks that exactly the given object is in the array, whereas
1366`contains` checks whether an object representing the same user as the given
1367object or ID is in the array.
1368
1369<a id="waitlist-positionof"></a>
1370### waitlist.positionOf(user): number
1371
1372Returns the position of a user in the waitlist. `user` is a [User](#class-user)
1373object or a user ID. Returns -1 if the given user is not in the waitlist.
1374
1375This is similar to the `Array#indexOf` method of JavaScript arrays. The same
1376differences apply as with <code>[waitlist.contains](#waitlist-contains)</code>.
1377
1378<a id="class-waitlistban"></a>
1379## WaitlistBan
1380
1381### Properties
1382
1383 - [wlban.user](#waitlistban-user)
1384 - [wlban.moderator](#waitlistban-moderator)
1385 - [wlban.moderatorName](#waitlistban-moderatorname)
1386 - [wlban.duration](#waitlistban-duration)
1387 - [wlban.reason](#waitlistban-reason)
1388 - [wlban.timestamp](#waitlistban-timestamp)
1389 - [wlban.getUser()](#waitlistban-getuser)
1390 - [wlban.remove()](#waitlistban-remove)
1391
1392<a id="waitlistban-user"></a>
1393### wlban.user: [User](#class-user)
1394
1395The user who was banned from the waitlist.
1396This object is only guaranteed to have the `id` and `username` properties.
1397Most user methods will work, but if more properties are required, the [`wlban.getUser()`](#waitlistban-getuser) method should be used.
1398
1399<a id="waitlistban-moderator"></a>
1400### wlban.moderator: [User](#class-user)
1401
1402The moderator who installed the waitlist ban.
1403**This property is only guaranteed to exist on WaitlistBan objects from the ['modWaitlistBan'](#event-modwaitlistban) event.**
1404
1405<a id="waitlistban-moderatorname"></a>
1406### wlban.moderatorName: string
1407
1408The username of the moderator who installed the waitlist ban.
1409
1410<a id="waitlistban-duration"></a>
1411### wlban.duration: [WAITLIST_BAN_DURATION](#waitlistbanduration)
1412
1413The duration of the waitlist ban.
1414
1415<a id="waitlistban-reason"></a>
1416### wlban.reason: [WAITLIST_BAN_REASON](#waitlistbanreason)
1417
1418The reason for the waitlist ban.
1419This property is always `null` on WaitlistBan objects from the ['modWaitlistBan'](#event-modwaitlistban) event.
1420
1421<a id="waitlistban-timestamp"></a>
1422### wlban.timestamp: Date
1423
1424When the waitlist ban was installed.
1425
1426<a id="waitlistban-getuser"></a>
1427### wlban.getUser(): Promise&lt;[User](#class-user)>
1428
1429Get the banned user object.
1430
1431<a id="waitlistban-remove"></a>
1432### wlban.remove(): Promise
1433
1434Remove the waitlist ban.
1435
1436<a id="class-chatmessage"></a>
1437## ChatMessage
1438
1439### Properties
1440
1441 - [message.id](#chatmessage-id)
1442 - [message.message](#chatmessage-message)
1443 - [message.uid](#chatmessage-uid)
1444 - [message.un](#chatmessage-un)
1445 - [message.user](#chatmessage-user)
1446 - [message.getUser()](#chatmessage-getuser)
1447 - [message.own()](#chatmessage-own)
1448 - [message.reply(text)](#chatmessage-reply)
1449 - [message.emote(text)](#chatmessage-emote)
1450 - [message.delete()](#chatmessage-delete)
1451
1452<a id="chatmessage-id"></a>
1453### message.id: string
1454
1455Message ID.
1456
1457<a id="chatmessage-message"></a>
1458### message.message: string
1459
1460Message text contents.
1461
1462<a id="chatmessage-uid"></a>
1463### message.uid: number
1464
1465User ID of the sender of the message.
1466
1467<a id="chatmessage-un"></a>
1468### message.un: string
1469
1470Username of the sender of the message.
1471
1472<a id="chatmessage-user"></a>
1473### message.user: [User](#class-user)
1474
1475The user that sent the message.
1476
1477In some cases, plug.dj might send chat messages from users who aren't reported as being in the room.
1478In those cases, the `user` property will only have the user's username and ID, which is good enough to use for most purposes.
1479If you require the full user object, use [`message.getUser()`](#chatmessage-getuser).
1480Notably, if you need to use the user's `role` for a chat command permissions check, it's best to call `getUser()`.
1481
1482<a id="chatmessage-getuser"></a>
1483### message.getUser(): Promise&lt;[User](#class-user)>
1484
1485Get the sender of the message.
1486This uses the local user object (from [`mp.user()`](#mp-user)) if available, and falls back to a network request (through [`mp.getUser()`](#mp-getuser)) if not.
1487
1488<a id="chatmessage-own"></a>
1489### message.own(): bool
1490
1491Returns true if the message was sent by the logged-in user, or false if it was
1492sent by someone else.
1493
1494```js
1495mp.chat('My own message').then((message) => {
1496 assert.ok(message.own() === true)
1497})
1498
1499mp.on('chat', (message) => {
1500 // True if it was sent using mp.chat() or mp.emote().
1501 // False if it was sent by some other user.
1502 message.own()
1503})
1504```
1505
1506<a id="chatmessage-reply"></a>
1507### message.reply(text): Promise&lt;[ChatMessage](#class-chatmessage)>
1508
1509Reply to the sender of the message using an @-mention.
1510
1511```js
1512mp.on('chat', (message) => {
1513 if (message.message === '!myid') {
1514 // Sends "@Username Your user ID is 123456"
1515 message.reply('Your user ID is ' + message.uid)
1516 }
1517})
1518```
1519
1520<a id="chatmessage-emote"></a>
1521### message.emote(text): Promise&lt;[ChatMessage](#class-chatmessage)>
1522
1523Reply to the sender of the message using an @-mention in an [emote](#mp-emote)
1524message.
1525
1526<a id="chatmessage-delete"></a>
1527### message.delete(): Promise
1528
1529Delete the message.
1530
1531```js
1532mp.on('chat', (message) => {
1533 message.delete().then(() => {
1534 console.log('Deleted message from ' + message.un)
1535 })
1536})
1537```
1538
1539<a id="class-playlist"></a>
1540## Playlist
1541
1542### Properties
1543
1544 - [playlist.id](#playlist-id)
1545 - [playlist.name](#playlist-name)
1546 - [playlist.count](#playlist-count)
1547 - [playlist.active](#playlist-active)
1548 - [playlist.delete()](#playlist-delete)
1549 - [playlist.activate()](#playlist-activate)
1550 - [playlist.rename(name)](#playlist-rename)
1551 - [playlist.shuffle()](#playlist-shuffle)
1552 - [playlist.getMedia()](#playlist-getmedia)
1553 - [playlist.insert(media, append)](#playlist-insert)
1554 - [playlist.move(media, before)](#playlist-move)
1555
1556<a id="playlist-id"></a>
1557### playlist.id: number
1558
1559The playlist ID.
1560
1561<a id="playlist-name"></a>
1562### playlist.name: string
1563
1564Playlist name.
1565
1566<a id="playlist-count"></a>
1567### playlist.count: number
1568
1569The amount of media items in the playlist.
1570
1571<a id="playlist-active"></a>
1572### playlist.active: bool
1573
1574True if this is the active playlist.
1575
1576<a id="playlist-delete"></a>
1577### playlist.delete(): Promise
1578
1579Permanently delete the playlist.
1580
1581<a id="playlist-activate"></a>
1582### playlist.activate(): Promise
1583
1584Set this playlist to active.
1585
1586<a id="playlist-rename"></a>
1587### playlist.rename(name): Promise
1588
1589Rename the playlist.
1590
1591<a id="playlist-shuffle"></a>
1592### playlist.shuffle(): Promise&lt;Array&lt;[Media](#class-media)>>
1593
1594Shuffle the items in the playlist. Returns a Promise that resolves to the
1595shuffled media items in the playlist.
1596
1597<a id="playlist-getmedia"></a>
1598### playlist.getMedia(): Promise&lt;Array&lt;[Media](#class-media)>>
1599
1600Get the items in the playlist.
1601
1602<a id="playlist-insert"></a>
1603### playlist.insert(media, append=true): Promise&lt;{id, count}>
1604
1605Add media items to the playlist. `media` can be a [Media](#class-media) object
1606or ID, or an array of [Media](#class-media) objects or IDs. When `append` is
1607true, the medias are added to the end of the playlist. When `append` is false,
1608they are added to the front.
1609
1610Returns a Promise that resolves to an object containing the playlist `id`, and
1611the new total `count` of items in the playlist.
1612
1613<a id="playlist-move"></a>
1614### playlist.move(media, before): Promise&lt;Array&lt;[Media](#class-media)>>
1615
1616Move media items in the playlist. `media` can be a [Media](#class-media) object
1617or ID, or an array of [Media](#class-media) objects or IDs. The items will be
1618moved in front of the [Media](#class-media) objects or ID given in `before`.
1619If `before` is -1, the items will be moved to the end of the playlist.
1620
1621Returns a Promise that resolves with the Media items in the playlist after the
1622move was finished.
1623
1624<a id="class-media"></a>
1625## Media
1626
1627### Properties
1628
1629 - [media.id](#media-id)
1630 - [media.format](#media-format)
1631 - [media.cid](#media-cid)
1632 - [media.author](#media-author)
1633 - [media.title](#media-title)
1634 - [media.duration](#media-duration)
1635 - [media.image](#media-image)
1636 - [media.update(author, title)](#media-update)
1637 - [media.delete()](#media-delete)
1638
1639<a id="media-id"></a>
1640### media.id: number
1641
1642The media ID on plug.dj.
1643
1644<a id="media-format"></a>
1645### media.format: [MEDIA_SOURCE](#mediasource)
1646
1647The media source. Can be `MEDIA_SOURCE.YOUTUBE` or `MEDIA_SOURCE.SOUNDCLOUD`.
1648
1649<a id="media-cid"></a>
1650### media.cid: string
1651
1652The media ID on the relevant source.
1653
1654<a id="media-author"></a>
1655### media.author: string
1656
1657The author / artist tag of the media.
1658
1659<a id="media-title"></a>
1660### media.title: string
1661
1662The title tag of the media.
1663
1664<a id="media-duration"></a>
1665### media.duration: number
1666
1667Duration in seconds of the media.
1668
1669<a id="media-image"></a>
1670### media.image: string
1671
1672A URL pointing to a thumbnail image.
1673
1674<a id="media-update"></a>
1675### media.update(author, title): Promise&lt;{author, title}>
1676
1677Update the author and title tags of a media item. Returns a Promise that
1678resolves with the new actual author and title as used by plug.dj, with HTML
1679escapes.
1680
1681<a id="media-delete"></a>
1682### media.delete(): Promise
1683
1684Delete the media from the playlist it belongs to.
1685
1686<a id="class-historyentry"></a>
1687## HistoryEntry
1688
1689### Properties
1690
1691 - [entry.id](#historyentry-id)
1692 - [entry.media](#historyentry-media)
1693 - [entry.room](#historyentry-room)
1694 - [entry.user](#historyentry-user)
1695 - [entry.timestamp](#historyentry-timestamp)
1696 - [entry.score](#historyentry-score)
1697 - [entry.getUser()](#historyentry-getuser)
1698 - [entry.skip()](#historyentry-skip)
1699
1700<a id="historyentry-id"></a>
1701### entry.id: string
1702
1703The unique ID of the history entry.
1704
1705<a id="historyentry-media"></a>
1706### entry.media: [Media](#class-media)
1707
1708The media that was played.
1709
1710<a id="historyentry-room"></a>
1711### entry.room: [Room](#class-room)
1712
1713The room where the history entry was played. Note that this `.room` object only
1714contains three of the Room class properties:
1715
1716 - `entry.room.name` - The name of the room;
1717 - `entry.room.slug` - The URL slug of the room;
1718 - `entry.room.private` - Whether the room is private.
1719
1720There is not currently a way to load a full Room object if you need more
1721information. This will hopefully be added in a future update.
1722
1723<a id="historyentry-user"></a>
1724### entry.user: [User](#class-user)
1725
1726The user that played this song. Note that this `.user` object only contains two
1727of the User class properties:
1728
1729 - `entry.user.id` - The user's ID. This allows you to use most User class
1730 methods.
1731 - `entry.user.username` - The user's name.
1732
1733If you need anything else, use the [entry.getUser()](#historyentry-getuser)
1734method to load a full User object.
1735
1736<a id="historyentry-time"></a>
1737<a id="historyentry-timestamp"></a>
1738### entry.timestamp: Date
1739
1740Timestamp at which the history entry was played.
1741
1742<a id="historyentry-score"></a>
1743### entry.score: {positive, negative, grabs, listeners}
1744
1745An object describing audience response to the song. Contains four properties,
1746all numbers:
1747
1748 - `entry.score.positive` - The amount of woots.
1749 - `entry.score.negative` - The amount of mehs.
1750 - `entry.score.grabs` - The amount of grabs.
1751 - `entry.score.listeners` - The amount of people in the room at the time the
1752 song was played.
1753 - `entry.score.skipped` - Contains the number 0 if this song was played through
1754 to the end, and nonzero if it was skipped.
1755 (Not available on the current Booth entry.)
1756
1757<a id="historyentry-getuser"></a>
1758### entry.getUser(): Promise&lt;[User](#class-user)>
1759
1760Get the full user object of the user who played this song.
1761
1762<a id="historyentry-skip"></a>
1763### entry.skip(): Promise
1764
1765Skip this play.
1766
1767```js
1768mp.historyEntry().skip()
1769```
1770
1771<a id="class-storeproduct"></a>
1772## StoreProduct
1773
1774### Properties
1775
1776 - [product.type](#storeproduct-type)
1777 - [product.category](#storeproduct-category)
1778 - [product.id](#storeproduct-id)
1779 - [product.name](#storeproduct-name)
1780 - [product.level](#storeproduct-level)
1781 - [product.pp](#storeproduct-pp)
1782 - [product.sub](#storeproduct-sub)
1783 - [product.cash](#storeproduct-cash)
1784 - [product.purchase()](#storeproduct-purchase)
1785
1786<a id="storeproduct-type"></a>
1787### product.type: string
1788
1789The product type: 'avatars', 'badges', or 'misc'.
1790
1791<a id="storeproduct-category"></a>
1792### product.category: string
1793
1794The product category, i.e. the page on which it appears in the store. See
1795[Product Categories](#productcategories).
1796
1797<a id="storeproduct-id"></a>
1798### product.id: number
1799
1800The product ID.
1801
1802<a id="storeproduct-name"></a>
1803### product.name: string
1804
1805The product name. This is _not_ a human-readable name. Examples include
1806"classic01" and "admin-o01".
1807
1808<a id="storeproduct-level"></a>
1809### product.level: number
1810
1811The minimum level the user has to have to unlock the product.
1812
1813<a id="storeproduct-pp"></a>
1814### product.pp: number?
1815
1816The price of the product in plug points. If the product cannot be purchased with
1817points, this property will not exist (i.e. be `undefined`).
1818
1819<a id="storeproduct-sub"></a>
1820### product.sub: number?
1821
1822`1` if the product is for Subscribers only. Subscriber-only products are
1823automatically added to the inventories of subscribed users. If the product is
1824not automatically available to subscribers, this property will not exist
1825(i.e. be `undefined`).
1826
1827Note that `1` is a "truthy" value and `undefined` is falsy, so a simple `if`
1828statement can be used to check if a product is subscriber-only:
1829
1830```js
1831mp.getStoreAvatars().each((avatar) => {
1832 let description = `Avatar: ${avatar.name}`
1833 if ('pp' in avatar) {
1834 description += ` - Points: ${avatar.pp}`
1835 }
1836 if ('cash' in avatar) {
1837 description += ` - $${avatar.cash}`
1838 }
1839 if (avatar.sub) {
1840 description += ' - Free for Subscribers'
1841 }
1842 console.log(description)
1843})
1844```
1845
1846<a id="storeproduct-cash"></a>
1847### product.cash: number?
1848
1849The price of the product in US dollars. If the product cannot be purchased with
1850real money, this property will not exist (i.e. be `undefined`).
1851
1852<a id="storeproduct-purchase"></a>
1853### product.purchase(): Promise
1854
1855Purchase the product. Only works for products that can be purchased with points.
1856
1857<a id="class-inventoryproduct"></a>
1858## InventoryProduct
1859
1860### Properties
1861
1862 - [product.type](#inventoryproduct-type)
1863 - [product.category](#inventoryproduct-category)
1864 - [product.id](#inventoryproduct-id)
1865
1866<a id="inventoryproduct-type"></a>
1867### product.type: string
1868
1869The product type: 'avatars', 'badges', or 'misc'.
1870
1871<a id="inventoryproduct-category"></a>
1872### product.category: string
1873
1874The product category, i.e. the page on which it appears in the user's inventory.
1875See [Product Categories](#productcategories).
1876
1877<a id="inventoryproduct-id"></a>
1878### product.name: string
1879
1880The internal product name.
1881
1882<hr>
1883
1884<a id="class-notification"></a>
1885## Notification
1886
1887A plug.dj service notification. These are the notifications listed on your user
1888profile under My Profile » Notifications.
1889
1890### Properties
1891
1892 - [notification.id](#notification-id)
1893 - [notification.action](#notification-action)
1894 - [notification.timestamp](#notification-timestamp)
1895 - [notification.value](#notification-value)
1896 - [notification.level](#notification-level)
1897 - [notification.message](#notification-message)
1898 - [notification.from](#notification-from)
1899 - [notification.amount](#notification-amount)
1900 - [notification.acknowledge()](#notification-acknowledge)
1901
1902<a id="notification-id"></a>
1903### notification.id: number
1904
1905Unique ID of the notification.
1906
1907<a id="notification-action"></a>
1908### notification.action: string
1909
1910Type of notification.
1911This determines what the [Notification](#class-notification)'s
1912[`value`](#notification-value) stands for. Miniplug parses the `value` for some
1913notification types.
1914
1915 - `levelUp` - The user leveled up. `level` is the new level.
1916 - `custom` - A custom notification sent by plug.dj. `message` contains the
1917 notification message. Note that the message can contain HTML.
1918 - `gift` - The user received a gift. `from` contains the username of the
1919 sender, and `amount` contains the amount of PP that was gifted.
1920 - `boostExpired` - An XP boost purchased by the user has expired. Obsolete,
1921 since plug.dj doesn't sell XP boosts anymore.
1922
1923<a id="notification-timestamp"></a>
1924### notification.timestamp: Date
1925
1926Date and time when the notification came in.
1927
1928<a id="notification-value"></a>
1929### notification.value: string
1930
1931Raw value of the notification. This can mean different things for different
1932actions. It's best to use one of the other properties documented below if you
1933can.
1934
1935See [`notification.action`](#notification-action).
1936
1937<a id="notification-level"></a>
1938### notification.level: number
1939
1940The user's new level after leveling up. Only present when the notification
1941`action` is `levelUp`.
1942
1943<a id="notification-message"></a>
1944### notification.message: string
1945
1946HTML message contents of a plug.dj announcement notification. Only present when
1947the notification `action` is `custom`.
1948
1949<a id="notification-from"></a>
1950### notification.from: string
1951
1952Nickname of the sender of a gift. Only present when the notification `action` is
1953`gift`.
1954
1955<a id="notification-amount"></a>
1956### notification.amount: number
1957
1958Amount of PP in a gift. Only present when the notification `action` is `gift`.
1959
1960<a id="notification-acknowledge"></a>
1961### notification.acknowledge(): Promise
1962
1963Acknowledge and remove the notification.
1964
1965<hr>
1966
1967<a id="role"></a>
1968## User Roles
1969
1970```js
1971const { ROLE } = require('miniplug')
1972```
1973
1974### ROLE.NONE
1975
1976A normal user.
1977
1978### ROLE.DJ
1979
1980A Resident DJ in the current room.
1981
1982### ROLE.BOUNCER
1983
1984A Bouncer in the current room.
1985
1986### ROLE.MANAGER
1987
1988A Manager in the current room.
1989
1990### ROLE.COHOST
1991
1992A Cohost in the current room.
1993
1994### ROLE.HOST
1995
1996The current room's host.
1997
1998### ROLE.PROMOTER
1999
2000A plug.dj Promoter.
2001
2002### ROLE.PLOT
2003
2004A PLoT (Plug.dj League of Translators) member, who works on plug.dj localization.
2005
2006### ROLE.SITEMOD
2007
2008A site-wide moderator.
2009
2010### ROLE.AMBASSADOR
2011
2012A plug.dj Brand Ambassador.
2013
2014### ROLE.ADMIN
2015
2016A plug.dj site admin.
2017
2018<a id="muteduration"></a>
2019## Mute Durations
2020
2021```js
2022const { MUTE_DURATION } = require('miniplug')
2023```
2024
2025### MUTE_DURATION.SHORT
2026
202715 minutes.
2028
2029### MUTE_DURATION.MEDIUM
2030
203130 minutes.
2032
2033### MUTE_DURATION.LONG
2034
203545 minutes.
2036
2037<a id="mutereason"></a>
2038## Mute Reasons
2039
2040```js
2041const { MUTE_REASON } = require('miniplug')
2042```
2043
2044### MUTE_REASON.VIOLATING_RULES
2045
2046Violating community rules.
2047
2048### MUTE_REASON.VERBAL_ABUSE
2049
2050Verbal abuse or harassment.
2051
2052### MUTE_REASON.SPAMMING
2053
2054Spamming or trolling.
2055
2056### MUTE_REASON.LANGUAGE
2057
2058Offensive language.
2059
2060### MUTE_REASON.ATTITUDE
2061
2062Negative attitude
2063
2064<a id="banduration"></a>
2065## Ban Durations
2066
2067```js
2068const { BAN_DURATION } = require('miniplug')
2069```
2070
2071### BAN_DURATION.HOUR
2072
2073A 1 hour ban.
2074
2075### BAN_DURATION.DAY
2076
2077A 1 day ban.
2078
2079### BAN_DURATION.PERMA
2080
2081A permanent ban.
2082
2083<a id="banreason"></a>
2084## Ban Reasons
2085
2086```js
2087const { BAN_REASON } = require('miniplug')
2088```
2089
2090### BAN_REASON.SPAMMING
2091
2092Spamming or trolling.
2093
2094### BAN_REASON.VERBAL_ABUSE
2095
2096Verbal abuse or offensive language.
2097
2098### BAN_REASON.OFFENSIVE_PLAYS
2099
2100Playing offensive videos/songs.
2101
2102### BAN_REASON.GENRE
2103
2104Repeatedly playing inappropriate genre(s).
2105
2106### BAN_REASON.ATTITUDE
2107
2108Negative attitude.
2109
2110<a id="waitlistbanduration"></a>
2111## Waitlist Ban Durations
2112
2113```js
2114const { WAITLIST_BAN_DURATION } = require('miniplug')
2115```
2116
2117### WAITLIST_BAN_DURATION.SHORT
2118
2119A 15 minute waitlist ban.
2120
2121### WAITLIST_BAN_DURATION.MEDIUM
2122
2123A 1 hour waitlist ban.
2124
2125### WAITLIST_BAN_DURATION.LONG
2126
2127A 1 day waitlist ban.
2128
2129### WAITLIST_BAN_DURATION.PERMA
2130
2131A permanent waitlist ban.
2132
2133<a id="waitlistbanreason"></a>
2134## Waitlist Ban Reasons
2135
2136```js
2137const { WAITLIST_BAN_REASON } = require('miniplug')
2138```
2139
2140### WAITLIST_BAN_REASON.SPAMMING
2141
2142Spamming or trolling.
2143
2144### WAITLIST_BAN_REASON.VERBAL_ABUSE
2145
2146Verbal abuse or offensive language.
2147
2148### WAITLIST_BAN_REASON.OFFENSIVE_PLAYS
2149
2150Playing offensive videos/songs.
2151
2152### WAITLIST_BAN_REASON.GENRE
2153
2154Repeatedly playing inappropriate genre(s).
2155
2156### WAITLIST_BAN_REASON.ATTITUDE
2157
2158Negative attitude.
2159
2160<a id="mediasource"></a>
2161## Media Sources
2162
2163```js
2164const { MEDIA_SOURCE } = require('miniplug')
2165```
2166
2167### MEDIA_SOURCE.YOUTUBE
2168
2169Identifies a YouTube video.
2170
2171### MEDIA_SOURCE.SOUNDCLOUD
2172
2173Identifies a SoundCloud track.
2174
2175<a id="productcategories"></a>
2176## Product Categories
2177
2178Note: These listings were last updated on 03 December 2016. It's not guaranteed
2179to be 100% correct. If you spot a mistake or a missing category, please send a
2180PR!
2181
2182### Avatars
2183
2184 - 'classic'
2185 - 'hiphop'
2186 - 'rave'
2187 - 'base'
2188 - 'country'
2189 - '80s'
2190 - 'rock'
2191 - '2014hw'
2192 - 'robot'
2193 - 'zoo'
2194 - 'warrior'
2195 - 'dragon'
2196 - '2014winter'
2197 - 'sea'
2198 - 'island'
2199 - 'diner'
2200 - 'beach'
2201 - 'nyc'
2202
2203### Badges
2204
2205 - 'b-original'
2206 - 'b-sea'
2207 - 'b-island'
2208 - 'b-rave'
2209 - 'b-base'
2210 - 'b-food'
2211 - 'b-diner'
2212 - 'b-country'
2213 - 'b-robot'
2214 - 'b-zoo'
2215 - 'b-hiphop'
2216 - 'b-80s'
2217 - 'b-warrior'
2218 - 'b-beach'
2219 - 'b-nyc'
2220
2221### Misc
2222
2223 - 'username'
2224 - 'boost' is obsolete, but used to contain XP boost items in the past.
2225
2226<a id="mp-rest"></a>
2227## mp.get/post/put/del(url: string, data: object): Promise
2228
2229> These are low-level REST methods. You most likely do not need to use them
2230> directly. Instead, use one of the methods described in the rest of this
2231> document.
2232
2233Send an HTTP request to the given plug.dj API endpoint. The `url` is relative
2234to the plug.dj API base URL. `data` is used for the request body for POST, PUT
2235and DELETE requests, and as the query string for GET requests.
2236
2237```js
2238mp.get('rooms', { q: 'k-pop' }).then(console.log)
2239// sends `GET https://plug.dj/_/rooms?q=k-pop`
2240
2241mp.post('booth/skip', { userID: 123456, historyID: mp.historyEntry().id })
2242// sends `POST https://plug.dj/_/booth/skip` with a request body like:
2243// { "userID": 123456, "historyID": "ab0c47eb-6c92-45f8-8711-75e27977db06" }
2244```
2245
2246<a id="mp-ws"></a>
2247# WebSocket
2248
2249## mp.ws: WebSocket
2250
2251The [plug-socket](https://github.com/miniplug/plug-socket) WebSocket
2252instance. This is also an instance of the [ws](https://github.com/websockets/ws)
2253module.
2254
2255It has a few methods, but miniplug has better wrappers around all of them.
2256The [mp.ws](#mp-ws) property is useful if you need to attach native WebSocket
2257events (eg. `'close'`), but otherwise there are better options.
2258
2259<a id="events"></a>
2260# Events
2261
2262 - [advance](#event-advance)
2263 - [ban](#event-ban)
2264 - [chat](#event-chat)
2265 - [chatDelete](#event-chatdelete)
2266 - [disconnected](#event-disconnected)
2267 - [earn](#event-earn)
2268 - [friendAccept](#event-friendaccept)
2269 - [friendRequest](#event-friendrequest)
2270 - [gifted](#event-gifted)
2271 - [grab](#event-grab)
2272 - [guestJoin](#event-guestjoin)
2273 - [guestLeave](#event-guestleave)
2274 - [modAddDj](#event-modadddj)
2275 - [modBan](#event-modban)
2276 - [modMoveDj](#event-modmovedj)
2277 - [modMute](#event-modmute)
2278 - [modRemoveDj](#event-modremovedj)
2279 - [modSkip](#event-modskip)
2280 - [modStaff](#event-modstaff)
2281 - [modWaitlistBan](#event-modwaitlistban)
2282 - [roomUpdate](#event-roomupdate)
2283 - [roomNameUpdate](#event-roomnameupdate)
2284 - [roomDescriptionUpdate](#event-roomdescriptionupdate)
2285 - [roomWelcomeUpdate](#event-roomwelcomeupdate)
2286 - [roomMinChatLevelUpdate](#event-roomminchatlevelupdate)
2287 - [skip](#event-skip)
2288 - [sub](#event-sub)
2289 - [userJoin](#event-userjoin)
2290 - [userLeave](#event-userleave)
2291 - [userUpdate](#event-userupdate)
2292 - [vote](#event-vote)
2293 - [waitlistClear](#event-waitlistclear)
2294 - [waitlistCycle](#event-waitlistcycle)
2295 - [waitlistLock](#event-waitlistlock)
2296 - [waitlistUpdate](#event-waitlistupdate)
2297
2298<a id="event-advance"></a>
2299## 'advance'
2300
2301Fired when the DJ booth advances, and the next song starts playing.
2302
2303**Parameters**
2304
2305 - `next` - The new [HistoryEntry](#class-historyentry), or `null` if there is
2306 no new DJ.
2307 - `previous` - The previous [HistoryEntry](#class-historyentry), or `null` if
2308 there was no DJ earlier.
2309
2310```js
2311mp.on('advance', (next, previous) => {
2312 if (previous) {
2313 console.log('Last song:', previous.media.author, '-', previous.media.title)
2314 }
2315 if (next) {
2316 console.log('Next song:', next.media.author, '-', next.media.title)
2317 }
2318})
2319```
2320
2321<a id="event-ban"></a>
2322## 'ban'
2323
2324Fired when a moderator bans you.
2325
2326**Parameters**
2327
2328 - `duration` - The duration of how long the ban lasts.
2329 - `reason` - The reason why the ban was issued.
2330
2331```js
2332mp.on('ban', (data) => {
2333 var duration = '', reason = ''
2334
2335 switch (data.duration) {
2336 case 'h': duration = 'for one hour'; break;
2337 case 'd': duration = 'for a day'; break;
2338 case 'f': duration = 'forever'; break;
2339 }
2340
2341 switch (data.reason) {
2342 case 1: reason = 'spamming or trolling'; break;
2343 case 2: reason = 'verbal abuse or harassment'; break;
2344 case 3: reason = 'playing offensive videos/songs'; break;
2345 case 4: reason = 'repeatedly playing inappropriate genre(s)'; break;
2346 case 5: reason = 'negative attitude'; break;
2347 }
2348
2349 console.log(`I have been banned ${duration} (reason: ${reason})`)
2350})
2351```
2352
2353<a id="event-chat"></a>
2354## 'chat'
2355
2356Fired when a chat message is received.
2357
2358**Parameters**
2359
2360 - `message` - The incoming [ChatMessage](#class-chatmessage).
2361
2362```js
2363mp.on('chat', (message) => {
2364 if (/^!whoami/.test(message.message)) {
2365 message.reply(`You are ${message.un}, #${message.uid}.`)
2366 }
2367})
2368```
2369
2370<a id="event-chatdelete"></a>
2371## 'chatDelete'
2372
2373Fired when a chat message is deleted.
2374
2375**Parameters**
2376
2377 - `del` - An object with two properties:
2378 - `cid` - The ID of the chat message that is being deleted.
2379 - `user` - The [User](#class-user) that deleted the message.
2380
2381```js
2382mp.on('chatDelete', (del) => {
2383 console.info(`${del.user.username} deleted message #${del.cid}.`)
2384})
2385```
2386
2387<a id="event-disconnected"></a>
2388## 'disconnected'
2389
2390Fired when the connection to the plug.dj WebSocket server has ended.
2391With this event you can implement an auto-reconnect system.
2392
2393```js
2394let timeout = 0
2395function reconnect () {
2396 console.info('Trying to reconnect...')
2397 mp.connect({ email: 'xyz@hoi.com', password: 'whatever' })
2398 .then(() => {
2399 console.info('Reconnected!')
2400 })
2401 .catch(() => {
2402 console.warn('Failed to reconnect, trying again in', timeout, 'ms')
2403 setTimeout(reconnect, timeout)
2404 })
2405 timeout += 1000 // 1 second
2406}
2407
2408mp.on('disconnected', () => {
2409 console.warn('!! Connection lost.')
2410 reconnect()
2411})
2412```
2413
2414<a id="event-earn"></a>
2415## 'earn'
2416
2417Fired when xp/pp is added to your account.
2418
2419**Parameters**
2420
2421 - `xp` - The new xp amount.
2422 - `pp` - The new pp amount.
2423 - `level` - The current level, or new level on level up.
2424
2425```js
2426mp.on('earn', (data) => {
2427 console.info(`I now have ${data.xp} xp, ${data.pp} pp, and am level ${data.level}.`)
2428})
2429```
2430
2431<a id="event-friendaccept"></a>
2432## 'friendAccept'
2433
2434Fired when a user accepts a friend request.
2435
2436**Parameters**
2437
2438 - `user` - The [User](#class-user) that accepted the request.
2439
2440```js
2441mp.on('friendAccept', (user) => {
2442 mp.chat(`Thanks ${user}, for accepting my friend request!`)
2443})
2444```
2445
2446<a id="event-friendrequest"></a>
2447## 'friendRequest'
2448
2449Fired when a user sends you a friend request. The [User](#class-user) methods
2450[.befriend](#user-befriend) and [.rejectRequest](#user-rejectrequest) can be
2451used to respond to the request.
2452
2453**Parameters**
2454
2455 - `user` - The [User](#class-user) that sent the request.
2456
2457```js
2458mp.on('friendRequest', (user) => {
2459 if (user.level < 5) {
2460 user.befriend()
2461 } else {
2462 user.chat('I only befriend users whose level is below 5, sorry.')
2463 user.rejectRequest()
2464 }
2465})
2466```
2467
2468<a id="event-gifted"></a>
2469## 'gifted'
2470
2471Fired when a user sends another user a gift.
2472
2473**Parameters**
2474
2475 - `sender` - The name of the user who sent the gift.
2476 - `recipient` - The name of the user who received the gift.
2477
2478```js
2479mp.on('gifted', (data) => {
2480 console.log(`${data.sender} sent ${data.recipient} a gift!`)
2481})
2482```
2483
2484<a id="event-grab"></a>
2485## 'grab'
2486
2487Fired when a user grabs the current song.
2488
2489**Parameters**
2490
2491 - `user` - The [User](#class-user) who grabbed the song.
2492
2493```js
2494mp.on('grab', (user) => {
2495 const media = mp.media()
2496 console.log(user.mention(), 'grabbed', media.author, '-', media.title)
2497})
2498```
2499
2500<a id="event-guestjoin"></a>
2501## 'guestJoin'
2502
2503Fired when a guest joins the room. Does not receive any parameters.
2504
2505```js
2506mp.on('guestJoin', () => {
2507 console.log('A wild guest appeared!')
2508})
2509```
2510
2511<a id="event-guestleave"></a>
2512## 'guestLeave'
2513
2514Fired when a guest leaves the room. Does not receive any parameters.
2515
2516```js
2517mp.on('guestLeave', () => {
2518 console.log('A guest left the room.')
2519})
2520```
2521
2522<a id="#event-modadddj"></a>
2523## 'modAddDj'
2524
2525Fired when a moderator adds a user to the waitlist.
2526
2527**Parameters**
2528
2529 - `moderator` - The staff [User](#class-user) who added the user to the waitlist.
2530 - `username` - The name of the user that was added.
2531 - `cycle` - Weather the waitlist should cycle (true/false)
2532
2533```js
2534mp.on('modAddDj', (data) => {
2535 console.log(`Moderator ${data.moderator.username} has added ${data.username} to the waitlist.`)
2536})
2537```
2538
2539<a id="#event-modban"></a>
2540## 'modBan'
2541
2542Fired when a moderator bans a user.
2543
2544**Parameters**
2545
2546 - `moderator` - The staff [User](#class-user) who banned the user.
2547 - `username` - The name of the user that was banned.
2548 - `duration` - The duration of time the ban lasts for
2549
2550```js
2551mp.on('modBan', (data) => {
2552 var duration = '';
2553
2554 switch (data.duration) {
2555 case 'h': duration = 'for an hour'; break;
2556 case 'd': duration = 'for a day'; break;
2557 case 'f': duration = 'forever'; break;
2558 }
2559
2560 console.log(`Moderator ${data.moderator.username} has banned ${data.username} ${duration}.`)
2561})
2562```
2563
2564<a id="#event-modmovedj"></a>
2565## 'modMoveDj'
2566
2567Fired when a moderator moves the position of a user in the waitlist.
2568
2569**Parameters**
2570
2571 - `moderator` - The staff [User](#class-user) who moved the user in the waitlist.
2572 - `username` - The name of the user that was moved.
2573 - `movedFrom` - The position the user was at.
2574 - `movedTo` - The position the user was moved to.
2575
2576 ```js
2577mp.on('modMoveDj', (data) => {
2578 // movedFrom and movedTo are both 0 indexed
2579 console.log(`${data.moderator.username} has moved ${data.username} from position ${data.movedFrom + 1} to position ${data.movedTo + 1}`)
2580})
2581```
2582
2583<a id="#event-modmute"></a>
2584## 'modMute'
2585
2586Fired when a moderator mutes a user.
2587
2588**Parameters**
2589
2590 - `moderator` - The staff [User](#class-user) who muted the user.
2591 - `username` - The [User](#class-user) object of the user who was muted.
2592 - `reason` - The reason for the mute.
2593 - `duration` - The length of time the mute lasts for.
2594
2595 ```js
2596mp.on('modMute', (data) => {
2597 var length = '', reason = '', msg = `${data.moderator.username} `;
2598
2599 switch (data.duration) {
2600 case 'o': length = 'unmuted'; break;
2601 case 's': length = '15'; break;
2602 case 'm': length = '30'; break;
2603 case 'l': length = '45'; break;
2604 }
2605
2606 switch (data.reason) {
2607 case 1: reason = 'violating community rules'; break;
2608 case 2: reason = 'verbal abuse or harassment'; break;
2609 case 3: reason = 'spamming or trolling'; break;
2610 case 4: reason = 'offensive language'; break;
2611 case 5: reason = 'negative attitude'; break;
2612 }
2613
2614 if (data.duration == 'o')
2615 msg += `unmuted ${data.user.username}`
2616 else
2617 msg += `muted ${data.user.username} (${length} mins) for ${reason}`
2618
2619 console.log(msg)
2620})
2621```
2622
2623<a id="#event-modremovedj"></a>
2624## 'modRemoveDj'
2625
2626Fired when a moderator removes a user from the waitlist.
2627
2628**Parameters**
2629
2630 - `moderator` - The staff [User](#class-user) who removed the user from the waitlist.
2631 - `username` - The name of the user that was removed.
2632 - `inBooth` - Weather the user was in the booth/djing (true/false)
2633
2634 ```js
2635mp.on('modRemoveDj', (data) => {
2636 console.log(`${data.moderator.username} has removed ${data.username} from the ${data.inBooth ? 'booth' : 'waitlist'}`)
2637})
2638```
2639
2640<a id="#event-modskip"></a>
2641## 'modSkip'
2642
2643Fired when a moderator skips the current song playing.
2644
2645**Parameters**
2646
2647 - `moderator` - The staff [User](#class-user) who skipped the song.
2648
2649 ```js
2650mp.on('modSkip', (moderator) => {
2651 console.log(`${moderator.username} has skipped the current DJ`)
2652})
2653```
2654
2655<a id="#event-modstaff"></a>
2656## 'modStaff'
2657
2658Fired when a user is promoted or demoted.
2659
2660**Parameters**
2661
2662 - `moderator` - The staff [User](#class-user) who promoted/demoted the user.
2663 - `user` - The [User](#class-user) who was promoted/demoted.
2664 - `role` - The role of the user who was promoted/demoted.
2665
2666 ```js
2667mp.on('modStaff', (data) => {
2668 var role = ''
2669
2670 if (data.role === 1)
2671 role = 'Resident DJ'
2672 else if (data.role === 2)
2673 role = 'Bouncer'
2674 else if (data.role === 3)
2675 role = 'Manager'
2676 else if (data.role === 4)
2677 role = 'Co-Host'
2678 else if (data.role === 5)
2679 role = 'Host'
2680
2681 if (data.role == 0)
2682 console.log(`${data.moderator.username} removed ${data.user.username} from the staff.`)
2683 else
2684 console.log(`${data.moderator.username} set ${data.user.username} as a ${role}.`)
2685})
2686```
2687
2688<a id="event-waitlistban"></a>
2689<a id="event-modwaitlistban"></a>
2690## 'modWaitlistBan'
2691
2692Fired when a user is banned from the waitlist.
2693
2694**Parameters**
2695
2696 - `ban` - A [WaitlistBan](#class-waitlistban) object representing the new ban.
2697
2698```js
2699mp.on('modWaitlistBan', (ban) => {
2700 ban.user.chat('Ha! Sucker!')
2701})
2702```
2703
2704<a id="event-roomupdate"></a>
2705## 'roomUpdate'
2706
2707Fired when an attribute of the current room updates.
2708
2709**Parameters**
2710
2711 - `change` - Object containing the new attribute/value pair. For example, if
2712 the welcome message was changed, the object may contain
2713 `{ welcome: 'Hello!' }`.
2714 - `user` - The staff [User](#class-user) who made the change.
2715
2716```js
2717const roomProperties = mp.room().toJSON()
2718
2719mp.on('roomUpdate', (change) => {
2720 Object.assign(roomProperties, change)
2721})
2722```
2723
2724<a id="event-roomnameupdate"></a>
2725## 'roomNameUpdate'
2726
2727Fired when the room name was changed.
2728
2729**Parameters**
2730
2731 - `name` - The new room name.
2732 - `user` - The staff [User](#class-user) who made the change.
2733
2734```js
2735mp.on('roomNameUpdate', (name, user) => {
2736 console.log(user.mention(), 'changed the room name to', name)
2737})
2738```
2739
2740<a id="event-roomdescriptionupdate"></a>
2741## 'roomDescriptionUpdate'
2742
2743Fired when the room description was changed.
2744
2745**Parameters**
2746
2747 - `description` - The new room description.
2748 - `user` - The staff [User](#class-user) who made the change.
2749
2750```js
2751mp.on('roomDescriptionUpdate', (description, user) => {
2752 console.log(user.mention(), 'changed the room description to:')
2753 console.log(description)
2754})
2755```
2756
2757<a id="event-roomwelcomeupdate"></a>
2758## 'roomWelcomeUpdate'
2759
2760Fired when the room welcome message was changed.
2761
2762**Parameters**
2763
2764 - `welcome` - The new welcome message.
2765 - `user` - The staff [User](#class-user) who made the change.
2766
2767```js
2768mp.on('roomWelcomeUpdate', (welcome, user) => {
2769 console.log(user.mention(), 'changed the welcome message.')
2770 console.log('New users will now see', welcome)
2771})
2772```
2773
2774<a id="event-roomminchatlevelupdate"></a>
2775## 'roomMinChatLevelUpdate'
2776
2777Fired when the room's minimum chat level changes.
2778
2779**Parameters**
2780
2781 - `minChatLevel` - The new minimum chat level.
2782 - `user` - The staff [User](#class-user) who made the change.
2783
2784```js
2785mp.on('roomMinChatLevelUpdate', (level, user) => {
2786 console.log(user.mention(), 'changed the minimum chat level to', level)
2787})
2788```
2789
2790<a id="event-skip"></a>
2791## 'skip'
2792
2793Fired when a user skips their own play.
2794
2795**Parameters**
2796
2797 - `user` - The [User](#class-user) object of the user who skipped.
2798
2799```js
2800mp.on('skip', (user) => {
2801 console.log(`${user.username} has decided to skip.`)
2802})
2803```
2804
2805<a id="event-sub"></a>
2806## 'sub'
2807
2808Fired when the current user gets a gold subscription membership.
2809
2810**Parameters**
2811
2812 - `value` - The subscription value. 0 for no subscription, 1 for a gold subscription.
2813
2814```js
2815mp.on('sub', (value) => {
2816 if (value) mp.emote('is now a gold subscriber :tada:')
2817})
2818```
2819
2820<a id="event-userjoin"></a>
2821## 'userJoin'
2822
2823Fired when a user joins the room.
2824
2825**Parameters**
2826
2827 - `user` - The [User](#class-user) object of the new user.
2828
2829```js
2830mp.on('userJoin', (user) => {
2831 user.send('Welcome!')
2832})
2833```
2834
2835<a id="event-userleave"></a>
2836## 'userLeave'
2837
2838Fired when a user leaves the room.
2839
2840**Parameters**
2841
2842 - `user` - The [User](#class-user) object of the leaving user.
2843
2844```js
2845const { BAN_DURATION, BAN_REASON } = require('miniplug')
2846mp.on('userLeave', (user) => {
2847 // Alright then. GOOD BYE AND NEVER COME BACK!! 😠💢
2848 user.ban(BAN_DURATION.PERMANENT, BAN_REASON.ATTITUDE)
2849})
2850```
2851
2852<a id="event-userupdate"></a>
2853## 'userUpdate'
2854
2855Fired when a user object was updated.
2856
2857**Parameters**
2858
2859 - `user` - The [User](#class-user) object that is being updated.
2860 - `prevProps` - An object containing the old values of the properties that have
2861 changed.
2862
2863```js
2864const { BAN_DURATION, BAN_REASON } = require('miniplug')
2865const { pick, keys } = require('lodash')
2866
2867mp.on('userUpdate', (user, prevProps) => {
2868 const updatedPropsOnly = pick(user, keys(prevProps))
2869
2870 console.log(`Updated ${user.mention()}:`)
2871 console.log(prevProps, '→', updatedPropsOnly)
2872})
2873```
2874
2875<a id="event-vote"></a>
2876## 'vote'
2877
2878Fired when a user woots or mehs a song.
2879
2880**Parameters**
2881
2882 - `data` - An object with two properties:
2883 - `user` - The [User](#class-user) who voted.
2884 - `vote` - The direction of the vote: `1` for a woot, `-1` for a meh.
2885
2886```js
2887mp.on('vote', (data) => {
2888 if (data.vote === 1) {
2889 console.log(data.user.mention(), 'wooted this track!')
2890 } else if (data.vote === -1) {
2891 console.log(data.user.mention(), 'meh\'d this track…')
2892 }
2893})
2894```
2895
2896<a id="event-waitlistclear"></a>
2897## 'waitlistClear'
2898
2899Fired when the waitlist is cleared.
2900
2901**Parameters**
2902
2903 - `update` - An object with the following properties:
2904 - `user` - The [User](#class-user) that cleared the waitlist.
2905
2906```js
2907mp.on('waitlistClear', (update) => {
2908 console.info(`${update.user.mention()} cleared the waitlist!`)
2909})
2910```
2911
2912<a id="event-waitlistcycle"></a>
2913## 'waitlistCycle'
2914
2915Fired when the waitlist cycle status changes.
2916
2917**Parameters**
2918
2919 - `update` - An object with two properties:
2920 - `shouldCycle` - Whether the waitlist should cycle.
2921 - `user` - The [User](#class-user) that changed this setting.
2922
2923```js
2924mp.on('waitlistCycle', (update) => {
2925 console.info(`Waitlist cycling is now ${update.shouldCycle ? 'enabled' : 'disabled'}!`)
2926})
2927```
2928
2929<a id="event-waitlistlock"></a>
2930## 'waitlistLock'
2931
2932Fired when the waitlist lock status changes.
2933
2934**Parameters**
2935
2936 - `update` - An object with the following properties:
2937 - `locked` - A boolean indicating the new waitlist locked status.
2938 - `cleared` - True if the waitlist was also cleared.
2939 - `user` - The [User](#class-user) that changed this setting.
2940
2941```js
2942mp.on('waitlistLock', (update) => {
2943 let verb = 'unlocked'
2944 if (update.cleared) verb = 'cleared'
2945 else if (update.locked) verb = 'locked'
2946
2947 console.info(`${update.user.mention()} ${verb} the waitlist.`)
2948})
2949```
2950
2951<a id="event-waitlistupdate"></a>
2952## 'waitlistUpdate'
2953
2954Fired when the waitlist changes.
2955
2956**Parameters**
2957
2958 - `next` - The new [Waitlist](#class-waitlist).
2959 - `previous` - The previous [Waitlist](#class-waitlist).
2960
2961```js
2962mp.on('waitlistUpdate', (next, previous) => {
2963 const me = mp.me()
2964
2965 // Notify the next DJ that it is almost their turn.
2966 if (next.length > 0) {
2967 next[0].send('You are next!')
2968 }
2969
2970 // Both parameters are full Waitlist objects.
2971 console.log('I moved from', previous.positionOf(me), 'to', next.positionOf(me))
2972})
2973```
2974
2975<a id="errors"></a>
2976# Errors
2977
2978Miniplug wraps errors from the plug.dj API in custom error classes.
2979Specific types of errors can be caught using Bluebird's `catch` function:
2980
2981```js
2982const miniplug = require('miniplug')
2983
2984const mp = miniplug({ /* credentials */ })
2985mp.purchaseNameChange('Test Name')
2986 .catch(miniplug.NotEnoughPPError, (err) => {
2987 console.error('You do not have enough Plug Points to change your name.')
2988 })
2989```
2990
2991All error objects have the following properties:
2992
2993 - `message` - A human-readable string describing the reason for the error.
2994 - `status` - A status code from plug.dj.
2995 - `response` - The HTTP response object from [got](https://github.com/sindresorhus/got#goturl-options).
2996 - `cause` - The error that was wrapped, usually one from [got](https://github.com/sindresorhus/got#errors).
2997
2998<a id="error-requesterror"></a>
2999## RequestError
3000
3001A generic error that indicates that you have tried to do something impossible.
3002
3003<a id="error-badloginerror"></a>
3004## BadLoginError
3005
3006The username/password combination was incorrect.
3007
3008<a id="error-notauthorizederror"></a>
3009## NotAuthorizedError
3010
3011The bot account does not have permission to do this thing. Perhaps because the
3012thing requires you to be logged in, or to be a certain rank in the room.
3013
3014<a id="error-notfounderror"></a>
3015## NotFoundError
3016
3017The thing you are looking for does not exist.
3018
3019<a id="error-novalidplaylisterror"></a>
3020## NoValidPlaylistError
3021
3022The user to be added to the waitlist does not have a valid playlist.
3023
3024<a id="error-notenoughpperror"></a>
3025## NotEnoughPPError
3026
3027The bot account does not have enough Plug Points to purchase this thing.