Skip to content
This repository has been archived by the owner on Apr 13, 2022. It is now read-only.

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
Dustin Blackman committed Mar 4, 2016
0 parents commit cd4d60a
Show file tree
Hide file tree
Showing 16 changed files with 726 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .dockerignore
@@ -0,0 +1,12 @@
.git/
bk/
scripts/
vendor/

.DS_Store
config.json
speakerbot
README.md
.travis.yml

test.go
8 changes: 8 additions & 0 deletions .gitignore
@@ -0,0 +1,8 @@
bk/
vendor/

.DS_Store
config.json
speakerbot

test.go
5 changes: 5 additions & 0 deletions .travis.yml
@@ -0,0 +1,5 @@
language: go
go:
- 1.6
install: make
script: ./scripts/test.sh
22 changes: 22 additions & 0 deletions Dockerfile
@@ -0,0 +1,22 @@
FROM alpine:3.3
MAINTAINER Dustin Blackman

ENV GOROOT /usr/lib/go
ENV GOPATH /gopath
ENV GOBIN /gopath/bin
ENV PATH $PATH:$GOROOT/bin:$GOPATH/bin

COPY . /gopath/src/github.com/dustinblackman/speakerbot

RUN apk add --update ffmpeg opus opus-dev bash git make pkgconfig build-base && \
apk add go --update-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/community/ --allow-untrusted && \
cd /gopath/src/github.com/dustinblackman/speakerbot && \
make && \
make build && \
mkdir /app && \
mv ./speakerbot /app/ && \
apk del go git make pkgconfig opus-dev build-base && \
rm -rf /usr/share/man /tmp/* /var/tmp/* /var/cache/apk/* /gopath

WORKDIR /app
CMD ["./speakerbot"]
21 changes: 21 additions & 0 deletions LICENSE
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2016 Dustin Blackman

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
14 changes: 14 additions & 0 deletions Makefile
@@ -0,0 +1,14 @@
all:
which glide || go get github.com/Masterminds/glide && glide install

build:
go build -o speakerbot *.go

dev:
which CompileDaemon || go get github.com/githubnemo/CompileDaemon && CompileDaemon -directory=. -exclude-dir=.git -exclude-dir=vendor -exclude=speakerbot -command=./speakerbot

docker-build:
docker build -t dustinblackman/speakerbot .

test:
./scripts/test.sh
58 changes: 58 additions & 0 deletions README.md
@@ -0,0 +1,58 @@
![Speakerbot](assets/banner.jpg)

Speakerbot is a multiserver music bot for Discord written in Go. Supports Youtube links and querying Youtube, as well as on the fly converting resulting in instant playback (no wait times between songs!).

## Commands

- `!play` - Queues/Plays Youtube link, or searches Youtube and picks the first result
- `!skip` - Skips current track
- `!stops` - Stops playing and clears queue

## Installation

Speakerbot requires both [`ffmpeg`](https://ffmpeg.org/download.html) and [`opus-tools`](https://www.opus-codec.org/downloads/) to be installed locally and available in PATH. Currently tested with Go 1.6 on OSX.

```bash
go get github.com/dustinblackman/speakerbot
make
make build
```

A configuration file is available to plugin your Discord email and password, as well as a Google API key that can search Youtube. You can either rename the `config.example.json` to `config.json`, or copy/paste the following.

```json
{
"email": "",
"password": "",
"googleKey": ""
}
```

Lastly, start Speakerbot

```bash
./speakerbot
```

## Docker

An automated docker build is available here. You can boot it up with `docker-compose` like so as an example.

```yaml
speakerbot:
image: dustinblackman/speakerbot
environment:
EMAIL:
PASSWORD:
GOOGLEKEY:
```

## Contribute/Development

If you wish to contribute and add features to Speakerbot, feel free! This app was just a practice app to begin learning Go, so there won't be very much (or any at all) future development from myself.

Make sure to run `make test` before submitting a PR.

## [License](LICENSE)

MIT
Binary file added assets/banner.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions config.example.json
@@ -0,0 +1,5 @@
{
"email": "",
"password": "",
"googleKey": ""
}
45 changes: 45 additions & 0 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions glide.yaml
@@ -0,0 +1,12 @@
package: github.com/dustinblackman/speakerbot
import:
- package: github.com/bwmarrin/discordgo
version: develop
- package: github.com/davecgh/go-spew
subpackages:
- spew
- package: github.com/layeh/gopus
- package: github.com/oleiade/lane
- package: github.com/Jeffail/gabs
- package: github.com/paked/configure
- package: github.com/parnurzeal/gorequest
90 changes: 90 additions & 0 deletions main.go
@@ -0,0 +1,90 @@
package main

import (
"fmt"
"os"
"strings"
"time"

"github.com/bwmarrin/discordgo"
"github.com/paked/configure"
)

const (
// VERSION of Speakerbot
VERSION = "1.0.0"
)

var (
conf = configure.New()
email = conf.String("email", "", "Discord email address")
password = conf.String("password", "", "Discord password")
googleKey = conf.String("googleKey", "", "Google API key for Youtube API")
)

func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
if s.State.Ready.User.Username == m.Author.Username {
return
}

fmt.Printf("%20s %20s %20s > %s\n", m.ChannelID, time.Now().Format(time.Stamp), m.Author.Username, m.Content)

if m.Content[:1] == "!" {
channel, _ := s.Channel(m.ChannelID)
serverID := channel.GuildID
method := strings.Split(m.Content, " ")[0][1:]

if method == "play" {
youtubeLink, youtubeTitle, err := GetYoutubeURL(strings.Split(m.Content, " ")[1])
if err != nil {
fmt.Println(err)
s.ChannelMessageSend(m.ChannelID, "Error: No video found")
return
}

if voiceInstances[serverID] != nil {
voiceInstances[serverID].QueueVideo(youtubeLink)
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Queued: %s", youtubeTitle))
} else {
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Playing: %s", youtubeTitle))
go CreateVoiceInstance(youtubeLink, serverID)
}
} else if method == "stop" && voiceInstances[serverID] != nil {
voiceInstances[serverID].StopVideo()
} else if method == "skip" && voiceInstances[serverID] != nil {
voiceInstances[serverID].SkipVideo()
} else if method == "help" {
s.ChannelMessageSend(m.ChannelID, `**!play** <youtube link or query> - Search/Play Youtube link, queues up if another track is playing
**!skip** - Skip current playing track
**!stop** - Stops tracks and clears queue`)
}
}
}

func main() {
// Pull in configuration
conf.Use(configure.NewFlag())
conf.Use(configure.NewEnvironment())
if _, err := os.Stat("config.json"); err == nil {
conf.Use(configure.NewJSONFromFile("config.json"))
}
conf.Parse()

discord, err := discordgo.New(*email, *password)
if err != nil {
fmt.Println("Error logging in")
fmt.Println(err)
}

discord.AddHandler(messageCreate)

// Open the websocket and begin listening.
err = discord.Open()
if err != nil {
fmt.Println(err)
}

fmt.Println("Listening...")
lock := make(chan int)
<-lock
}
61 changes: 61 additions & 0 deletions pcm.go
@@ -0,0 +1,61 @@
package main

import (
"fmt"
"sync"

"github.com/bwmarrin/discordgo"
"github.com/layeh/gopus"
)

var (
sendpcm bool
recv chan *discordgo.Packet
mu sync.Mutex
)

const (
maxBytes int = (frameSize * 2) * 2 // max size of opus data
)

// SendPCM will receive on the provied channel encode
// received PCM data into Opus then send that to Discordgo
func SendPCM(v *discordgo.Voice, pcm <-chan []int16) {
mu.Lock()
if sendpcm || pcm == nil {
mu.Unlock()
return
}
sendpcm = true
mu.Unlock()
defer func() { sendpcm = false }()

opusEncoder, err := gopus.NewEncoder(frameRate, channels, gopus.Audio)
if err != nil {
fmt.Println("NewEncoder Error:", err)
return
}

for {
// read pcm from chan, exit if channel is closed.
recv, ok := <-pcm
if !ok {
fmt.Println("PCM Channel closed.")
return
}

// try encoding pcm frame with Opus
opus, err := opusEncoder.Encode(recv, frameSize, maxBytes)
if err != nil {
fmt.Println("Encoding Error:", err)
return
}

if v.Ready == false || v.OpusSend == nil {
// fmt.Printf("Discordgo not ready for opus packets. %+v : %+v", v.Ready, v.OpusSend)
return
}
// send encoded opus data to the sendOpus channel
v.OpusSend <- opus
}
}
18 changes: 18 additions & 0 deletions scripts/test.sh
@@ -0,0 +1,18 @@
set -e
cd $PWD

go vet

if [[ $(golint *.go) ]]; then
golint *.go
echo "golint failed"
exit 1
fi

if [[ $(gofmt -d ./*.go) ]]; then
gofmt -d ./*.go
echo "gofmt returned suggested changes, please run gofmt first. Exiting..."
exit 1
fi

echo "Hooray! Tests passed."

0 comments on commit cd4d60a

Please sign in to comment.