ytLiveChatBot is a golang library for cli base applications that makes it easy to read and write live-chat on/from youtube live streams using youtube api.
It is designed for handling multiple live-streams at a time. But can also be used for a single live-stream
- Abstracts youtube API Oauth logic
- converts youtube live-stream chat in easily manageable readable and writable go channels
ChatReader
channel will receive incoming chat-messages- Anything written on
ChatWriter
channel will be sent directly to youtube stream
- Obtain OAuth 2.0 credentials from the Google API Console
Go through before you start section of youtube api, and downloadclient_secret.json
- Make sure
client_secret.json
is stored inside your application root directory.
import "github.com/ketan-10/ytLiveChatBot"
- Intantiate
LiveChatBot
with youtube live-stream Urls, urls can be in any of the following formatshttps://www.youtube.com/watch?v=5qap5aO4i9A", "5qap5aO4i9A", "https://youtu.be/5qap5aO4i9A
var chatBot *ytbot.LiveChatBot = ytbot.NewLiveChatBot(&ytbot.LiveChatBotInput{
Urls: []string{"https://youtu.be/KSU023LJKS", "https://youtu.be/eo22kjof2", "5qap5aO4i9A"},
})
LiveChatBot
haveChatReaders
andChatWriters
which are Maps havingkey
of youtube-url and value as respective chat reader or writer channel
type LiveChatBot struct {
ChatReaders map[string]<-chan *youtube.LiveChatMessage
ChatWriters map[string]chan<- string
}
NewLiveChatBot
func will initiate oauth flow, it will print the google oauth url in console where user has open the url in browser and grant youtube Access.
Choose Account | Grant Access |
---|---|
-
Google Sign in will show a token, which to be copy pasted to console
-
For subsequent re-runs token will be cached in
.credentials
file in home directory, to ignore cache useRefetchCache: true
chatBot := ytbot.NewLiveChatBot(&ytbot.LiveChatBotInput{
RefetchCache: true,
Urls: []string{"5qap5aO4i9A", "3304aO430C"},
},
- Read live chats from a single live-stream
package main
import (
"fmt"
"github.com/ketan-10/ytLiveChatBot"
)
func main() {
chatBot := ytbot.NewLiveChatBot(&ytbot.LiveChatBotInput{
Urls: []string{"5qap5aO4i9A"},
})
chatReader := chatBot.ChatReaders["5qap5aO4i9A"]
for newChat := range chatReader {
fmt.Println(newChat.Snippet.DisplayMessage)
}
}
- Read from console and write directly to youtube live-stream chat
package main
import (
"bufio"
"os"
"github.com/ketan-10/ytLiveChatBot"
)
func main() {
chatBot := ytbot.NewLiveChatBot(&ytbot.LiveChatBotInput{
Urls: []string{"5qap5aO4i9A"},
})
chatWriter := chatBot.ChatWriters["5qap5aO4i9A"]
scanner := bufio.NewScanner(os.Stdin)
for {
if scanner.Scan() {
newChat := scanner.Text()
chatWriter <- newChat
}
}
}
- Read multiple youtube live-stream chat and print live result.
package main
import (
"fmt"
"sync"
"github.com/ketan-10/ytLiveChatBot"
"google.golang.org/api/youtube/v3"
)
var wg = sync.WaitGroup{}
// read multiple youtube live stream chat
func main() {
chatBot := ytbot.NewLiveChatBot(&ytbot.LiveChatBotInput{
// enter list of livestream urls
Urls: []string{"https://youtu.be/KSU023LJKS", "https://youtu.be/eo22kjof2", "5qap5aO4i9A"},
})
for url, valueReader := range chatBot.ChatReaders {
wg.Add(1)
go readChannel(valueReader, url)
}
wg.Wait()
}
func readChannel(valueReader <-chan *youtube.LiveChatMessage, url string) {
defer wg.Done()
for item := range valueReader {
newMessage := item.Snippet.DisplayMessage
fmt.Println("Form stream: " + url + " -> Message: " + newMessage)
}
}
- If chat-message have prefix
/a
send the message to all other live-streams
package main
import (
"fmt"
"os"
"regexp"
"strings"
"sync"
"github.com/ketan-10/ytLiveChatBot"
"google.golang.org/api/youtube/v3"
)
func main() {
refetchCache := false
if len(os.Args) > 1 && os.Args[1] == "ignoreCache" {
refetchCache = true
}
chatBot := ytbot.NewLiveChatBot(&ytbot.LiveChatBotInput{
RefetchCache: refetchCache,
Urls: []string{"5qap5aO4i9A", "WUG1AocK2Ys"},
})
var wg = sync.WaitGroup{}
const prefix string = "/a "
re := regexp.MustCompile("^(" + prefix + ")*")
fmt.Println("Starting bot...")
for rUrl, readChannel := range chatBot.ChatReaders {
wg.Add(1)
go func(readChannel <-chan *youtube.LiveChatMessage, rUrl string) {
defer wg.Done()
for item := range readChannel {
newMessage := item.Snippet.DisplayMessage
if !strings.HasPrefix(newMessage, prefix) {
continue
}
// remove prefix
newMessage = re.ReplaceAllString(newMessage, "")
fmt.Println(item.AuthorDetails)
// send to all other live-stream
sendMessage := "@" + item.AuthorDetails.DisplayName + " From: " + rUrl + " Said: " + newMessage
fmt.Println(sendMessage)
for wUrl, writeChannel := range chatBot.ChatWriters {
if wUrl != rUrl {
writeChannel <- sendMessage
}
}
}
}(readChannel, rUrl)
}
wg.Wait()
}
Are there any security concerns with sharing the client secrets of a Google API project?
Flutter Example Video 1 Flutter Example Video 2
go run . new
go mod init github.com/ketan-10/combine-youtube-live-chat
go mod tidy
- If
client-id
is compromised, an attacker can request use-data on your behalf, But the attacker will not be able to access actual user-data as he will just getauthorization code
after user login/consent NOTaccess or refresh
token, for that hey have to exchangeauthorization code
withaccess/refresh token
which requiresclient-secret
. - If
client-secret
andclient-id
is compromised, the attacker might be able to access user data, assuming we are using a web application, we have to register theredirect url
as our on google API. so Google will send theauthorization-code
to onlyredirect-url
so the user will be navigated to our site and not attacker site. But if the browser is also compromised that will cause an issue.