diff --git a/client.go b/client.go
index 0ff9d18..af65da9 100644
--- a/client.go
+++ b/client.go
@@ -26,6 +26,9 @@ func main() {
c.HandleFunc(irc.DISCONNECTED,
func(conn *irc.Conn, line *irc.Line) { quit <- true })
+ c.HandleFunc(irc.PRIVMSG, YouTubeFunc)
+ c.HandleFunc(irc.PRIVMSG, UrlFunc)
+
// set up a goroutine to read commands from stdin
in := make(chan string, 4)
reallyquit := false
diff --git a/client/funcs.go b/client/funcs.go
new file mode 100644
index 0000000..65b4164
--- /dev/null
+++ b/client/funcs.go
@@ -0,0 +1,71 @@
+package client
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "regexp"
+ "strings"
+)
+
+type youTubeVideo struct {
+ Entry struct {
+ Info struct {
+ Title struct {
+ Text string `json:"$t"`
+ } `json:"media$title"`
+ Description struct {
+ Text string `json:"$t"`
+ } `json:"media$description"`
+ } `json:"media$group"`
+ Rating struct {
+ Likes string `json:"numLikes"`
+ Dislikes string `json:"numDislikes"`
+ } `json:"yt$rating"`
+ Statistics struct {
+ Views string `json:"viewCount"`
+ } `json:"yt$statistics"`
+ } `json:entry`
+}
+
+func UrlFunc(conn *Conn, line *Line) {
+ text := line.Message()
+ if regex, err := regexp.Compile(`(\s|^)(http://|https://)(.*?)(\s|$)`); err == nil {
+ url := strings.TrimSpace(regex.FindString(text))
+ if url != "" {
+ if resp, err := http.Get(url); err == nil {
+ if strings.HasPrefix(resp.Header.Get("Content-Type"), "text/html") {
+ defer resp.Body.Close()
+ if content, err := ioutil.ReadAll(resp.Body); err == nil {
+ if regex, err := regexp.Compile(`
(.*?)`); err == nil {
+ if regex.Match([]byte(content)) {
+ conn.Privmsg(line.Target(), strings.TrimSpace(regex.FindStringSubmatch(string(content))[1]))
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+func YouTubeFunc(conn *Conn, line *Line) {
+ text := line.Message()
+ if regex, err := regexp.Compile(`(\s|^)(http://|https://)?(www.)?(youtube.com/watch\?v=|youtu.be/)(.*?)(\s|$|\&|#)`); err == nil {
+ if regex.Match([]byte(text)) {
+ matches := regex.FindStringSubmatch(text)
+ id := matches[len(matches)-2]
+ url := fmt.Sprintf("https://gdata.youtube.com/feeds/api/videos/%s?v=2&alt=json", id)
+ if resp, err := http.Get(url); err == nil {
+ defer resp.Body.Close()
+ if contents, err := ioutil.ReadAll(resp.Body); err == nil {
+ var data youTubeVideo
+ if err := json.Unmarshal(contents, &data); err == nil {
+ conn.Privmsg(line.Target(), fmt.Sprintf("%s - %s views (%s likes, %s dislikes)", data.Entry.Info.Title.Text, data.Entry.Statistics.Views, data.Entry.Rating.Likes, data.Entry.Rating.Dislikes))
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/client/line.go b/client/line.go
index b29a8fe..2cb53e1 100644
--- a/client/line.go
+++ b/client/line.go
@@ -88,3 +88,26 @@ func parseLine(s string) *Line {
}
return line
}
+
+// Return the contents of the message portion of a line.
+// This only really makes sense for messages with a :message portion, but there
+// are a lot of them.
+func (line *Line) Message() string {
+ if len(line.Args) > 0 {
+ return line.Args[len(line.Args)-1]
+ }
+ return ""
+}
+
+// Return the target of the line. This only really makes sense for PRIVMSG.
+// If the line was broadcast from a channel, the target will be that channel.
+// If the line was broadcast by a user, the target will be that user.
+func (line *Line) Target() string {
+ if line.Cmd == PRIVMSG {
+ if !strings.HasPrefix(line.Args[0], "#") {
+ return line.Nick
+ }
+ return line.Args[0]
+ }
+ return ""
+}