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
ChatReaderchannel will receive incoming chat-messages- Anything written on
ChatWriterchannel 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.jsonis stored inside your application root directory.
import "github.com/ketan-10/ytLiveChatBot"- Intantiate
LiveChatBotwith 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"}, })LiveChatBothaveChatReadersandChatWriterswhich are Maps havingkeyof 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 }NewLiveChatBotfunc 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
.credentialsfile 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
/asend 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-idis 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 codeafter user login/consent NOTaccess or refreshtoken, for that hey have to exchangeauthorization codewithaccess/refresh tokenwhich requiresclient-secret. - If
client-secretandclient-idis compromised, the attacker might be able to access user data, assuming we are using a web application, we have to register theredirect urlas our on google API. so Google will send theauthorization-codeto onlyredirect-urlso the user will be navigated to our site and not attacker site. But if the browser is also compromised that will cause an issue.


