Using a web template
This commit is contained in:
parent
ef0d9691b8
commit
dbc58bd95b
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
28
index.html
28
index.html
|
@ -2,17 +2,37 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="ISO-8859-1">
|
||||
<title>%s - mumbledj</title>
|
||||
<title>{{user}} - mumbledj</title>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
function addURL(url) {
|
||||
function api(type) {
|
||||
return "{{.siteURL}}" + type + "?token={{.token}}";
|
||||
}
|
||||
|
||||
function addURL() {
|
||||
var url = $("#textbox");
|
||||
$.ajax(api("add") + "&value=" + url.value);
|
||||
url.value = "";
|
||||
}
|
||||
|
||||
function volume() {
|
||||
var volume = $("#textbox");
|
||||
$.ajax(api("volume") + "&value=" + volume.value);
|
||||
volume.value = "";
|
||||
}
|
||||
|
||||
function skip(val) {
|
||||
$.ajax(api("skip") + "&value=" + val);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Add Song Form</h1>
|
||||
<input type="text"/>
|
||||
<input type="button" value="Add Song" />
|
||||
<input id="textbox" type="text"/>
|
||||
<input id="add" type="button" value="Add Song" onclick="addURL()"/>
|
||||
<input id="volume" type="button" value="Set Volume" onclick="volume()"/>
|
||||
<input id="skipSong" type="button" value="Skip Current Song" onclick="skip('song')"/>
|
||||
<input id="skipPlaylist" type="button" value="Skip Current Playlist" onclick="skip('playlist')"/>
|
||||
</body>
|
||||
</html>
|
13
main.go
13
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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
61
web.go
61
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
|
||||
}
|
||||
|
|
Reference in a new issue