all repos — paprika @ 6db4885ec5acb77b0a73fe306c42874b18e2bed3

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