Skip to main content

Whisper Implementation

A simple implementation of whisper that when syced up with the m3u8 downloader it keeps down the waste.

My devcontainer for the whisper project

Create the main file main.py:

This is a sample from my fbomb script

main.py
import datetime
import json
import logging
import logging.handlers
import time
import os
import re
import time

import requests
import whisper

model = whisper.load_model("base")
filesDone = []

os.system("rm file.log")

logger = logging.getLogger('logit')
handler = logging.handlers.RotatingFileHandler("file.log")
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s %(levelname)8s: %(message)s')
handler.setFormatter(formatter)
logging.Formatter.converter = time.gmtime
logger.addHandler(handler)
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(levelname)8s: %(message)s')

while True:
for x in os.listdir("./audio"):
logger.info(f"[+] Checking File: {x}")
try:
timestamp = os.path.getmtime("./audio/" + x)
datestamp = datetime.datetime.fromtimestamp(timestamp)
logger.debug(f'Modified Date/Time: {datestamp}')
except:
pass
if x in filesDone:
logger.warning(f"Skipping File {x}, I read this already.")
continue

filesDone.append(x)

try:
audio = whisper.load_audio("./audio/" + x)
except Exception as e:
logger.error(e)
continue
audio = whisper.pad_or_trim(audio)
mel = whisper.log_mel_spectrogram(audio).to(model.device)
_, probs = model.detect_language(mel)

logger.info(f"Detected language: {max(probs, key=probs.get)}")

options = whisper.DecodingOptions(fp16=False)
result = whisper.decode(model, mel, options)

logger.debug(f"-> Decoded Audio: {result.text}")

for match in re.finditer(r"fuck(s|ing|er)?", result.text):
logger.warning("Found: " + match.group())
access = requests.post(
'http://127.0.0.1:8085/increment', timeout=10)
logger.debug(access.text)

if len(filesDone) > 3:
logger.info("Cleaning up files")
for item in filesDone:
try:
os.system("sudo rm ./audio/" + item)
except:
pass
filesDone = []

logger.debug("-> Sleeping in anticipation for new files")
time.sleep(1)

Configure Golang server with twitch bot

Custom IRC reader in go for twitch bot that is very flexable

main.go
package main

import (
"bufio"
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"net/textproto"
"os"
"os/signal"
"regexp"
"strings"
"syscall"
"time"
)

var lastUsed time.Time = time.Now().Add(200 * time.Second)

type myData struct {
Fbombs int `json:"fbombs"`
}

type ircMessage struct {
Raw string
Tags map[string]string
Source ircMessageSource
Command string
Params []string
}

type ircMessageSource struct {
Nickname string
Username string
Host string
}

func parseIRCMessage(line string) (*ircMessage, error) {
message := ircMessage{
Raw: line,
Tags: make(map[string]string),
Params: []string{},
}

split := strings.Split(line, " ")
index := 0

if strings.HasPrefix(split[index], "@") {
message.Tags = parseIRCTags(split[index])
index++
}

if index >= len(split) {
return &message, fmt.Errorf("parseIRCMessage: partial message")
}

if strings.HasPrefix(split[index], ":") {
message.Source = *parseIRCMessageSource(split[index])
index++
}

if index >= len(split) {
return &message, fmt.Errorf("parseIRCMessage: no command")
}

message.Command = split[index]
index++

if index >= len(split) {
return &message, nil
}

var params []string
for i, v := range split[index:] {
if strings.HasPrefix(v, ":") {
v = strings.Join(split[index+i:], " ")
v = strings.TrimPrefix(v, ":")
params = append(params, v)
break
}

params = append(params, v)
}

message.Params = params

return &message, nil
}

func parseIRCTags(rawTags string) map[string]string {
tags := make(map[string]string)

rawTags = strings.TrimPrefix(rawTags, "@")

for _, tag := range strings.Split(rawTags, ";") {
pair := strings.SplitN(tag, "=", 2)
key := pair[0]

var value string
if len(pair) == 2 {
value = parseIRCTagValue(pair[1])
}

tags[key] = value
}

return tags
}

var tagEscapeCharacters = []struct {
from string
to string
}{
{`\s`, ` `},
{`\n`, ``},
{`\r`, ``},
{`\:`, `;`},
{`\\`, `\`},
}

func parseIRCTagValue(rawValue string) string {
for _, escape := range tagEscapeCharacters {
rawValue = strings.ReplaceAll(rawValue, escape.from, escape.to)
}

rawValue = strings.TrimSuffix(rawValue, "\\")
rawValue = strings.TrimSpace(rawValue)

return rawValue
}

func parseIRCMessageSource(rawSource string) *ircMessageSource {
var source ircMessageSource

rawSource = strings.TrimPrefix(rawSource, ":")

regex := regexp.MustCompile(`!|@`)
split := regex.Split(rawSource, -1)

if len(split) == 0 {
return &source
}

switch len(split) {
case 1:
source.Host = split[0]
case 2:
source.Nickname = split[0]
source.Host = split[1]
default:
source.Nickname = split[0]
source.Username = split[1]
source.Host = split[2]
}

return &source
}

func postServer() {
http.HandleFunc("/increment", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
return
}

// Read the JSON file
file, _ := ioutil.ReadFile("counter.json")
var data myData
json.Unmarshal(file, &data)

// Increment the number
data.Fbombs++

// Write the updated data to the JSON file
updatedData, _ := json.MarshalIndent(data, "", " ")
ioutil.WriteFile("counter.json", updatedData, 0644)

log.Println("[+] Incremented successfully")
w.Write([]byte("fbombs incremented successfully"))
})

http.HandleFunc("/reset", func(w http.ResponseWriter, r *http.Request) {
// Read the JSON file
file, _ := ioutil.ReadFile("counter.json")
var data myData
json.Unmarshal(file, &data)

// Increment the number
data.Fbombs = 0

// Write the updated data to the JSON file
updatedData, _ := json.MarshalIndent(data, "", " ")
ioutil.WriteFile("counter.json", updatedData, 0644)

log.Println("[+] Counter reset to zero")
w.Write([]byte("Reset counter to zero"))
})

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "counter.json")
})

http.ListenAndServe(":8085", nil)
}

func main() {
fmt.Println(`
.--.
|__| .-------.
|=.| |.-----.|
|--| || TTV ||
| | |'-----'|
|__|~')_____('
>>F-Bomb Bot<<
`)

go postServer()

SetupCloseHandler()
const username string = "ringomar" // Set your bot's user name
const channel string = "ringomar" // Set your channel you want to join

chat := connect(username, "oauth:123") // Your Oauth Key here
chat.join(channel)

for message := range chat.messages {
if strings.HasPrefix(message, "PING") {
chat.send("PONG :tmi.twitch.tv")
continue
}

ircTranslate, _ := parseIRCMessage(message)
if ircTranslate.Command == "PRIVMSG" && len(ircTranslate.Params) > 1 {
cooldownTime := int(time.Since(lastUsed).Seconds())
if cooldownTime >= 120 && ircTranslate.Params[1] == "?fbomb" {
file, _ := ioutil.ReadFile("counter.json")
var data myData
json.Unmarshal(file, &data)
returnMes := fmt.Sprintf("The F word has been heard on this stream: %d times!", data.Fbombs)
lastUsed = time.Now()
chat.say(channel, returnMes)
}
}
}
}
func SetupCloseHandler() {
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
fmt.Println("\n\n\r- Ctrl+C pressed in Terminal")
os.Exit(0)
}()
}

type irc struct {
conn net.Conn
messages chan string
}

func connect(username, oauth string) *irc {
fmt.Printf("[%s][RIN-Connect] Dialing TCP server.\n", string(time.Now().Format(time.Stamp)))

conn, err := tls.Dial("tcp", "irc.chat.twitch.tv:443", nil)
if err != nil {
log.Fatal("cannot connect to twitch irc server", err)
}
i := &irc{
conn: conn,
messages: make(chan string, 10),
}
i.send("PASS " + oauth)
i.send("NICK " + username)
i.send("CAP REQ twitch.tv/membership")
i.send("CAP REQ twitch.tv/commands")
i.send("CAP REQ twitch.tv/tags")
go i.read()

fmt.Printf("[%s][RIN-Connect] connected to Twitch irc server\n", string(time.Now().Format(time.Stamp)))
return i
}

func (i *irc) join(channel string) {
i.send("JOIN #" + strings.ToLower(channel))
fmt.Printf("[%s][RIN-Connect] Joined channel: %s\n", string(time.Now().Format(time.Stamp)), channel)

}

func (i *irc) send(msg string) {
_, err := i.conn.Write([]byte(msg + "\r\n"))
if err != nil {
log.Fatal("Disconnected from twitch irc server", err)
}
}

func (i *irc) say(channel, msg string) {
fmt.Printf("[%s][RIN-SAY] sending #%s: %s\n", string(time.Now().Format(time.Stamp)), channel, msg)
i.send(fmt.Sprintf("PRIVMSG #%s :%s", channel, msg))
}

func (i *irc) read() {
reader := bufio.NewReader(i.conn)
tp := textproto.NewReader(reader)
for {
message, err := tp.ReadLine()
if err != nil {
log.Fatal("Disconnected from twitch irc server", err)
}
i.messages <- message
}
}

Sometimes it wont auto connect still yet to figure that out, but running it again it works.