I’m trying to add a certain command to an already existent code of a Stream Elements widget named Stream Marathon Timer that creates a timer for twitch marathons, that adds time to your stream timer when you recieve subs, bits, etc (t You can find it on: Stream Elements Overlays Gallery >>> Wigdets
Search for Stream Marathon Timer
Click on Create >>> Create new overlay
and then open Settings >>> Open The Editor
Now you have all of the code (HTML,CSS,JS, including other data)
I have no clue on how to add a command to pause and resume the timer without bugging the ammount of time increased by events like subs, tips, raids, etc.
Could you please help me? I don’t know much of this stuff
You can help me so much bt editing this code,sharing an already existent code that does the same or make a new one. Since I’m not experienced I won’t understand much of the tips, but I’ll try my best to not take so much of your time. Sorry for the inconvenience and Thanks by now.
I’ve tried to use ChatGPT honestly.
Here’s a comparison to JS original code (1st) to ChatGPT full code(2nd):
//MULTIPLIERS:
let fieldData;
let maxTime = new Date(); // Time cap you want to use
let minTime = new Date();
let addOnZero = false;
let stopOnZero = false;
let start;
function countdown(seconds) {
if (seconds == 0) return;
let toCountDown = start;
if (stopOnZero && toCountDown < new Date()) return;
if (addOnZero) {
let a = [toCountDown, new Date()];
a.sort(function (a, b) {
return Date.parse(a) - Date.parse(b);
});
toCountDown = a[1];
}
toCountDown.setSeconds(toCountDown.getSeconds() + seconds);
let a = [toCountDown, maxTime];
a.sort(function (a, b) {
return Date.parse(a) - Date.parse(b);
});
toCountDown = new Date(a[0].getTime());
start = toCountDown;
$('#countdown').countdown(toCountDown, function (event) {
if (event.type === "finish") $(this).html(fieldData.onComplete);
else $(this).html(event.strftime('%I:%M:%S'));
});
saveState();
}
window.addEventListener('onEventReceived', function (obj) {
const listener = obj.detail.listener;
// Handling chat message
if (listener === 'message') {
console.log(obj.detail.event);
const {text, nick, tags, channel} = obj.detail.event.data;
const userstate = {
'mod': parseInt(tags.mod),
'sub': parseInt(tags.subscriber),
'vip': (tags.badges.indexOf("vip") !== -1),
'badges': {
'broadcaster': (nick === channel),
}
};
if (!(userstate.mod && fieldData['managePermissions'] === 'mods' || userstate.badges.broadcaster || fieldData.additionalUsers.includes(nick.toLowerCase()))) return;
if (text.startsWith(fieldData.addTimeCommand)) {
const seconds = parseFloat(text.split(' ')[1]) * 60;
if (isNaN(seconds)) return;
countdown(seconds);
}
return;
}
// Handling widget buttons
if (obj.detail.event) {
if (obj.detail.event.listener === 'widget-button') {
if (obj.detail.event.field === 'resetTimer') {
minTime = new Date();
minTime.setMinutes(minTime.getMinutes() + fieldData.minTime);
maxTime = new Date();
maxTime.setMinutes(maxTime.getMinutes() + fieldData.maxTime);
start = minTime;
countdown(1);
}
if (obj.detail.event.field === 'addTime') {
countdown(60);
}
return;
}
} else if (listener.indexOf("-latest") === -1) return;
const data = obj.detail.event;
if (listener === 'follower-latest') {
if (fieldData.followSeconds !== 0) countdown(fieldData.followSeconds);
} else if (listener === 'subscriber-latest') {
if (data.bulkGifted) { // Ignore gifting event and count only real subs
return;
}
if (parseInt(data.tier) === 2000) {
if (fieldData.sub2Seconds !== 0) countdown(fieldData.sub2Seconds);
} else if (parseInt(data.tier) === 3000) {
if (fieldData.sub3Seconds !== 0) countdown(fieldData.sub3Seconds);
} else {
if (fieldData.sub1Seconds !== 0) countdown(fieldData.sub1Seconds);
}
} else if (listener === 'host-latest') {
if (data['amount'] < fieldData.hostMin || fieldData.hostSeconds === 0) {
return;
}
countdown(fieldData.hostSeconds * data["amount"]);
} else if (listener === 'raid-latest') {
if (data['amount'] < fieldData.raidMin || fieldData.raidSeconds === 0) {
return;
}
countdown(fieldData.raidSeconds * data["amount"]);
} else if (listener === 'cheer-latest') {
if (data['amount'] < fieldData.cheerMin || fieldData.cheerSeconds === 0) {
return;
}
countdown(parseInt(fieldData.cheerSeconds * data["amount"] / 100));
} else if (listener === 'tip-latest') {
if (data['amount'] < fieldData.tipMin || fieldData.tipSeconds === 0) {
return;
}
countdown(parseInt(fieldData.tipSeconds * data["amount"]));
} else if (listener === 'merch-latest') {
if (fieldData.merchSeconds === 0) {
return;
}
countdown(parseInt(fieldData.merchSeconds * data["amount"]));
}
});
window.addEventListener('onWidgetLoad', function (obj) {
fieldData = obj.detail.fieldData;
addOnZero = (fieldData.addOnZero === "add");
stopOnZero = (fieldData.addOnZero === "stop");
fieldData.additionalUsers = fieldData.additionalUsers.toLowerCase().split(',').map(el => el.trim());
loadState();
});
function saveState() {
SE_API.store.set('marathon', {current: start, maxTime: maxTime, minTime: minTime});
}
function loadState() {
SE_API.store.get('marathon').then(obj => {
if (obj !== null) {
let current = new Date();
if (fieldData.preserveTime === "save") {
current = new Date(obj.current);
minTime = new Date(obj.minTime);
maxTime = new Date(obj.maxTime);
} else if (fieldData.preserveTime === "restart") {
minTime = new Date();
current = minTime;
minTime.setMinutes(minTime.getMinutes() + fieldData.minTime);
maxTime = new Date();
maxTime.setMinutes(maxTime.getMinutes() + fieldData.maxTime);
start = minTime;
}
if (current > 0) {
current = Math.max(current, minTime);
start = new Date(current);
countdown(1);
} else {
start = minTime;
countdown(0);
}
} else {
start = minTime;
countdown(0);
}
});
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Countdown Timer</title>
<!-- Include Google Fonts -->
<link href="https://fonts.googleapis.com/css?family={{fontName}}:400,{{fontWeight}}" rel="stylesheet">
<!-- Include jQuery library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Include Countdown.js library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.countdown/2.2.0/jquery.countdown.min.js"></script>
<style>
/* Apply styles to all elements */
* {
font-family: '{{fontName}}', sans-serif; /* Font family */
color: {{fontColor}}; /* Text color */
font-size: {{fontSize}}px; /* Font size */
font-weight: {{fontWeight}}; /* Font weight */
overflow: hidden; /* Hide overflow content */
text-align: {{textAlign}}; /* Text alignment */
-webkit-text-stroke-width: {{strokeSize}}px; /* Text stroke width */
-webkit-text-stroke-color: {{strokeColor}}; /* Text stroke color */
}
</style>
</head>
<body>
<div id="countdown"></div>
<script>
//MULTIPLIERS:
let fieldData;
let maxTime = new Date(); // Time cap you want to use
let minTime = new Date();
let addOnZero = false;
let stopOnZero = false;
let start;
let isTimerRunning = false;
function countdown(seconds) {
if (seconds == 0) return;
isTimerRunning = true; // Start or resume timer
let toCountDown = start;
if (stopOnZero && toCountDown < new Date()) return;
if (addOnZero) {
let a = [toCountDown, new Date()];
a.sort(function (a, b) {
return Date.parse(a) - Date.parse(b);
});
toCountDown = a[1];
}
toCountDown.setSeconds(toCountDown.getSeconds() + seconds);
let a = [toCountDown, maxTime];
a.sort(function (a, b) {
return Date.parse(a) - Date.parse(b);
});
toCountDown = new Date(a[0].getTime());
start = toCountDown;
$('#countdown').countdown(toCountDown, function (event) {
if (event.type === "finish") $(this).html(fieldData.onComplete);
else $(this).html(event.strftime('%I:%M:%S'));
});
saveState();
}
window.addEventListener('onEventReceived', function (obj) {
const listener = obj.detail.listener;
// Handling chat message
if (listener === 'message') {
console.log(obj.detail.event);
const {text, nick, tags, channel} = obj.detail.event.data;
const userstate = {
'mod': parseInt(tags.mod),
'sub': parseInt(tags.subscriber),
'vip': (tags.badges.indexOf("vip") !== -1),
'badges': {
'broadcaster': (nick === channel),
}
};
if (!(userstate.mod && fieldData['managePermissions'] === 'mods' || userstate.badges.broadcaster || fieldData.additionalUsers.includes(nick.toLowerCase()))) return;
if (text.startsWith(fieldData.addTimeCommand)) {
const seconds = parseFloat(text.split(' ')[1]) * 60;
if (isNaN(seconds)) return;
countdown(seconds);
}
if (text === fieldData.stopTimeCommand) {
$('#countdown').countdown('stop'); // Assuming you have a method to stop the countdown timer
if (isTimerRunning) {
saveState(); // Save current state only if the timer is running
isTimerRunning = false;
}
return;
}
if (text === fieldData.resumeTimeCommand) {
if (!isTimerRunning) {
loadState(); // Load the saved state only if the timer is not running
isTimerRunning = true;
}
$('#countdown').countdown('resume'); // Assuming you have a method to resume the countdown timer
return;
}
return;
}
// Handling widget buttons
if (obj.detail.event) {
if (obj.detail.event.listener === 'widget-button') {
if (obj.detail.event.field === 'resetTimer') {
minTime = new Date();
minTime.setMinutes(minTime.getMinutes() + fieldData.minTime);
maxTime = new Date();
maxTime.setMinutes(maxTime.getMinutes() + fieldData.maxTime);
start = minTime;
countdown(1);
}
if (obj.detail.event.field === 'addTime') {
countdown(60);
}
return;
}
} else if (listener.indexOf("-latest") === -1) return;
const data = obj.detail.event;
if (listener === 'follower-latest') {
if (fieldData.followSeconds !== 0) countdown(fieldData.followSeconds);
} else if (listener === 'subscriber-latest') {
if (data.bulkGifted) { // Ignore gifting event and count only real subs
return;
}
if (parseInt(data.tier) === 2000) {
if (fieldData.sub2Seconds !== 0) countdown(fieldData.sub2Seconds);
} else if (parseInt(data.tier) === 3000) {
if (fieldData.sub3Seconds !== 0) countdown(fieldData.sub3Seconds);
} else {
if (fieldData.sub1Seconds !== 0) countdown(fieldData.sub1Seconds);
}
} else if (listener === 'host-latest') {
if (data['amount'] < fieldData.hostMin || fieldData.hostSeconds === 0) {
return;
}
countdown(fieldData.hostSeconds * data["amount"]);
} else if (listener === 'raid-latest') {
if (data['amount'] < fieldData.raidMin || fieldData.raidSeconds === 0) {
return;
}
countdown(fieldData.raidSeconds * data["amount"]);
} else if (listener === 'cheer-latest') {
if (data['amount'] < fieldData.cheerMin || fieldData.cheerSeconds === 0) {
return;
}
countdown(parseInt(fieldData.cheerSeconds * data["amount"] / 100));
} else if (listener === 'tip-latest') {
if (data['amount'] < fieldData.tipMin || fieldData.tipSeconds === 0) {
return;
}
countdown(parseInt(fieldData.tipSeconds * data["amount"]));
} else if (listener === 'merch-latest') {
if (fieldData.merchSeconds === 0) {
return;
}
countdown(parseInt(fieldData.merchSeconds * data["amount"]));
}
});
window.addEventListener('onWidgetLoad', function (obj) {
fieldData = obj.detail.fieldData;
addOnZero = (fieldData.addOnZero === "add");
stopOnZero = (fieldData.addOnZero === "stop");
fieldData.additionalUsers = fieldData.additionalUsers.toLowerCase().split(',').map(el => el.trim());
loadState();
// Update fieldData with stop and resume commands
fieldData.stopTimeCommand = "!stoptimer";
fieldData.resumeTimeCommand = "!resumetimer";
});
function saveState() {
SE_API.store.set('marathon', {current: start, maxTime: maxTime, minTime: minTime, isTimerRunning: isTimerRunning});
}
function loadState() {
SE_API.store.get('marathon').then(obj => {
if (obj !== null) {
let current = new Date();
if (fieldData.preserveTime === "save") {
current = new Date(obj.current);
minTime = new Date(obj.minTime);
maxTime = new Date(obj.maxTime);
isTimerRunning = obj.isTimerRunning;
} else if (fieldData.preserveTime === "restart") {
minTime = new Date();
current = minTime;
minTime.setMinutes(minTime.getMinutes() + fieldData.minTime);
maxTime = new Date();
maxTime.setMinutes(maxTime.getMinutes() + fieldData.maxTime);
start = minTime;
}
if (current > 0 && isTimerRunning) {
current = Math.max(current, minTime);
start = new Date(current);
countdown(1);
} else {
start = minTime;
countdown(0);
}
} else {
start = minTime;
countdown(0);
}
});
}
</script>
</body>
</html>
Tonin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.