convert to sugoi web services
This commit is contained in:
@@ -1,65 +1,24 @@
|
||||
<h1 align="center">Improved Twitch Subathon Countdown</h1>
|
||||
<p align="center">This is a Twitch Subathon Countdown originally by JayexDesigns.</p>
|
||||
<p align="center">The CSS Code is updated by Johnnycyan. The JS Files are updated by leabdd and danilotitato to add functionalities.</p>
|
||||
<br/>
|
||||
# Improved Twitch Subathon Countdown
|
||||
This is a Twitch Subathon Countdown originally by JayexDesigns.
|
||||
|
||||
<h2>Description</h2>
|
||||
<p>A subathon timer that increases when someone subscribes, donates money, donates bits or purchases streamloots chests.</p>
|
||||
<p>Added is a Timer that gets saved (in localStorage) and can be reset.</p>
|
||||
<p>When you open the index.html you get to chose between "Reset" or "Start".</p>
|
||||
<br/>
|
||||
The CSS Code is updated by Johnnycyan.
|
||||
|
||||
<h2>Shortcuts</h2>
|
||||
<p>To pause the Timer: CTRL+ALT+P</p>
|
||||
<p>To enable/disable Happy Hour: CTRL+ALT+H</p>
|
||||
<p>To enable/disable Random Hour: CTRL+ALT+R</p>
|
||||
<p>Shortcuts can be changed in config.js</p>
|
||||
<br/>
|
||||
The JS Files have been re-written by SugoiDogo.
|
||||
|
||||
<h2>Preview</h2>
|
||||
<h3 align="center"><img width="90%" src="./preview.webp"></h3>
|
||||
<br/>
|
||||
## Description
|
||||
A subathon timer that increases when someone subscribes, donates to your charity, donates bits, follows or raids.
|
||||
|
||||
<h2>Usage</h2>
|
||||
<p>After cloning this repository you'll have to edit the "config.js" file with any plain text editor, then change the value of the variables according to what you want:</p>
|
||||
## Usage
|
||||
Go to the [config page](https://sugoidogo.github.io/twitch-subathon-countdown/config.html), authorize the timer, and configure to your liking.
|
||||
|
||||
<h3>Twitch</h3>
|
||||
<p>To get your Subs and Bits you just have to add your Channel Name.</p>
|
||||
## Support
|
||||
See [my github profile](https://github.com/sugoidogo)
|
||||
|
||||
<h3>Streamlabs Token</h3>
|
||||
<p>To get the token you'll have to go to the API settings tab of your <a href="https://streamlabs.com/dashboard#/settings/api-settings">Streamlabs dashboard</a> then click on API Tokens, copy your socket API token and finally paste the code on the "streamlabs_token" variable in the "config.js" file.</p>
|
||||
<img src="./auth_streamlabs.png">
|
||||
|
||||
<h3>StreamElements Token</h3>
|
||||
<p>To get the token you'll have to go to your <a href="https://streamelements.com/dashboard/account/channels">StreamElements channels dashboard</a>, then click on show secrets, copy the Overlay token and paste the code on the "streamelements_token" variable in the "config.js" file.</p>
|
||||
<img src="./auth_streamelements.png">
|
||||
|
||||
<h3>Streamloots Token</h3>
|
||||
<p>To get the token you'll have to go to your Streamloots creator dashboard, then to alerts & widgets, then go to alerts, then copy the last part of the alerts url and finally paste the code on the "streamloots_token" variable in the "config.js" file.</p>
|
||||
<img src="./auth_streamloots.png">
|
||||
|
||||
<h3>Initial Time</h3>
|
||||
<p>You can set the initial time of the timer by setting the hours, minutes and seconds to be added when the timer is created.</p>
|
||||
|
||||
<h3>Random Happy Hour</h3>
|
||||
<p>If this is true, you can turn enable Happy or Random Hour with the Shortcut. If it is false, the feature is disabled and cant be enabled.</p>
|
||||
<p>You have to set the Happy Hour time values manually.</p>
|
||||
<p>Random Hour has a bell curve which can be edited in the config. It multiplies the normal time by a random amount for each sub.</p>
|
||||
<p>If enabled randHappy it can randomly activate the Happy Hour. It will last for one hour, but can be turned off manually with the Shortkey.</p>
|
||||
<p>In the Config you can set a specific Date and Time. At that a Happy Hour will happen. scheduleHappy needs to be turned on.</p>
|
||||
|
||||
<h3>Bulk</h3>
|
||||
<p>This enables that multiple Subs get added to the timer at once.</p>
|
||||
<p>For Example when a user gifts 10 Subs.</p>
|
||||
|
||||
<h3>Full control on what to use</h3>
|
||||
<p>You can enable and disable if you want to add time for Subscriptions, Bits, Donations or Chests.</p>
|
||||
|
||||
<h3>Other Values</h3>
|
||||
<p>Change the other values to set the amount of seconds that will be added for the subscriptions, donations... And the minimum donation amounts to trigger the countdown increase.</p>
|
||||
|
||||
<h3>Add To OBS</h3>
|
||||
<p>To add it to OBS you just have to drag the "index.html" file to the sources section or add a browser source that points to the "index.html" file.</p>
|
||||
|
||||
<h2>Known Problems</h2>
|
||||
<p2>Only Streamelements Token in config.js does not add time for Subscriptions. Emulate with the Overlay Editor does work.</p>
|
||||
## Missing Features
|
||||
The original version of this overlay included support for events from StreamElements, StreamLabs, and Streamloots,
|
||||
and the version this is forked from included additional features by leabdd and danilotitato,
|
||||
such as Random Happy Hour and Bulk Events.
|
||||
This fork is an almost total re-write of the core JS code behind the timer,
|
||||
so those features will also have to be re-written to be included in this fork.
|
||||
Future versions of this timer will include a plug-in loader,
|
||||
allowing additional features and event sources to be added without additional forking.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 78 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
@@ -1,80 +0,0 @@
|
||||
// Happy Hour
|
||||
var happy_hour = true // set to true or false, to enable/disable the happy hours function
|
||||
var random_hour = true
|
||||
var randHappy = false // only works if happy_hour = true
|
||||
var scheduleHappy = false // only works if happy_hour = true
|
||||
|
||||
// needs scheduleHappy to be true
|
||||
var scheduleHappyDay = 5 // Weekdays from 0 to 6 from Sunday to Saturday | Default 5 is Friday
|
||||
var scheduleHappyHour = 18 // Hours in 24 format UTC Time | Default 18 is 20:00 CEST
|
||||
|
||||
// Bulk (if you want multiple subs to add to a big sum or each alone)
|
||||
var bulk_enabled = false
|
||||
|
||||
//Shortcuts
|
||||
var pauseShort = "ctrl+alt+p"
|
||||
var happyHourShort = "ctrl+alt+h"
|
||||
var randomHourShort = "ctrl+alt+r"
|
||||
|
||||
// Login Data
|
||||
var twitch_channel_name = ""
|
||||
var streamlabs_token = ""
|
||||
var streamelements_token = ""
|
||||
var streamloots_token = ""
|
||||
|
||||
// Initial Counter Config
|
||||
var initialHoursConfig = 2
|
||||
var initialMinutesConfig = 0
|
||||
var initialSecondsConfig = 0
|
||||
|
||||
// Sync Time, amount of seconds it waits after the timer hit 0 to stop it. Useful for last Second Subs.
|
||||
var syncTime = 2 // Default 2 seconds.
|
||||
|
||||
// Enable/Disable Subs, Bits, Donations, Chests
|
||||
var subEnable = true
|
||||
var bitEnable = false
|
||||
var donationEnable = false
|
||||
var chestEnable = false
|
||||
|
||||
// General Twitch, Streamlabs And StreamElements Config
|
||||
var seconds_added_per_sub_prime = 60
|
||||
var seconds_added_per_sub_tier1 = 60
|
||||
var seconds_added_per_sub_tier2 = 180
|
||||
var seconds_added_per_sub_tier3 = 480
|
||||
|
||||
var seconds_added_per_resub_prime = 60
|
||||
var seconds_added_per_resub_tier1 = 60
|
||||
var seconds_added_per_resub_tier2 = 180
|
||||
var seconds_added_per_resub_tier3 = 480
|
||||
|
||||
var seconds_added_per_giftsub_tier1 = 60
|
||||
var seconds_added_per_giftsub_tier2 = 180
|
||||
var seconds_added_per_giftsub_tier3 = 480
|
||||
|
||||
var min_amount_of_bits = 50
|
||||
var seconds_added_per_bits = 30
|
||||
|
||||
// Streamlabs And StreamElements Config
|
||||
var min_donation_amount = 1
|
||||
var seconds_added_per_donation = 30
|
||||
|
||||
// Streamloots Config
|
||||
var min_amount_of_chests = 1
|
||||
var seconds_added_per_chests = 30
|
||||
|
||||
|
||||
// General Twitch, Streamlabs And StreamElements Config for Happy Hour
|
||||
var factor_t1 = 1.5
|
||||
var factor_t2 = 1.75
|
||||
var factor_t3 = 2.0
|
||||
var factor_bits = 1.5
|
||||
var factor_donations = 1.5
|
||||
|
||||
|
||||
// General Twitch, Streamlabs And StreamElements Config for Random Hour
|
||||
// [min, max, skew]
|
||||
var range_t1 = [0.1, 3, 1]
|
||||
var range_t2 = [0.1, 3, 2]
|
||||
var range_t3 = [0.1, 3, 3]
|
||||
var range_bits = [0.1, 3, 1]
|
||||
var range_donations = [0.1, 3, 1]
|
||||
+13
-163
@@ -2,7 +2,8 @@
|
||||
font-family: 'Ubuntu', sans-serif !important;
|
||||
}
|
||||
|
||||
body, body * {
|
||||
body,
|
||||
body * {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: 'Manrope', sans-serif;
|
||||
@@ -13,16 +14,12 @@ body {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
:root {
|
||||
--background-color: #A020F0;
|
||||
--shadow-color: #00000090;
|
||||
--text-color: #FFFFFF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#container {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
@@ -32,7 +29,7 @@ body {
|
||||
background-image:
|
||||
-webkit-linear-gradient(-45deg,
|
||||
transparent 33%, rgba(0, 0, 0, .1) 33%,
|
||||
rgba(0,0, 0, .1) 66%, transparent 66%),
|
||||
rgba(0, 0, 0, .1) 66%, transparent 66%),
|
||||
-webkit-linear-gradient(top,
|
||||
rgba(255, 255, 255, .25),
|
||||
rgba(0, 0, 0, .25)),
|
||||
@@ -41,52 +38,6 @@ body {
|
||||
width: 500px;
|
||||
height: 180px;
|
||||
border-radius: 30px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#SpecialHourText {
|
||||
opacity: 0;
|
||||
font-size: 2.5rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* #HappyHourDeactive {
|
||||
visibility: hidden;
|
||||
font-size: 3rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#HappyHourError {
|
||||
visibility: hidden;
|
||||
font-size: 3rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
} */
|
||||
|
||||
#SpecialHourHTML {
|
||||
top:-200px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#startPage {
|
||||
position: absolute;
|
||||
align-items: center;
|
||||
top: 75%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
/*background-color: var(--background-color);*/
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
border-radius: 30px;
|
||||
background:none;
|
||||
}
|
||||
|
||||
#textDiv {
|
||||
@@ -96,79 +47,6 @@ body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.button {
|
||||
border-radius: 30px;
|
||||
box-shadow: 0 0 1.25rem 0.5rem var(--shadow-color);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
color:white;
|
||||
/*background-image:
|
||||
-webkit-linear-gradient(-45deg,
|
||||
transparent 33%, rgba(0, 0, 0, .1) 33%,
|
||||
rgba(0,0, 0, .1) 66%, transparent 66%),
|
||||
-webkit-linear-gradient(top,
|
||||
rgba(255, 255, 255, .25),
|
||||
rgba(0, 0, 0, .25)),
|
||||
-webkit-linear-gradient(left, #0074cc, #a700cc);*/
|
||||
background:none;
|
||||
}
|
||||
|
||||
#firstButtonDiv, #secondButtonDiv {
|
||||
background-image:
|
||||
-webkit-linear-gradient(-45deg,
|
||||
transparent 33%, rgba(0, 0, 0, .1) 33%,
|
||||
rgba(0,0, 0, .1) 66%, transparent 66%),
|
||||
-webkit-linear-gradient(top,
|
||||
rgba(255, 255, 255, .25),
|
||||
rgba(0, 0, 0, .25)),
|
||||
-webkit-linear-gradient(left, #0074cc, #a700cc);
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#firstButtonDiv:hover, #secondButtonDiv:hover {
|
||||
background-image:
|
||||
-webkit-linear-gradient(-45deg,
|
||||
transparent 33%, rgba(0, 0, 0, .1) 33%,
|
||||
rgba(0,0, 0, .1) 66%, transparent 66%),
|
||||
-webkit-linear-gradient(top,
|
||||
rgba(255, 255, 255, .25),
|
||||
rgba(0, 0, 0, .25)),
|
||||
-webkit-linear-gradient(left, #0061ac, #8e00ad)!important;
|
||||
}
|
||||
|
||||
#firstButtonDiv, #secondButtonDiv {
|
||||
border-radius: 30px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
color:white;
|
||||
background-image:
|
||||
-webkit-linear-gradient(-45deg,
|
||||
transparent 33%, rgba(0, 0, 0, .1) 33%,
|
||||
rgba(0,0, 0, .1) 66%, transparent 66%),
|
||||
-webkit-linear-gradient(top,
|
||||
rgba(255, 255, 255, .25),
|
||||
rgba(0, 0, 0, .25)),
|
||||
-webkit-linear-gradient(left, #0074cc, #a700cc);
|
||||
}
|
||||
|
||||
#secondButtonDiv {
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: var(--text-color);
|
||||
font-size: 5.8rem;
|
||||
@@ -176,54 +54,26 @@ p {
|
||||
text-shadow: 0px 0px 10px var(--shadow-color);
|
||||
}
|
||||
|
||||
img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
canvas {
|
||||
width: 500px;
|
||||
height: 180px;
|
||||
border-radius: 20px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.addedTime {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
opacity: 0;
|
||||
display: none;
|
||||
z-index: 5;
|
||||
font-weight: 400;
|
||||
font-size: 3.25rem;
|
||||
/*color: var(--background-color);*/
|
||||
color:white;
|
||||
transition: top 1s ease-out, opacity .5s ease-out;
|
||||
color: white;
|
||||
animation: slidefadeout 2s ease-out;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.gold {
|
||||
position: absolute;
|
||||
@keyframes slidefadeout {
|
||||
0% {
|
||||
opacity: 1;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
display: none;
|
||||
z-index: 5;
|
||||
font-weight: 400;
|
||||
font-size: 3.25rem;
|
||||
/*color: var(--background-color);*/
|
||||
color:gold;
|
||||
background: linear-gradient(to right, #BF953F, #FCF6BA, #B38728, #FBF5B7, #AA771C);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
transition: top 1s ease-out, opacity .5s ease-out;
|
||||
text-shadow:none !important;
|
||||
top: 25%;
|
||||
}
|
||||
}
|
||||
-30
@@ -11,41 +11,11 @@
|
||||
<title>Subathon Timer</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="startPage">
|
||||
<div id="firstButtonDiv">
|
||||
<button id="resetBtn" class="button">Reset</button>
|
||||
</div>
|
||||
<div id="secondButtonDiv">
|
||||
<button id="startBtn" class="button">Start</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container" class="timer">
|
||||
<div id="textDiv">
|
||||
<p id="timeText">00:00:00</p>
|
||||
</div>
|
||||
<div id="SpecialHourHTML">
|
||||
<p id="SpecialHourText">Happy Hour Activated!</p>
|
||||
<!-- <p id="SpecialHourDeactive">Happy Hour Deactivated :(</p>
|
||||
<p id="SpecialHourError">Happy Hour not available D:</p> -->
|
||||
</div>
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
|
||||
<script src="js/lib/mousetrap.min.js"></script>
|
||||
<script src='https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js' type='text/javascript'></script>
|
||||
<script src='js/lib/tmi.min.js'></script>
|
||||
<script src="js/lib/generalFunc.js"></script>
|
||||
<script src="js/lib/timeFunc.js"></script>
|
||||
|
||||
<script src="config.js"></script>
|
||||
<script src="js/script.js"></script>
|
||||
|
||||
<script src="js/api/twitch.js"></script>
|
||||
<!-- <script src="js/api/streamlabs.js"></script> -->
|
||||
<script src="js/api/streamelements.js"></script>
|
||||
<!-- <script src="js/api/streamloots.js"></script> -->
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,128 +0,0 @@
|
||||
if (streamelements_token !== "") {
|
||||
var streamElementsSocket;
|
||||
const streamElementsConnect = () => {
|
||||
streamElementsSocket = undefined;
|
||||
streamElementsSocket = io('https://realtime.streamelements.com', {
|
||||
transports: ['websocket']
|
||||
});
|
||||
|
||||
streamElementsSocket.on('connect', onConnect);
|
||||
streamElementsSocket.on('disconnect', onDisconnect);
|
||||
streamElementsSocket.on('authenticated', onAuthenticated);
|
||||
streamElementsSocket.on('unauthorized', console.error);
|
||||
streamElementsSocket.on('event:test', onEvent);
|
||||
streamElementsSocket.on('event', onEvent);
|
||||
streamElementsSocket.on('event:update', onEvent);
|
||||
streamElementsSocket.on('event:reset', onEvent);
|
||||
|
||||
function onConnect() {
|
||||
logMessage("StreamElements", "Socket Connected");
|
||||
streamElementsSocket.emit('authenticate', {method: 'apikey', token: streamelements_token});
|
||||
}
|
||||
|
||||
function onDisconnect() {
|
||||
logMessage("StreamElements", "Socket Disconnected");
|
||||
streamElementsConnect();
|
||||
}
|
||||
|
||||
function onAuthenticated(data) {
|
||||
const {
|
||||
channelId
|
||||
} = data;
|
||||
logMessage("StreamElements", `Channel ${channelId} Connected`);
|
||||
}
|
||||
|
||||
function onEvent(data) {
|
||||
logObject("StreamElements", data);
|
||||
if (!countdownEnded) {
|
||||
let factor_t1_local = (happy_hour_active ? factor_t1 : 1) * (random_hour_active ? randomBellSkew(...range_t1): 1);
|
||||
let factor_t2_local = (happy_hour_active ? factor_t2 : 1) * (random_hour_active ? randomBellSkew(...range_t2): 1);
|
||||
let factor_t3_local = (happy_hour_active ? factor_t3 : 1) * (random_hour_active ? randomBellSkew(...range_t3): 1);
|
||||
let factor_bits_local = (happy_hour_active ? factor_bits : 1) * (random_hour_active ? randomBellSkew(...range_bits): 1);
|
||||
let factor_donations_local = (happy_hour_active ? factor_donations : 1) * (random_hour_active ? randomBellSkew(...range_donations): 1);
|
||||
|
||||
if ((data['listener'] === "subscriber-latest") && subEnable) {
|
||||
if (data['event']['gifted'] || data['event']['bulkGifted']) {
|
||||
let amount;
|
||||
if (data['event']['gifted']) amount = 1;
|
||||
else amount = data['event']['amount'];
|
||||
if (data['event']['tier'] == "prime" || data['event']['tier'] == "1000") {
|
||||
addTime(endingTime, seconds_added_per_giftsub_tier1 * amount * factor_t1_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_giftsub_tier1 * amount * factor_t1_local} Seconds Because ${data['event']['name']} Gifted ${amount} Tier 1 Subs`);
|
||||
}
|
||||
else if (data['event']['tier'] == "2000") {
|
||||
addTime(endingTime, seconds_added_per_giftsub_tier2 * amount * factor_t2_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_giftsub_tier2 * amount * factor_t2_local} Seconds Because ${data['event']['name']} Gifted ${amount} Tier 2 Subs`);
|
||||
}
|
||||
else if (data['event']['tier'] == "3000") {
|
||||
addTime(endingTime, seconds_added_per_giftsub_tier3 * amount * factor_t3_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_giftsub_tier3 * amount * factor_t3_local} Seconds Because ${data['event']['name']} Gifted ${amount} Tier 3 Subs`);
|
||||
}
|
||||
}
|
||||
else if (data['event']['amount'] != "1") {
|
||||
if (data['event']['tier'] == "prime") {
|
||||
addTime(endingTime, seconds_added_per_resub_prime * factor_t1_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_resub_prime * factor_t1_local} Seconds Because ${data['event']['name']} ReSubscribed With Prime`);
|
||||
}
|
||||
else if (data['event']['tier'] == "1000") {
|
||||
addTime(endingTime, seconds_added_per_resub_tier1 * factor_t1_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_resub_tier1 * factor_t1_local} Seconds Because ${data['event']['name']} ReSubscribed With Tier 1`);
|
||||
}
|
||||
else if (data['event']['tier'] == "2000") {
|
||||
addTime(endingTime, seconds_added_per_resub_tier2 * factor_t2_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_resub_tier2 * factor_t2_local} Seconds Because ${data['event']['name']} ReSubscribed With Tier 2`);
|
||||
}
|
||||
else if (data['event']['tier'] == "3000") {
|
||||
addTime(endingTime, seconds_added_per_resub_tier3 * factor_t3_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_resub_tier3 * factor_t3_local} Seconds Because ${data['event']['name']} ReSubscribed With Tier 3`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (data['event']['tier'] == "prime") {
|
||||
addTime(endingTime, seconds_added_per_sub_prime * factor_t1_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_sub_prime * factor_t1_local} Seconds Because ${data['event']['name']} Subscribed With Prime`);
|
||||
}
|
||||
else if (data['event']['tier'] == "1000") {
|
||||
addTime(endingTime, seconds_added_per_sub_tier1 * factor_t1_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_sub_tier1 * factor_t1_local} Seconds Because ${data['event']['name']} Subscribed With Tier 1`);
|
||||
}
|
||||
else if (data['event']['tier'] == "2000") {
|
||||
addTime(endingTime, seconds_added_per_sub_tier2 * factor_t2_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_sub_tier2 * factor_t2_local} Seconds Because ${data['event']['name']} Subscribed With Tier 2`);
|
||||
}
|
||||
else if (data['event']['tier'] == "3000") {
|
||||
addTime(endingTime, seconds_added_per_sub_tier3 * factor_t3_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_sub_tier3 * factor_t3_local} Seconds Because ${data['event']['name']} Subscribed With Tier 3`);
|
||||
}
|
||||
}
|
||||
if (!users.includes(data['event']['name'])) {
|
||||
users.push(data['event']['name']);
|
||||
}
|
||||
}
|
||||
|
||||
else if ((data['listener'] === "cheer-latest") && bitEnable) {
|
||||
if (data['event']['amount'] >= min_amount_of_bits) {
|
||||
let times = Math.floor(data['event']['amount']/min_amount_of_bits);
|
||||
addTime(endingTime, seconds_added_per_bits * times * factor_bits_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_bits * times * factor_bits_local} Seconds Because ${data['event']['name']} Donated ${data['event']['amount']} Bits`);
|
||||
if (!users.includes(data['event']['name'])) {
|
||||
users.push(data['event']['name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ((data['listener'] === "tip-latest") && donationEnable) {
|
||||
if (data['event']['amount'] >= min_donation_amount) {
|
||||
let times = Math.floor(data['event']['amount']/min_donation_amount);
|
||||
addTime(endingTime, seconds_added_per_donation * times * factor_donations_local);
|
||||
logMessage("StreamElements", `Added ${seconds_added_per_donation * times * factor_donations_local} Seconds Because ${data['event']['name']} Donated ${data['event']['amount']}$`);
|
||||
if (!users.includes(data['event']['name'])) {
|
||||
users.push(data['event']['name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
streamElementsConnect();
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
if (streamlabs_token !== "") {
|
||||
socket = io(`https://sockets.streamlabs.com?token=${streamlabs_token}`, {transports: ['websocket']});
|
||||
|
||||
socket.on("connect", () => {
|
||||
logMessage("Streamlabs", "Socket Connected");
|
||||
});
|
||||
|
||||
socket.on("event", (event) => {
|
||||
logObject("Streamlabs", event);
|
||||
let factor_t1_local = (happy_hour_active ? factor_t1 : 1) * (random_hour_active ? randomBellSkew(...range_t1): 1);
|
||||
let factor_t2_local = (happy_hour_active ? factor_t2 : 1) * (random_hour_active ? randomBellSkew(...range_t2): 1);
|
||||
let factor_t3_local = (happy_hour_active ? factor_t3 : 1) * (random_hour_active ? randomBellSkew(...range_t3): 1);
|
||||
let factor_bits_local = (happy_hour_active ? factor_bits : 1) * (random_hour_active ? randomBellSkew(...range_bits): 1);
|
||||
let factor_donations_local = (happy_hour_active ? factor_donations : 1) * (random_hour_active ? randomBellSkew(...range_donations): 1);
|
||||
|
||||
if (event.type == "subscription" && !event.message[0].gifter) {
|
||||
if (!countdownEnded && subEnable) {
|
||||
if (event.message[0].sub_plan == "1000") {
|
||||
addTime(endingTime, seconds_added_per_sub_tier1 * factor_t1_local);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_sub_tier1 * factor_t1_local} Seconds Because ${event.message[0].name} Subscribed With Tier 1`);
|
||||
}
|
||||
else if (event.message[0].sub_plan == "2000") {
|
||||
addTime(endingTime, seconds_added_per_sub_tier2 * factor_t2_local);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_sub_tier2 * factor_t2_local} Seconds Because ${event.message[0].name} Subscribed With Tier 2`);
|
||||
}
|
||||
else if (event.message[0].sub_plan == "3000") {
|
||||
addTime(endingTime, seconds_added_per_sub_tier3 * factor_t3_local);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_sub_tier3 * factor_t3_local} Seconds Because ${event.message[0].name} Subscribed With Tier 3`);
|
||||
}
|
||||
else {
|
||||
addTime(endingTime, seconds_added_per_sub_prime * factor_t1_local);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_sub_prime * factor_t1_local} Seconds Because ${event.message[0].name} Subscribed With Prime`);
|
||||
}
|
||||
if (!users.includes(event.message[0].name)) {
|
||||
users.push(event.message[0].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (event.type == "resub" && !event.message[0].gifter) {
|
||||
if (!countdownEnded && subEnable) {
|
||||
if (event.message[0].sub_plan == "1000") {
|
||||
addTime(endingTime, seconds_added_per_resub_tier1 * factor_t1_local);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_resub_tier1 * factor_t1_local} Seconds Because ${event.message[0].name} ReSubscribed With Tier 1`);
|
||||
}
|
||||
else if (event.message[0].sub_plan == "2000") {
|
||||
addTime(endingTime, seconds_added_per_resub_tier2 * factor_t2_local);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_resub_tier2 * factor_t2_local} Seconds Because ${event.message[0].name} ReSubscribed With Tier 2`);
|
||||
}
|
||||
else if (event.message[0].sub_plan == "3000") {
|
||||
addTime(endingTime, seconds_added_per_resub_tier3 * factor_t3_local);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_resub_tier3 * factor_t3_local} Seconds Because ${event.message[0].name} ReSubscribed With Tier 3`);
|
||||
}
|
||||
else {
|
||||
addTime(endingTime, seconds_added_per_resub_prime * factor_t1_local);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_resub_prime * factor_t1_local} Seconds Because ${event.message[0].name} ReSubscribed With Prime`);
|
||||
}
|
||||
if (!users.includes(event.message[0].name)) {
|
||||
users.push(event.message[0].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (event.message[0].gifter) {
|
||||
if (!countdownEnded && subEnable) {
|
||||
if (event.message[0].sub_plan == "1000") {
|
||||
addTime(endingTime, seconds_added_per_giftsub_tier1 * factor_t1_local);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_giftsub_tier1 * factor_t1_local} Seconds Because ${event.message[0].gifter} Gifted A Tier 1 Sub`);
|
||||
}
|
||||
else if (event.message[0].sub_plan == "2000") {
|
||||
addTime(endingTime, seconds_added_per_giftsub_tier2 * factor_t2_local);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_giftsub_tier2 * factor_t2_local} Seconds Because ${event.message[0].gifter} Gifted A Tier 2 Sub`);
|
||||
}
|
||||
else if (event.message[0].sub_plan == "3000") {
|
||||
addTime(endingTime, seconds_added_per_giftsub_tier3 * factor_t3_local);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_giftsub_tier3 * factor_t3_local} Seconds Because ${event.message[0].gifter} Gifted A Tier 3 Sub`);
|
||||
}
|
||||
if (!users.includes(event.message[0].name)) {
|
||||
users.push(event.message[0].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (event.type == "donation") {
|
||||
if (!countdownEnded && donationEnable) {
|
||||
let dono = parseInt(event.message[0].amount);
|
||||
let currency = event.message[0].currency;
|
||||
if (dono >= min_donation_amount) {
|
||||
let times = Math.floor(dono/min_donation_amount);
|
||||
addTime(endingTime, seconds_added_per_donation * times * factor_donations_local);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_donation * times} Seconds Because ${event.message[0].name} Donated ${dono} ${currency}`);
|
||||
if (!users.includes(event.message[0].name)) {
|
||||
users.push(event.message[0].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (event.type == "bits") {
|
||||
if (!countdownEnded && donationEnable) {
|
||||
let bits = parseInt(event.message[0].amount);
|
||||
if (bits >= min_amount_of_bits) {
|
||||
let times = Math.floor(bits/min_amount_of_bits);
|
||||
addTime(endingTime, seconds_added_per_bits * times);
|
||||
logMessage("Streamlabs", `Added ${seconds_added_per_bits * times * factor_bits_local} Seconds Because ${event.message[0].name} Donated ${bits} Bits`);
|
||||
if (!users.includes(event.message[0].name)) {
|
||||
users.push(event.message[0].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
logMessage("Streamlabs", "Socket Disconnected");
|
||||
socket.connect();
|
||||
});
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
if (streamloots_token !== "") {
|
||||
evtSourceStreamLoots = new EventSource(`https://widgets.streamloots.com/alerts/${streamloots_token}/media-stream`);
|
||||
logMessage("Streamloots", "Event Source Created");
|
||||
|
||||
evtSourceStreamLoots.onmessage = async (event) => {
|
||||
data = await JSON.parse(event.data);
|
||||
logObject("Streamloots", data);
|
||||
if (data.data.type == "purchase") {
|
||||
if (!countdownEnded && chestEnable) {
|
||||
if(!happy_hour_active){
|
||||
let chests;
|
||||
if (typeof(data.data.fields[0].value) == "number") {
|
||||
chests = data.data.fields[0].value;
|
||||
if (chests >= min_amount_of_chests) {
|
||||
let times = Math.floor(chests/min_amount_of_chests);
|
||||
addTime(endingTime, seconds_added_per_chests * times);
|
||||
logMessage("Streamloots", `Added ${seconds_added_per_chests * times} Seconds Because ${data.data.fields[1].value} Bought ${chests} Chests`);
|
||||
if (!users.includes(data.data.fields[1].value)) {
|
||||
users.push(data.data.fields[1].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
chests = data.data.fields[1].value;
|
||||
if (chests >= min_amount_of_chests) {
|
||||
let times = Math.floor(chests/min_amount_of_chests);
|
||||
addTime(endingTime, seconds_added_per_chests * times);
|
||||
logMessage("Streamloots", `Added ${seconds_added_per_chests * times} Seconds Because ${data.data.fields[0].value} Gifted ${chests} Chests`);
|
||||
if (!users.includes(data.data.fields[0].value)) {
|
||||
users.push(data.data.fields[0].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(happy_hour_active){
|
||||
let chests;
|
||||
if (typeof(data.data.fields[0].value) == "number") {
|
||||
chests = data.data.fields[0].value;
|
||||
if (chests >= min_amount_of_chests) {
|
||||
let times = Math.floor(chests/min_amount_of_chests);
|
||||
addTime(endingTime, seconds_added_per_chests_happy * times);
|
||||
logMessage("Streamloots", `Added ${seconds_added_per_chests_happy * times} Seconds Because ${data.data.fields[1].value} Bought ${chests} Chests`);
|
||||
if (!users.includes(data.data.fields[1].value)) {
|
||||
users.push(data.data.fields[1].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
chests = data.data.fields[1].value;
|
||||
if (chests >= min_amount_of_chests) {
|
||||
let times = Math.floor(chests/min_amount_of_chests);
|
||||
addTime(endingTime, seconds_added_per_chests_happy * times);
|
||||
logMessage("Streamloots", `Added ${seconds_added_per_chests_happy * times} Seconds Because ${data.data.fields[0].value} Gifted ${chests} Chests`);
|
||||
if (!users.includes(data.data.fields[0].value)) {
|
||||
users.push(data.data.fields[0].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
if (twitch_channel_name !== "") {
|
||||
const client = new tmi.client({
|
||||
connection: {
|
||||
reconnect: true,
|
||||
secure: true,
|
||||
},
|
||||
channels: [twitch_channel_name],
|
||||
});
|
||||
|
||||
client.connect();
|
||||
logMessage("Twitch", `Client Connected`);
|
||||
|
||||
client.on('subscription', (channel, username, methods, message, userstate) => {
|
||||
if (!countdownEnded && subEnable) {
|
||||
let factor_t1_local = (happy_hour_active ? factor_t1 : 1) * (random_hour_active ? randomBellSkew(...range_t1): 1);
|
||||
let factor_t2_local = (happy_hour_active ? factor_t2 : 1) * (random_hour_active ? randomBellSkew(...range_t2): 1);
|
||||
let factor_t3_local = (happy_hour_active ? factor_t3 : 1) * (random_hour_active ? randomBellSkew(...range_t3): 1);
|
||||
|
||||
switch (methods['plan']) {
|
||||
case "Prime":
|
||||
addTime(endingTime, seconds_added_per_sub_prime * factor_t1_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_sub_prime * factor_t1_local} Seconds Because ${username} Subscribed With Prime`);
|
||||
break;
|
||||
case "1000":
|
||||
addTime(endingTime, seconds_added_per_sub_tier1 * factor_t1_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_sub_tier1 * factor_t1_local} Seconds Because ${username} Subscribed With Tier 1`);
|
||||
break;
|
||||
case "2000":
|
||||
addTime(endingTime, seconds_added_per_sub_tier2 * factor_t2_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_sub_tier2 * factor_t2_local} Seconds Because ${username} Subscribed With Tier 2`);
|
||||
break;
|
||||
case "3000":
|
||||
addTime(endingTime, seconds_added_per_sub_tier3 * factor_t3_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_sub_tier3 * factor_t3_local} Seconds Because ${username} Subscribed With Tier 3`);
|
||||
break;
|
||||
}
|
||||
if (!users.includes(username)) {
|
||||
users.push(username);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.on('resub', (channel, username, months, message, userstate, methods) => {
|
||||
if (!countdownEnded && subEnable) {
|
||||
let factor_t1_local = (happy_hour_active ? factor_t1 : 1) * (random_hour_active ? randomBellSkew(...range_t1): 1);
|
||||
let factor_t2_local = (happy_hour_active ? factor_t2 : 1) * (random_hour_active ? randomBellSkew(...range_t2): 1);
|
||||
let factor_t3_local = (happy_hour_active ? factor_t3 : 1) * (random_hour_active ? randomBellSkew(...range_t3): 1);
|
||||
|
||||
switch (methods['plan']) {
|
||||
case "Prime":
|
||||
addTime(endingTime, seconds_added_per_resub_prime * factor_t1_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_resub_prime * factor_t1_local} Seconds Because ${username} ReSubscribed With Prime`);
|
||||
break;
|
||||
case "1000":
|
||||
addTime(endingTime, seconds_added_per_resub_tier1 * factor_t1_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_resub_tier1 * factor_t1_local} Seconds Because ${username} ReSubscribed With Tier 1`);
|
||||
break;
|
||||
case "2000":
|
||||
addTime(endingTime, seconds_added_per_resub_tier2 * factor_t2_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_resub_tier2 * factor_t2_local} Seconds Because ${username} ReSubscribed With Tier 2`);
|
||||
break;
|
||||
case "3000":
|
||||
addTime(endingTime, seconds_added_per_resub_tier3 * factor_t3_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_resub_tier3 * factor_t3_local} Seconds Because ${username} ReSubscribed With Tier 3`);
|
||||
break;
|
||||
}
|
||||
if (!users.includes(username)) {
|
||||
users.push(username);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.on('subgift', (channel, username, months, recipient, methods, userstate) => {
|
||||
if (!countdownEnded && subEnable) {
|
||||
let factor_t1_local = (happy_hour_active ? factor_t1 : 1) * (random_hour_active ? randomBellSkew(...range_t1): 1);
|
||||
let factor_t2_local = (happy_hour_active ? factor_t2 : 1) * (random_hour_active ? randomBellSkew(...range_t2): 1);
|
||||
let factor_t3_local = (happy_hour_active ? factor_t3 : 1) * (random_hour_active ? randomBellSkew(...range_t3): 1);
|
||||
|
||||
switch (methods['plan']) {
|
||||
case "Prime":
|
||||
addTime(endingTime, seconds_added_per_giftsub_prime * factor_t1_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_giftsub_prime * factor_t1_local} Seconds Because ${username} gifted Sub With Prime`);
|
||||
break;
|
||||
case "1000":
|
||||
addTime(endingTime, seconds_added_per_giftsub_tier1 * factor_t1_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_giftsub_tier1 * factor_t1_local} Seconds Because ${username} gifted Sub With Tier 1`);
|
||||
break;
|
||||
case "2000":
|
||||
addTime(endingTime, seconds_added_per_giftsub_tier2 * factor_t2_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_giftsub_tier2 * factor_t2_local} Seconds Because ${username} gifted Sub With Tier 2`);
|
||||
break;
|
||||
case "3000":
|
||||
addTime(endingTime, seconds_added_per_giftsub_tier3 * factor_t3_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_giftsub_tier3 * factor_t3_local} Seconds Because ${username} gifted Sub With Tier 3`);
|
||||
break;
|
||||
}
|
||||
if (!users.includes(username)) {
|
||||
users.push(username);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.on('cheer', (channel, userstate, message) => {
|
||||
if (!countdownEnded && bitEnable) {
|
||||
let factor_bits_local = (happy_hour_active ? factor_bits : 1) * (random_hour_active ? randomBellSkew(...range_bits): 1);
|
||||
|
||||
if (userstate.bits >= min_amount_of_bits) {
|
||||
let times = Math.floor(userstate.bits/min_amount_of_bits);
|
||||
addTime(endingTime, seconds_added_per_bits * times * factor_bits_local);
|
||||
logMessage("Twitch", `Added ${seconds_added_per_bits * times} Seconds Because ${userstate['display-name']} Donated ${userstate.bits} Bits`);
|
||||
if (!users.includes(userstate['display-name'])) {
|
||||
users.push(userstate['display-name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
const sleep = (ms) => {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
};
|
||||
|
||||
const randomInRange = (min, max) => {
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
};
|
||||
|
||||
const randomBellSkew = (min, max, skew) => {
|
||||
let u = 0, v = 0;
|
||||
while(u === 0) u = Math.random() //Converting [0,1) to (0,1)
|
||||
while(v === 0) v = Math.random()
|
||||
let num = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v )
|
||||
|
||||
num = num / 10.0 + 0.5 // Translate to 0 -> 1
|
||||
if (num > 1 || num < 0)
|
||||
num = randomBellSkew(min, max, skew) // resample between 0 and 1 if out of range
|
||||
|
||||
else{
|
||||
num = Math.pow(num, skew) // Skew
|
||||
num *= max - min // Stretch to fill range
|
||||
num += min // offset to min
|
||||
}
|
||||
|
||||
return num
|
||||
}
|
||||
|
||||
const logMessage = (module, message) => {
|
||||
console.log(`[${module}]: ${message}`);
|
||||
};
|
||||
|
||||
const logObject = (module, object) => {
|
||||
console.log(`[${module}]: `, object);
|
||||
};
|
||||
|
||||
|
||||
Vendored
-11
@@ -1,11 +0,0 @@
|
||||
/* mousetrap v1.6.5 craig.is/killing/mice */
|
||||
(function(q,u,c){function v(a,b,g){a.addEventListener?a.addEventListener(b,g,!1):a.attachEvent("on"+b,g)}function z(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return n[a.which]?n[a.which]:r[a.which]?r[a.which]:String.fromCharCode(a.which).toLowerCase()}function F(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function w(a){return"shift"==a||"ctrl"==a||"alt"==a||
|
||||
"meta"==a}function A(a,b){var g,d=[];var e=a;"+"===e?e=["+"]:(e=e.replace(/\+{2}/g,"+plus"),e=e.split("+"));for(g=0;g<e.length;++g){var m=e[g];B[m]&&(m=B[m]);b&&"keypress"!=b&&C[m]&&(m=C[m],d.push("shift"));w(m)&&d.push(m)}e=m;g=b;if(!g){if(!p){p={};for(var c in n)95<c&&112>c||n.hasOwnProperty(c)&&(p[n[c]]=c)}g=p[e]?"keydown":"keypress"}"keypress"==g&&d.length&&(g="keydown");return{key:m,modifiers:d,action:g}}function D(a,b){return null===a||a===u?!1:a===b?!0:D(a.parentNode,b)}function d(a){function b(a){a=
|
||||
a||{};var b=!1,l;for(l in p)a[l]?b=!0:p[l]=0;b||(x=!1)}function g(a,b,t,f,g,d){var l,E=[],h=t.type;if(!k._callbacks[a])return[];"keyup"==h&&w(a)&&(b=[a]);for(l=0;l<k._callbacks[a].length;++l){var c=k._callbacks[a][l];if((f||!c.seq||p[c.seq]==c.level)&&h==c.action){var e;(e="keypress"==h&&!t.metaKey&&!t.ctrlKey)||(e=c.modifiers,e=b.sort().join(",")===e.sort().join(","));e&&(e=f&&c.seq==f&&c.level==d,(!f&&c.combo==g||e)&&k._callbacks[a].splice(l,1),E.push(c))}}return E}function c(a,b,c,f){k.stopCallback(b,
|
||||
b.target||b.srcElement,c,f)||!1!==a(b,c)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation?b.stopPropagation():b.cancelBubble=!0)}function e(a){"number"!==typeof a.which&&(a.which=a.keyCode);var b=z(a);b&&("keyup"==a.type&&y===b?y=!1:k.handleKey(b,F(a),a))}function m(a,g,t,f){function h(c){return function(){x=c;++p[a];clearTimeout(q);q=setTimeout(b,1E3)}}function l(g){c(t,g,a);"keyup"!==f&&(y=z(g));setTimeout(b,10)}for(var d=p[a]=0;d<g.length;++d){var e=d+1===g.length?l:h(f||
|
||||
A(g[d+1]).action);n(g[d],e,f,a,d)}}function n(a,b,c,f,d){k._directMap[a+":"+c]=b;a=a.replace(/\s+/g," ");var e=a.split(" ");1<e.length?m(a,e,b,c):(c=A(a,c),k._callbacks[c.key]=k._callbacks[c.key]||[],g(c.key,c.modifiers,{type:c.action},f,a,d),k._callbacks[c.key][f?"unshift":"push"]({callback:b,modifiers:c.modifiers,action:c.action,seq:f,level:d,combo:a}))}var k=this;a=a||u;if(!(k instanceof d))return new d(a);k.target=a;k._callbacks={};k._directMap={};var p={},q,y=!1,r=!1,x=!1;k._handleKey=function(a,
|
||||
d,e){var f=g(a,d,e),h;d={};var k=0,l=!1;for(h=0;h<f.length;++h)f[h].seq&&(k=Math.max(k,f[h].level));for(h=0;h<f.length;++h)f[h].seq?f[h].level==k&&(l=!0,d[f[h].seq]=1,c(f[h].callback,e,f[h].combo,f[h].seq)):l||c(f[h].callback,e,f[h].combo);f="keypress"==e.type&&r;e.type!=x||w(a)||f||b(d);r=l&&"keydown"==e.type};k._bindMultiple=function(a,b,c){for(var d=0;d<a.length;++d)n(a[d],b,c)};v(a,"keypress",e);v(a,"keydown",e);v(a,"keyup",e)}if(q){var n={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",
|
||||
18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},r={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},C={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},B={option:"alt",command:"meta","return":"enter",
|
||||
escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},p;for(c=1;20>c;++c)n[111+c]="f"+c;for(c=0;9>=c;++c)n[c+96]=c.toString();d.prototype.bind=function(a,b,c){a=a instanceof Array?a:[a];this._bindMultiple.call(this,a,b,c);return this};d.prototype.unbind=function(a,b){return this.bind.call(this,a,function(){},b)};d.prototype.trigger=function(a,b){if(this._directMap[a+":"+b])this._directMap[a+":"+b]({},a);return this};d.prototype.reset=function(){this._callbacks={};
|
||||
this._directMap={};return this};d.prototype.stopCallback=function(a,b){if(-1<(" "+b.className+" ").indexOf(" mousetrap ")||D(b,this.target))return!1;if("composedPath"in a&&"function"===typeof a.composedPath){var c=a.composedPath()[0];c!==a.target&&(b=c)}return"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable};d.prototype.handleKey=function(){return this._handleKey.apply(this,arguments)};d.addKeycodes=function(a){for(var b in a)a.hasOwnProperty(b)&&(n[b]=a[b]);p=null};
|
||||
d.init=function(){var a=d(u),b;for(b in a)"_"!==b.charAt(0)&&(d[b]=function(b){return function(){return a[b].apply(a,arguments)}}(b))};d.init();q.Mousetrap=d;"undefined"!==typeof module&&module.exports&&(module.exports=d);"function"===typeof define&&define.amd&&define(function(){return d})}})("undefined"!==typeof window?window:null,"undefined"!==typeof window?document:null);
|
||||
@@ -1,52 +0,0 @@
|
||||
timeFunc = {
|
||||
addHours(time, h) {
|
||||
time.setTime(time.getTime() + (h * 60 * 60 * 1000));
|
||||
return time;
|
||||
},
|
||||
|
||||
addMinutes(time, m) {
|
||||
time.setTime(time.getTime() + (m * 60 * 1000));
|
||||
return time;
|
||||
},
|
||||
|
||||
addSeconds (time, s) {
|
||||
time.setTime(time.getTime() + (s * 1000));
|
||||
return time;
|
||||
},
|
||||
|
||||
getHours(time) {
|
||||
let hours;
|
||||
if (typeof time !== 'number') {
|
||||
hours = time.getHours().toString();
|
||||
}
|
||||
else {
|
||||
hours = Math.floor(time / (1000 * 60 * 60)).toString();
|
||||
}
|
||||
hours = (hours.length < 2) ? `0${hours}` : hours;
|
||||
return hours;
|
||||
},
|
||||
|
||||
getMinutes(time) {
|
||||
let minutes;
|
||||
if (typeof time !== 'number') {
|
||||
minutes = time.getMinutes().toString();
|
||||
}
|
||||
else {
|
||||
minutes = Math.floor((time % (1000 * 60 * 60)) / (1000 * 60)).toString();
|
||||
}
|
||||
minutes = (minutes.length < 2) ? `0${minutes}` : minutes;
|
||||
return minutes;
|
||||
},
|
||||
|
||||
getSeconds(time) {
|
||||
let seconds;
|
||||
if (typeof time !== 'number') {
|
||||
seconds = time.getSeconds().toString();
|
||||
}
|
||||
else {
|
||||
seconds = Math.floor((time % (1000 * 60)) / 1000).toString();
|
||||
}
|
||||
seconds = (seconds.length < 2) ? `0${seconds}` : seconds;
|
||||
return seconds;
|
||||
}
|
||||
};
|
||||
Vendored
-1
File diff suppressed because one or more lines are too long
+341
-275
@@ -1,296 +1,362 @@
|
||||
const timeText = document.getElementById("timeText");
|
||||
const client_id='ib2n7v7mur7ab2mcxv7rjju2ctsyoi'
|
||||
const message_ids=[]
|
||||
const timer=document.querySelector('#timeText')
|
||||
let tba,tokens,pubsub,ping_tid,pong_tid,eventsub,sse,time_started,time_passed,time_total,config,localforage
|
||||
/** @type WebSocket */
|
||||
let irc
|
||||
|
||||
var initialHours;
|
||||
var initialMinutes;
|
||||
var initialSeconds;
|
||||
var paused = false;
|
||||
var happy_hour_active = false;
|
||||
var random_hour_active = false;
|
||||
let countdownEnded = false;
|
||||
let countdownUpdater = null;
|
||||
|
||||
var initialHoursLocal = window.localStorage.getItem('initialHours')
|
||||
if (initialHoursLocal !== null) {
|
||||
initialHours = initialHoursLocal;
|
||||
logMessage("Core", "Found initialHours in localStorage.")
|
||||
} else {
|
||||
initialHours = initialHoursConfig;
|
||||
}
|
||||
var initialMinutesLocal = window.localStorage.getItem('initialMinutes')
|
||||
if (initialMinutesLocal !== null) {
|
||||
initialMinutes = initialMinutesLocal;
|
||||
logMessage("Core", "Found initialMinutes in localStorage.")
|
||||
} else {
|
||||
initialMinutes = initialMinutesConfig;
|
||||
}
|
||||
var initialSecondsLocal = window.localStorage.getItem('initialSeconds')
|
||||
if (initialSecondsLocal !== null) {
|
||||
initialSeconds = initialSecondsLocal;
|
||||
logMessage("Core", "Found initialSeconds in localStorage.")
|
||||
} else {
|
||||
initialSeconds = initialSecondsConfig;
|
||||
window.onanimationend=function(event){
|
||||
event.target.remove()
|
||||
}
|
||||
|
||||
resetBtn.addEventListener("click", function(){
|
||||
|
||||
if (happy_hour_active) specialHourHandler('Happy');
|
||||
if (random_hour_active) specialHourHandler('Random');
|
||||
countdownEnded = false;
|
||||
|
||||
initialHours = initialHoursConfig;
|
||||
initialMinutes = initialMinutesConfig;
|
||||
initialSeconds = initialSecondsConfig;
|
||||
|
||||
let timeNow = new Date(Date.now());
|
||||
|
||||
endingTime = timeFunc.addHours(timeNow, initialHours);
|
||||
endingTime = timeFunc.addMinutes(timeNow, initialMinutes);
|
||||
endingTime = timeFunc.addSeconds(timeNow, initialSeconds);
|
||||
|
||||
window.localStorage.removeItem('initialHours');
|
||||
window.localStorage.removeItem('initialMinutes');
|
||||
window.localStorage.removeItem('initialSeconds');
|
||||
|
||||
logMessage("Core", "Timer Reset.");
|
||||
});
|
||||
|
||||
startBtn.addEventListener("click", function(){
|
||||
|
||||
if (paused){
|
||||
var initialHoursLocal = window.localStorage.getItem('initialHours')
|
||||
if (initialHoursLocal !== null) {
|
||||
initialHours = initialHoursLocal;
|
||||
logMessage("Core", "Found initialHours in localStorage.")
|
||||
} else {
|
||||
initialHours = initialHoursConfig;
|
||||
}
|
||||
var initialMinutesLocal = window.localStorage.getItem('initialMinutes')
|
||||
if (initialMinutesLocal !== null) {
|
||||
initialMinutes = initialMinutesLocal;
|
||||
logMessage("Core", "Found initialMinutes in localStorage.")
|
||||
} else {
|
||||
initialMinutes = initialMinutesConfig;
|
||||
}
|
||||
var initialSecondsLocal = window.localStorage.getItem('initialSeconds')
|
||||
if (initialSecondsLocal !== null) {
|
||||
initialSeconds = initialSecondsLocal;
|
||||
logMessage("Core", "Found initialSeconds in localStorage.")
|
||||
} else {
|
||||
initialSeconds = initialSecondsConfig;
|
||||
}
|
||||
}
|
||||
|
||||
let timeNow = new Date(Date.now());
|
||||
|
||||
document.getElementById("startPage").style.visibility = "hidden";
|
||||
document.getElementById("container").style.visibility = "visible";
|
||||
|
||||
endingTime = timeFunc.addHours(timeNow, initialHours);
|
||||
endingTime = timeFunc.addMinutes(timeNow, initialMinutes);
|
||||
endingTime = timeFunc.addSeconds(timeNow, initialSeconds);
|
||||
|
||||
paused = false;
|
||||
|
||||
countdownUpdater = setInterval(() => {
|
||||
getNextTime();
|
||||
}, 1);
|
||||
|
||||
});
|
||||
|
||||
Mousetrap.bind(pauseShort, function(e) {
|
||||
paused = true;
|
||||
logMessage("Core", "Timer was paused");
|
||||
document.getElementById("startPage").style.visibility = "visible";
|
||||
document.getElementById("container").style.visibility = "hidden";
|
||||
clearInterval(countdownUpdater);
|
||||
});
|
||||
|
||||
Mousetrap.bind(happyHourShort, async function(e){
|
||||
specialHourHandler('Happy');
|
||||
});
|
||||
|
||||
Mousetrap.bind(randomHourShort, async function(e){
|
||||
specialHourHandler('Random');
|
||||
});
|
||||
|
||||
async function specialHourHandler(type){
|
||||
if ((type === 'Happy' && happy_hour) || (type === 'Random' && random_hour)){
|
||||
specialHourFunc(type)
|
||||
}
|
||||
else {
|
||||
logMessage("Core", `${type} Hour is not available`)
|
||||
document.getElementById("SpecialHourText").innerHTML = `${type} Hour error`;
|
||||
document.getElementById("SpecialHourText").animate({opacity: [ 0, 1 ], easing: [ 'ease-in', 'ease-out' ],}, 500);
|
||||
document.getElementById("SpecialHourText").style.opacity = "1";
|
||||
document.getElementById("SpecialHourHTML").animate({top: [ "-200px", "-250px" ], easing: [ 'ease-in', 'ease-out' ],}, 500);
|
||||
document.getElementById("SpecialHourHTML").style.top = "-250px";
|
||||
await sleep(5000)
|
||||
document.getElementById("SpecialHourText").animate({opacity: [ 1, 0 ], easing: [ 'ease-in', 'ease-out' ],}, 500);
|
||||
document.getElementById("SpecialHourText").style.opacity = "0";
|
||||
}
|
||||
window.onload=async function(){
|
||||
// init localforage
|
||||
localforage=(await import('https://cdn.jsdelivr.net/npm/localforage/+esm')).default
|
||||
localforage=localforage.createInstance({name:'sugoi-subathon-countdown'})
|
||||
// init timer display
|
||||
time_started=await localforage.getItem('time_started')
|
||||
time_passed=await localforage.getItem('time_passed')
|
||||
time_total=await localforage.getItem('time_total')
|
||||
updateTime()
|
||||
// init twitch api tokens
|
||||
tba=await import('https://tba.sugoidogo.com/tba.mjs')
|
||||
tokens=await tba.get_tokens(client_id)
|
||||
// load user config
|
||||
load_config()
|
||||
// init event sources
|
||||
init_irc()
|
||||
init_pubsub()
|
||||
init_eventsub()
|
||||
}
|
||||
|
||||
async function specialHourFunc(type){
|
||||
let activate = ((type === 'Happy' && !happy_hour_active) || (type === 'Random' && !random_hour_active));
|
||||
let toggleText = activate ? 'Activated' : 'Deactivated';
|
||||
|
||||
logMessage("Core", `${type} Hour ${toggleText}`);
|
||||
|
||||
if (type === 'Happy') happy_hour_active = activate;
|
||||
if (type === 'Random') random_hour_active = activate;
|
||||
|
||||
let animation = (happy_hour_active || random_hour_active) ? ', url(https://drive.google.com/uc?id=1oduFlPg84O1DliM5FsLvJJsnwZ4m1Vpm)' : '';
|
||||
|
||||
document.getElementById("SpecialHourText").innerHTML = `${type} Hour ${toggleText}!`;
|
||||
document.getElementById("SpecialHourText").animate({opacity: [ 0, 1 ], easing: [ 'ease-in', 'ease-out' ],}, 500);
|
||||
document.getElementById("SpecialHourText").style.opacity = "1";
|
||||
|
||||
document.getElementById("SpecialHourHTML").animate({top: [ "-200px", "-250px" ], easing: [ 'ease-in', 'ease-out' ],}, 500);
|
||||
document.getElementById("SpecialHourHTML").style.top = "-250px";
|
||||
|
||||
document.getElementById("container").style.backgroundImage = `-webkit-linear-gradient(-45deg, transparent 33%, rgba(0, 0, 0, .1) 33%, rgba(0,0, 0, .1) 66%, transparent 66%), -webkit-linear-gradient(top, rgba(255, 255, 255, .25), rgba(0, 0, 0, .25))${animation}, -webkit-linear-gradient(left, #0074cc, #a700cc)`;
|
||||
|
||||
await sleep(activate ? 5000 : 10000);
|
||||
|
||||
document.getElementById("SpecialHourText").animate({opacity: [ 1, 0 ], easing: [ 'ease-in', 'ease-out' ],}, 500);
|
||||
document.getElementById("SpecialHourText").style.opacity = "0";
|
||||
function handle_event(event_name,event_amount=1){
|
||||
if(!config[event_name+'-time-enabled']){
|
||||
return false
|
||||
}
|
||||
add_time(parseReadableTimeIntoMilliseconds(config[event_name+'-time'])*event_amount)
|
||||
return true
|
||||
}
|
||||
|
||||
let users = [];
|
||||
let time;
|
||||
|
||||
let endingTime = new Date(Date.now());
|
||||
endingTime = timeFunc.addHours(endingTime, initialHours);
|
||||
endingTime = timeFunc.addMinutes(endingTime, initialMinutes);
|
||||
endingTime = timeFunc.addSeconds(endingTime, initialSeconds);
|
||||
|
||||
function getRandomInt(min, max) {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
function reset(){
|
||||
localforage.removeItem('time_started')
|
||||
localforage.removeItem('time_passed')
|
||||
time_started=null
|
||||
time_passed=null
|
||||
time_total=parseReadableTimeIntoMilliseconds(config['start-time'])
|
||||
localforage.setItem('time_total',time_total)
|
||||
}
|
||||
|
||||
var randomHappyBool = false
|
||||
var scheduleHappyBool = false
|
||||
|
||||
const getNextTime = () => {
|
||||
|
||||
let currentTime = new Date(Date.now());
|
||||
let differenceTime = endingTime - currentTime;
|
||||
time = `${timeFunc.getHours(differenceTime)}:${timeFunc.getMinutes(differenceTime)}:${timeFunc.getSeconds(differenceTime)}`;
|
||||
if (differenceTime <= 0) {
|
||||
time = "00:00:00";
|
||||
if (differenceTime <= (syncTime * 1000 * -1)) {
|
||||
clearInterval(countdownUpdater);
|
||||
countdownEnded = true;
|
||||
logMessage("Core", "Timer Ended");
|
||||
}
|
||||
}
|
||||
if (!paused){
|
||||
window.localStorage.setItem('initialHours', timeFunc.getHours(differenceTime));
|
||||
window.localStorage.setItem('initialMinutes', timeFunc.getMinutes(differenceTime));
|
||||
window.localStorage.setItem('initialSeconds', timeFunc.getSeconds(differenceTime));
|
||||
|
||||
if (randHappy && happy_hour && !randomHappyBool){
|
||||
randomHappyBool = true
|
||||
setTimeout(randomHappy,1000)
|
||||
}
|
||||
if (scheduleHappy && happy_hour && !scheduleHappyBool){
|
||||
scheduleHappyBool = true
|
||||
scheduleHappyFunc()
|
||||
}
|
||||
}
|
||||
timeText.innerText = time;
|
||||
|
||||
};
|
||||
|
||||
function randomHappy(){
|
||||
if (!happy_hour_active){
|
||||
if ((getRandomInt(0,10000) == 127)){
|
||||
logMessage("RandomHappy","It's not rigged!")
|
||||
specialHourFunc()
|
||||
setTimeout(specialHourFunc, 3600000)
|
||||
}
|
||||
setTimeout(randomHappy,1000)
|
||||
function load_config(){
|
||||
return fetch('https://ts.sugoidogo.com/config.json',{headers:tokens.auth_headers})
|
||||
.then(response=>response.json())
|
||||
.then(json=>{
|
||||
config=json
|
||||
if(!time_started && !time_passed){
|
||||
reset()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function scheduleHappyFunc(){
|
||||
let now = new Date()
|
||||
if (now.getDay() == scheduleHappyDay){
|
||||
if (now.getUTCHours() == scheduleHappyHour){
|
||||
if (now.getUTCMinutes() == 00){
|
||||
logMessage("Schedule","It's time!")
|
||||
specialHourFunc()
|
||||
setTimeout(specialHourFunc, 3600000)
|
||||
setTimeout(scheduleHappyFunc, 36000000)
|
||||
function add_time(time){
|
||||
if(config['max-time-enabled']){
|
||||
const new_time=time_total+time
|
||||
const max_time=parseReadableTimeIntoMilliseconds(config['max-time'])
|
||||
if(new_time>max_time){
|
||||
time=max_time-time_total
|
||||
}
|
||||
}
|
||||
let addedTime=document.createElement('p')
|
||||
let timeString=parseMillisecondsIntoReadableTime(time)
|
||||
if(time>0){
|
||||
timeString='+'+timeString
|
||||
}
|
||||
}
|
||||
|
||||
var firstSub = true;
|
||||
var endingTimeBeforeCounter;
|
||||
var addedTimeCounter;
|
||||
var timeoutID;
|
||||
|
||||
const addTime = async (time, s) => {
|
||||
let addedTime = Math.floor(s);
|
||||
if (!bulk_enabled) {
|
||||
endingTimeBeforeCounter = time;
|
||||
addedTimeCounter = addedTime;
|
||||
addTimeInternal();
|
||||
return;
|
||||
if(time==0){
|
||||
timeString='Timer Maxed!'
|
||||
}
|
||||
if (firstSub) {
|
||||
firstSub = false;
|
||||
endingTimeBeforeCounter = time;
|
||||
addedTimeCounter = addedTime;
|
||||
} else {
|
||||
addedTimeCounter += addedTime;
|
||||
window.clearTimeout(timeoutID);
|
||||
}
|
||||
timeoutID = window.setTimeout(addTimeInternal, 1000);
|
||||
};
|
||||
|
||||
const addTimeInternal = async () => {
|
||||
let time = endingTimeBeforeCounter;
|
||||
let s = addedTimeCounter;
|
||||
addedTimeCounter = 0;
|
||||
firstSub = true;
|
||||
|
||||
let addedTime = document.createElement("p");
|
||||
|
||||
happy_hour_active ? addedTime.classList = "gold" : addedTime.classList = "addedTime";
|
||||
|
||||
addedTime.innerText = `+${s}s`;
|
||||
addedTime.innerHTML=timeString
|
||||
addedTime.className='addedTime'
|
||||
document.body.appendChild(addedTime);
|
||||
addedTime.style.display = "block";
|
||||
await sleep(50);
|
||||
addedTime.style.left = `${randomInRange(35, 65)}%`;
|
||||
addedTime.style.top = `${randomInRange(15, 40)}%`;
|
||||
addedTime.style.opacity = "1";
|
||||
while (s > 0){
|
||||
timeStep = s > 60 ? s/30 : 2
|
||||
endingTime = timeFunc.addSeconds(time, timeStep)
|
||||
await sleep(50);
|
||||
s -= timeStep
|
||||
}
|
||||
await sleep(200);
|
||||
addedTime.style.opacity = "0";
|
||||
await sleep(200);
|
||||
addedTime.remove();
|
||||
time_total+=time
|
||||
localforage.setItem('time_total',time_total)
|
||||
}
|
||||
|
||||
const testAddTime = (times, delay, s) => {
|
||||
let addTimeInterval = setInterval(async () => {
|
||||
if (times > 0) {
|
||||
await sleep(randomInRange(50, delay-50));
|
||||
addTime(endingTime, s);
|
||||
--times;
|
||||
function start(){
|
||||
time_started=Date.now()
|
||||
localforage.setItem('time_started',time_started)
|
||||
}
|
||||
|
||||
function pause(){
|
||||
time_passed+=Date.now()-time_started
|
||||
time_started=null
|
||||
localforage.removeItem('time_started')
|
||||
localforage.setItem('time_passed',time_passed)
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/33909506
|
||||
function parseMillisecondsIntoReadableTime(milliseconds){
|
||||
let negative=false
|
||||
if(milliseconds<0){
|
||||
milliseconds=Math.abs(milliseconds)
|
||||
negative=true
|
||||
}
|
||||
else {
|
||||
clearInterval(addTimeInterval);
|
||||
|
||||
//Get hours from milliseconds
|
||||
var hours = milliseconds / (1000*60*60);
|
||||
var absoluteHours = Math.floor(hours);
|
||||
var h = absoluteHours > 9 ? absoluteHours : '0' + absoluteHours;
|
||||
|
||||
//Get remainder from hours and convert to minutes
|
||||
var minutes = (hours - absoluteHours) * 60;
|
||||
var absoluteMinutes = Math.floor(minutes);
|
||||
var m = absoluteMinutes > 9 ? absoluteMinutes : '0' + absoluteMinutes;
|
||||
|
||||
//Get remainder from minutes and convert to seconds
|
||||
var seconds = (minutes - absoluteMinutes) * 60;
|
||||
var absoluteSeconds = Math.floor(seconds);
|
||||
var s = absoluteSeconds > 9 ? absoluteSeconds : '0' + absoluteSeconds;
|
||||
|
||||
let time = h + ':' + m + ':' + s;
|
||||
|
||||
if(negative){
|
||||
time='-'+time
|
||||
}
|
||||
}, delay);
|
||||
};
|
||||
|
||||
return time
|
||||
}
|
||||
|
||||
function parseReadableTimeIntoMilliseconds(readableTime){
|
||||
let negative=false
|
||||
if(readableTime.startsWith('-')){
|
||||
negative=true
|
||||
readableTime=readableTime.substring(1)
|
||||
}
|
||||
const [seconds,minutes,hours]=readableTime.split(':').reverse()
|
||||
let time=((hours||0)*1000*60*60)+((minutes||0)*1000*60)+((seconds||0)*1000)
|
||||
if(negative){
|
||||
time=0-time
|
||||
}
|
||||
return time
|
||||
}
|
||||
|
||||
function updateTime(){
|
||||
let time_remaining=time_total
|
||||
if(time_passed){
|
||||
time_remaining-=time_passed
|
||||
}
|
||||
if(time_started){
|
||||
time_remaining-=Date.now()-time_started
|
||||
}
|
||||
timer.innerHTML=parseMillisecondsIntoReadableTime(time_remaining)
|
||||
requestAnimationFrame(updateTime)
|
||||
}
|
||||
|
||||
function init_pubsub(){
|
||||
if(pong_tid){
|
||||
clearTimeout(pong_tid)
|
||||
pong_tid=null
|
||||
}
|
||||
if(ping_tid){
|
||||
clearTimeout(ping_tid)
|
||||
ping_tid=null
|
||||
}
|
||||
if(pubsub){
|
||||
pubsub.close()
|
||||
}
|
||||
pubsub=new WebSocket('wss://pubsub-edge.twitch.tv')
|
||||
pubsub.onopen=function(){
|
||||
pubsub.send(JSON.stringify({
|
||||
"type":"LISTEN",
|
||||
"data":{
|
||||
"auth_token":tokens.access_token,
|
||||
"topics":[
|
||||
"channel-bits-events-v2."+tokens.user_id,
|
||||
"channel-subscribe-events-v1."+tokens.user_id
|
||||
]
|
||||
}
|
||||
}))
|
||||
}
|
||||
pubsub.onmessage=function(event){
|
||||
let message=JSON.parse(event.data)
|
||||
console.debug(message)
|
||||
switch(message.type){
|
||||
case 'RESPONSE':{
|
||||
if(message.error){
|
||||
throw message.error
|
||||
}
|
||||
pubsub_ping()
|
||||
break
|
||||
}
|
||||
case 'PONG':{
|
||||
clearTimeout(pong_tid)
|
||||
pong_tid=null
|
||||
break
|
||||
}
|
||||
case 'RECONNECT':{
|
||||
init_pubsub()
|
||||
break
|
||||
}
|
||||
case 'AUTH_REVOKED':{
|
||||
location.reload()
|
||||
break
|
||||
}
|
||||
case 'MESSAGE':{
|
||||
message=message.data.message
|
||||
if('sub_plan' in message){
|
||||
handle_event('sub'+message.sub_plan)
|
||||
break
|
||||
}
|
||||
if('bits_used' in message){
|
||||
handle_bits('bit',message.bits_used)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pubsub_ping(){
|
||||
pubsub.send(JSON.stringify({'type':'PING'}))
|
||||
const time=Math.floor(Math.random() * (5*60*1000))
|
||||
ping_tid=setTimeout(pubsub_ping,time)
|
||||
pong_tid=setTimeout(init_pubsub,20000)
|
||||
}
|
||||
|
||||
function init_eventsub(){
|
||||
eventsub=new WebSocket('wss://eventsub.wss.twitch.tv/ws')
|
||||
eventsub.onmessage=function(event){
|
||||
let message=JSON.parse(event.data)
|
||||
console.debug(message)
|
||||
if(message.metadata.message_id in message_ids){
|
||||
return
|
||||
}else{
|
||||
message_ids.push(message.metadata.message_id)
|
||||
}
|
||||
switch(message.metadata.message_type){
|
||||
case 'session_welcome':{
|
||||
let session_id=message.payload.session.id
|
||||
const headers={'content-type':'application/json'}
|
||||
Object.assign(headers,tokens.auth_headers)
|
||||
const url=new URL('https://api.twitch.tv/helix/eventsub/subscriptions')
|
||||
subscriptions=[
|
||||
{
|
||||
"type": "channel.follow",
|
||||
"version": "2",
|
||||
"condition": {
|
||||
"broadcaster_user_id": tokens.user_id,
|
||||
"moderator_user_id": tokens.user_id
|
||||
},
|
||||
"transport": {
|
||||
"method": "websocket",
|
||||
"session_id": session_id,
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "channel.raid",
|
||||
"version": "1",
|
||||
"condition": {
|
||||
"to_broadcaster_user_id": tokens.user_id
|
||||
},
|
||||
"transport": {
|
||||
"method": "websocket",
|
||||
"session_id": session_id,
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "channel.charity_campaign.donate",
|
||||
"version": "1",
|
||||
"condition": {
|
||||
"broadcaster_user_id": tokens.user_id
|
||||
},
|
||||
"transport": {
|
||||
"method": "websocket",
|
||||
"session_id": session_id,
|
||||
}
|
||||
}
|
||||
]
|
||||
for(const subscription of subscriptions){
|
||||
fetch(url,{
|
||||
headers:headers,
|
||||
method:"POST",
|
||||
body:JSON.stringify(subscription)
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'notification':{
|
||||
switch(message.metadata.subscription_type){
|
||||
case 'channel.follow':{
|
||||
handle_event('follow')
|
||||
break
|
||||
}
|
||||
case 'channel.raid':{
|
||||
handle_event('raid')
|
||||
break
|
||||
}
|
||||
case 'channel.charity_campaign.donate':{
|
||||
handle_event('charity',message.event.amount.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ircSend(message){
|
||||
console.debug('< '+message)
|
||||
irc.send(message)
|
||||
}
|
||||
|
||||
async function init_irc(){
|
||||
if(irc){
|
||||
irc.close()
|
||||
}
|
||||
irc=new WebSocket('wss://irc-ws.chat.twitch.tv:443')
|
||||
irc.onclose=init_irc
|
||||
irc.onopen=function(){
|
||||
ircSend('CAP REQ twitch.tv/tags')
|
||||
ircSend('PASS oauth:'+tokens.access_token)
|
||||
ircSend('NICK '+tokens.login)
|
||||
ircSend('JOIN #'+tokens.login)
|
||||
}
|
||||
irc.onmessage=function(event){
|
||||
console.log(event)
|
||||
for(let data of event.data.split('\r\n')){
|
||||
console.debug('> '+data)
|
||||
/** @type string */
|
||||
data=data.split(':')
|
||||
const tags=data.shift()
|
||||
const type=data.shift()
|
||||
const message=data.join(':')
|
||||
console.debug(tags,type,message)
|
||||
if(!message){
|
||||
continue
|
||||
}
|
||||
if(!(tags.includes('broadcaster') || tags.includes('moderator'))){
|
||||
continue
|
||||
}
|
||||
const command=message.split(' ')
|
||||
console.debug(command)
|
||||
if(command.shift()!='!subathon'){
|
||||
continue
|
||||
}
|
||||
switch(command.shift()){
|
||||
case 'start':{
|
||||
start()
|
||||
break
|
||||
}
|
||||
case 'pause':{
|
||||
pause()
|
||||
break
|
||||
}
|
||||
case 'reset':{
|
||||
reset()
|
||||
break
|
||||
}
|
||||
case 'add':{
|
||||
add_time(parseReadableTimeIntoMilliseconds(command.shift()))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 10 MiB |
Reference in New Issue
Block a user