From dbc58bd95b18c47042dfb249bea2e36e6d239d73 Mon Sep 17 00:00:00 2001 From: MichaelOultram Date: Thu, 30 Jul 2015 13:48:53 +0100 Subject: [PATCH] Using a web template --- commands.go | 8 +- index.html | 28 ++++++- main.go | 13 ++- service.go | 8 +- service_youtube.go | 196 ++++++++++++++++++++++----------------------- web.go | 61 ++++++++++---- 6 files changed, 185 insertions(+), 129 deletions(-) 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 }