365 lines
12 KiB
JavaScript
365 lines
12 KiB
JavaScript
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
|
|
const STV_GLOBAL_URL = () => "https://api.7tv.app/v2/emotes/global";
|
|
const STV_CHANNEL_URL = (user) => "https://api.7tv.app/v2/users/" + user + "/emotes";
|
|
const FFZ_GLOBAL_URL = () => "https://api.frankerfacez.com/v1/set/global";
|
|
const FFZ_CHANNEL_URL = (user) => "https://api.frankerfacez.com/v1/room/" + user;
|
|
const BTT_GLOBAL_URL = () => "https://api.betterttv.net/3/cached/emotes/global";
|
|
const BTT_CHANNEL_URL = (id) => "https://api.betterttv.net/3/cached/users/twitch/" + id;
|
|
|
|
function getData(ajaxurl) {
|
|
return $.ajax({
|
|
url: ajaxurl,
|
|
type: 'GET',
|
|
});
|
|
};
|
|
|
|
const get_g7TV = async() => {
|
|
const req = await getData(STV_GLOBAL_URL())
|
|
return req.map((v,i)=> ({str:v.name, url: (v.urls['2']||v.urls['2']||v.urls['1'])[1]}));
|
|
}
|
|
const get_p7TV = async(user) => {
|
|
try{
|
|
const req = await getData(STV_CHANNEL_URL(user))
|
|
return req.map((v,i)=> ({str:v.name, url: (v.urls['2']||v.urls['2']||v.urls['1'])[1]}));
|
|
}catch(e){return []}
|
|
}
|
|
const get_gFFZ = async() => {
|
|
const req = await getData(FFZ_GLOBAL_URL())
|
|
return req.sets['3'].emoticons.map((v,i)=> ({str:v.name, url: 'https:'+(v.urls['2']||v.urls['2']||v.urls['1'])}))
|
|
}
|
|
const get_pFFZ = async(user) => {
|
|
try{
|
|
const req = await getData(FFZ_CHANNEL_URL(user))
|
|
return req.sets[req.room.set].emoticons.map((v,i)=> ({str:v.name, url: 'https:'+(v.urls['2']||v.urls['2']||v.urls['1'])}))
|
|
}catch(e){return []}
|
|
}
|
|
|
|
const get_gBTT = async() => {
|
|
const req = await getData(BTT_GLOBAL_URL())
|
|
return req.map((v,i) => ({str:v.code, url: 'https://cdn.betterttv.net/emote/'+v.id+'/2x'}))
|
|
}
|
|
const get_pBTT = async(id) => {
|
|
try{
|
|
id = '486183840'
|
|
const req = await getData(BTT_CHANNEL_URL(id))
|
|
return req.sharedEmotes.map((v,i) => ({str:v.code, url: 'https://cdn.betterttv.net/emote/'+v.id+'/2x'}))
|
|
}catch(e){return []}
|
|
}
|
|
|
|
const get_emotes = async(username, userid) => {
|
|
return [].concat(await get_g7TV(), await get_p7TV(username),
|
|
await get_gFFZ(), await get_pFFZ(username),
|
|
await get_gBTT(), await get_pBTT(userid))
|
|
}
|
|
|
|
const canvasSizing = (cnv) => {
|
|
const resizeCanvas = () => {
|
|
cnv.width = window.innerWidth;
|
|
cnv.height = window.innerHeight;
|
|
}
|
|
window.addEventListener('resize', resizeCanvas, false);
|
|
resizeCanvas();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$(async function () {
|
|
const webSocket = window.socket;
|
|
|
|
var img_map = {}, static_emotes = {};
|
|
var lastframe = 0;
|
|
var preloaded = false, initialized = false;
|
|
var particles = [];
|
|
|
|
const canvas = document.getElementById('wall');
|
|
const ctx = canvas.getContext('2d');
|
|
canvasSizing(canvas);
|
|
|
|
const loadImages = (emotes) => {
|
|
let loadcount = 0, loadtotal = emotes.length;
|
|
preloaded = false;
|
|
var loadedimages = {};
|
|
for (let i=0; i<emotes.length; i++) {
|
|
var image = new Image();
|
|
image.onload = function () {
|
|
loadcount++;
|
|
if (loadcount == loadtotal) preloaded = true;
|
|
};
|
|
image.src = emotes[i].url;
|
|
loadedimages[emotes[i].str] = image;
|
|
}
|
|
return loadedimages;
|
|
}
|
|
|
|
const randEmote = (set) => {
|
|
if(!Array.isArray(set))
|
|
set = Object.keys(img_map) || []
|
|
return set[parseInt(set.length* Math.random())]
|
|
}
|
|
|
|
const username = "soraefir"
|
|
const userid = "486204587"
|
|
static_emotes = await get_emotes(username,userid)
|
|
img_map = loadImages(static_emotes)
|
|
|
|
const part_speed = 50;
|
|
const part_bounce_el = 0.9
|
|
const fdt = 1;
|
|
const drt = 8;
|
|
const tWave = (t) => (t<0 || t>drt )? 0 : (t<fdt ? t/fdt : (t>(drt-fdt) ? (drt-t)/fdt : 1))
|
|
const sWave = (t, s) => (t<0 || t>drt) ? 1 : (t<fdt ? t*s/fdt : (t>(drt-fdt) ? (drt-t)*s/fdt : s))
|
|
const randRange = (min,max) => (Math.random()* (max-min) + min)
|
|
|
|
class Particle {
|
|
constructor(emote,data){
|
|
this.size = 64;
|
|
this.data = data;
|
|
this.setPhysics(randRange(0,canvas.width),
|
|
randRange(0,canvas.height),
|
|
0,0,0,0);
|
|
this.sete = emote ? emote:null
|
|
this.emote = emote || randEmote(this.sete)
|
|
this.time = 0;
|
|
}
|
|
|
|
setPhysics(x,y,vx,vy,ax,ay){
|
|
this.x = x || this.x || 0;
|
|
this.y = y || this.y || 0;
|
|
this.vx = vx || this.vx || 0;
|
|
this.vy = vy || this.vy || 0;
|
|
this.ax = ax || this.ax || 0;
|
|
this.ay = ay || this.ay || 0;
|
|
}
|
|
|
|
draw(){
|
|
ctx.globalAlpha = tWave(this.time);
|
|
if(img_map[this.emote])
|
|
ctx.drawImage(img_map[this.emote], this.x, this.y,
|
|
sWave(this.time,this.size), sWave(this.time,this.size));
|
|
}
|
|
|
|
update(tick){
|
|
this.time += tick;
|
|
this.vx += tick * this.ax;
|
|
this.vy += tick * this.ay;
|
|
this.x += tick * this.vx * part_speed;
|
|
this.y += tick * this.vy * part_speed;
|
|
}
|
|
}
|
|
|
|
|
|
class RainP extends Particle {
|
|
constructor(emote,data) {
|
|
super(emote,data)
|
|
this.setPhysics(randRange(0, canvas.width),
|
|
randRange(0, -this.size),
|
|
0,randRange(10,15),
|
|
0,0)
|
|
this.size = randRange(this.size/2,this.size)
|
|
this.time = 5.5+this.y/canvas.height*2;
|
|
}
|
|
|
|
draw(){
|
|
ctx.globalAlpha = tWave(this.time);
|
|
if(img_map[this.emote])
|
|
ctx.drawImage(img_map[this.emote], this.x, this.y,
|
|
this.size, this.size);
|
|
}
|
|
}
|
|
|
|
class BounceP extends Particle {
|
|
constructor(emote,data) {
|
|
super(emote,data)
|
|
let speed = randRange(5,10);
|
|
let ang = randRange(0, 2*Math.PI);
|
|
this.setPhysics(randRange(0, canvas.width),
|
|
randRange(0, canvas.height),
|
|
Math.cos(ang)*speed,
|
|
Math.sin(ang)*speed,
|
|
0,0)
|
|
}
|
|
|
|
update(tick){
|
|
super.update(tick);
|
|
if (this.x < 0) {
|
|
this.vx = this.vx < 0 ? -this.vx * part_bounce_el : this.vx;
|
|
this.x = 0;
|
|
} else if (this.x + this.size > canvas.width) {
|
|
this.vx = this.vx > 0 ? -this.vx * part_bounce_el : this.vx;
|
|
this.x = canvas.width - this.size;
|
|
}
|
|
if (this.y <0) {
|
|
this.vy = this.vy < 0 ? -this.vy * part_bounce_el : this.vy;
|
|
this.y = 0;
|
|
} else if (this.y + this.size > canvas.height) {
|
|
this.vy = this.vy > 0 ? -this.vy * part_bounce_el : this.vy;
|
|
this.y = canvas.height - this.size;
|
|
}
|
|
}
|
|
}
|
|
|
|
class BounceGP extends BounceP {
|
|
constructor(emote,data) {
|
|
super(emote,data)
|
|
let speed = randRange(5,10);
|
|
let ang = randRange(0,2*Math.PI);
|
|
this.setPhysics(randRange(0,canvas.width),
|
|
randRange(0,canvas.height),
|
|
Math.cos(ang)*speed,
|
|
Math.sin(ang)*speed,
|
|
0,10);
|
|
}
|
|
}
|
|
|
|
class ExplosionP extends RainP {
|
|
constructor(emote,data,args){
|
|
super(emote,data)
|
|
let speed = randRange(5,15);
|
|
let fang = 2*Math.PI* (args.angle/360)
|
|
let ang = randRange(-fang/2, +fang/2)+Math.PI/2 ;//+ 2*(angle/360)*Math.PI;
|
|
this.setPhysics(args.x,args.y,
|
|
Math.cos(ang)*speed,
|
|
-Math.sin(ang)*speed,
|
|
0,10);
|
|
this.time = drt - fdt*2;
|
|
this.size = randRange(this.size/2,this.size)
|
|
}
|
|
|
|
}
|
|
|
|
class FireworkP extends Particle {
|
|
constructor(emote,data) {
|
|
super(emote,data)
|
|
this.setPhysics(canvas.width/2,canvas.height,
|
|
0,-15,
|
|
0,0);
|
|
this.time=fdt;
|
|
}
|
|
|
|
update(tick){
|
|
super.update(tick);
|
|
if(this.y <= canvas.height/4 && this.time < drt){
|
|
this.time = drt;
|
|
genExplosion(this.x,this.y,360)
|
|
}
|
|
}
|
|
}
|
|
|
|
class BombP extends Particle {
|
|
constructor(emote,data) {
|
|
super(emote,data)
|
|
this.setPhysics(randRange(0, canvas.width-this.size),
|
|
-this.size,
|
|
0,15,
|
|
0,0)
|
|
this.time=fdt;
|
|
}
|
|
|
|
update(tick){
|
|
super.update(tick);
|
|
if(this.y >= canvas.height - this.size && this.time < drt){
|
|
this.time = drt;
|
|
genExplosion(this.x,this.y,60)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
const createParticule = (partP, emote, data, args) => {
|
|
let a = new partP(emote,data,args)
|
|
particles.push(a);
|
|
setTimeout(()=>{particles.pop()}, drt*1000+2000);
|
|
}
|
|
|
|
const genExplosion = (x,y,ang) =>{
|
|
for(let i=0; i<100; ++i) createParticule(ExplosionP, randEmote(), {},{x:x,y:y,angle:ang});
|
|
}
|
|
|
|
const genRain = () => {
|
|
let xpos = randRange(0, canvas.width);
|
|
let time = 0;
|
|
const interval = setInterval(()=>{
|
|
for(let i=0; i<10; ++i) createParticule(RainP, randEmote(), {},{});
|
|
++time;
|
|
if(time > 50) clearInterval(interval);
|
|
}, 100);
|
|
}
|
|
|
|
const genVolcano = () => {
|
|
let xpos = randRange(0, canvas.width);
|
|
let time = 0;
|
|
const interval = setInterval(()=>{
|
|
for(let i=0; i<10; ++i) createParticule(ExplosionP, randEmote(), {},{x:xpos,y:canvas.height,angle:30});
|
|
++time;
|
|
if(time > 50) clearInterval(interval);
|
|
}, 100);
|
|
}
|
|
|
|
|
|
|
|
async function init() {
|
|
main(0);
|
|
sleep(1000).then(()=>{
|
|
createParticule(BounceGP, randEmote(), {}, {})
|
|
createParticule(BounceP, randEmote(), {}, {})
|
|
createParticule(BounceP, randEmote(), {}, {})
|
|
createParticule(BombP, randEmote(), {}, {})
|
|
createParticule(FireworkP, randEmote(), {}, {})
|
|
genRain();
|
|
genVolcano();
|
|
})
|
|
}
|
|
|
|
function main(tframe) {
|
|
window.requestAnimationFrame(main);
|
|
|
|
var dt = (tframe - lastframe) / 1000;
|
|
lastframe = tframe;
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
if (!initialized) {
|
|
if (preloaded) setTimeout(function(){initialized = true;}, 1000);
|
|
} else {
|
|
particles.forEach(p => p.update(dt));
|
|
particles.forEach(p => p.draw());
|
|
}
|
|
}
|
|
|
|
init()
|
|
|
|
const handleSocketMessage = (e)=>{
|
|
try {
|
|
let rawMessage = e.data,
|
|
message = JSON.parse(rawMessage);
|
|
|
|
if(!message.hasOwnProperty('eventFamily') || message.eventFamily != 'emotewall' ||
|
|
!message.hasOwnProperty('eventType') || !message.hasOwnProperty('data'))
|
|
return;
|
|
|
|
console.log(message.eventType, message.data)
|
|
if(message.eventType == 'message') {
|
|
//....
|
|
}
|
|
} catch (ex) {
|
|
console.log(ex)
|
|
}
|
|
};
|
|
|
|
|
|
jQuery(async ()=>{
|
|
|
|
try{
|
|
socket.addFamilyHandler("overlay", handleSocketMessage);
|
|
if(socket){
|
|
while(socket.getReadyState() === 0){
|
|
await new Promise(r => setTimeout(r, 500));
|
|
}
|
|
}
|
|
}catch(e) {console.log(e)}
|
|
})
|
|
|
|
}); |