1. add youtube command
2. add google webhook
3. add twitch oauth route
4. add api checkSession middleware
This commit is contained in:
Jay
2018-09-16 23:39:15 +08:00
parent 3318352135
commit e8db6fdab5
12 changed files with 487 additions and 13 deletions
+6
View File
@@ -37,6 +37,12 @@ var objs = map[string]*ResObject{
"message": "input data format error",
},
},
"LoginFirst": &ResObject{
Status: 401,
Obj: map[string]string{
"message": "login first",
},
},
}
// GetRes -
+157
View File
@@ -0,0 +1,157 @@
package google
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"git.trj.tw/golang/mtfosbot/module/apis"
"git.trj.tw/golang/mtfosbot/module/config"
)
var baseURL = "https://www.googleapis.com"
func getURL(p string, querystring ...interface{}) (string, bool) {
u, err := url.Parse(baseURL)
if err != nil {
return "", false
}
ref, err := u.Parse(p)
if err != nil {
return "", false
}
if len(querystring) > 0 {
switch querystring[0].(type) {
case string:
ref, err = ref.Parse(fmt.Sprintf("?%s", (querystring[0].(string))))
if err != nil {
return "", false
}
break
default:
}
}
str := ref.String()
return str, true
}
func getHeaders(token ...interface{}) map[string]string {
m := make(map[string]string)
m["Content-Type"] = "application/json"
return m
}
type channelItem struct {
ID string `json:"id"`
Sinppet channelSinppet `json:"sinppet"`
}
type channelSinppet struct {
Title string `json:"title"`
Description string `json:"description"`
CustomURL string `json:"customUrl"`
}
// QueryYoutubeName -
func QueryYoutubeName(id string) (n string, err error) {
conf := config.GetConf()
if len(id) == 0 {
return "", errors.New("id is empty")
}
qs := url.Values{}
qs.Add("id", id)
qs.Add("key", conf.Google.APIKey)
qs.Add("part", "snippet")
apiURL, ok := getURL("/youtube/v3/channels", qs.Encode())
if !ok {
return "", errors.New("url parser fail")
}
reqObj := apis.RequestObj{
Method: "GET",
URL: apiURL,
Headers: getHeaders(),
}
req, err := apis.GetRequest(reqObj)
if err != nil {
return "", err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != 200 || !strings.HasPrefix(resp.Header.Get("Content-Type"), "application/json") {
return "", errors.New("api response fail")
}
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
apiRes := struct {
Items []channelItem `json:"items"`
}{}
err = json.Unmarshal(bodyBytes, &apiRes)
if err != nil {
return "", err
}
if len(apiRes.Items) == 0 {
return "", errors.New("channel data not found")
}
for _, v := range apiRes.Items {
if v.ID == id {
return v.Sinppet.Title, nil
}
}
return "", errors.New("channel data not found")
}
// SubscribeYoutube -
func SubscribeYoutube(id string) {
if len(id) == 0 {
return
}
conf := config.GetConf()
apiURL := "https://pubsubhubbub.appspot.com/subscribe"
cbURL, err := url.Parse(conf.URL)
if err != nil {
return
}
cbURL, err = cbURL.Parse(fmt.Sprintf("/google/youtube/webhook?id=%s", id))
if err != nil {
return
}
qs := url.Values{}
qs.Add("hub.mode", "subscribe")
qs.Add("hub.verify", "async")
qs.Add("hub.topic", fmt.Sprintf("https://www.youtube.com/xml/feeds/videos.xml?channel_id=%s", id))
qs.Add("hub.callback", cbURL.String())
qs.Add("hub.lease_seconds", "86400")
req, err := http.NewRequest("POST", apiURL, strings.NewReader(qs.Encode()))
if err != nil {
return
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
return
}
+64
View File
@@ -2,6 +2,7 @@ package twitch
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
@@ -234,3 +235,66 @@ func GetUserStreamStatus(ids []string) (info []*StreamInfo) {
return apiData.Data
}
// TwitchTokenData -
type TwitchTokenData struct {
AccessToken string `json:"access_token" cc:"access_token"`
RefreshToken string `json:"refresh_token" cc:"refresh_token"`
ExpiresIn int64 `json:"expires_in" cc:"expires_in"`
Scope string `json:"scope" cc:"scope"`
TokenType string `json:"token_type" cc:"token_type"`
}
// GetTokenData -
func GetTokenData(code string) (token *TwitchTokenData, err error) {
if len(code) == 0 {
return nil, errors.New("code is empty")
}
conf := config.GetConf()
twitchURL := "https://id.twitch.tv/oauth2/token"
redirectTo := strings.TrimRight(conf.URL, "/") + "/twitch/oauth"
qs := url.Values{}
qs.Add("client_id", conf.Twitch.ClientID)
qs.Add("client_secret", conf.Twitch.ClientSecret)
qs.Add("code", code)
qs.Add("grant_type", "authorization_code")
qs.Add("redirect_uri", redirectTo)
u, err := url.Parse(twitchURL)
if err != nil {
return nil, err
}
u, err = u.Parse(qs.Encode())
if err != nil {
return nil, err
}
reqObj := apis.RequestObj{
URL: u.String(),
Method: "POST",
}
req, err := apis.GetRequest(reqObj)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 || strings.HasPrefix(resp.Header.Get("Content-Type"), "application/json") {
return nil, errors.New("api response error")
}
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
err = json.Unmarshal(bodyBytes, &token)
return
}
+6
View File
@@ -35,6 +35,12 @@ func (c *Context) CustomRes(status int, msg interface{}) {
c.AbortWithStatusJSON(status, msg)
}
// LoginFirst -
func (c *Context) LoginFirst(msg interface{}) {
obj := apimsg.GetRes("LoginFirst", msg)
c.AbortWithStatusJSON(obj.Status, obj.Obj)
}
// NotFound -
func (c *Context) NotFound(msg interface{}) {
obj := apimsg.GetRes("NotFound", msg)
+60 -6
View File
@@ -7,6 +7,7 @@ import (
"git.trj.tw/golang/mtfosbot/module/apis/twitch"
"git.trj.tw/golang/mtfosbot/model"
googleapi "git.trj.tw/golang/mtfosbot/module/apis/google"
lineobj "git.trj.tw/golang/mtfosbot/module/line-message/line-object"
)
@@ -173,13 +174,19 @@ func addTwitchChannel(sub, txt string, s *lineobj.SourceObject) (res string) {
return "get twitch user id fail"
}
ch := &model.TwitchChannel{
ID: info.ID,
Name: info.DisplayName,
}
err = ch.Add()
ch, err := model.GetTwitchChannelWithName(args[0])
if err != nil {
return "add twitch channel fail"
return "check channel fail"
}
if ch == nil {
ch = &model.TwitchChannel{
ID: info.ID,
Name: info.DisplayName,
}
err = ch.Add()
if err != nil {
return "add twitch channel fail"
}
}
rt := &model.LineTwitchRT{
@@ -239,3 +246,50 @@ func delTwitchChannel(sub, txt string, s *lineobj.SourceObject) (res string) {
return "Success"
}
func addYoutubeChannel(sub, txt string, s *lineobj.SourceObject) (res string) {
// args = youtubeID tmpl
ok, err := checkGroupOwner(s)
if err != nil {
return "check group fail"
}
if !ok {
return "not owner"
}
args := strings.Split(strings.Trim(txt, " "), " ")
if len(args) < 2 {
return "command arg not match"
}
ytName, err := googleapi.QueryYoutubeName(args[0])
if err != nil || len(ytName) == 0 {
return "get youtube channel name fail"
}
ytData, err := model.GetYoutubeChannelWithID(args[0])
if err != nil {
return "check youtube fail"
}
if ytData == nil {
ytData = &model.YoutubeChannel{
ID: args[0],
Name: ytName,
}
err = ytData.Add()
if err != nil {
return "add youtube channel fail"
}
}
rt := &model.LineYoutubeRT{
Line: s.GroupID,
Youtube: args[0],
Tmpl: strings.Join(args[1:], " "),
}
err = rt.AddRT()
if err != nil {
return "add youtube channel rt fail"
}
return "Success"
}