Перенос чатов из другого репозитория
This commit is contained in:
13
StreamLabsChats/sadkawaai/generation 1/index.html
Normal file
13
StreamLabsChats/sadkawaai/generation 1/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<div id="chatbox" class="sl__chat__layout">
|
||||
<a class="font-1">1</a>
|
||||
<a class="font-2">2</a>
|
||||
</div>
|
||||
|
||||
<script type="text/template" id="chatlist_item">
|
||||
<message id="{messageId}">
|
||||
<top>
|
||||
<author>{from}</author>
|
||||
</top>
|
||||
<content>{message}</content>
|
||||
</message>
|
||||
</script>
|
||||
510
StreamLabsChats/sadkawaai/generation 1/script.js
Normal file
510
StreamLabsChats/sadkawaai/generation 1/script.js
Normal file
@ -0,0 +1,510 @@
|
||||
let $chatBox = $(".sl__chat__layout");
|
||||
|
||||
let usersPfp = {};
|
||||
let parity = true;
|
||||
|
||||
let emoteSetId;
|
||||
let websocketEmotesConnected = false;
|
||||
let globalEmotes = [];
|
||||
let channelEmotes = [];
|
||||
let subMysteries = [];
|
||||
|
||||
let messageProcessingList = [
|
||||
detachMessage,
|
||||
loadGlobalEmotes,
|
||||
loadChannelEmotes,
|
||||
processTags,
|
||||
getProfilePicture,
|
||||
cleanText,
|
||||
userPings,
|
||||
upscaleBadges,
|
||||
upscaleEmotes,
|
||||
process7TVEmotes,
|
||||
fixEmotesPadding,
|
||||
largeEmotes,
|
||||
parityParse,
|
||||
preloadImages,
|
||||
animate,
|
||||
];
|
||||
|
||||
$(document).on("onEventReceived", function (event) {
|
||||
let details = event.detail;
|
||||
let command = details.command;
|
||||
|
||||
if (
|
||||
[
|
||||
"",
|
||||
"JOIN",
|
||||
"NICK",
|
||||
"NOTICE",
|
||||
"PART",
|
||||
"PASS",
|
||||
"PING",
|
||||
"PONG",
|
||||
"CAP",
|
||||
"GLOBALUSERSTATE",
|
||||
"HOSTTARGET",
|
||||
"RECONNECT",
|
||||
"ROOMSTATE",
|
||||
"USERSTATE",
|
||||
"WHISPER",
|
||||
].includes(command)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
case "PRIVMSG":
|
||||
commandPRIVMSG(details);
|
||||
break;
|
||||
|
||||
case "USERNOTICE":
|
||||
commandUSERNOTICE(details);
|
||||
break;
|
||||
|
||||
case "CLEARCHAT":
|
||||
commandClearCHAT(details);
|
||||
break;
|
||||
|
||||
case "CLEARMSG":
|
||||
commandClearMSG(details);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log(`Event ${command} not handled.`, details);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
async function nextFunction(
|
||||
$messageElement,
|
||||
$parentElement,
|
||||
details,
|
||||
functions
|
||||
) {
|
||||
if (functions[0] != undefined)
|
||||
await functions[0](
|
||||
$messageElement,
|
||||
$parentElement,
|
||||
details,
|
||||
functions.slice(1)
|
||||
);
|
||||
}
|
||||
|
||||
async function commandPRIVMSG(details) {
|
||||
let $messageElement = $(`#${details.messageId}`);
|
||||
let $parentElement = $messageElement.parent() || $chatBox;
|
||||
|
||||
if (details.body == '!event' && details.tags['user-id'] == details.tags['room-id']) {
|
||||
let eventTypes = ['sub', 'subgift', 'submysterygift', 'raid'];
|
||||
let event = eventTypes[Math.floor(Math.random()*eventTypes.length)];
|
||||
details.tags['msg-id'] = event;
|
||||
return commandUSERNOTICE(details);
|
||||
}
|
||||
|
||||
if (!$messageElement.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
await nextFunction(
|
||||
$messageElement,
|
||||
$parentElement,
|
||||
details,
|
||||
messageProcessingList
|
||||
);
|
||||
}
|
||||
|
||||
async function commandUSERNOTICE(details) {
|
||||
let $eventElement = $('#chatlist_event')
|
||||
let eventType = details.tags['msg-id']
|
||||
let author = details.tags['display-name']
|
||||
let content;
|
||||
let type;
|
||||
|
||||
let displayName = details.tags['display-name']
|
||||
let recipient = details.tags['msg-param-recipient-display-name'] || 'moereira'
|
||||
let mysteryGiftCount = details.tags['msg-param-mass-gift-count'] || 100
|
||||
let viewerCount = details.tags['msg-param-viewerCount'] || 100
|
||||
|
||||
if (!$eventElement.length) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (eventType) {
|
||||
case 'sub':
|
||||
case 'resub':
|
||||
case 'standardpayforward':
|
||||
case 'communitypayforward':
|
||||
case 'giftpaidupgrade':
|
||||
case 'primepaidupgrade':
|
||||
content = 'подписался'
|
||||
type = 'sub';
|
||||
break;
|
||||
case 'subgift':
|
||||
case 'anonsubgift':
|
||||
if (subMysteries.includes(details.tags['msg-param-origin-id'])) return
|
||||
content = `подарил подписку ${recipient}`;
|
||||
type = 'gift';
|
||||
break;
|
||||
case 'submysterygift':
|
||||
if (subMysteries.includes(details.tags['msg-param-origin-id'])) return
|
||||
subMysteries.push(details.tags['msg-param-origin-id'])
|
||||
content = `подарил ${mysteryGiftCount} сабок!`;
|
||||
type = 'gift';
|
||||
break;
|
||||
case 'raid':
|
||||
content = `притопал с ${viewerCount} зрителями!`;
|
||||
type = 'raid';
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
$eventElement = $eventElement.html()
|
||||
$eventElement = $eventElement.replace('{messageId}', details.messageId)
|
||||
$eventElement = $eventElement.replace('{author}', author)
|
||||
$eventElement = $eventElement.replace('{content}', content)
|
||||
$eventElement = $($eventElement)
|
||||
|
||||
$eventElement.addClass(type)
|
||||
$eventElement.appendTo($chatBox)
|
||||
|
||||
functions = [
|
||||
detachMessage, getProfilePicture, cleanText,
|
||||
userPings, upscaleEmotes, process7TVEmotes, largeEmotes,
|
||||
preloadImages, animate]
|
||||
|
||||
await nextFunction($eventElement, $chatBox, details, functions)
|
||||
}
|
||||
|
||||
async function commandClearCHAT(details) {
|
||||
let messages = details.body
|
||||
? $(`[userId="${details.tags["target-user-id"]}"]`)
|
||||
: $("message");
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
const message = messages.eq(i);
|
||||
setTimeout(() => {
|
||||
message.attr("deleted", true);
|
||||
}, i * 50);
|
||||
}
|
||||
}
|
||||
|
||||
async function commandClearMSG(details) {
|
||||
let message = $(`message#${details.messageId}`);
|
||||
message.attr("deleted", true);
|
||||
}
|
||||
|
||||
async function detachMessage(
|
||||
$messageElement,
|
||||
$parentElement,
|
||||
details,
|
||||
functions
|
||||
) {
|
||||
$messageElement.detach();
|
||||
$messageElement.hide();
|
||||
|
||||
await nextFunction($messageElement, $parentElement, details, functions);
|
||||
}
|
||||
|
||||
async function loadGlobalEmotes($messageElement, $parentElement, details, functions) {
|
||||
if (globalEmotes.length == 0) {
|
||||
fetch('https://7tv.io/v3/emote-sets/global')
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Global emotes: Error: (${response.status})`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log(`Global emotes: Success (${data.emotes.length})`);
|
||||
globalEmotes = data.emotes;
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error.message);
|
||||
});
|
||||
}
|
||||
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
};
|
||||
|
||||
async function loadChannelEmotes($messageElement, $parentElement, details, functions) {
|
||||
nextFunction($messageElement, $parentElement, details, functions)
|
||||
|
||||
let tags = details.tags;
|
||||
let roomId = tags['room-id'];
|
||||
|
||||
if (!emoteSetId) {
|
||||
try {
|
||||
let response = await fetch(`https://7tv.io/v3/users/twitch/${roomId}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Channel emotes: Error: (${response.status})`);
|
||||
}
|
||||
let data = await response.json();
|
||||
console.log(`Channel emotes: Success (${data.emote_set.emotes.length})`);
|
||||
channelEmotes = data.emote_set.emotes;
|
||||
emoteSetId = data.emote_set.id;
|
||||
} catch (error) {
|
||||
console.log(error.message);
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (!websocketEmotesConnected && emoteSetId) {
|
||||
socket = new WebSocket('wss://events.7tv.io/v3');
|
||||
websocketEmotesConnected = true;
|
||||
|
||||
socket.onopen = function (event) {
|
||||
console.log('Connected to 7TV WebSocket');
|
||||
socket.send(JSON.stringify({
|
||||
'op': 35,
|
||||
'd': {
|
||||
'type': 'emote_set.update',
|
||||
'condition': {
|
||||
'object_id': emoteSetId
|
||||
}
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
socket.onmessage = function (event) {
|
||||
let data = JSON.parse(event.data);
|
||||
|
||||
switch (data.op) {
|
||||
case 0:
|
||||
let eventData = data.d.body;
|
||||
|
||||
if (eventData.hasOwnProperty('pulled')) {
|
||||
let emoteId = eventData.pulled[0].old_value.id;
|
||||
channelEmotes = channelEmotes.filter(obj =>
|
||||
obj.id !== emoteId);
|
||||
};
|
||||
if (eventData.hasOwnProperty('pushed')) {
|
||||
let emoteData = eventData.pushed[0].value;
|
||||
channelEmotes.push(emoteData);
|
||||
};
|
||||
if (eventData.hasOwnProperty('updated')) {
|
||||
let emoteId = eventData.updated[0].old_value.id;
|
||||
let emoteData = eventData.updated[0].value;
|
||||
|
||||
let emoteIndex = channelEmotes.findIndex(
|
||||
obj => obj.id === emoteId);
|
||||
|
||||
if (emoteIndex !== -1) {
|
||||
channelEmotes[emoteIndex] = emoteData;
|
||||
};
|
||||
};
|
||||
|
||||
break;
|
||||
case 4:
|
||||
socket.close();
|
||||
websocketEmotesConnected = false;
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
socket.onerror = function (error) {
|
||||
console.error('WebSocket error:', error);
|
||||
};
|
||||
|
||||
socket.onclose = function (event) {
|
||||
console.log('WebSocket closed:', event.code, event.reason);
|
||||
websocketEmotesConnected = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function processTags(
|
||||
$messageElement,
|
||||
$parentElement,
|
||||
details,
|
||||
functions
|
||||
) {
|
||||
let tags = details.tags;
|
||||
let info = tags["badge-info"];
|
||||
let badges = tags.badges.split(",");
|
||||
let msgId = tags["msg-id"];
|
||||
|
||||
if (info) {
|
||||
let badge = info.replace("/", "-");
|
||||
$messageElement.addClass(badge);
|
||||
}
|
||||
|
||||
badges.forEach((badge) => {
|
||||
let name = badge.split("/")[0];
|
||||
if (name) {
|
||||
$messageElement.addClass(name);
|
||||
}
|
||||
});
|
||||
|
||||
$messageElement.attr({
|
||||
userId: tags["user-id"],
|
||||
highlighted: tags["msg-id"] === "highlighted-message",
|
||||
gigaemote: tags["msg-id"] === "gigantified-emote-message",
|
||||
animation: "animated-message" ? tags["animation-id"] : "",
|
||||
"first-msg": tags["first-msg"] === true && msgId !== "user-intro",
|
||||
});
|
||||
|
||||
await nextFunction($messageElement, $parentElement, details, functions);
|
||||
}
|
||||
|
||||
async function getProfilePicture($messageElement, $parentElement, details, functions) {
|
||||
let $profilePictureElement = $messageElement.find('pfp').eq(0);
|
||||
let userId = details.tags['user-id'];
|
||||
|
||||
if ($profilePictureElement.length != 0 && !(userId in usersPfp)) {
|
||||
try { let response = await fetch('https' + '://st' + 'reaml' + 'abs.c' + 'om/ap' + 'i/v5/' + 'helix' + '/user' + 's?bro' + 'adcas' + 'ter_i' + 'd=' + userId); if (!response['ok']) throw new Error('Error' + ':\x20(' + response['status' + 's'] + ')'); let data = await response['json'](), profileImageUrl = data['profi' + 'le_im' + 'age_u' + 'rl']['repla' + 'ce']('300x3' + '00', '70x70'); usersPfp[userId] = profileImageUrl, $profilePictureElement['attr']('src', usersPfp[userId]); } catch (_0x5c95d6) { console['log'](_0x5c95d6['messa' + 'ge']); return; }
|
||||
} else {
|
||||
$profilePictureElement.attr('src', usersPfp[userId]);
|
||||
}
|
||||
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function cleanText($messageElement, $parentElement, details, functions) {
|
||||
let $contentElement = $messageElement.find('content').eq(0);
|
||||
let specialChar = new TextDecoder().decode(new Uint8Array([243, 160, 128, 128]));
|
||||
let cleanedHTML = $contentElement.html().replaceAll(specialChar, '').replaceAll('\n', '');
|
||||
|
||||
$contentElement.html(cleanedHTML);
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function userPings($messageElement, $parentElement, details, functions) {
|
||||
let $content = $messageElement.find('content');
|
||||
let contentHTML = $content.html();
|
||||
let pings = $content.text().match(/@\w+/g) || [];
|
||||
|
||||
pings.forEach(user => {
|
||||
contentHTML = contentHTML.replace(
|
||||
new RegExp(user, 'g'),
|
||||
`<user-ping>${user}</user-ping>`
|
||||
);
|
||||
});
|
||||
|
||||
$content.html(contentHTML);
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function upscaleBadges($messageElement, $parentElement, details, functions) {
|
||||
$messageElement.find('.badge').each(function () {
|
||||
let $badge = $(this);
|
||||
let $badgeImage = $badge.children('img').eq(0);
|
||||
|
||||
if ($badgeImage.attr('src').includes('jtvnw')) {
|
||||
$badgeImage.attr('src', function (index, oldSrc) {
|
||||
return oldSrc.replace('1.0', '4.0');
|
||||
});
|
||||
}
|
||||
});
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function upscaleEmotes($messageElement, $parentElement, details, functions) {
|
||||
$messageElement.find('.emote').each(function () {
|
||||
let $emote = $(this);
|
||||
let $emoteImage = $emote.children('img').eq(0);
|
||||
|
||||
if ($emoteImage.attr('src').includes('jtvnw')) {
|
||||
$emoteImage.attr('src', function (index, oldSrc) {
|
||||
return oldSrc.replace('1.0', '4.0');
|
||||
});
|
||||
}
|
||||
});
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function process7TVEmotes($messageElement, $parentElement, details, functions) {
|
||||
let $contentElement = $messageElement.find('content').eq(0);
|
||||
let $headElement = $contentElement.find('head').eq(0);
|
||||
let $content = ` ${$contentElement.html()} `;
|
||||
let emotes = globalEmotes.concat(channelEmotes);
|
||||
|
||||
if ($headElement[0] != undefined) {
|
||||
$content = $content.replace($headElement[0].outerHTML,
|
||||
` ${$headElement[0].outerHTML} `);
|
||||
}
|
||||
|
||||
emotes.forEach(emote => {
|
||||
let temp_text = '';
|
||||
let emoteSrc = `https://${emote.data.host.url}/4x.avif`;
|
||||
let emoteClasses = 'emote';
|
||||
|
||||
if (emote.flags == 1) {
|
||||
emoteClasses = 'emote zero-width';
|
||||
};
|
||||
|
||||
while (($content = (temp_text = $content).replace(
|
||||
` ${emote.name} `,
|
||||
` <span class="${emoteClasses}"><img src="${emoteSrc}"></span> `
|
||||
)) !== temp_text) { }
|
||||
});
|
||||
|
||||
$contentElement.html($content);
|
||||
$contentElement.find('.zero-width').each(function () {
|
||||
let previousSibling = this.previousSibling.nodeValue;
|
||||
|
||||
if (previousSibling && previousSibling.trim() === '') {
|
||||
this.children[0].classList.add('zero-width');
|
||||
this.previousElementSibling.innerHTML += this.innerHTML;
|
||||
this.remove();
|
||||
};
|
||||
});
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function fixEmotesPadding($messageElement, $parentElement, details, functions) {
|
||||
let $contentElement = $messageElement.find('content').eq(0);
|
||||
|
||||
$contentElement.find('.emote').each(function () {
|
||||
let previousSibling = this.previousSibling.nodeValue;
|
||||
let nextSibling = this.nextSibling.nodeValue;
|
||||
|
||||
if (previousSibling && previousSibling.trim() === '') {
|
||||
this.classList.add('emote-left');
|
||||
};
|
||||
|
||||
if (nextSibling && nextSibling.trim() === '') {
|
||||
this.classList.add('emote-right');
|
||||
};
|
||||
});
|
||||
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function largeEmotes($messageElement, $parentElement, details, functions) {
|
||||
let $contentElement = $messageElement.find('content').eq(0);
|
||||
let $content = $contentElement.clone().find('head').remove().end().text().replace(/\s+/g, '');
|
||||
let emoteCount = $messageElement.find('.emote').length;
|
||||
|
||||
$messageElement.attr('large-emotes', !$content && emoteCount <= 3);
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function parityParse($messageElement, $parentElement, details, functions) {
|
||||
$messageElement.attr('parity', parity ? 'even' : 'odd');
|
||||
parity = !parity;
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function preloadImages($messageElement, $parentElement, details, functions) {
|
||||
let $images = $messageElement.find('img');
|
||||
let imagesCount = $images.length;
|
||||
|
||||
if (imagesCount > 0) {
|
||||
let imagesLoaded = 0;
|
||||
$images.on('load', function () {
|
||||
if (++imagesLoaded === imagesCount) {
|
||||
nextFunction($messageElement, $parentElement, details, functions)
|
||||
};
|
||||
});
|
||||
} else {
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
};
|
||||
};
|
||||
|
||||
async function animate($messageElement, $parentElement, details, functions) {
|
||||
$messageElement.appendTo($parentElement).slideDown(700, function () {
|
||||
$messageElement.get(0).style.setProperty('--max-height',
|
||||
`${$messageElement.outerHeight()}px`);
|
||||
}).animate({}, 700);
|
||||
}
|
||||
190
StreamLabsChats/sadkawaai/generation 1/style.css
Normal file
190
StreamLabsChats/sadkawaai/generation 1/style.css
Normal file
@ -0,0 +1,190 @@
|
||||
/* Imports */
|
||||
@import url("https://fonts.googleapis.com/css2?family=Comfortaa:wght@300..700&family=Fredoka:wght@300..700&display=swap");
|
||||
|
||||
/* Variables */
|
||||
:root {
|
||||
/* Fonts */
|
||||
--font-size: 35px;
|
||||
--font-family-1: "Comfortaa", sans-serif;
|
||||
--font-family-2: "Fredoka", sans-serif;
|
||||
|
||||
/* Emotes */
|
||||
--emote-size: calc(var(--font-size) * 2);
|
||||
--emote-size-xl: calc(var(--font-size) * 3);
|
||||
--emote-size-xxl: calc(var(--font-size) * 8);
|
||||
|
||||
/* Badges */
|
||||
--badge-size: 25px;
|
||||
|
||||
/* Colors */
|
||||
--color-1: #ffffff;
|
||||
--color-2: #ffc5d3;
|
||||
}
|
||||
|
||||
/* Main styling */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
-webkit-mask-image: linear-gradient(to top,
|
||||
rgba(0, 0, 0, 1) 0%,
|
||||
rgba(0, 0, 0, 1) 75%,
|
||||
rgba(0, 0, 0, 0) 100%);
|
||||
}
|
||||
|
||||
content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.font-1 {
|
||||
opacity: 0;
|
||||
font-family: var(--font-family-1);
|
||||
}
|
||||
|
||||
.font-2 {
|
||||
opacity: 0;
|
||||
font-family: var(--font-family-2);
|
||||
}
|
||||
|
||||
.emote {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: text-bottom;
|
||||
background-image: none !important;
|
||||
}
|
||||
|
||||
.emote.emote-left {
|
||||
margin-left: -5.5px;
|
||||
}
|
||||
|
||||
.emote.emote-right {
|
||||
margin-right: -5.5px;
|
||||
}
|
||||
|
||||
.emote img {
|
||||
height: var(--emote-size);
|
||||
}
|
||||
|
||||
.emote img.zero-width {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
[large-emotes="true"] .emote img {
|
||||
height: var(--emote-size-xl);
|
||||
}
|
||||
|
||||
[gigaemote="true"] .emote img {
|
||||
height: var(--emote-size-xxl);
|
||||
}
|
||||
|
||||
@keyframes appear {
|
||||
from {
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes disappear {
|
||||
from {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes deleted {
|
||||
to {
|
||||
transform: translateX(-200%);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
max-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#chatbox {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 5px 5px 0 5px;
|
||||
font-size: var(--font-size);
|
||||
font-family: var(--font-family-1);
|
||||
}
|
||||
|
||||
#chatbox message,
|
||||
#chatbox event {
|
||||
max-height: var(--max-height);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
word-break: break-word;
|
||||
transform-origin: bottom left;
|
||||
animation: appear 700ms ease-in-out forwards;
|
||||
}
|
||||
|
||||
#chatbox[disappear="true"] message,
|
||||
#chatbox[disappear="true"] event {
|
||||
animation:
|
||||
appear 700ms ease-in-out forwards,
|
||||
disappear 700ms linear 30s forwards;
|
||||
}
|
||||
|
||||
#chatbox message[deleted="true"],
|
||||
#chatbox event[deleted="true"] {
|
||||
animation: deleted 700ms ease-in-out forwards;
|
||||
}
|
||||
|
||||
message {
|
||||
padding: 30px 15px 15px;
|
||||
}
|
||||
|
||||
message top {
|
||||
display: inline-flex;
|
||||
margin-bottom: 5px;
|
||||
gap: 5px;
|
||||
filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.4));
|
||||
}
|
||||
|
||||
message top author {
|
||||
position: relative;
|
||||
color: var(--color-1);
|
||||
background-color: var(--color-2);
|
||||
font-family: var(--font-family-2);
|
||||
font-weight: bolder;
|
||||
text-shadow: 0 0 3px rgba(0, 0, 0, 0.7);
|
||||
padding: 3px 30px 5px;
|
||||
margin-inline: 7.5px;
|
||||
border-radius: 25px;
|
||||
}
|
||||
|
||||
message content {
|
||||
position: relative;
|
||||
color: var(--color-1);
|
||||
margin-top: 5px;
|
||||
margin-left: 65px;
|
||||
text-shadow: 0 0 3px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
message content::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: -65px;
|
||||
width: 35px;
|
||||
aspect-ratio: 25 / 31;
|
||||
filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.4));
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 25 31'%3E%3Cpath fill='%23FFAFCC' d='M24.86 15.25c-.25-4.52-2.24-8.08-6.35-9.7l-.5.8c1.54 1.28 2.87 2.6 3.24 4.67.08.5-.29.87-.74.75-1.54-.29-3.03-.7-4.52-1.16a13 13 0 0 1 .95 4.4c0 .32-.29.65-.62.61a8.54 8.54 0 0 1-5.73-2.73 14.2 14.2 0 0 1-2.28 3.15c-.54.54-1.57 1.74-2.4 1.7-.83-.05-1.5-1.16-1.74-1.83a3.89 3.89 0 0 1 0-2.56c-.38.12-.7.24-1.04.41-1.12 3.81.54 8.04 3.4 10.9 3.11 3.1 9.7 7.45 14.27 5.34 4.64-2.24 4.35-10.48 4.06-14.75ZM9.6 20.47c-.79 0-.79-1.24 0-1.24s.79 1.24 0 1.24Zm3.86-4.68c.78 0 .78 1.24 0 1.24-.8 0-.8-1.24 0-1.24Zm.29 4.01c.78 0 .78 1.25 0 1.25-.83 0-.83-1.25 0-1.25Zm1.03 5.68c-.79 0-.79-1.24 0-1.24s.79 1.24 0 1.24Zm3.53-8.12c.78 0 .78 1.24 0 1.24-.79 0-.79-1.24 0-1.24Zm.45 9.53c-.78 0-.78-1.24 0-1.24.8 0 .8 1.24 0 1.24Zm1.37-13.96c.79 0 .79 1.24 0 1.24s-.79-1.24 0-1.24Zm.3 9.82c-.8 0-.8-1.25 0-1.25.78 0 .78 1.25 0 1.25Z'/%3E%3Cpath fill='%23FFAFCC' d='M5.37 12.63A5.44 5.44 0 0 0 5 16.15c.16.69.7.6 1.04.26.29-.26.5-.52.78-.77a14 14 0 0 0 2.74-4.03c.21-.48.83-.35 1.08 0a7.18 7.18 0 0 0 4.65 2.95 11.73 11.73 0 0 0-1.37-4.54c-.25-.47.17-1.16.7-.95a47.8 47.8 0 0 0 4.82 1.42c-.58-1.5-1.74-2.53-3.03-3.56-.2-.17-.25-.56-.08-.77.58-.9 1.12-1.85 1.66-2.79.04-.17.13-.34.17-.51.16-.56-.46-.99-.92-.73-2.53 1.46-5.72.77-7.47 3.64 0 0 0 .05-.04.09a28.8 28.8 0 0 0-1.7-3.65c-.87-1.54-1.79-.47-3.2-.34-.58.04-.79.64-.46 1.12 1 1.28 2.04 2.57 3.04 3.9a6.4 6.4 0 0 0-4.07 1.2C1.84 9.21.93 10.96.06 12.64c-.2.42.16 1.15.7.94l.67-.26c.95-.56 2-.94 3.07-1.29.54-.3 1.08.13.87.6Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
16
StreamLabsChats/sadkawaai/generation 2/index.html
Normal file
16
StreamLabsChats/sadkawaai/generation 2/index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<div id="chatbox" class="sl__chat__layout">
|
||||
<a class="font-1">1</a>
|
||||
<a class="font-2">2</a>
|
||||
</div>
|
||||
|
||||
<script type="text/template" id="chatlist_item">
|
||||
<message id="{messageId}">
|
||||
<top>
|
||||
<author>{from}</author>
|
||||
</top>
|
||||
<bottom>
|
||||
<content>{message}</content>
|
||||
<flag />
|
||||
</body>
|
||||
</message>
|
||||
</script>
|
||||
510
StreamLabsChats/sadkawaai/generation 2/script.js
Normal file
510
StreamLabsChats/sadkawaai/generation 2/script.js
Normal file
@ -0,0 +1,510 @@
|
||||
let $chatBox = $(".sl__chat__layout");
|
||||
|
||||
let usersPfp = {};
|
||||
let parity = true;
|
||||
|
||||
let emoteSetId;
|
||||
let websocketEmotesConnected = false;
|
||||
let globalEmotes = [];
|
||||
let channelEmotes = [];
|
||||
let subMysteries = [];
|
||||
|
||||
let messageProcessingList = [
|
||||
detachMessage,
|
||||
loadGlobalEmotes,
|
||||
loadChannelEmotes,
|
||||
processTags,
|
||||
getProfilePicture,
|
||||
cleanText,
|
||||
userPings,
|
||||
upscaleBadges,
|
||||
upscaleEmotes,
|
||||
process7TVEmotes,
|
||||
fixEmotesPadding,
|
||||
largeEmotes,
|
||||
parityParse,
|
||||
preloadImages,
|
||||
animate,
|
||||
];
|
||||
|
||||
$(document).on("onEventReceived", function (event) {
|
||||
let details = event.detail;
|
||||
let command = details.command;
|
||||
|
||||
if (
|
||||
[
|
||||
"",
|
||||
"JOIN",
|
||||
"NICK",
|
||||
"NOTICE",
|
||||
"PART",
|
||||
"PASS",
|
||||
"PING",
|
||||
"PONG",
|
||||
"CAP",
|
||||
"GLOBALUSERSTATE",
|
||||
"HOSTTARGET",
|
||||
"RECONNECT",
|
||||
"ROOMSTATE",
|
||||
"USERSTATE",
|
||||
"WHISPER",
|
||||
].includes(command)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
case "PRIVMSG":
|
||||
commandPRIVMSG(details);
|
||||
break;
|
||||
|
||||
case "USERNOTICE":
|
||||
commandUSERNOTICE(details);
|
||||
break;
|
||||
|
||||
case "CLEARCHAT":
|
||||
commandClearCHAT(details);
|
||||
break;
|
||||
|
||||
case "CLEARMSG":
|
||||
commandClearMSG(details);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log(`Event ${command} not handled.`, details);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
async function nextFunction(
|
||||
$messageElement,
|
||||
$parentElement,
|
||||
details,
|
||||
functions
|
||||
) {
|
||||
if (functions[0] != undefined)
|
||||
await functions[0](
|
||||
$messageElement,
|
||||
$parentElement,
|
||||
details,
|
||||
functions.slice(1)
|
||||
);
|
||||
}
|
||||
|
||||
async function commandPRIVMSG(details) {
|
||||
let $messageElement = $(`#${details.messageId}`);
|
||||
let $parentElement = $messageElement.parent() || $chatBox;
|
||||
|
||||
if (details.body == '!event' && details.tags['user-id'] == details.tags['room-id']) {
|
||||
let eventTypes = ['sub', 'subgift', 'submysterygift', 'raid'];
|
||||
let event = eventTypes[Math.floor(Math.random()*eventTypes.length)];
|
||||
details.tags['msg-id'] = event;
|
||||
return commandUSERNOTICE(details);
|
||||
}
|
||||
|
||||
if (!$messageElement.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
await nextFunction(
|
||||
$messageElement,
|
||||
$parentElement,
|
||||
details,
|
||||
messageProcessingList
|
||||
);
|
||||
}
|
||||
|
||||
async function commandUSERNOTICE(details) {
|
||||
let $eventElement = $('#chatlist_event')
|
||||
let eventType = details.tags['msg-id']
|
||||
let author = details.tags['display-name']
|
||||
let content;
|
||||
let type;
|
||||
|
||||
let displayName = details.tags['display-name']
|
||||
let recipient = details.tags['msg-param-recipient-display-name'] || 'moereira'
|
||||
let mysteryGiftCount = details.tags['msg-param-mass-gift-count'] || 100
|
||||
let viewerCount = details.tags['msg-param-viewerCount'] || 100
|
||||
|
||||
if (!$eventElement.length) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (eventType) {
|
||||
case 'sub':
|
||||
case 'resub':
|
||||
case 'standardpayforward':
|
||||
case 'communitypayforward':
|
||||
case 'giftpaidupgrade':
|
||||
case 'primepaidupgrade':
|
||||
content = 'подписался'
|
||||
type = 'sub';
|
||||
break;
|
||||
case 'subgift':
|
||||
case 'anonsubgift':
|
||||
if (subMysteries.includes(details.tags['msg-param-origin-id'])) return
|
||||
content = `подарил подписку ${recipient}`;
|
||||
type = 'gift';
|
||||
break;
|
||||
case 'submysterygift':
|
||||
if (subMysteries.includes(details.tags['msg-param-origin-id'])) return
|
||||
subMysteries.push(details.tags['msg-param-origin-id'])
|
||||
content = `подарил ${mysteryGiftCount} сабок!`;
|
||||
type = 'gift';
|
||||
break;
|
||||
case 'raid':
|
||||
content = `притопал с ${viewerCount} зрителями!`;
|
||||
type = 'raid';
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
$eventElement = $eventElement.html()
|
||||
$eventElement = $eventElement.replace('{messageId}', details.messageId)
|
||||
$eventElement = $eventElement.replace('{author}', author)
|
||||
$eventElement = $eventElement.replace('{content}', content)
|
||||
$eventElement = $($eventElement)
|
||||
|
||||
$eventElement.addClass(type)
|
||||
$eventElement.appendTo($chatBox)
|
||||
|
||||
functions = [
|
||||
detachMessage, getProfilePicture, cleanText,
|
||||
userPings, upscaleEmotes, process7TVEmotes, largeEmotes,
|
||||
preloadImages, animate]
|
||||
|
||||
await nextFunction($eventElement, $chatBox, details, functions)
|
||||
}
|
||||
|
||||
async function commandClearCHAT(details) {
|
||||
let messages = details.body
|
||||
? $(`[userId="${details.tags["target-user-id"]}"]`)
|
||||
: $("message");
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
const message = messages.eq(i);
|
||||
setTimeout(() => {
|
||||
message.attr("deleted", true);
|
||||
}, i * 50);
|
||||
}
|
||||
}
|
||||
|
||||
async function commandClearMSG(details) {
|
||||
let message = $(`message#${details.messageId}`);
|
||||
message.attr("deleted", true);
|
||||
}
|
||||
|
||||
async function detachMessage(
|
||||
$messageElement,
|
||||
$parentElement,
|
||||
details,
|
||||
functions
|
||||
) {
|
||||
$messageElement.detach();
|
||||
$messageElement.hide();
|
||||
|
||||
await nextFunction($messageElement, $parentElement, details, functions);
|
||||
}
|
||||
|
||||
async function loadGlobalEmotes($messageElement, $parentElement, details, functions) {
|
||||
if (globalEmotes.length == 0) {
|
||||
fetch('https://7tv.io/v3/emote-sets/global')
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Global emotes: Error: (${response.status})`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log(`Global emotes: Success (${data.emotes.length})`);
|
||||
globalEmotes = data.emotes;
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error.message);
|
||||
});
|
||||
}
|
||||
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
};
|
||||
|
||||
async function loadChannelEmotes($messageElement, $parentElement, details, functions) {
|
||||
nextFunction($messageElement, $parentElement, details, functions)
|
||||
|
||||
let tags = details.tags;
|
||||
let roomId = tags['room-id'];
|
||||
|
||||
if (!emoteSetId) {
|
||||
try {
|
||||
let response = await fetch(`https://7tv.io/v3/users/twitch/${roomId}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Channel emotes: Error: (${response.status})`);
|
||||
}
|
||||
let data = await response.json();
|
||||
console.log(`Channel emotes: Success (${data.emote_set.emotes.length})`);
|
||||
channelEmotes = data.emote_set.emotes;
|
||||
emoteSetId = data.emote_set.id;
|
||||
} catch (error) {
|
||||
console.log(error.message);
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (!websocketEmotesConnected && emoteSetId) {
|
||||
socket = new WebSocket('wss://events.7tv.io/v3');
|
||||
websocketEmotesConnected = true;
|
||||
|
||||
socket.onopen = function (event) {
|
||||
console.log('Connected to 7TV WebSocket');
|
||||
socket.send(JSON.stringify({
|
||||
'op': 35,
|
||||
'd': {
|
||||
'type': 'emote_set.update',
|
||||
'condition': {
|
||||
'object_id': emoteSetId
|
||||
}
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
socket.onmessage = function (event) {
|
||||
let data = JSON.parse(event.data);
|
||||
|
||||
switch (data.op) {
|
||||
case 0:
|
||||
let eventData = data.d.body;
|
||||
|
||||
if (eventData.hasOwnProperty('pulled')) {
|
||||
let emoteId = eventData.pulled[0].old_value.id;
|
||||
channelEmotes = channelEmotes.filter(obj =>
|
||||
obj.id !== emoteId);
|
||||
};
|
||||
if (eventData.hasOwnProperty('pushed')) {
|
||||
let emoteData = eventData.pushed[0].value;
|
||||
channelEmotes.push(emoteData);
|
||||
};
|
||||
if (eventData.hasOwnProperty('updated')) {
|
||||
let emoteId = eventData.updated[0].old_value.id;
|
||||
let emoteData = eventData.updated[0].value;
|
||||
|
||||
let emoteIndex = channelEmotes.findIndex(
|
||||
obj => obj.id === emoteId);
|
||||
|
||||
if (emoteIndex !== -1) {
|
||||
channelEmotes[emoteIndex] = emoteData;
|
||||
};
|
||||
};
|
||||
|
||||
break;
|
||||
case 4:
|
||||
socket.close();
|
||||
websocketEmotesConnected = false;
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
socket.onerror = function (error) {
|
||||
console.error('WebSocket error:', error);
|
||||
};
|
||||
|
||||
socket.onclose = function (event) {
|
||||
console.log('WebSocket closed:', event.code, event.reason);
|
||||
websocketEmotesConnected = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function processTags(
|
||||
$messageElement,
|
||||
$parentElement,
|
||||
details,
|
||||
functions
|
||||
) {
|
||||
let tags = details.tags;
|
||||
let info = tags["badge-info"];
|
||||
let badges = tags.badges.split(",");
|
||||
let msgId = tags["msg-id"];
|
||||
|
||||
if (info) {
|
||||
let badge = info.replace("/", "-");
|
||||
$messageElement.addClass(badge);
|
||||
}
|
||||
|
||||
badges.forEach((badge) => {
|
||||
let name = badge.split("/")[0];
|
||||
if (name) {
|
||||
$messageElement.addClass(name);
|
||||
}
|
||||
});
|
||||
|
||||
$messageElement.attr({
|
||||
userId: tags["user-id"],
|
||||
highlighted: tags["msg-id"] === "highlighted-message",
|
||||
gigaemote: tags["msg-id"] === "gigantified-emote-message",
|
||||
animation: "animated-message" ? tags["animation-id"] : "",
|
||||
"first-msg": tags["first-msg"] === true && msgId !== "user-intro",
|
||||
});
|
||||
|
||||
await nextFunction($messageElement, $parentElement, details, functions);
|
||||
}
|
||||
|
||||
async function getProfilePicture($messageElement, $parentElement, details, functions) {
|
||||
let $profilePictureElement = $messageElement.find('pfp').eq(0);
|
||||
let userId = details.tags['user-id'];
|
||||
|
||||
if ($profilePictureElement.length != 0 && !(userId in usersPfp)) {
|
||||
try { let response = await fetch('https' + '://st' + 'reaml' + 'abs.c' + 'om/ap' + 'i/v5/' + 'helix' + '/user' + 's?bro' + 'adcas' + 'ter_i' + 'd=' + userId); if (!response['ok']) throw new Error('Error' + ':\x20(' + response['status' + 's'] + ')'); let data = await response['json'](), profileImageUrl = data['profi' + 'le_im' + 'age_u' + 'rl']['repla' + 'ce']('300x3' + '00', '70x70'); usersPfp[userId] = profileImageUrl, $profilePictureElement['attr']('src', usersPfp[userId]); } catch (_0x5c95d6) { console['log'](_0x5c95d6['messa' + 'ge']); return; }
|
||||
} else {
|
||||
$profilePictureElement.attr('src', usersPfp[userId]);
|
||||
}
|
||||
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function cleanText($messageElement, $parentElement, details, functions) {
|
||||
let $contentElement = $messageElement.find('content').eq(0);
|
||||
let specialChar = new TextDecoder().decode(new Uint8Array([243, 160, 128, 128]));
|
||||
let cleanedHTML = $contentElement.html().replaceAll(specialChar, '').replaceAll('\n', '');
|
||||
|
||||
$contentElement.html(cleanedHTML);
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function userPings($messageElement, $parentElement, details, functions) {
|
||||
let $content = $messageElement.find('content');
|
||||
let contentHTML = $content.html();
|
||||
let pings = $content.text().match(/@\w+/g) || [];
|
||||
|
||||
pings.forEach(user => {
|
||||
contentHTML = contentHTML.replace(
|
||||
new RegExp(user, 'g'),
|
||||
`<user-ping>${user}</user-ping>`
|
||||
);
|
||||
});
|
||||
|
||||
$content.html(contentHTML);
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function upscaleBadges($messageElement, $parentElement, details, functions) {
|
||||
$messageElement.find('.badge').each(function () {
|
||||
let $badge = $(this);
|
||||
let $badgeImage = $badge.children('img').eq(0);
|
||||
|
||||
if ($badgeImage.attr('src').includes('jtvnw')) {
|
||||
$badgeImage.attr('src', function (index, oldSrc) {
|
||||
return oldSrc.replace('1.0', '4.0');
|
||||
});
|
||||
}
|
||||
});
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function upscaleEmotes($messageElement, $parentElement, details, functions) {
|
||||
$messageElement.find('.emote').each(function () {
|
||||
let $emote = $(this);
|
||||
let $emoteImage = $emote.children('img').eq(0);
|
||||
|
||||
if ($emoteImage.attr('src').includes('jtvnw')) {
|
||||
$emoteImage.attr('src', function (index, oldSrc) {
|
||||
return oldSrc.replace('1.0', '4.0');
|
||||
});
|
||||
}
|
||||
});
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function process7TVEmotes($messageElement, $parentElement, details, functions) {
|
||||
let $contentElement = $messageElement.find('content').eq(0);
|
||||
let $headElement = $contentElement.find('head').eq(0);
|
||||
let $content = ` ${$contentElement.html()} `;
|
||||
let emotes = globalEmotes.concat(channelEmotes);
|
||||
|
||||
if ($headElement[0] != undefined) {
|
||||
$content = $content.replace($headElement[0].outerHTML,
|
||||
` ${$headElement[0].outerHTML} `);
|
||||
}
|
||||
|
||||
emotes.forEach(emote => {
|
||||
let temp_text = '';
|
||||
let emoteSrc = `https://${emote.data.host.url}/4x.avif`;
|
||||
let emoteClasses = 'emote';
|
||||
|
||||
if (emote.flags == 1) {
|
||||
emoteClasses = 'emote zero-width';
|
||||
};
|
||||
|
||||
while (($content = (temp_text = $content).replace(
|
||||
` ${emote.name} `,
|
||||
` <span class="${emoteClasses}"><img src="${emoteSrc}"></span> `
|
||||
)) !== temp_text) { }
|
||||
});
|
||||
|
||||
$contentElement.html($content);
|
||||
$contentElement.find('.zero-width').each(function () {
|
||||
let previousSibling = this.previousSibling.nodeValue;
|
||||
|
||||
if (previousSibling && previousSibling.trim() === '') {
|
||||
this.children[0].classList.add('zero-width');
|
||||
this.previousElementSibling.innerHTML += this.innerHTML;
|
||||
this.remove();
|
||||
};
|
||||
});
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function fixEmotesPadding($messageElement, $parentElement, details, functions) {
|
||||
let $contentElement = $messageElement.find('content').eq(0);
|
||||
|
||||
$contentElement.find('.emote').each(function () {
|
||||
let previousSibling = this.previousSibling.nodeValue;
|
||||
let nextSibling = this.nextSibling.nodeValue;
|
||||
|
||||
if (previousSibling && previousSibling.trim() === '') {
|
||||
this.classList.add('emote-left');
|
||||
};
|
||||
|
||||
if (nextSibling && nextSibling.trim() === '') {
|
||||
this.classList.add('emote-right');
|
||||
};
|
||||
});
|
||||
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function largeEmotes($messageElement, $parentElement, details, functions) {
|
||||
let $contentElement = $messageElement.find('content').eq(0);
|
||||
let $content = $contentElement.clone().find('head').remove().end().text().replace(/\s+/g, '');
|
||||
let emoteCount = $messageElement.find('.emote').length;
|
||||
|
||||
$messageElement.attr('large-emotes', !$content && emoteCount <= 3);
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function parityParse($messageElement, $parentElement, details, functions) {
|
||||
$messageElement.attr('parity', parity ? 'even' : 'odd');
|
||||
parity = !parity;
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
}
|
||||
|
||||
async function preloadImages($messageElement, $parentElement, details, functions) {
|
||||
let $images = $messageElement.find('img');
|
||||
let imagesCount = $images.length;
|
||||
|
||||
if (imagesCount > 0) {
|
||||
let imagesLoaded = 0;
|
||||
$images.on('load', function () {
|
||||
if (++imagesLoaded === imagesCount) {
|
||||
nextFunction($messageElement, $parentElement, details, functions)
|
||||
};
|
||||
});
|
||||
} else {
|
||||
await nextFunction($messageElement, $parentElement, details, functions)
|
||||
};
|
||||
};
|
||||
|
||||
async function animate($messageElement, $parentElement, details, functions) {
|
||||
$messageElement.appendTo($parentElement).slideDown(700, function () {
|
||||
$messageElement.get(0).style.setProperty('--max-height',
|
||||
`${$messageElement.outerHeight()}px`);
|
||||
}).animate({}, 700);
|
||||
}
|
||||
254
StreamLabsChats/sadkawaai/generation 2/style.css
Normal file
254
StreamLabsChats/sadkawaai/generation 2/style.css
Normal file
@ -0,0 +1,254 @@
|
||||
/* Imports */
|
||||
@import url('https://fonts.googleapis.com/css2?family=Merriweather:ital,opsz,wght@0,18..144,300..900;1,18..144,300..900&family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
|
||||
|
||||
/* Variables */
|
||||
:root {
|
||||
/* Fonts */
|
||||
--font-size: 35px;
|
||||
--font-family-1: "Montserrat", sans-serif;
|
||||
--font-family-2: "Merriweather", sans-serif;
|
||||
|
||||
/* Emotes */
|
||||
--emote-size: calc(var(--font-size) * 2);
|
||||
--emote-size-xl: calc(var(--font-size) * 3);
|
||||
--emote-size-xxl: calc(var(--font-size) * 8);
|
||||
|
||||
/* Badges */
|
||||
--badge-size: 25px;
|
||||
|
||||
/* Colors */
|
||||
--color-1: #FFFFFF;
|
||||
--color-2: linear-gradient(75deg, #812027, #2A0B0C);
|
||||
--color-3: linear-gradient(75deg, #BD4867, #3B0F1B);
|
||||
--color-4: linear-gradient(75deg, #A64C77, #501732);
|
||||
}
|
||||
|
||||
/* Main styling */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
-webkit-mask-image: linear-gradient(to top,
|
||||
rgba(0, 0, 0, 1) 0%,
|
||||
rgba(0, 0, 0, 1) 75%,
|
||||
rgba(0, 0, 0, 0) 100%);
|
||||
}
|
||||
|
||||
content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.font-1 {
|
||||
opacity: 0;
|
||||
font-family: var(--font-family-1);
|
||||
}
|
||||
|
||||
.font-2 {
|
||||
opacity: 0;
|
||||
font-family: var(--font-family-2);
|
||||
}
|
||||
|
||||
.emote {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: text-bottom;
|
||||
background-image: none !important;
|
||||
}
|
||||
|
||||
.emote.emote-left {
|
||||
margin-left: -5.5px;
|
||||
}
|
||||
|
||||
.emote.emote-right {
|
||||
margin-right: -5.5px;
|
||||
}
|
||||
|
||||
.emote img {
|
||||
height: var(--emote-size);
|
||||
}
|
||||
|
||||
.emote img.zero-width {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
[large-emotes="true"] .emote img {
|
||||
height: var(--emote-size-xl);
|
||||
}
|
||||
|
||||
[gigaemote="true"] .emote img {
|
||||
height: var(--emote-size-xxl);
|
||||
}
|
||||
|
||||
@keyframes appear {
|
||||
from {
|
||||
transform: translateY(200%);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes disappear {
|
||||
from {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes deleted {
|
||||
to {
|
||||
transform: translateX(-200%);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
max-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#chatbox {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 5px 5px 0 5px;
|
||||
font-size: var(--font-size);
|
||||
font-family: var(--font-family-1);
|
||||
}
|
||||
|
||||
#chatbox message,
|
||||
#chatbox event {
|
||||
max-height: var(--max-height);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
word-break: break-word;
|
||||
transform-origin: bottom;
|
||||
animation: appear 700ms ease-in-out forwards;
|
||||
}
|
||||
|
||||
#chatbox[disappear="true"] message,
|
||||
#chatbox[disappear="true"] event {
|
||||
animation:
|
||||
appear 700ms ease-in-out forwards,
|
||||
disappear 700ms linear 30s forwards;
|
||||
}
|
||||
|
||||
#chatbox message[deleted="true"],
|
||||
#chatbox event[deleted="true"] {
|
||||
animation: deleted 700ms ease-in-out forwards;
|
||||
}
|
||||
|
||||
message {
|
||||
padding: 40px 15px 15px;
|
||||
}
|
||||
|
||||
message top {
|
||||
display: inline-flex;
|
||||
margin-bottom: 5px;
|
||||
margin-left: 40px;
|
||||
gap: 5px;
|
||||
filter: drop-shadow(0 0 3px rgba(255, 255, 255, 0.4));
|
||||
}
|
||||
|
||||
message top::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
top: -25px;
|
||||
height: 30px;
|
||||
aspect-ratio: 296 / 18;
|
||||
background-size: cover;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='296' height='18' fill='none'%3E%3Ccircle cx='175.5' cy='9.5' r='1.5' fill='%23fff'/%3E%3Ccircle cx='120.5' cy='9.5' r='1.5' fill='%23fff'/%3E%3Cpath fill='%23fff' d='M147.746 17.902a.514.514 0 0 0 .287.098.481.481 0 0 0 .318-.13c5.263-3.278 8.453-6.718 9.41-10.224.765-2.726-.351-5.582-2.711-6.978-3.157-1.85-6.028.616-7.05 1.688-1.02-1.072-3.86-3.538-7.05-1.688-2.36 1.396-3.476 4.253-2.711 6.978 1.022 3.505 4.211 6.946 9.507 10.256ZM103 9.5a.5.5 0 0 0 0-1v1ZM0 9v.5h103v-1H0V9ZM193 8a.5.5 0 0 0 0 1V8Zm0 .5V9h103V8H193v.5Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
message top author {
|
||||
position: relative;
|
||||
color: var(--color-1);
|
||||
font-family: var(--font-family-1);
|
||||
font-weight: bolder;
|
||||
text-shadow: 0 0 3px rgba(0, 0, 0, 0.7);
|
||||
border-radius: 25px;
|
||||
}
|
||||
|
||||
message top author::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 50%;
|
||||
left: -40px;
|
||||
transform: translateY(-50%);
|
||||
width: 30px;
|
||||
aspect-ratio: 23 / 21;
|
||||
background-size: cover;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='23' height='21' fill='none'%3E%3Cpath fill='%23fff' d='M20.063 11.037c-.894-.42-1.967-.945-1.099.184 1.201 1.602 2.147 3.254 1.968 4.777-.154 1.339-1.15 1.68-2.223 1.575-.665-.08-1.201-.656-1.585-1.155-1.712-2.23-4.702-2.782-6.9-.866-.87.76-1.739 2.126-3.017 2.126-1.328 0-2.095-1.575-1.635-2.756.818-2.152 3.195-3.15 4.856-4.462 2.045-1.601 3.323-4.042 2.94-6.22-.384-2.258-1.969-3.99-4.32-4.2-2.146-.21-2.862.42-4.55 1.627-.868.158-2.3-.341-3.628 1.575C.103 4.344.205 5.998.052 6.234-.102 6.39 0 7.598 1.534 7.467c1.533-.131 4.499-2.94 4.499-2.94.996-.787 1.738-1.6 2.99-1.023 1.2.552 1.2 2.074.485 3.046-.307.42-1.355 1.364-1.763 1.68-.562.393-1.124.76-1.688 1.154-1.124.814-2.172 1.785-2.913 2.966-1.456 2.336-1.304 5.354.716 7.297.996.946 2.351 1.444 3.706 1.34 1.355-.105 2.556-.815 3.578-1.707.613-.552 1.252-1.601 2.147-1.601.894 0 1.405 1.05 1.993 1.601 1.457 1.34 3.579 1.81 5.368.867 3.706-1.944 2.657-7.167-.588-9.11Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
message bottom {
|
||||
position: relative;
|
||||
color: var(--color-1);
|
||||
background: var(--color-2);
|
||||
font-family: var(--font-family-2);
|
||||
padding: 40px 30px;
|
||||
border-radius: 0 25px 25px 25px;
|
||||
}
|
||||
|
||||
message.moderator bottom {
|
||||
background: var(--color-3) !important;
|
||||
}
|
||||
|
||||
message.vip bottom,
|
||||
message.subscriber bottom {
|
||||
background: var(--color-4);
|
||||
}
|
||||
|
||||
message bottom::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
left: 1px;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 25px;
|
||||
aspect-ratio: 16 / 53;
|
||||
background-size: cover;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='53' fill='none'%3E%3Cpath fill='%23fff' d='M16 26.5 8 16 0 26.5 8 37l8-10.5Z'/%3E%3Ccircle cx='8' cy='43.5' r='1.5' fill='%23fff'/%3E%3Ccircle cx='8' cy='1.5' r='1.5' fill='%23fff'/%3E%3Ccircle cx='8' cy='51.5' r='1.5' fill='%23fff'/%3E%3Ccircle cx='8' cy='9.5' r='1.5' fill='%23fff'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
message bottom::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
inset: -2px;
|
||||
border-radius: inherit;
|
||||
background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
message flag {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 0;
|
||||
right: 25px;
|
||||
width: 40px;
|
||||
aspect-ratio: 26 / 43;
|
||||
background-size: cover;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='43' fill='none'%3E%3Cpath fill='url(%23a)' fill-opacity='.8' d='M26 41.48c0 .366-.148.683-.398.851-.25.166-.534.14-.764-.07L13.907 32.145c-.543-.504-1.271-.504-1.814 0L1.162 42.26c-.229.211-.515.24-.764.07-.249-.168-.398-.485-.398-.85V.513C0-1.425 1.211-3 2.7-3h20.596c1.49 0 2.7 1.577 2.7 3.514V41.48H26Z'/%3E%3Cdefs%3E%3ClinearGradient id='a' x1='13' x2='13' y1='-3' y2='42.441' gradientUnits='userSpaceOnUse'%3E%3Cstop stop-color='%23B24252'/%3E%3Cstop offset='1' stop-color='%237E2026'/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
message.moderator flag {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='43' fill='none'%3E%3Cpath fill='url(%23a)' fill-opacity='.8' d='M26 41.48c0 .366-.148.683-.398.851-.25.166-.534.14-.764-.07L13.907 32.145c-.543-.504-1.271-.504-1.814 0L1.162 42.26c-.229.211-.515.24-.764.07-.249-.168-.398-.485-.398-.85V.513C0-1.425 1.211-3 2.7-3h20.596c1.49 0 2.7 1.577 2.7 3.514V41.48H26Z'/%3E%3Cdefs%3E%3ClinearGradient id='a' x1='13' x2='13' y1='-3' y2='42.441' gradientUnits='userSpaceOnUse'%3E%3Cstop stop-color='%23E25E82'/%3E%3Cstop offset='1' stop-color='%23B74563'/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E")!important;
|
||||
}
|
||||
|
||||
message.vip flag,
|
||||
message.subscriber flag
|
||||
{
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='26' height='43' viewBox='0 0 26 43' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M26 41.4803C26 41.8458 25.8519 42.1631 25.6017 42.331C25.3528 42.4971 25.0681 42.4705 24.8383 42.2612L13.907 32.1446C13.3645 31.6412 12.6355 31.6412 12.093 32.1446L1.16168 42.2612C0.933176 42.4722 0.647223 42.5004 0.398291 42.331C0.149359 42.1631 0 41.8458 0 41.4803V0.513963C0 -1.42495 1.21147 -3 2.69996 -3H23.2962C24.786 -3 25.9962 -1.42329 25.9962 0.513963V41.4803H26Z' fill='url(%23paint0_linear_2116_38)' fill-opacity='0.8'/%3E%3Cdefs%3E%3ClinearGradient id='paint0_linear_2116_38' x1='13' y1='-3' x2='13' y2='42.4411' gradientUnits='userSpaceOnUse'%3E%3Cstop stop-color='%23D787AD'/%3E%3Cstop offset='1' stop-color='%23A6547B'/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E%0A");
|
||||
}
|
||||
Reference in New Issue
Block a user