diff --git a/commands.go b/commands.go
index c5f282f..61c83fb 100644
--- a/commands.go
+++ b/commands.go
@@ -82,6 +82,13 @@ func parseCommand(user *gumble.User, username, command string) {
} else {
dj.SendPrivateMessage(user, NO_PERMISSION_MSG)
}
+ // Web command
+ case dj.conf.Aliases.WebAlias:
+ if dj.HasPermission(username, dj.conf.Permissions.AdminWeb) {
+ GetWebAddress(user)
+ } else {
+ dj.SendPrivateMessage(user, NO_PERMISSION_MSG)
+ }
// Move command
case dj.conf.Aliases.MoveAlias:
if dj.HasPermission(username, dj.conf.Permissions.AdminMove) {
diff --git a/config.gcfg b/config.gcfg
index db67c05..5c7a595 100644
--- a/config.gcfg
+++ b/config.gcfg
@@ -86,6 +86,10 @@ HelpAlias = "help"
# DEFAULT VALUE: "volume"
VolumeAlias = "volume"
+# Alias used for web address command
+# DEFAULT VALUE: "web"
+WebAlias = "web"
+
# Alias used for move command
# DEFAULT VALUE: "move"
MoveAlias = "move"
@@ -162,6 +166,10 @@ AdminHelp = false
# DEFAULT VALUE: false
AdminVolume = false
+# Make web an admin command?
+# DEFAULT VALUE: false
+AdminWeb = false
+
# Make move an admin command?
# DEFAULT VALUE: true
AdminMove = true
diff --git a/main.go b/main.go
index 6ef1170..bc8d710 100644
--- a/main.go
+++ b/main.go
@@ -13,9 +13,9 @@ import (
"fmt"
"os"
"os/user"
+ "reflect"
"strings"
"time"
- "reflect"
"github.com/layeh/gopus"
"github.com/layeh/gumble/gumble"
@@ -148,8 +148,8 @@ func Verbose(msg string) {
}
func isNil(a interface{}) bool {
- defer func() { recover() }()
- return a == nil || reflect.ValueOf(a).IsNil()
+ defer func() { recover() }()
+ return a == nil || reflect.ValueOf(a).IsNil()
}
// dj variable declaration. This is done outside of main() to allow global use.
@@ -228,7 +228,9 @@ func main() {
if err := dj.client.Connect(); err != nil {
fmt.Printf("Could not connect to Mumble server at %s:%s.\n", address, port)
os.Exit(1)
- }
+ }
+
+ Webserver()
<-dj.keepAlive
}
diff --git a/parseconfig.go b/parseconfig.go
index 9da7ec2..4b4a16a 100644
--- a/parseconfig.go
+++ b/parseconfig.go
@@ -51,6 +51,7 @@ type DjConfig struct {
NumCachedAlias string
CacheSizeAlias string
KillAlias string
+ WebAlias string
}
Permissions struct {
AdminsEnabled bool
@@ -70,6 +71,7 @@ type DjConfig struct {
AdminNumCached bool
AdminCacheSize bool
AdminKill bool
+ AdminWeb bool
}
}
diff --git a/service_youtube.go b/service_youtube.go
index 7754935..4c60cd0 100644
--- a/service_youtube.go
+++ b/service_youtube.go
@@ -39,8 +39,7 @@ var youtubeVideoPatterns = []string{
// YOUTUBE SERVICE
// ---------------
-type YouTube struct {
-}
+type YouTube struct {}
// Name of the service
func (y YouTube) ServiceName() string {
@@ -405,14 +404,14 @@ func NewYouTubePlaylist(user, id string) (*YouTubePlaylist, error) {
}
// Retrieve items in playlist
- url = fmt.Sprintf("https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=2&playlistId=%s&key=%s",
+ url = fmt.Sprintf("https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=%s&key=%s",
id, os.Getenv("YOUTUBE_API_KEY"))
if apiResponse, err = PerformGetRequest(url); err != nil {
return nil, err
}
numVideos, _ := apiResponse.Int("pageInfo", "totalResults")
- if numVideos > 2 {
- numVideos = 2
+ if numVideos > 50 {
+ numVideos = 50
}
for i := 0; i < numVideos; i++ {
diff --git a/songqueue.go b/songqueue.go
index 67db542..f1bdc1c 100644
--- a/songqueue.go
+++ b/songqueue.go
@@ -42,14 +42,16 @@ func (q *SongQueue) CurrentSong() Song {
// NextSong moves to the next Song in SongQueue. NextSong() removes the first Song in the queue.
func (q *SongQueue) NextSong() {
- if s, err := q.PeekNext(); err == nil {
- if !isNil(q.CurrentSong().Playlist()) && !isNil(s.Playlist()) {
- if q.CurrentSong().Playlist().ID() != s.Playlist().ID() {
- q.CurrentSong().Playlist().DeleteSkippers()
+ if !isNil(q.CurrentSong().Playlist()) {
+ if s, err := q.PeekNext(); err == nil {
+ if !isNil(s.Playlist()) {
+ if q.CurrentSong().Playlist().ID() != s.Playlist().ID() {
+ q.CurrentSong().Playlist().DeleteSkippers()
+ }
}
+ } else {
+ q.CurrentSong().Playlist().DeleteSkippers()
}
- } else {
- q.CurrentSong().Playlist().DeleteSkippers()
}
q.queue = q.queue[1:]
}
diff --git a/strings.go b/strings.go
index d48e7a7..e8cf2b5 100644
--- a/strings.go
+++ b/strings.go
@@ -170,3 +170,8 @@ const CURRENT_SONG_HTML = `
const CURRENT_SONG_PLAYLIST_HTML = `
The song currently playing is "%s", added %s from the playlist "%s".
`
+
+// URL of the server for connecting via a web address
+const WEB_ADDRESS = `
+ Control mumbledj from a web browser: http://%s:9563/%s
+`
\ No newline at end of file
diff --git a/web.go b/web.go
new file mode 100644
index 0000000..76f826b
--- /dev/null
+++ b/web.go
@@ -0,0 +1,90 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "math/rand"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/layeh/gumble/gumble"
+)
+
+var client_token = make(map[string]string)
+var token_client = make(map[string]string)
+var external_ip = ""
+
+type Page struct {
+ Title string
+ Body []byte
+}
+
+func (p *Page) save() error {
+ filename := p.Title + ".txt"
+ return ioutil.WriteFile(filename, p.Body, 0600)
+}
+
+func loadPage(title string) (*Page, error) {
+ filename := title + ".txt"
+ body, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return &Page{Title: title, Body: body}, nil
+}
+
+func handler(w http.ResponseWriter, r *http.Request) {
+ var uname = token_client[r.URL.Path[1:]]
+ if uname == "" {
+ fmt.Fprintf(w, "I don't know you")
+ } else {
+ fmt.Fprintf(w, "Hi there, I love %s!", uname)
+ }
+}
+
+func Webserver() {
+ http.HandleFunc("/", handler)
+ http.ListenAndServe(":9563", nil)
+ rand.Seed(time.Now().UnixNano())
+}
+
+func GetWebAddress(user *gumble.User) {
+ if client_token[user.Name] != "" {
+ token_client[client_token[user.Name]] = ""
+ }
+ // dealing with collisions
+ var firstLoop = true
+ for firstLoop || token_client[client_token[user.Name]] != "" {
+ client_token[user.Name] = randSeq(10)
+ firstLoop = false
+ }
+ token_client[client_token[user.Name]] = user.Name
+ dj.SendPrivateMessage(user, fmt.Sprintf(WEB_ADDRESS, getIP(), client_token[user.Name], getIP(), client_token[user.Name]))
+}
+
+func getIP() string {
+ if external_ip != "" {
+ return external_ip
+ } else {
+ if response, err := http.Get("http://myexternalip.com/raw"); err == nil {
+ defer response.Body.Close()
+ if response.StatusCode == 200 {
+ if body, err := ioutil.ReadAll(response.Body); err == nil {
+ external_ip = strings.TrimSpace(string(body))
+ }
+ }
+ }
+ return external_ip
+ }
+}
+
+var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
+
+func randSeq(n int) string {
+ b := make([]rune, n)
+ for i := range b {
+ b[i] = letters[rand.Intn(len(letters))]
+ }
+ return string(b)
+}