×

支持Twitch的简单可穿戴设备

消耗积分:0 | 格式:zip | 大小:0.07 MB | 2023-01-04

王丽

分享资料个

描述

描述

这是另一个支持 Twitch 的简单可穿戴设备。这一次是关于如何帮助流以某种小车的方式跟上大型聊天室的步伐。

让我们快速模仿我们最喜欢的紫色反派。

让我们变得真实。每个人都会从抽取中恢复过来,所以让我们暂停一半的聊天而不是全面禁止。

构建说明

步骤1

Snap 手套与 esp32 搭配起来相当简单。我把它连接到一个单细胞脂肪上以获得动力。Gpio 14是电容式触摸管脚,编码时称为T6。我将一根电线连接到 gpio 14 并将其焊接到银导电线上! 

*请记住保持您的触摸板小,以便它们具有良好的灵敏控制。太大的垫将导致没有触摸触发或持续触摸,具体取决于灵敏度的设置方式。

第2步

导电织物肯定很难焊接(如果你是我的话)。我发现让你的熨斗刚好热到足以熔化你的焊料,除此之外什么都不是你想要留下的地方。

通过将一些焊料熔化到电线上来给电线镀锡,将其放在导电织物上,并在 3 秒内用烙铁加热。每次爆裂后检查焊点,看看是否需要施加更多的热量,或者它是否有效。

慢慢来,不要害怕搞砸这一步。

步骤 3

我用普通线缝合了所有传感器垫,并缝合了一些电缆。这有助于反复弯曲焊点。

最靠近拇指的传感器是中指末端的位置,同时弹响。<

图>

第4步

此代码的文件托管在此项目的文件部分中。

让我们从导入套接字、时间、随机和数学库开始。

import cfg
import socket
import time
import random
import math

他们的 cfg 文件是使用您的用户名、密码和您要放入 twitch 频道的机器人的频道名称定制的。

现在让我们定义我们的超时命令将如何运行。

def timeout(sock, user, secs):
    """
    Time out a user for a set period of time.
    Keyword arguments:
    sock -- the socket over which to send the timeout command
    user -- the user to be timed out
    secs -- the length of the timeout in seconds (default 600)
    """
    chat(sock, "/timeout {}".format(user, secs))
    
def untimeout(sock,user):
    chat(sock,"/unban {}".format(user))

当你调用这个函数时,你需要指出你试图与哪个套接字进行通信,你超时的用户名,以及他们将被禁止多长时间。

我还包含了一个使用 Twitch 的 unban 功能的撤销超时命令。

s = socket.socket()
s.connect((cfg.HOST,cfg.PORT))
s.send("PASS {}\r\n".format(cfg.PASS).encode("utf-8"))
s.send("NICK {}\r\n".format(cfg.NICK).encode("utf-8"))
s.send("JOIN {}\r\n".format(cfg.CHAN).encode("utf-8"))
CHAT_MSG=re.compile(r"^:\w+!\w+@\w+.tmi.twitch.tv PRIVMSG #\w+ :")

这部分代码创建套接字,并传递在我前面提到的 cfg 文件中排序的信息。它还为 twitch 消息创建编译器/反编译器。

让我们创建一些变量来存储用户名,甚至是每个人的聊天计数器。

vips = []
vrem = []
vipc = []
vipCount = 0

 现在让我们创建一个无限循环来运行,并等待来自 twitch(聊天)的消息。然后我们将检查它是否是 ping。如果我们的机器人要保持与 Twitch 的连接,则需要发送一个 pong。

while True:    
        response = s.recv(1024).decode("utf-8")
        if response == "PING :tmi.twitch.tv\r\n":
            s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) 
            print('sent')

但是,如果它不是 ping,而是我们想要关注的实际聊天呢?我们会将消息和用户名从我们收到的信息中分离出来。

 else:
            username = re.search(r"\w+", response).group(0) # return the entire match
            message = CHAT_MSG.sub("", response)
            # s.send(s,username +" + " + message)
            print(username + ": " + message) 

有了这些信息,我们将开始收集聊天中的每个人,将他们放入列表中,并计算他们在聊天中发言的次数。

 if username in vips: # will need to edit out tvheadbot, atltvhead, tmi from the messages collected! before doing the thanos glove
                # if its tvhead bot do nothing
                ind = vips.index(username)
                vipCount = vipc[ind]
                vipCount = vipCount + 1
                vipc[ind] = vipCount
                print(vips)
                print(vipc)
                # print(username + " has spoken " + str(vipCount) + " times.")
                
            else:
                vips.append(username)
                vipc.append(1)

如果用户名不在列表 VIPS 中,它将把它们添加到列表中。它还将一个整数添加到另一个列表中以计算它们的交互。如果用户在列表中,它将添加到他们的整数中。

接下来让我们看看消息是否是我们的 SNAP 命令。Snap 命令将为那些将被随机超时的人创建一个新列表,不会重复。这个新列表被计算为所有在聊天中发言的人的一半,四舍五入。它还说明了所有聊天 tmi 和您的聊天机器人中的 twitch 实体。在我的例子中是 tvheadbot。

if message.strip() == "SNAP" and username == "tvheadbot":
                # these operations move half of the chat to a new list for removal
                oglength = len(vips)
                delenght = math.ceil((oglength-3)/2)
                while len(vrem) < delenght:
                    userToMove = random.choice(vips)
                    if userToMove == "tmi" or userToMove == "tvheadbot" or userToMove == "atltvhead":
                        # do nothing
                        print("Encountered either Tmi or tvheadbot or atltvhead")
                    else:
                        if userToMove in vrem:
                            print("User " + userToMove + " is already to be timed out.")
                        else:
                            vrem.append(userToMove)

 一旦我们将一半的聊天分类到删除列表中。是时候让他们超时了。

 # this is where I do the timeout
                for q in vrem:
                    # print(q)
                    timeout(s, q, 10)
                    time.sleep(1 / cfg.RATE)
                # remember to wipe out vrem  I want to unban / untimout
                
                
        time.sleep(1 / cfg.RATE)

将每个人都列在一个列表中,您也可以轻松取消对他们的封禁!

您的聊天机器人不能做的一些事情是超时版主并将您的聊天设置为仅表情模式。我希望我可以启用仅表情模式,但我必须使用主播用户名来实现。

步骤 5

我使用的是旧版本的 IRCClient,我对其进行了修改以用于 Twitch。如果您使用最新版本,它将开箱即可与 Twitch 一起使用。<>

首先要添加的是库,定义我们的 wifi 网络,以及传递给 twitch 的信息。

#include 
#include 
/*-----------------------------------------------------------------------------------*/
#define ssid1         "Wifi"
#define password1     "Password"
#define IRC_SERVER   "irc.chat.twitch.tv"
#define IRC_PORT     6667
#define IRC_NICK     "Bot_Name"
#define IRC_CHAN     "#Channel_Name"
#define IRC_PASS     "oauth:####"
WiFiClient wiFiClient;
IRCClient client(IRC_SERVER, IRC_PORT, wiFiClient);

我们在这里调用我们的 wificlient 和我们的 ircclients,并列出适当的 twitch 端口。您的机器人、频道名称和密码都是您需要更改的内容。

让我们定义一些变量,这些变量将帮助我们在我们不想的时候不让人们超时。

boolean snapboo = false;
boolean emoteboo = false;

 下一部分代码用于 esp 32 中内置的触摸传感器。我们还创建了一个函数,该函数将在触发快照时调用。

int thresholdTwo = 60;
bool touch2detected = false;
byte touchCountTwo = 0;
unsigned long touchTimeTwo;
unsigned long oldTouchTimeTwo;
void gotTouch2(){
  //figure out calibration here!
//get time and incriment timer
touchTimeTwo = millis();
touchCountTwo++;
// if counter is above a certain # in a certain timeout decrease sensitivity (time is going to be half second)
if(touchCountTwo >=3 && (touchTimeTwo-oldTouchTimeTwo)<=400 && thresholdTwo > 20){
  thresholdTwo=thresholdTwo-1;
  // reset count
  touchCountTwo=0;
  }
// if counter is below a # and a certain timeout increase sensitivity (time is going to be 2 min?)
else if((touchTimeTwo-oldTouchTimeTwo)>=60000){ // touchCount<1 && probably doesn't need the <1 touch count. if it creates too sensitive of a sensor, it will be backed off imediatly after. it should jut create more triggers after the high five
  thresholdTwo++;
  // reset counter
  touchCountTwo=0;
  }
// if counter is below # and timer is between sensitivity triggers touch detected
else if(400<(touchTimeTwo-oldTouchTimeTwo) && (touchTimeTwo-oldTouchTimeTwo)<60000){
  touch2detected = true;
  delay(500);
  // reset counter
  }
// time saved to new variable and reset
oldTouchTimeTwo = touchTimeTwo;

每次触发快照时,它都会校准传感器,通过比较时间间隔和触发次数来检查它是否是真正的触摸。

 接下来让我们创建我们的设置循环并附加我们的中断。wifi 和客户端也将开始。

void setup() {
  WiFi.begin(ssid1, password1);
  client.setCallback(callback);
  client.setSentCallback(debugSentCallback);
  touchAttachInterrupt(T7,gotTouch2,thresholdTwo);
}

 现在,在我们的主循环中,我们将把我们的信息传递给 twitch,并一直传递它直到我们建立连接。

void loop() {
  // put your main code here, to run repeatedly:
    if (!client.connected()) {
    //Serial.println("Attempting IRC connection...");
    // Attempt to connect
    if (client.connect(IRC_NICK, IRC_CHAN, IRC_PASS)) {
    //Serial.println("connected");
      client.sendMessage(IRC_CHAN, "Hello everyone! I'm TvheadBot, a construct, assistant within the head of Atltvhead. If you have any questions type !help , and I'll post a link to all the channel commands. Let's Tune into Good Vibes! <3");
    } else {
      //Serial.println("failed... try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
    return;
  }

 我们将调用我们的回调函数来检查 twitch 消息并将其分解为 ping/pong 交互、聊天消息和用户名。我们还将开始检查是否检测到快照,并查看我们的任何密钥是否已解锁。

client.loop();
  
  //Time Outs or Emote Only 
  if(touch2detected){
    touch2detected = false;
    if(snapboo){
      snapboo = false;
      client.sendMessage(IRC_CHAN,"SNAP");
      
    } else if(emoteboo){
      emoteboo = false;
      client.sendMessage(IRC_CHAN,"IT'S EMOTE TIME!");
    } else{
      client.sendMessage(IRC_CHAN,"High Five Mode Initiated");
    }
  }
}

 不幸的是,聊天机器人无法触发仅表情模式,真可惜。

这些命令被我们的 python 脚本识别以启动超时。

上面提到,我们分解了 twitch 消息,用于 ping/pong、用户名、消息。

如果一个特定的单词是由特定的用户名(用户名)写的,那么解锁快照或仅表情模式(我又很笨,聊天机器人无法触发)。

void callback(IRCMessage ircMessage) {
//Serial.println("In CallBack");
  // PRIVMSG ignoring CTCP messages
  if (ircMessage.command == "PRIVMSG" && ircMessage.text[0] != '\001') {
    //Serial.println("Passed private message.");
    String message("<" + ircMessage.nick + "> " + ircMessage.text);
    
    if(ircMessage.text == "sk" && ircMessage.nick == "username"){
      snapboo = true;
      client.sendMessage(IRC_CHAN,"The Snap has been unlocked!");
    }
    else if(ircMessage.text == "ek" && ircMessage.nick == "username"){
      emoteboo = true;
      client.sendMessage(IRC_CHAN,"Emote only ready!");
    }
    return;
  }
}

 最后,只需为客户端设置调试。

void debugSentCallback(String data) {
  //Serial.println("I am in debug");
  Serial.println(data);
}

步骤 6

如何关闭你的构建并捕捉你的聊天!

不要忘记切一个洞,这样你的手指就可以接触到传感器! 

文件

Snap_Glove.ino :ESP32 和 Arduino 的 Snap Glove 代码

 

Thanos Twitch Bot.py :一个基本的 Twitch 机器人,它收集聊天中的所有用户,将其中一半的用户分段以超时,并在特定人员发送特定消息时将其超时缺少用于与 twitch 通信的 cfg 文件(它的密码和其他)-> # cfg.pyHOST = "irc.twitch.tv" # Twitch IRC 服务器端口 = 6667 # 总是使用端口 6667!NICK = "twitch_username" # 你的 Twitch 用户名,小写 PASS = "oauth:xxxxxxxxxxxxxxxxxxxx " # 你的 Twitch OAuth tokenCHAN = "#channel" # 你想加入的频道

 

 


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.obk20.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'支持Twitch的简单可穿戴设备',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.obk20.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);