all repos — paprika @ 59bc10a1b861af4a0035e8909e17995edec13ce2

go rewrite of taigabot

plugins/youtube.go (view raw)

  1package plugins
  2
  3import (
  4	"context"
  5	"errors"
  6	"fmt"
  7	"net/url"
  8	"strings"
  9	"time"
 10
 11	"git.icyphox.sh/paprika/config"
 12	"github.com/dustin/go-humanize"
 13	"google.golang.org/api/option"
 14	"google.golang.org/api/youtube/v3"
 15	"gopkg.in/irc.v3"
 16)
 17
 18type Youtube struct{}
 19
 20func (Youtube) Triggers() []string {
 21	return []string{".yt"}
 22}
 23
 24func (Youtube) Execute(m *irc.Message) (string, error) {
 25	parsed := strings.SplitN(m.Trailing(), " ", 2)
 26	if len(parsed) == 1 && parsed[0] == ".yt" {
 27		return "Usage: .yt QUERY", nil
 28	} else if parsed[0] != ".yt" {
 29		return "", NoReply // ???
 30	}
 31
 32	return YoutubeSearch(parsed[1])
 33}
 34
 35func init() {
 36	Register(Youtube{})
 37}
 38
 39var NoYtApiKey = errors.New("No Youtube Api Key")
 40
 41func constructApiService() (*youtube.Service, error) {
 42	if apiKey, ok := config.C.ApiKeys["youtube"]; ok {
 43		service, err := youtube.NewService(
 44			context.TODO(),
 45			option.WithAPIKey(apiKey),
 46			option.WithUserAgent("github.com/icyphox/paprika"),
 47			option.WithTelemetryDisabled(), // wtf?
 48		)
 49		return service, err
 50	} else {
 51		return nil, NoYtApiKey
 52	}
 53}
 54
 55func YoutubeSearch(query string) (string, error) {
 56	service, err := constructApiService()
 57	if err != nil {
 58		return "", err
 59	}
 60
 61	search := youtube.NewSearchService(service).List([]string{})
 62	search = search.Q(query)
 63	res, err := search.Do()
 64	if err != nil {
 65		return "", err
 66	}
 67
 68	if len(res.Items) == 0 ||
 69		res.Items[0].Id == nil ||
 70		res.Items[0].Id.VideoId == "" {
 71		return "[Youtube] No videos found.", nil
 72	}
 73	item := res.Items[0]
 74
 75	vid := item.Id.VideoId
 76	println(vid)
 77	description, err := YoutubeDescription(vid)
 78	if err != nil {
 79		return description, err
 80	}
 81
 82	return fmt.Sprintf("%s - https://youtu.be/%s", description, vid), nil
 83}
 84
 85func YoutubeDescriptionFromUrl(url *url.URL) (string, error) {
 86	var vid string
 87	if url.Host == "youtu.be" {
 88		vid = url.Path[1:]
 89	} else {
 90		vid = url.Query().Get("v")
 91	}
 92
 93	return YoutubeDescription(vid)
 94}
 95
 96func YoutubeDescription(vid string) (string, error) {
 97	if vid == "" {
 98		return "[Youtube] Could not find video id.", nil
 99	}
100
101	service, err := constructApiService()
102	if err != nil {
103		return "", err
104	}
105
106	vidservice := youtube.NewVideosService(service)
107	vcall := vidservice.List([]string{"snippet", "statistics", "contentDetails"})
108	vcall = vcall.Id(vid)
109	vres, err := vcall.Do()
110	if err != nil {
111		return "", err
112	}
113
114	if len(vres.Items) == 0 {
115		return "[Youtube] No video found", nil
116	}
117
118	snippet := vres.Items[0]
119	if snippet.Snippet == nil || snippet.ContentDetails == nil || snippet.Statistics == nil {
120		return "[Youtube] API Error. Required fields are nil.", nil
121	}
122
123	title := snippet.Snippet.Title
124	duration := strings.ToLower(snippet.ContentDetails.Duration[2:])
125	likes := humanize.Comma(int64(snippet.Statistics.LikeCount))
126	// disabled
127	// dislikes := humanize.Comma(int64(snippet.Statistics.DislikeCount))
128	views := humanize.Comma(int64(snippet.Statistics.ViewCount))
129	channelName := snippet.Snippet.ChannelTitle
130	publishedParsed, err := time.Parse(time.RFC3339, snippet.Snippet.PublishedAt)
131	var published string
132	if err == nil {
133		published = humanize.Time(publishedParsed)
134	} else {
135		published = snippet.Snippet.PublishedAt[:10]
136	}
137
138	return fmt.Sprintf(
139		"\x02%s\x02 %s - \x0303↑ %s\x03 \x0304↓ ?\x03 - \x02%s\x02 views - \x02%s\x02 %s",
140		title,
141		duration,
142		likes,
143		views,
144		channelName,
145		published,
146	), nil
147}