diff --git a/commands.go b/commands.go
index 59d66ea..d4dc02d 100644
--- a/commands.go
+++ b/commands.go
@@ -171,13 +171,7 @@ func add(user *gumble.User, url string) error {
dj.SendPrivateMessage(user, NO_ARGUMENT_MSG)
return errors.New("NO_ARGUMENT")
} else {
- title, err := findServiceAndAdd(user, url)
- if err == nil {
- dj.client.Self.Channel.Send(fmt.Sprintf(SONG_ADDED_HTML, user.Name, title), false)
- } else {
- dj.SendPrivateMessage(user, err.Error())
- }
- return err
+ return findServiceAndAdd(user, url)
}
}
diff --git a/index.html b/index.html
index e4c1635..5659235 100644
--- a/index.html
+++ b/index.html
@@ -2,17 +2,37 @@
- %s - mumbledj
+ {{user}} - mumbledj
+
Add Song Form
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/main.go b/main.go
index dd7bec3..91c00bb 100644
--- a/main.go
+++ b/main.go
@@ -152,6 +152,17 @@ func isNil(a interface{}) bool {
return a == nil || reflect.ValueOf(a).IsNil()
}
+func RegexpFromURL(url string, patterns []string) *regexp.Regexp {
+ for _, pattern := range patterns {
+ if re, err := regexp.Compile(pattern); err == nil {
+ if re.MatchString(url) {
+ return re
+ }
+ }
+ }
+ return nil
+}
+
// dj variable declaration. This is done outside of main() to allow global use.
var dj = mumbledj{
keepAlive: make(chan bool),
@@ -230,7 +241,7 @@ func main() {
os.Exit(1)
}
- Webserver()
+ Webserver(9563)
<-dj.keepAlive
}
diff --git a/service.go b/service.go
index bc0db34..36c77ab 100644
--- a/service.go
+++ b/service.go
@@ -53,7 +53,7 @@ type Playlist interface {
var services = []Service{YouTube{}}
-func findServiceAndAdd(user *gumble.User, url string) (string, error) {
+func findServiceAndAdd(user *gumble.User, url string) error {
var urlService Service
// Checks all services to see if any can take the URL
@@ -69,7 +69,9 @@ func findServiceAndAdd(user *gumble.User, url string) (string, error) {
oldLength := dj.queue.Len()
var title string
var err error
+
if title, err = urlService.NewRequest(user, url); err == nil {
+ dj.client.Self.Channel.Send(fmt.Sprintf(SONG_ADDED_HTML, user.Name, title), false)
// Starts playing the new song if nothing else is playing
if oldLength == 0 && dj.queue.Len() != 0 && !dj.audioStream.IsPlaying() {
@@ -81,7 +83,9 @@ func findServiceAndAdd(user *gumble.User, url string) (string, error) {
return "", errors.New("FAILED_TO_DOWNLOAD")
}
}
+ } else {
+ dj.SendPrivateMessage(user, err.Error())
}
- return title, err
+ return err
}
}
diff --git a/service_youtube.go b/service_youtube.go
index 9a94723..63a343d 100644
--- a/service_youtube.go
+++ b/service_youtube.go
@@ -35,64 +35,13 @@ var youtubeVideoPatterns = []string{
`https?:\/\/www.youtube.com\/v\/([\w-]+)(\?t=\d*m?\d*s?)?`,
}
-// ---------------
-// YOUTUBE SERVICE
-// ---------------
+// ------
+// TYPES
+// ------
+// YouTube implements the Service interface
type YouTube struct{}
-// Name of the service
-func (y YouTube) ServiceName() string {
- return "Youtube"
-}
-
-// Checks to see if service will accept URL
-func (y YouTube) URLRegex(url string) bool {
- return RegexpFromURL(url, append(youtubeVideoPatterns, []string{youtubePlaylistPattern}...)) != nil
-}
-
-func RegexpFromURL(url string, patterns []string) *regexp.Regexp {
- for _, pattern := range patterns {
- if re, err := regexp.Compile(pattern); err == nil {
- if re.MatchString(url) {
- return re
- }
- }
- }
- return nil
-}
-
-// Creates the requested song/playlist and adds to the queue
-func (y YouTube) NewRequest(user *gumble.User, url string) (string, error) {
- var shortURL, startOffset = "", ""
- if re, err := regexp.Compile(youtubePlaylistPattern); err == nil {
- if re.MatchString(url) {
- if dj.HasPermission(user.Name, dj.conf.Permissions.AdminAddPlaylists) {
- shortURL = re.FindStringSubmatch(url)[1]
- playlist, err := NewYouTubePlaylist(user.Name, shortURL)
- return playlist.Title(), err
- } else {
- return "", errors.New("NO_PLAYLIST_PERMISSION")
- }
- } else {
- re = RegexpFromURL(url, youtubeVideoPatterns)
- matches := re.FindAllStringSubmatch(url, -1)
- shortURL = matches[0][1]
- if len(matches[0]) == 3 {
- startOffset = matches[0][2]
- }
- song, err := NewYouTubeSong(user.Name, shortURL, startOffset, nil)
- return song.Title(), err
- }
- } else {
- return "", err
- }
-}
-
-// ------------
-// YOUTUBE SONG
-// ------------
-
// YouTubeSong holds the metadata for a song extracted from a YouTube video.
type YouTubeSong struct {
submitter string
@@ -107,14 +56,61 @@ type YouTubeSong struct {
dontSkip bool
}
-// NewYouTubeSong gathers the metadata for a song extracted from a YouTube video, and returns
+// YouTubePlaylist holds the metadata for a YouTube playlist.
+type YouTubePlaylist struct {
+ id string
+ title string
+}
+
+// ---------------
+// YOUTUBE SERVICE
+// ---------------
+
+// Name of the service
+func (yt YouTube) ServiceName() string {
+ return "Youtube"
+}
+
+// Checks to see if service will accept URL
+func (yt YouTube) URLRegex(url string) bool {
+ return RegexpFromURL(url, append(youtubeVideoPatterns, []string{youtubePlaylistPattern}...)) != nil
+}
+
+// Creates the requested song/playlist and adds to the queue
+func (yt YouTube) NewRequest(user *gumble.User, url string) (string, error) {
+ var shortURL, startOffset = "", ""
+ if re, err := regexp.Compile(youtubePlaylistPattern); err == nil {
+ if re.MatchString(url) {
+ if dj.HasPermission(user.Name, dj.conf.Permissions.AdminAddPlaylists) {
+ shortURL = re.FindStringSubmatch(url)[1]
+ playlist, err := yt.NewPlaylist(user.Name, shortURL)
+ return playlist.Title(), err
+ } else {
+ return "", errors.New("NO_PLAYLIST_PERMISSION")
+ }
+ } else {
+ re = RegexpFromURL(url, youtubeVideoPatterns)
+ matches := re.FindAllStringSubmatch(url, -1)
+ shortURL = matches[0][1]
+ if len(matches[0]) == 3 {
+ startOffset = matches[0][2]
+ }
+ song, err := yt.NewSong(user.Name, shortURL, startOffset, nil)
+ return song.Title(), err
+ }
+ } else {
+ return "", err
+ }
+}
+
+// NewSong gathers the metadata for a song extracted from a YouTube video, and returns
// the song.
-func NewYouTubeSong(user, id, offset string, playlist *YouTubePlaylist) (*YouTubeSong, error) {
+func (yt YouTube) NewSong(user, id, offset string, playlist *YouTubePlaylist) (*YouTubeSong, error) {
var apiResponse *jsonq.JsonQuery
var err error
url := fmt.Sprintf("https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails&id=%s&key=%s",
id, os.Getenv("YOUTUBE_API_KEY"))
- if apiResponse, err = PerformGetRequest(url); err != nil {
+ if apiResponse, err = yt.PerformGetRequest(url); err != nil {
return nil, errors.New(INVALID_API_KEY)
}
@@ -203,6 +199,46 @@ func NewYouTubeSong(user, id, offset string, playlist *YouTubePlaylist) (*YouTub
return nil, errors.New(VIDEO_TOO_LONG_MSG)
}
+// NewPlaylist gathers the metadata for a YouTube playlist and returns it.
+func (yt YouTube) NewPlaylist(user, id string) (*YouTubePlaylist, error) {
+ var apiResponse *jsonq.JsonQuery
+ var err error
+ // Retrieve title of playlist
+ url := fmt.Sprintf("https://www.googleapis.com/youtube/v3/playlists?part=snippet&id=%s&key=%s",
+ id, os.Getenv("YOUTUBE_API_KEY"))
+ if apiResponse, err = yt.PerformGetRequest(url); err != nil {
+ return nil, err
+ }
+ title, _ := apiResponse.String("items", "0", "snippet", "title")
+
+ playlist := &YouTubePlaylist{
+ id: id,
+ title: title,
+ }
+
+ // Retrieve items in playlist
+ 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 = yt.PerformGetRequest(url); err != nil {
+ return nil, err
+ }
+ numVideos, _ := apiResponse.Int("pageInfo", "totalResults")
+ if numVideos > 50 {
+ numVideos = 50
+ }
+
+ for i := 0; i < numVideos; i++ {
+ index := strconv.Itoa(i)
+ videoID, _ := apiResponse.String("items", index, "snippet", "resourceId", "videoId")
+ yt.NewSong(user, videoID, "", playlist)
+ }
+ return playlist, nil
+}
+
+// ------------
+// YOUTUBE SONG
+// ------------
+
// Download downloads the song via youtube-dl if it does not already exist on disk.
// All downloaded songs are stored in ~/.mumbledj/songs and should be automatically cleaned.
func (s *YouTubeSong) Download() error {
@@ -380,48 +416,6 @@ func (s *YouTubeSong) SetDontSkip(value bool) {
// YOUTUBE PLAYLIST
// ----------------
-// YouTubePlaylist holds the metadata for a YouTube playlist.
-type YouTubePlaylist struct {
- id string
- title string
-}
-
-// NewYouTubePlaylist gathers the metadata for a YouTube playlist and returns it.
-func NewYouTubePlaylist(user, id string) (*YouTubePlaylist, error) {
- var apiResponse *jsonq.JsonQuery
- var err error
- // Retrieve title of playlist
- url := fmt.Sprintf("https://www.googleapis.com/youtube/v3/playlists?part=snippet&id=%s&key=%s",
- id, os.Getenv("YOUTUBE_API_KEY"))
- if apiResponse, err = PerformGetRequest(url); err != nil {
- return nil, err
- }
- title, _ := apiResponse.String("items", "0", "snippet", "title")
-
- playlist := &YouTubePlaylist{
- id: id,
- title: title,
- }
-
- // Retrieve items in playlist
- 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 > 50 {
- numVideos = 50
- }
-
- for i := 0; i < numVideos; i++ {
- index := strconv.Itoa(i)
- videoID, _ := apiResponse.String("items", index, "snippet", "resourceId", "videoId")
- NewYouTubeSong(user, videoID, "", playlist)
- }
- return playlist, nil
-}
-
// AddSkip adds a skip to the playlist's skippers slice.
func (p *YouTubePlaylist) AddSkip(username string) error {
for _, user := range dj.playlistSkips[p.ID()] {
@@ -475,7 +469,7 @@ func (p *YouTubePlaylist) Title() string {
// -----------
// PerformGetRequest does all the grunt work for a YouTube HTTPS GET request.
-func PerformGetRequest(url string) (*jsonq.JsonQuery, error) {
+func (yt YouTube) PerformGetRequest(url string) (*jsonq.JsonQuery, error) {
jsonString := ""
if response, err := http.Get(url); err == nil {
diff --git a/web.go b/web.go
index c26bcf6..25ce20f 100644
--- a/web.go
+++ b/web.go
@@ -12,37 +12,70 @@ import (
"github.com/layeh/gumble/gumble"
)
-var client_token = make(map[*gumble.User]string)
-var token_client = make(map[string]*gumble.User)
-var external_ip = ""
-
-func Webserver() {
- http.HandleFunc("/", homepage)
- http.HandleFunc("/add", addSong)
- http.ListenAndServe(":9563", nil)
- rand.Seed(time.Now().UnixNano())
+type WebServer struct {
+ port int
+ client_token map[*gumble.User]string
+ token_client map[string]*gumble.User
}
-func homepage(w http.ResponseWriter, r *http.Request) {
+type Page struct {
+ siteUrl string
+ token string
+}
+
+var external_ip = ""
+
+func Webserver(port int) *WebServer {
+ var webserver = WebServer{port, make(map[*gumble.User]string), make(map[string]*gumble.User)}
+ http.HandleFunc("/", webServer.homepage)
+ http.HandleFunc("/add", webserver.add)
+ http.HandleFunc("/volume", webserver.volume)
+ http.HandleFunc("/skip", webserver.skip)
+ http.ListenAndServe(":"+port, nil)
+ rand.Seed(time.Now().UnixNano())
+ return &webserver
+}
+
+func (w WebServer) homepage(w http.ResponseWriter, r *http.Request) {
var uname = token_client[r.URL.Path[1:]]
if uname == nil {
fmt.Fprintf(w, "Invalid Token")
} else {
- fmt.Fprintf(w, "Hang in there %s, I haven't made the website yet!", uname.Name)
+ t, _ := template.ParseFiles("index.html")
+ t.Execute(w, Page{"http://" + getIp() + ":" + w.port + "/", r.URL.Path[1:]})
}
}
-func addSong(w http.ResponseWriter, r *http.Request) {
+func (w WebServer) add(w http.ResponseWriter, r *http.Request) {
var uname = token_client[r.FormValue("token")]
if uname == nil {
fmt.Fprintf(w, "Invalid Token")
} else {
- var url = html.UnescapeString(r.FormValue("url"))
+ add(uname, html.UnescapeString(r.FormValue("value")))
+ }
+}
+
+func (w WebServer) volume(w http.ResponseWriter, r *http.Request) {
+ var uname = token_client[r.FormValue("token")]
+ if uname == nil {
+ fmt.Fprintf(w, "Invalid Token")
+ } else {
+ var url = html.UnescapeString(r.FormValue("value"))
add(uname, url)
}
}
-func GetWebAddress(user *gumble.User) {
+func (w WebServer) skip(w http.ResponseWriter, r *http.Request) {
+ var uname = token_client[r.FormValue("token")]
+ if uname == nil {
+ fmt.Fprintf(w, "Invalid Token")
+ } else {
+ var url = html.UnescapeString(r.FormValue("value"))
+ add(uname, url)
+ }
+}
+
+func (w WebServer) GetWebAddress(user *gumble.User) {
if client_token[user] != "" {
token_client[client_token[user]] = nil
}