add youtube webhook
This commit is contained in:
parent
e954afe80b
commit
16190c49c4
@ -34,11 +34,11 @@ func GetFacebookPage(id string) (page *FacebookPage, err error) {
|
|||||||
|
|
||||||
// AddPage -
|
// AddPage -
|
||||||
func (p *FacebookPage) AddPage() (err error) {
|
func (p *FacebookPage) AddPage() (err error) {
|
||||||
rows, err := x.NamedQuery(`insert into "public"."facebook_page" ("id", "lastpost") values (:id, :lastpost) returning *`, p)
|
stmt, err := x.PrepareNamed(`insert into "public"."facebook_page" ("id", "lastpost") values (:id, :lastpost) returning *`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rows.StructScan(&p)
|
err = stmt.Get(p, p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,14 +25,42 @@ func (p *LineFacebookRT) AddRT() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DelRT -
|
||||||
|
func (p *LineFacebookRT) DelRT() (err error) {
|
||||||
|
_, err = x.NamedExec(`delete from "public"."line_fb_rt" where "line" = :line and "facebook" = :facebook`, p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRT -
|
||||||
|
func (p *LineFacebookRT) GetRT() (err error) {
|
||||||
|
stmt, err := x.PrepareNamed(`select * from "public"."line_fb_rt" where "line" = :line and "facebook" = :facebook`)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = stmt.Get(p, p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// AddRT - add twitch line rt
|
// AddRT - add twitch line rt
|
||||||
func (p *LineTwitchRT) AddRT() (err error) {
|
func (p *LineTwitchRT) AddRT() (err error) {
|
||||||
_, err = x.NamedExec(`insert into "public"."line_twitch_rt" ("line", "twitch", "type", "tmpl") values (:line, :twitch, :type, :tmpl)`, p)
|
_, err = x.NamedExec(`insert into "public"."line_twitch_rt" ("line", "twitch", "type", "tmpl") values (:line, :twitch, :type, :tmpl)`, p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DelRT -
|
||||||
|
func (p *LineTwitchRT) DelRT() (err error) {
|
||||||
|
_, err = x.NamedExec(`delete from "public"."line_twitch_rt" where "line" = :line and "twitch" = :twitch and "type" = :type`, p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// AddRT - add youtube line rt
|
// AddRT - add youtube line rt
|
||||||
func (p *LineYoutubeRT) AddRT() (err error) {
|
func (p *LineYoutubeRT) AddRT() (err error) {
|
||||||
_, err = x.NamedExec(`insert into "public"."line_youtube_rt" ("line", "youtube", "tmpl") values (:line, :youtube, :tmpl)`, p)
|
_, err = x.NamedExec(`insert into "public"."line_youtube_rt" ("line", "youtube", "tmpl") values (:line, :youtube, :tmpl)`, p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DelRT -
|
||||||
|
func (p *LineYoutubeRT) DelRT() (err error) {
|
||||||
|
_, err = x.NamedExec(`delete from "public"."line_youtube_rt" where "line" = :line and "youtube" = :youtube`, p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -32,13 +32,24 @@ func GetJoinChatChannel() (channels []*TwitchChannel, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add -
|
// GetWithName -
|
||||||
func (p *TwitchChannel) Add() (err error) {
|
func (p *TwitchChannel) GetWithName() (err error) {
|
||||||
rows, err := x.NamedQuery(`insert into "public"."twitch_channel" ("name", "laststream", "join", "opayid") values (:name, :laststream, :join, :opayid) returning *`, p)
|
stmt, err := x.PrepareNamed(`select * from "public"."twitch_channel" where "name" = :name`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rows.StructScan(p)
|
|
||||||
|
err = stmt.Get(p, p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add -
|
||||||
|
func (p *TwitchChannel) Add() (err error) {
|
||||||
|
stmt, err := x.PrepareNamed(`insert into "public"."twitch_channel" ("name", "laststream", "join", "opayid") values (:name, :laststream, :join, :opayid) returning *`)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = stmt.Get(p, p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,12 +2,55 @@ package model
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
// YoutubeGroup -
|
||||||
|
type YoutubeGroup struct {
|
||||||
|
*LineGroup
|
||||||
|
Tmpl string `db:"tmpl"`
|
||||||
|
}
|
||||||
|
|
||||||
// YoutubeChannel -
|
// YoutubeChannel -
|
||||||
type YoutubeChannel struct {
|
type YoutubeChannel struct {
|
||||||
ID string `db:"id" cc:"id"`
|
ID string `db:"id" cc:"id"`
|
||||||
Name string `db:"name" cc:"name"`
|
Name string `db:"name" cc:"name"`
|
||||||
LastVideo string `db:"lastvideo" cc:"lastvideo"`
|
LastVideo string `db:"lastvideo" cc:"lastvideo"`
|
||||||
Expire int32 `db:"expire" cc:"expire"`
|
Expire int64 `db:"expire" cc:"expire"`
|
||||||
Ctime time.Time `db:"ctime" cc:"ctime"`
|
Ctime time.Time `db:"ctime" cc:"ctime"`
|
||||||
Mtime time.Time `db:"mtime" cc:"mtime"`
|
Mtime time.Time `db:"mtime" cc:"mtime"`
|
||||||
|
Groups []*YoutubeGroup `db:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetYoutubeChannelWithID -
|
||||||
|
func GetYoutubeChannelWithID(id string) (yt *YoutubeChannel, err error) {
|
||||||
|
err = x.Get(&yt, `select * from "public"."youtube_channel" where "id" = $1`, id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateLastVideo -
|
||||||
|
func (p *YoutubeChannel) UpdateLastVideo(vid string) (err error) {
|
||||||
|
p.LastVideo = vid
|
||||||
|
_, err = x.NamedExec(`update "public"."youtube_channel" set "lastvideo" = :lastvideo where "id" = :id`, p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateExpire -
|
||||||
|
func (p *YoutubeChannel) UpdateExpire(t int64) (err error) {
|
||||||
|
p.Expire = t
|
||||||
|
_, err = x.NamedExec(`update "public"."youtube_channel" set "expire" = :expire where "id" = :id`, p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroups -
|
||||||
|
func (p *YoutubeChannel) GetGroups() (err error) {
|
||||||
|
query := `select g.*, rt.tmpl as tmpl from "public"."youtube_channel" yt
|
||||||
|
left join "public"."line_youtube_rt" rt
|
||||||
|
on rt.youtube = yt.id
|
||||||
|
left join "public"."line_group" g
|
||||||
|
on g.id = rt.line
|
||||||
|
where
|
||||||
|
yt.id = $1`
|
||||||
|
err = x.Select(&p.Groups, query, p.ID)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,10 @@ func selectAct(cmd, sub, txt string, s *lineobj.SourceObject) (res string) {
|
|||||||
return addFacebookPage(sub, txt, s)
|
return addFacebookPage(sub, txt, s)
|
||||||
case "addtwitch":
|
case "addtwitch":
|
||||||
return addTwitchChannel(sub, txt, s)
|
return addTwitchChannel(sub, txt, s)
|
||||||
|
case "delpage":
|
||||||
|
return delFacebookPage(sub, txt, s)
|
||||||
|
case "deltwitch":
|
||||||
|
return delTwitchChannel(sub, txt, s)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -48,18 +52,29 @@ func addLineGroup(sub, txt string, s *lineobj.SourceObject) (res string) {
|
|||||||
return "Success"
|
return "Success"
|
||||||
}
|
}
|
||||||
|
|
||||||
func addFacebookPage(sub, txt string, s *lineobj.SourceObject) (res string) {
|
func checkGroupOwner(s *lineobj.SourceObject) (ok bool, err error) {
|
||||||
// args = pageid tmpl
|
|
||||||
exists, err := model.CheckGroup(s.GroupID)
|
exists, err := model.CheckGroup(s.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "run check group error"
|
return false, err
|
||||||
}
|
}
|
||||||
if !exists {
|
if !exists {
|
||||||
return "group not exists"
|
return false, nil
|
||||||
}
|
}
|
||||||
ok, err := model.CheckGroupOwner(s.UserID, s.GroupID)
|
ok, err = model.CheckGroupOwner(s.UserID, s.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "run check group owner fail"
|
return false, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFacebookPage(sub, txt string, s *lineobj.SourceObject) (res string) {
|
||||||
|
// args = pageid tmpl
|
||||||
|
ok, err := checkGroupOwner(s)
|
||||||
|
if err != nil {
|
||||||
|
return "check group fail"
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return "not owner"
|
return "not owner"
|
||||||
@ -98,18 +113,47 @@ func addFacebookPage(sub, txt string, s *lineobj.SourceObject) (res string) {
|
|||||||
return "Success"
|
return "Success"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func delFacebookPage(sub, txt string, s *lineobj.SourceObject) (res string) {
|
||||||
|
// args = pageid
|
||||||
|
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) < 1 {
|
||||||
|
return "commage arg not match"
|
||||||
|
}
|
||||||
|
|
||||||
|
rt := &model.LineFacebookRT{
|
||||||
|
Line: s.GroupID,
|
||||||
|
Facebook: args[0],
|
||||||
|
}
|
||||||
|
err = rt.DelRT()
|
||||||
|
if err != nil {
|
||||||
|
return "remove facebook page fail"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Success"
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkTwitchType(t string) bool {
|
||||||
|
switch t {
|
||||||
|
case "live":
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func addTwitchChannel(sub, txt string, s *lineobj.SourceObject) (res string) {
|
func addTwitchChannel(sub, txt string, s *lineobj.SourceObject) (res string) {
|
||||||
// args = twitchLogin type tmpl
|
// args = twitchLogin type tmpl
|
||||||
exists, err := model.CheckGroup(s.GroupID)
|
ok, err := checkGroupOwner(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "run check group error"
|
return "check group fail"
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
return "group not exists"
|
|
||||||
}
|
|
||||||
ok, err := model.CheckGroupOwner(s.UserID, s.GroupID)
|
|
||||||
if err != nil {
|
|
||||||
return "run check group owner fail"
|
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return "not owner"
|
return "not owner"
|
||||||
@ -120,6 +164,10 @@ func addTwitchChannel(sub, txt string, s *lineobj.SourceObject) (res string) {
|
|||||||
return "command args not match"
|
return "command args not match"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !checkTwitchType(args[1]) {
|
||||||
|
return "type not allow"
|
||||||
|
}
|
||||||
|
|
||||||
info := twitch.GetUserDataByName(args[0])
|
info := twitch.GetUserDataByName(args[0])
|
||||||
if info == nil {
|
if info == nil {
|
||||||
return "get twitch user id fail"
|
return "get twitch user id fail"
|
||||||
@ -137,6 +185,7 @@ func addTwitchChannel(sub, txt string, s *lineobj.SourceObject) (res string) {
|
|||||||
rt := &model.LineTwitchRT{
|
rt := &model.LineTwitchRT{
|
||||||
Line: s.GroupID,
|
Line: s.GroupID,
|
||||||
Twitch: info.ID,
|
Twitch: info.ID,
|
||||||
|
Type: args[1],
|
||||||
Tmpl: strings.Join(args[2:], " "),
|
Tmpl: strings.Join(args[2:], " "),
|
||||||
}
|
}
|
||||||
err = rt.AddRT()
|
err = rt.AddRT()
|
||||||
@ -146,3 +195,47 @@ func addTwitchChannel(sub, txt string, s *lineobj.SourceObject) (res string) {
|
|||||||
|
|
||||||
return "Success"
|
return "Success"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func delTwitchChannel(sub, txt string, s *lineobj.SourceObject) (res string) {
|
||||||
|
// args = twitchLogin type
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
if !checkTwitchType(args[1]) {
|
||||||
|
return "type not allow"
|
||||||
|
}
|
||||||
|
|
||||||
|
ch := &model.TwitchChannel{
|
||||||
|
Name: args[0],
|
||||||
|
}
|
||||||
|
err = ch.GetWithName()
|
||||||
|
if err != nil {
|
||||||
|
return "get channel data fail"
|
||||||
|
}
|
||||||
|
if ch == nil {
|
||||||
|
return "Success"
|
||||||
|
}
|
||||||
|
|
||||||
|
rt := &model.LineTwitchRT{
|
||||||
|
Line: s.GroupID,
|
||||||
|
Twitch: ch.ID,
|
||||||
|
Type: args[1],
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rt.DelRT()
|
||||||
|
if err != nil {
|
||||||
|
return "delete rt fail"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Success"
|
||||||
|
}
|
||||||
|
135
router/google/youtube.go
Normal file
135
router/google/youtube.go
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.trj.tw/golang/mtfosbot/model"
|
||||||
|
lineapi "git.trj.tw/golang/mtfosbot/module/apis/line"
|
||||||
|
"git.trj.tw/golang/mtfosbot/module/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type feed struct {
|
||||||
|
XMLName xml.Name `xml:"feed"`
|
||||||
|
Entry []entry `xml:"entry"`
|
||||||
|
}
|
||||||
|
type entry struct {
|
||||||
|
XMLName xml.Name `xml:"entry"`
|
||||||
|
Title string `xml:"title"`
|
||||||
|
ID string `xml:"id"`
|
||||||
|
Link link `xml:"link"`
|
||||||
|
Author []author `xml:"author"`
|
||||||
|
}
|
||||||
|
type link struct {
|
||||||
|
XMLName xml.Name `xml:"link"`
|
||||||
|
Href string `xml:"href,attr"`
|
||||||
|
}
|
||||||
|
type author struct {
|
||||||
|
XMLName xml.Name `xml:"author"`
|
||||||
|
Name string `xml:"name"`
|
||||||
|
URI string `xml:"uri"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyWebhook -
|
||||||
|
func VerifyWebhook(c *context.Context) {
|
||||||
|
hubMode, ok := c.GetQuery("hub.mode")
|
||||||
|
if !ok {
|
||||||
|
c.DataFormat(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
challenge, ok := c.GetQuery("hub.challenge")
|
||||||
|
if !ok {
|
||||||
|
c.DataFormat(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id, ok := c.GetQuery("id")
|
||||||
|
if !ok {
|
||||||
|
c.DataFormat(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if hubMode == "subscribe" {
|
||||||
|
t := time.Now().Unix() + 86400
|
||||||
|
yt, err := model.GetYoutubeChannelWithID(id)
|
||||||
|
if err != nil {
|
||||||
|
c.ServerError(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if yt == nil {
|
||||||
|
c.NotFound("channel not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = yt.UpdateExpire(t)
|
||||||
|
if err != nil {
|
||||||
|
c.ServerError(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.String(200, challenge)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNotifyWebhook -
|
||||||
|
func GetNotifyWebhook(c *context.Context) {
|
||||||
|
byteBody, err := ioutil.ReadAll(c.Request.Body)
|
||||||
|
defer c.Request.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
c.DataFormat(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
id, ok := c.GetQuery("id")
|
||||||
|
if !ok {
|
||||||
|
c.DataFormat(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hook := &feed{}
|
||||||
|
err = xml.Unmarshal(byteBody, &hook)
|
||||||
|
if err != nil {
|
||||||
|
c.DataFormat(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(hook.Entry) == 0 {
|
||||||
|
c.Success(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
yt, err := model.GetYoutubeChannelWithID(id)
|
||||||
|
if err != nil || yt == nil {
|
||||||
|
c.ServerError(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if hook.Entry[0].ID == yt.LastVideo {
|
||||||
|
c.Success(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = yt.UpdateLastVideo(hook.Entry[0].ID)
|
||||||
|
if err != nil {
|
||||||
|
c.ServerError(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range yt.Groups {
|
||||||
|
if v.Notify {
|
||||||
|
str := v.Tmpl
|
||||||
|
if len(str) == 0 {
|
||||||
|
str = fmt.Sprintf("%s\n%s", hook.Entry[0].Title, hook.Entry[0].Link.Href)
|
||||||
|
} else {
|
||||||
|
str = strings.Replace(str, "{link}", hook.Entry[0].Link.Href, -1)
|
||||||
|
str = strings.Replace(str, "{txt}", hook.Entry[0].Title, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := &lineapi.TextMessage{
|
||||||
|
Text: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
lineapi.PushMessage(v.ID, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Success(nil)
|
||||||
|
}
|
@ -5,6 +5,8 @@ import (
|
|||||||
|
|
||||||
"git.trj.tw/golang/mtfosbot/module/context"
|
"git.trj.tw/golang/mtfosbot/module/context"
|
||||||
"git.trj.tw/golang/mtfosbot/router/api"
|
"git.trj.tw/golang/mtfosbot/router/api"
|
||||||
|
"git.trj.tw/golang/mtfosbot/router/google"
|
||||||
|
"git.trj.tw/golang/mtfosbot/router/line"
|
||||||
"github.com/gin-contrib/cors"
|
"github.com/gin-contrib/cors"
|
||||||
"github.com/gin-gonic/contrib/sessions"
|
"github.com/gin-gonic/contrib/sessions"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -43,4 +45,15 @@ func SetRoutes(r *gin.Engine) {
|
|||||||
{
|
{
|
||||||
apiGroup.POST("/login", context.PatchCtx(api.UserLogin))
|
apiGroup.POST("/login", context.PatchCtx(api.UserLogin))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lineApis := r.Group("/line")
|
||||||
|
{
|
||||||
|
lineApis.POST("/", context.PatchCtx(line.GetRawBody), context.PatchCtx(line.VerifyLine), context.PatchCtx(line.GetLineMessage))
|
||||||
|
}
|
||||||
|
|
||||||
|
googleApis := r.Group("/google")
|
||||||
|
{
|
||||||
|
googleApis.GET("/youtube/webhook", context.PatchCtx(google.VerifyWebhook))
|
||||||
|
googleApis.POST("/youtube/webhook", context.PatchCtx(google.GetNotifyWebhook))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user