diff --git a/README.md b/README.md index 653ed43..4fd63ca 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Yuri is the best Discord sound board in whole North Korea, if you believe it or not! And now, even better with v.2 with way better performance, better code structure, easier installation and a brand new web interface! Also, now, Lavalink is completely implemented as Discord voice backend. With the new, open REST and Web Socket API you are now able to create applications hooking up the Yuri backend! -# Features + --- diff --git a/docs/ws-api-docs.md b/docs/ws-api-docs.md index e667cd0..4fdc808 100644 --- a/docs/ws-api-docs.md +++ b/docs/ws-api-docs.md @@ -187,6 +187,7 @@ You will only get valid `connected` and `voice_state` information when you are c "name": "HELLO", "data": { "connected": true, + "vol": 25, "voice_state": { "guild_id": "526196711962705925", "channel_id": "549871583364382771" @@ -198,6 +199,7 @@ You will only get valid `connected` and `voice_state` information when you are c | Field | Type | Description | |-------|------|-------------| | `connected` | `bool` | Identicates whether the bot is connected to any voice channel on the guild you are also connected to. | +| `vol` | `int` | The volume of the guilds player, if connected. | | `voice_state.guild_id` | `string` | The guild where the bot is in the voice channel. | | `voice_state.channel_id` | `string` | The voice channel where the bot is connected to. | @@ -237,7 +239,8 @@ Is fired when a track starts playing. "guild_id": "526196711962705925", "channel_id": "549871583364382771", "user_id": "221905671296253953", - "user_tag": "zekro#9131" + "user_tag": "zekro#9131", + "vol": 25 } } ``` @@ -253,6 +256,7 @@ The event data is a JSON object with following properties: | `guild_id` | `string` | The guild the track was played on. | | `user_id` | `string` | The users ID who played the track. | | `user_tag` | `string` | The users Tag who played the track. | +| `vol` | `int` | The current volume of the guilds player. | ### END @@ -389,7 +393,8 @@ Is fired when the bot joined a voice channel. "name": "JOINED", "data": { "guild_id": "526196711962705925", - "channel_id": "549871583364382771" + "channel_id": "549871583364382771", + "vol": 25 } } ``` @@ -402,6 +407,7 @@ The event data is a JSON object with following properties: |-------|------|-------------| | `guild_id` | `string` | The ID of the guild where the bot joined. | | `channel_id` | `string` | The ID of the channel where the bot joined into. | +| `vol` | `int` | The current volume of the guilds player. | ### LEFT diff --git a/internal/api/playerhandler.go b/internal/api/playerhandler.go index f8b5be8..a45c96f 100644 --- a/internal/api/playerhandler.go +++ b/internal/api/playerhandler.go @@ -16,6 +16,7 @@ type soundTrack struct { ChannelID string `json:"channel_id,omitempty"` UserID string `json:"user_id,omitempty"` UserTag string `json:"user_tag,omitempty"` + Vol int `json:"vol,omitempty"` } type wsPlayExceptionData struct { @@ -36,6 +37,7 @@ type wsVolumeChangedData struct { type wsGuildChannelData struct { GuildID string `json:"guild_id"` ChannelID string `json:"channel_id"` + Vol int `json:"vol"` } // OnTrackStart is the handler for PLAYING event @@ -49,6 +51,7 @@ func (api *API) OnTrackStart(player *gavalink.Player, track, ident string, ChannelID: channelID, UserID: userID, UserTag: userTag, + Vol: player.GetVolume(), } // The saved track ID is shortened by 5 characters because @@ -145,9 +148,12 @@ func (api *API) OnVolumeChanged(player *gavalink.Player, guildID string, vol int func (api *API) OnVoiceJoined(guildID, channelID string) { logger.Debug("API :: PLAYER HANDLER :: voice joined event") + vol, _ := api.player.GetVolume(guildID) + e := &wsGuildChannelData{ GuildID: guildID, ChannelID: channelID, + Vol: vol, } cond := condFactory(api.session, guildID) diff --git a/internal/api/wshandlers.go b/internal/api/wshandlers.go index 68c9863..fbee0ab 100644 --- a/internal/api/wshandlers.go +++ b/internal/api/wshandlers.go @@ -27,6 +27,7 @@ type wsIdent struct { type wsHelloData struct { Connected bool `json:"connected"` + Vol int `json:"vol"` VS *wsVoiceState `json:"voice_state"` } @@ -70,12 +71,15 @@ func (api *API) wsInitHandler(e *wsmgr.Event) { guild, _ := discordbot.GetUsersGuildInVoice(api.session, data.UserID) var svs *discordgo.VoiceState + var vol int if guild != nil { svs = api.player.GetSelfVoiceState(guild.ID) + vol, _ = api.player.GetVolume(guild.ID) } event := &wsHelloData{ + Vol: vol, Connected: svs != nil, } @@ -196,7 +200,7 @@ func (api *API) wsVolumeHandler(e *wsmgr.Event) { return } - vol, ok := e.Data.(int) + vol, ok := e.Data.(float64) if !ok { wsSendError(e.Sender, wsErrBadCommandArgs, "invalid command data format") return @@ -213,7 +217,7 @@ func (api *API) wsVolumeHandler(e *wsmgr.Event) { return } - err := api.player.SetVolume(guild.ID, vol) + err := api.player.SetVolume(guild.ID, int(vol)) if err != nil { wsSendError(e.Sender, wsErrInternal, fmt.Sprintf("command failed: %s", err.Error())) } diff --git a/internal/player/player.go b/internal/player/player.go index 8f5d5d0..abf5976 100644 --- a/internal/player/player.go +++ b/internal/player/player.go @@ -392,6 +392,17 @@ func (p *Player) SetVolume(guildID string, vol int) error { return p.db.SetGuildVolume(guildID, vol) } +// GetVolume returns the volume of the player +// for the specified guild. +func (p *Player) GetVolume(guildID string) (int, error) { + pl, err := p.link.GetPlayer(guildID) + if err != nil { + return 0, nil + } + + return pl.GetVolume(), nil +} + // GetSelfVoiceState returns the current voice state on // the specified guild. This will return nil if the bot // is not in any voice channel on this guild. diff --git a/web/pages/index.html b/web/pages/index.html index 00176db..9802994 100644 --- a/web/pages/index.html +++ b/web/pages/index.html @@ -20,6 +20,10 @@

YURI

JOIN LOG STATS +
+ +

+
diff --git a/web/static/css/main.css b/web/static/css/main.css index 6a8ea24..ab213ec 100644 --- a/web/static/css/main.css +++ b/web/static/css/main.css @@ -65,6 +65,10 @@ h1, h2, h3, h4, p, a { margin-bottom: 4rem !important; } +#sliderVol { + width: 100px; +} + .btn-sound { background-color: var(--c-btn-sound) !important; transition: all .25s ease; @@ -109,4 +113,40 @@ h1, h2, h3, h4, p, a { padding: 1rem; background-color: var(--c-footer); /* height: 60px; Set the fixed height of the footer here */ - } \ No newline at end of file +} + +.slider { + -webkit-appearance: none; + width: 100%; + height: 10px; + border-radius: 5px; + background: var(--c-vol-bg); + outline: none; + opacity: 0.7; + -webkit-transition: .2s; + transition: opacity .2s; +} + +.slider::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 15px; + height: 15px; + border-radius: 50%; + background: var(--c-vol); + border-color: #00000000; + cursor: pointer; +} + +.slider::-moz-range-thumb { + width: 15px; + height: 15px; + border-radius: 50%; + background: var(--c-vol); + border-color: #00000000; + cursor: pointer; +} + +.invis { + display: none !important; +} \ No newline at end of file diff --git a/web/static/css/vars.css b/web/static/css/vars.css index 10777b1..ad25388 100644 --- a/web/static/css/vars.css +++ b/web/static/css/vars.css @@ -11,6 +11,9 @@ --c-warning: #FFCA2833; --c-error: rgba(255, 40, 40, 0.2); + + --c-vol: #039BE5; + --c-vol-bg: #191e20; } @keyframes randomButtonHover { diff --git a/web/static/js/index.js b/web/static/js/index.js index a956675..55a7791 100644 --- a/web/static/js/index.js +++ b/web/static/js/index.js @@ -87,6 +87,14 @@ function displayError(desc, time) { }, time + 250); } +function setVolume(v) { + var container = $('#containerVol'); + if (container.hasClass('invis')) + container.removeClass('invis'); + $('#sliderVol').val(v); + $('#labelVol')[0].innerText = v + '%'; +} + ws.onEmit((e, raw) => console.log(`WS API :: COMMAND < ${e.name} > ::`, e.data)); // -------------------------- @@ -101,6 +109,10 @@ if (getCookieValue('cookies_accepted') !== '1') { $('#cookieInformation')[0].style.display = 'block'; } +fetchSoundsList(sortBy, (s) => { + if (s) sounds = s; +}); + // BUTTON EVENT HOOKS $('#btnSortBy').on('click', (e) => { @@ -218,13 +230,19 @@ $('#searchBox').on('input', (e) => { }, 250); }); -if (sortBy) - $('#btnSortBy')[0].innerText = 'SORT BY ' + (sortBy == 'DATE' ? 'NAME' : 'DATE'); +$('#sliderVol').on('input', (e) => { + var val = $('#sliderVol').val(); + $('#labelVol')[0].innerText = val + '%'; +}); -fetchSoundsList(sortBy, (s) => { - if (s) sounds = s; +$('#sliderVol').on('change', (e) => { + var val = $('#sliderVol').val(); + ws.emit('VOLUME', parseInt(val)); }); +if (sortBy) + $('#btnSortBy')[0].innerText = 'SORT BY ' + (sortBy == 'DATE' ? 'NAME' : 'DATE'); + // -------------------------- // --- WS EVENT HANDLERS @@ -239,6 +257,7 @@ ws.on('HELLO', (data) => { $('#btnJoinLeave')[0].innerText = 'LEAVE'; inChannel = true; guildID = data.data.voice_state.guild_id; + setVolume(data.data.vol); } }); @@ -250,6 +269,7 @@ ws.on('PLAYING', (data) => { inChannel = true; $('#btnJoinLeave')[0].innerText = 'LEAVE'; guildID = data.data.guild_id; + setVolume(data.data.vol); }); ws.on('END', (data) => { @@ -276,6 +296,7 @@ ws.on('JOINED', (data) => { inChannel = true; $('#btnJoinLeave')[0].innerText = 'LEAVE'; guildID = data.data.guild_id; + setVolume(data.data.vol); }); ws.on('LEFT', (data) => {