Skip to content

Commit aa2b2fd

Browse files
committed
Add AlertBox Overlay
1 parent 69d2563 commit aa2b2fd

11 files changed

Lines changed: 630 additions & 316 deletions

File tree

pages/css/alertBox.css

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
.alert-overlay {
2+
position: relative;
3+
}
4+
.alert-image {
5+
position: absolute;
6+
top: 50%;
7+
left: 50%;
8+
transform: translate(-50%, -50%);
9+
}
10+
.alert-text {
11+
position: absolute;
12+
top: 50%;
13+
left: 50%;
14+
margin-top: 170px;
15+
transform: translate(-50%, -50%);
16+
}
17+
.alert-main-text {
18+
padding-top: 30px;
19+
text-align: center;
20+
display: block;
21+
padding-bottom: 15px;
22+
font-family: Roboto;
23+
font-weight: 800;
24+
font-size: 1.5em;
25+
}
26+
.alert-sub-text {
27+
display: block;
28+
text-align: center;
29+
}
30+
@-webkit-keyframes fadeOut {
31+
0% {
32+
opacity: 1;
33+
}
34+
100% {
35+
opacity: 0;
36+
}
37+
}
38+
@keyframes fadeOut {
39+
0% {
40+
opacity: 1;
41+
}
42+
100% {
43+
opacity: 0;
44+
}
45+
}
46+
.fadeOut {
47+
-webkit-animation-name: fadeOut;
48+
animation-name: fadeOut;
49+
animation-duration: 2s;
50+
}
51+
@-webkit-keyframes fadeIn {
52+
0% {
53+
opacity: 0;
54+
}
55+
100% {
56+
opacity: 1;
57+
}
58+
}
59+
@keyframes fadeIn {
60+
0% {
61+
opacity: 0;
62+
}
63+
100% {
64+
opacity: 1;
65+
}
66+
}
67+
.fadeIn {
68+
-webkit-animation-name: fadeIn;
69+
animation-name: fadeIn;
70+
animation-duration: 2s;
71+
}

pages/img/alert-free-design.png

55.5 KB
Loading

pages/img/alert-prem-design.png

99.5 KB
Loading

pages/index.html

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,35 @@
8888
</div>
8989
</div>
9090
</div>
91+
<div class="subheader"><a href="/">Alert Box</a></div>
92+
<div class="prediction-container">
93+
<div class="img-container"> <img src="img/alert-free-design.png" width="460" height="340" alt=""/>
94+
<div class="body-text"> Free Alert Box Features:
95+
<div style="text-align: center;">
96+
<ul style="display: inline-block; text-align: left; vertical-align: top;">
97+
<li>Simple Fade In and Fade Out</li>
98+
<li>Supporting Subscribe, Follow, Cheer and Raid events</li>
99+
<li>Default Alert Sound</li>
100+
</ul>
101+
</div>
102+
</div>
103+
</div>
104+
<div class="img-container"> <img src="img/alert-prem-design.png" width="460" height="340" alt=""/>
105+
<div class="body-text"> Custom Alert Box Features:
106+
<div style="text-align: center;">
107+
<ul style="display: inline-block; text-align: left; vertical-align: top;">
108+
<li>Custom Design, Audio and Image in HTML and CSS</li>
109+
<li>Colored Text</li>
110+
<li>Animation Options</li>
111+
<li>To get a Custom Design, contact Logicism#9308 on Discord for quotes and pricing</li>
112+
<li>Changes to your design can be changed anytime for free</li>
113+
</ul>
114+
</div>
115+
</div>
116+
</div>
117+
</div>
91118
<div class="body-text">
92-
Get Started: <a class="login-button" href="https://id.twitch.tv/oauth2/authorize?response_type=code&client_id={client_id}&scope=channel:read:polls&redirect_uri={redirect_uri}"><i class="fa-brands fa-twitch"></i> Login to Twitch</a> <br>
119+
Get Started: <a class="login-button" href="https://id.twitch.tv/oauth2/authorize?response_type=code&client_id={client_id}&scope=moderator:read:followers+channel:read:subscriptions+bits:read&redirect_uri={redirect_uri}"><i class="fa-brands fa-twitch"></i> Login to Twitch</a> <br>
93120
<br>
94121
<br>
95122
<br>

pages/overlay/alert.mp3

91.2 KB
Binary file not shown.

pages/overlay/alerts.html

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600;700&display=swap" rel="stylesheet">
6+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
7+
<title>Logicism's Twitch Alert Box Overlay</title>
8+
<link href="/css/index.css" rel="stylesheet" type="text/css">
9+
<link href="/css/alertBox.css" rel="stylesheet" type="text/css">
10+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
11+
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
12+
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
13+
<link rel="manifest" href="/site.webmanifest">
14+
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
15+
<meta name="msapplication-TileColor" content="#da532c">
16+
<meta name="theme-color" content="#0084ff">
17+
<meta property="og:type" content="website">
18+
<meta property="og:title" content="Logicism's Twitch Overlays">
19+
<meta property="og:url" content="https://overlay.logicism.tv/">
20+
<meta property="og:image" content="https://logicism.tv/img/card-banner.png">
21+
<meta property="og:description" content="The Official Website of Live Streamer, Content Creator, Programmer and Graphic Designer Logicism!">
22+
<meta property="twitter:card" content="summary_large_image">
23+
<meta property="twitter:domain" content="overlay.logicism.tv">
24+
<meta property="twitter:url" content="https://overlay.logicism.tv/">
25+
<meta property="twitter:title" content="Logicism's Twitch Overlays">
26+
<meta property="twitter:description" content="Logicism's Twitch Overlays Programmed in HTML, CSS, Javascript with Twitch's API">
27+
<meta property="twitter:image" content="https://logicism.tv/img/card-banner.png">
28+
</head>
29+
<body>
30+
<div class="alerts-overlay fadeIn" style="display: none;"> <img class="alert-image" src="https://media4.giphy.com/avatars/100soft/WahNEDdlGjRZ.gif" alt=""/>
31+
<div class="alert-text">
32+
<span class="alert-main-text"></span>
33+
<span class="alert-sub-text"></span>
34+
</div>
35+
<audio class="alert-audio"></audio>
36+
</div>
37+
<script>
38+
const openSocket = () => {
39+
let timeoutId = 0;
40+
let timeoutId1 = 0;
41+
sock = new WebSocket("wss://ws.logicism.tv");
42+
43+
sock.addEventListener("open", e => {
44+
console.log("Connected to WebSocket Server");
45+
});
46+
47+
sock.addEventListener("message", e => {
48+
const messageObj = JSON.parse(e.data);
49+
50+
if (messageObj.subscription != undefined) {
51+
if (timeoutId != 0) {
52+
clearTimeout(timeoutId);
53+
timeoutId = 0;
54+
}
55+
if (timeoutId1 != 0) {
56+
clearTimeout(timeoutId1);
57+
timeoutId1 = 0;
58+
}
59+
60+
if (messageObj.subscription.type == "channel.follow") {
61+
document.getElementsByClassName("alert-main-text")[0].innerHTML = messageObj.event.user_name + " is now following " + messageObj.event.broadcaster_user_name;
62+
} else if (messageObj.subscription.type == "channel.subscribe" || messageObj.subscription.type == "channel.subscription.gift") {
63+
document.getElementsByClassName("alert-main-text")[0].innerHTML = messageObj.event.user_name + " has subscribed to " + messageObj.event.broadcaster_user_name;
64+
} else if (messageObj.subscription.type == "channel.raid") {
65+
document.getElementsByClassName("alert-main-text")[0].innerHTML = messageObj.event.user_name + " is raiding with " + messageObj.event.viewers + " viewers";
66+
} else if (messageObj.subscription.type == "channel.cheer") {
67+
document.getElementsByClassName("alert-main-text")[0].innerHTML = messageObj.event.user_name + " has cheered with " + messageObj.event.bits + " bits";
68+
document.getElementsByClassName("alert-sub-text")[0].innerHTML = messageObj.event.message;
69+
} else if (messageObj.subscription.type == "channel.subscription.message") {
70+
document.getElementsByClassName("alert-main-text")[0].innerHTML = messageObj.event.user_name + " has subscribed to " + messageObj.event.broadcaster_user_name;
71+
document.getElementsByClassName("alert-sub-text")[0].innerHTML = messageObj.event.message;
72+
}
73+
74+
if (document.getElementsByClassName("alerts-overlay")[0].getAttribute("style") != "display: inherit;") {
75+
document.getElementsByClassName("alerts-overlay")[0].setAttribute("style", "display: inherit;");
76+
}
77+
if (document.getElementsByClassName("alerts-overlay")[0].getAttribute("class") == "alerts-overlay fadeOut") {
78+
document.getElementsByClassName("alerts-overlay")[0].setAttribute("class", "alerts-overlay fadeIn");
79+
}
80+
81+
let audioF = document.getElementsByClassName("alert-audio")[0];
82+
audioF.src = "alert.mp3";
83+
audioF.play();
84+
audioF.onended = function() {
85+
if (messageObj.subscription.type == "channel.cheer") {
86+
audioF.src = "https://api.streamelements.com/kappa/v2/speech?voice=Brian&text=" + messageObj.event.message;
87+
audioF.play();
88+
89+
audioF.onended = undefined;
90+
}
91+
};
92+
93+
timeoutId = setTimeout(function () {
94+
document.getElementsByClassName("alerts-overlay")[0].setAttribute("class", "alerts-overlay fadeOut");
95+
96+
console.log("Removing Alerts Overlay");
97+
98+
timeoutId = 0;
99+
}, 7000);
100+
101+
timeoutId1 = setTimeout(function () {
102+
document.getElementsByClassName("alerts-overlay")[0].setAttribute("style", "display: none;");
103+
document.getElementsByClassName("alert-main-text")[0].innerHTML = "";
104+
document.getElementsByClassName("alert-sub-text")[0].innerHTML = "";
105+
106+
timeoutId1 = 0;
107+
}, 8500);
108+
109+
console.log("Displaying Alerts Overlay");
110+
} else {
111+
if (messageObj.type == "welcome") {
112+
sock.send(JSON.stringify({
113+
session_id: messageObj.session_id,
114+
type: "welcome",
115+
user_id: "53076312"
116+
}));
117+
}
118+
}
119+
});
120+
121+
sock.addEventListener("close", e => {
122+
setTimeout(function () {
123+
console.log("Reconnecting to WebSocket Server in 3 seconds");
124+
125+
openSocket();
126+
}, 3000)
127+
});
128+
};
129+
130+
openSocket();
131+
</script>
132+
</body>
133+
</html>

src/me/Logicism/TwitchOverlayServer/TwitchOverlayServer.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public static void main(String[] args) {
5656
server.createContext("/webhook", new WebhookHandler());
5757
server.createContext("/overlay", new OverlayHandler());
5858

59-
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
59+
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
6060
server.setExecutor(executor);
6161

6262
server.start();
@@ -130,6 +130,33 @@ public TokenHandle getTokenHandle(String userId, String scope) {
130130
return null;
131131
}
132132

133+
public void refreshHandle(String userAgent, TokenHandle handle) throws IOException {
134+
handle.refreshToken(userAgent);
135+
136+
if (TwitchOverlayServer.INSTANCE.getTokenHandleExpirations().containsKey(handle)) {
137+
TwitchOverlayServer.INSTANCE.getTokenHandleExpirations().get(handle)
138+
.cancel(true);
139+
140+
TwitchOverlayServer.INSTANCE.getTokenHandleExpirations().replace(handle,
141+
TwitchOverlayServer.INSTANCE.getWebsocketServer().getExecutor()
142+
.schedule(new Runnable() {
143+
@Override
144+
public void run() {
145+
handle.setExpired(true);
146+
}
147+
}, handle.getTimeToExpire(), TimeUnit.SECONDS));
148+
} else {
149+
TwitchOverlayServer.INSTANCE.getTokenHandleExpirations()
150+
.put(handle, TwitchOverlayServer.INSTANCE.getWebsocketServer().getExecutor()
151+
.schedule(new Runnable() {
152+
@Override
153+
public void run() {
154+
handle.setExpired(true);
155+
}
156+
}, handle.getTimeToExpire(), TimeUnit.SECONDS));
157+
}
158+
}
159+
133160
public void readTokenHandleList(File file) throws IOException, ClassNotFoundException {
134161
ObjectInputStream databaseInputStream = new ObjectInputStream(new FileInputStream(file));
135162

src/me/Logicism/TwitchOverlayServer/http/handlers/OverlayHandler.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,25 @@ public void handle(HttpExchange exchange) throws IOException {
5858
} else {
5959
HTTPUtils.throwError(exchange, "URL does not have id query!");
6060
}
61+
} else if (exchange.getRequestURI().toString().startsWith("/overlay/alerts")) {
62+
Map<String, String> queryMap = TextUtils.queryToMap(exchange.getRequestURI().getQuery());
63+
if (queryMap.containsKey("id")) {
64+
if (TwitchOverlayServer.INSTANCE.containsUserTokenHandle(queryMap.get("id"),
65+
"bits:read")) {
66+
if (HTTPUtils.containsFile("/overlay/alerts-premium/" + queryMap.get("id") + ".html")) {
67+
HTTPUtils.throwSuccessPage(exchange, HTTPUtils.getFile("/overlay/alerts-premium/" + queryMap.get("id") + ".html"));
68+
} else {
69+
String response = FileUtils.fileToString(HTTPUtils.getFile("/overlay/alerts.html"))
70+
.replace("{user_id}", queryMap.get("id"));
71+
72+
HTTPUtils.throwSuccessHTML(exchange, response);
73+
}
74+
} else {
75+
HTTPUtils.throwError(exchange, "User is not authenticated! Please reauthenticate and refresh!");
76+
}
77+
} else {
78+
HTTPUtils.throwError(exchange, "URL does not have id query!");
79+
}
6180
} else {
6281
HTTPUtils.throwError(exchange, "Cannot find that overlay!");
6382
}

0 commit comments

Comments
 (0)