WIP
@ -1,26 +0,0 @@
|
||||
import PIL.Image, PIL.ImageDraw, PIL.ImageFont
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
font = PIL.ImageFont.truetype(os.path.join(os.path.dirname(__file__), './customAlertsMedia/ibmplex.ttf'), 20)
|
||||
nFrames = 60
|
||||
width = 500
|
||||
height = 500
|
||||
if __name__ == "__main__":
|
||||
tpe = sys.argv[1]
|
||||
username = sys.argv[2]
|
||||
description = sys.argv[3]
|
||||
target = sys.argv[4]
|
||||
|
||||
animated_gif = Image.open("./customAlertsMedia/"+tpe+".gif")
|
||||
|
||||
frames = []
|
||||
for frame in ImageSequence.Iterator(animated_gif):
|
||||
frame = frame.convert('RGB')
|
||||
d = PIL.ImageDraw.Draw(frame)
|
||||
d.text((0, 0), description, font=font, fill=(255, 255, 255))
|
||||
d.text((0, 100), username, font=font, fill=(255, 255, 255))
|
||||
frames.append(frame)
|
||||
frames[0].save(target+tpe+".gif", save_all=True, append_images=frames[1:], duration=100, loop=0, optimize=0, comment="")
|
||||
os.popen('cp ./customAlertsMedia/'+tpe+'.mp3 '+target+tpe+'.mp3')
|
@ -1,47 +1,92 @@
|
||||
(function() {
|
||||
function alert(username, desc, tpe) {
|
||||
var pb = new java.lang.ProcessBuilder("/usr/bin/python3", "./Main.py", tpe, username, desc, "/opt/PhantomBot/config/gif-alerts/");
|
||||
var proc = pb.start();
|
||||
proc.waitFor();
|
||||
|
||||
$.panelsocketserver.alertImage(tpe+".gif?noise=" + Math.floor(Math.random() * 1000 + 1));
|
||||
}
|
||||
|
||||
$.bind('twitchFollow', function(event) {
|
||||
var follower = event.getFollower();
|
||||
alert(follower.toUpperCase(), "NEW FOLLOWER", "follow");
|
||||
function sendData(tpe, d) {
|
||||
$.panelsocketserver.sendJSONToAll(JSON.stringify({
|
||||
'eventFamily': 'calert',
|
||||
'eventType': tpe,
|
||||
'data': d
|
||||
}));
|
||||
}
|
||||
|
||||
$.bind('twitchFollow', function(event) {
|
||||
sendData('follow',{ 'user': event.getFollower()});
|
||||
});
|
||||
$.bind('twitchSubscriber', function(event) {
|
||||
sendData('subscribe', {
|
||||
'user': event.getSubscriber(),
|
||||
'isReSub': false,
|
||||
'months': 0,
|
||||
'tier': event.getPlan() / 1000,
|
||||
'message': event.getMessage()
|
||||
});
|
||||
$.bind('twitchSubscriber', function(event) {
|
||||
var subscriber = event.getSubscriber();
|
||||
alert(subscriber.toUpperCase(), "NEW SUBSCRIBER", "subscribe");
|
||||
});
|
||||
$.bind('twitchReSubscriber', function(event) {
|
||||
sendData('subscribe', {
|
||||
'user': event.getReSubscriber(),
|
||||
'isReSub': true,
|
||||
'months': event.getMonths(),
|
||||
'tier': event.getPlan() / 1000,
|
||||
'message': event.getMessage()
|
||||
});
|
||||
});
|
||||
$.bind('twitchSubscriptionGift', function(event) {
|
||||
sendData('gift', {
|
||||
'recipient': event.getRecipient(),
|
||||
'user': event.getUsername(),
|
||||
'months': event.getMonths(),
|
||||
'isReSub': (parseInt(event.getMonths()) > 1),
|
||||
'tier': event.getPlan() / 1000
|
||||
});
|
||||
|
||||
$.bind('command', function(event) {
|
||||
const sender = "" + event.getSender().toLowerCase(),
|
||||
command = event.getCommand(),
|
||||
args = event.getArgs(),
|
||||
action = args[0];
|
||||
|
||||
if (command.equalsIgnoreCase('calert')) {
|
||||
if (!action) {
|
||||
$.say($.whisperPrefix(sender) + $.lang.get('calert.help', ' Use "!calert [follow | subsribe | donation] user" to trigger alert.'));
|
||||
} else if (action.equalsIgnoreCase('follow')) {
|
||||
alert(args[1].toUpperCase(), "NEW FOLLOWER", "follow");
|
||||
} else if (action.equalsIgnoreCase('subscribe')) {
|
||||
alert(args[1].toUpperCase(), "NEW SUBSCRIBER", "subscribe");
|
||||
} else if (action.equalsIgnoreCase('donation')) {
|
||||
alert(args[1].toUpperCase(), "NEW DONATION", "donation");
|
||||
} else {
|
||||
$.say($.whisperPrefix(sender) + $.lang.get('calert.help', ' Use "!calert [follow | subsribe | donation] user" to trigger alert.'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.bind('initReady', function() {
|
||||
$.registerChatCommand('./custom/custom/customAlerts.js', 'calert');
|
||||
$.registerChatSubcommand('calert', 'follow', 2);
|
||||
$.registerChatSubcommand('calert', 'subscribe', 2);
|
||||
$.registerChatSubcommand('calert', 'donation', 2);
|
||||
$.bind('twitchMassSubscriptionGifted', function(event) {
|
||||
sendData('mgift', {
|
||||
'user': event.getUsername(),
|
||||
'amount': event.getAmount(),
|
||||
'tier': event.getPlan() / 1000
|
||||
});
|
||||
})();
|
||||
|
||||
});
|
||||
|
||||
$.bind('twitchRaid', function(event) {
|
||||
sendData('raid',{
|
||||
'user': event.getUsername(),
|
||||
'viewers': event.getViewers(),
|
||||
});
|
||||
});
|
||||
|
||||
$.bind('twitchBits', function (event) {
|
||||
sendData('bits', {
|
||||
'user': event.getUsername(),
|
||||
'amount': event.getBits(),
|
||||
'message': event.getMessage()
|
||||
});
|
||||
});
|
||||
|
||||
$.bind('command', function(event) {
|
||||
const sender = "" + event.getSender().toLowerCase(),
|
||||
command = event.getCommand(),
|
||||
args = event.getArgs(),
|
||||
action = args[0];
|
||||
|
||||
if (command.equalsIgnoreCase('calert')) {
|
||||
if (!action) {
|
||||
$.say($.whisperPrefix(sender) + $.lang.get('calert.help', ' Use "!calert [follow | subsribe | donation] user" to trigger alert.'));
|
||||
} else if (action.equalsIgnoreCase('follow')) {
|
||||
alert(args[1].toUpperCase(), "NEW FOLLOWER", "follow");
|
||||
} else if (action.equalsIgnoreCase('subscribe')) {
|
||||
alert(args[1].toUpperCase(), "NEW SUBSCRIBER", "subscribe");
|
||||
} else if (action.equalsIgnoreCase('donation')) {
|
||||
alert(args[1].toUpperCase(), "NEW DONATION", "donation");
|
||||
} else {
|
||||
$.say($.whisperPrefix(sender) + $.lang.get('calert.help', ' Use "!calert [follow | subsribe | donation] user" to trigger alert.'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.bind('initReady', function() {
|
||||
$.registerChatCommand('./custom/custom/customAlerts.js', 'calert');
|
||||
$.registerChatSubcommand('calert', 'follow', 2);
|
||||
$.registerChatSubcommand('calert', 'subscribe', 2);
|
||||
$.registerChatSubcommand('calert', 'donation', 2);
|
||||
});
|
||||
})();
|
||||
|
Before Width: | Height: | Size: 147 KiB |
62
web/alert/index.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>CustomAlerts</title>
|
||||
<!-- Load our styles -->
|
||||
<style>body {margin:0;overflow:hidden;}</style>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: IBM Plex Mono;
|
||||
src: url(./media/ibmplex.ttf);
|
||||
}
|
||||
.main{
|
||||
position: absolute;
|
||||
width:500px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
color: #5e81ac;
|
||||
text-align:center;
|
||||
font-size:32px;
|
||||
font-family: IBM Plex Mono;
|
||||
opacity: 0;
|
||||
transition:1s;
|
||||
}
|
||||
.img{
|
||||
position: absolute;
|
||||
top: calc(50% - 150px);
|
||||
left: 50%;
|
||||
width:auto;
|
||||
height:200px;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
opacity: 0;
|
||||
transition:1s;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<!-- Main body -->
|
||||
<body>
|
||||
<img class="img" id="img"></img>
|
||||
<div class="main" id="main">
|
||||
<!-- <canvas id="wall"></canvas> -->
|
||||
|
||||
</div>
|
||||
<!-- jQuery -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<!-- Load jQuery UI -->
|
||||
<script src="https://code.jquery.com/ui/1.13.1/jquery-ui.min.js"></script>
|
||||
<!-- Load Reconnecting socket -->
|
||||
<script src="/common/reconnecting-websocket/reconnectingWS.min.js"></script>
|
||||
<!-- Load Bot config file -->
|
||||
<script src="/common/js/wsConfig.js"></script>
|
||||
|
||||
<!-- Load functions copied out of panel dir, since can't directly read panel dir (http auth problem) -->
|
||||
<script src="/custom/js/socketWrapper.js"></script>
|
||||
|
||||
<!-- Load our script -->
|
||||
<script src="index.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.0.2/anime.min.js"></script>
|
||||
</body>
|
||||
</html>
|
157
web/alert/index.js
Normal file
@ -0,0 +1,157 @@
|
||||
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
const volume = parseInt((new URLSearchParams(window.location.search)).get('vol')) || 100
|
||||
|
||||
$(async function () {
|
||||
const webSocket = window.socket;
|
||||
const announceQueue = [];
|
||||
|
||||
const playAudio = (src) =>{
|
||||
return new Promise(resolve =>{
|
||||
var audio = new Audio();
|
||||
$(audio).on("loadedmetadata", function() {
|
||||
resolve(audio);
|
||||
});
|
||||
audio.volume = volume/100.0;
|
||||
audio.src = src;
|
||||
audio.play().catch((err)=>{
|
||||
if(err.toString().startsWith('NotAllowedError')){
|
||||
$('body').append($('<button/>', {
|
||||
'html': 'Enable Audio Hook',
|
||||
'style': 'top:80%;left:50%; position: absolute; font-size: 30px; transform: translateX(-50%) translateY(-50%);'
|
||||
}).on('click', function(){$(this).remove()}));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const renderEl = async (pic, music, message, detail) => {
|
||||
let node = document.getElementById('main');
|
||||
let nodeIm = document.getElementById('img');
|
||||
node.innerHTML = message;
|
||||
nodeIm.src = pic
|
||||
let audio = await playAudio(music);
|
||||
node.style.opacity = 1;
|
||||
nodeIm.style.opacity = 1;
|
||||
await sleep(audio.duration*1000 - 1000);
|
||||
node.style.opacity = 0;
|
||||
nodeIm.style.opacity = 0;
|
||||
}
|
||||
|
||||
const renderStart = async (an) => {
|
||||
await renderEl('','./media/sonar.ogg',
|
||||
`The Stream Started`, `...`)
|
||||
}
|
||||
|
||||
const renderFollow = async (an) => {
|
||||
await renderEl('./media/donate.gif','./media/sonar.ogg',
|
||||
`${an.user} joined the squad !`, `...`)
|
||||
}
|
||||
|
||||
const renderSubscribe = async (an) => {
|
||||
// TTS: an.details.message
|
||||
let v = an.details.isReSub ? 'resubscribed' : 'subscribed'
|
||||
let detail = an.details.months == 0 ? '' : `for ${an.details.months} months `
|
||||
let message = `${an.user} ${v} ${detail}!`
|
||||
await renderEl('./media/follow.gif','./media/follow.mp3',
|
||||
message,
|
||||
`...`)
|
||||
}
|
||||
|
||||
const renderGift = async (an) => {
|
||||
await renderEl('./media/follow.gif','./media/follow.mp3',
|
||||
`${an.user} gifted ${an.details.recipient} a sub !`,
|
||||
`...`)
|
||||
}
|
||||
|
||||
const renderMassGift = async (an) => {
|
||||
await renderEl('./media/follow.gif','./media/follow.mp3',
|
||||
`${an.user} gifted ${an.details.amount} subs to the community !`,
|
||||
`...`)
|
||||
}
|
||||
|
||||
const renderRaid = async (an) => {
|
||||
await renderEl('./media/raid.gif','./media/subscribe.mp3',
|
||||
`${an.user} is Raiding with a party of ${an.details.viewers} !`,
|
||||
`...`)
|
||||
}
|
||||
|
||||
const renderBits = async (an) => {
|
||||
// TTS: an.details.message
|
||||
await renderEl('','',
|
||||
`${an.user} cheered ${an.details.amount} bitties!`,
|
||||
`...`)
|
||||
}
|
||||
|
||||
const renderAnnouncement = async (an) => {
|
||||
if(an.tpe=='follow') await renderFollow(an)
|
||||
else if(an.tpe=='subscribe') await renderSubscribe(an)
|
||||
else if(an.tpe=='gift') await renderGift(an)
|
||||
else if(an.tpe=='mgift') await renderMassGift(an)
|
||||
else if(an.tpe=='raid') await renderRaid(an)
|
||||
else if(an.tpe=='bits') await renderBits(an)
|
||||
else if(an.tpe=='start') await renderStart(an)
|
||||
}
|
||||
|
||||
class Announcement {
|
||||
constructor(data){
|
||||
this.user = data.user;
|
||||
this.tpe = data.tpe;
|
||||
this.details = data.details || {};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
announceQueue.push(new Announcement({user:"-",tpe:"start"}));
|
||||
const main = async () => {
|
||||
while(true){
|
||||
if(announceQueue.length>0)
|
||||
await renderAnnouncement(announceQueue.shift());
|
||||
await sleep(1000);
|
||||
}
|
||||
}
|
||||
main();
|
||||
|
||||
const handleSocketMessage = async (e)=>{
|
||||
try {
|
||||
let rawMessage = e.data,
|
||||
message = JSON.parse(rawMessage);
|
||||
|
||||
if(!message.hasOwnProperty('eventFamily') || message.eventFamily != 'calert' ||
|
||||
!message.hasOwnProperty('eventType') || !message.hasOwnProperty('data'))
|
||||
return;
|
||||
if(message.eventType == 'follow') {
|
||||
announceQueue.push(new Announcement({user:message.data.user, tpe:'follow'}))
|
||||
}else if(message.eventType == 'subscribe') {
|
||||
announceQueue.push(new Announcement({user:message.data.user, tpe:'subscribe', details:message.data.details}))
|
||||
}else if(message.eventType == 'gift') {
|
||||
announceQueue.push(new Announcement({user:message.data.user, tpe:'gift', details:message.data.details}))
|
||||
}else if(message.eventType == 'mgift') {
|
||||
announceQueue.push(new Announcement({user:message.data.user, tpe:'mgift', details:message.data.details}))
|
||||
}else if(message.eventType == 'raid') {
|
||||
announceQueue.push(new Announcement({user:message.data.user, tpe:'raid', details:message.data.details}))
|
||||
}else if(message.eventType == 'bits') {
|
||||
announceQueue.push(new Announcement({user:message.data.user, tpe:'bits'}))
|
||||
}else{
|
||||
console.log("unhandled:", message.eventType)
|
||||
}
|
||||
} catch (ex) {
|
||||
console.log(ex)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
jQuery(async ()=>{
|
||||
|
||||
try{
|
||||
socket.addFamilyHandler("calert", handleSocketMessage);
|
||||
if(socket){
|
||||
while(socket.getReadyState() === 0){
|
||||
await new Promise(r => setTimeout(r, 500));
|
||||
}
|
||||
}
|
||||
}catch(e) {console.log(e)}
|
||||
})
|
||||
|
||||
});
|
Before Width: | Height: | Size: 399 KiB After Width: | Height: | Size: 399 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 547 KiB After Width: | Height: | Size: 547 KiB |
BIN
web/alert/media/sonar.ogg
Normal file
1752
web/chatguessr/SRC
@ -136,7 +136,7 @@ $(async function () {
|
||||
|
||||
class Particle {
|
||||
constructor(emote,data){
|
||||
this.size = 64;
|
||||
this.size = 56;
|
||||
this.data = data;
|
||||
this.setPhysics(randRange(0,canvas.width),
|
||||
randRange(0,canvas.height),
|
||||
@ -299,7 +299,7 @@ $(async function () {
|
||||
const createParticule = (partP, emote, data, args) => {
|
||||
let a = new partP(emote,data,args)
|
||||
particles.push(a);
|
||||
setTimeout(()=>{particles.pop()}, drt*1000+2000);
|
||||
setTimeout(()=>{particles.shift()}, drt*1000+2000);
|
||||
}
|
||||
|
||||
const genExplosion = (x,y,ang,em) =>{
|
||||
|