summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2024-07-31 22:59:58 -0400
committerLLLL Colonq <llll@colonq>2024-07-31 22:59:58 -0400
commit7ffb7b021eec46f2d714e04b47d752012e1bf8ea (patch)
tree15d9af7555300bd2b452dda55747cf5870b747d3
parent92556dc23ead56ed2c2d2bcc752fe0e7378fa022 (diff)
Frontend updates
-rw-r--r--fig-frontend-client/Makefile23
-rw-r--r--fig-frontend-client/config-deploy.m42
-rw-r--r--fig-frontend-client/config-extension.js2
-rw-r--r--fig-frontend-client/config-test.m42
-rw-r--r--fig-frontend-client/extension/main.css0
-rw-r--r--fig-frontend-client/extension/manifest.dhall2
-rw-r--r--fig-frontend-client/main.css6
-rw-r--r--fig-frontend-client/main.js464
-rw-r--r--fig-frontend-client/src/Config.js1
-rw-r--r--fig-frontend-client/src/Config.purs1
-rw-r--r--fig-frontend-client/src/Main.purs71
-rw-r--r--fig-frontend-client/src/Model.js12
-rw-r--r--fig-frontend-client/src/UI.js2
-rw-r--r--fig-frontend-client/src/UI.purs13
-rw-r--r--fig-frontend-client/templates/index.html (renamed from fig-frontend-client/index-template.html)2
-rw-r--r--fig-frontend-client/templates/obs.html18
-rw-r--r--fig-monitor-twitch/main/Main.hs3
-rw-r--r--fig-monitor-twitch/src/Fig/Monitor/Twitch.hs20
-rw-r--r--fig-monitor-twitch/src/Fig/Monitor/Twitch/Utils.hs3
19 files changed, 536 insertions, 111 deletions
diff --git a/fig-frontend-client/Makefile b/fig-frontend-client/Makefile
index 1f01f50..88295f0 100644
--- a/fig-frontend-client/Makefile
+++ b/fig-frontend-client/Makefile
@@ -1,8 +1,10 @@
-.PHONY: all deploy extension clean
+.PHONY: all dist deploy extension clean
-all: dist/test/index.html dist/test/assets dist/test/main.js dist/test/main.css
+TEMPLATES=$(shell ls templates)
-deploy: dist/deploy/index.html dist/deploy/assets dist/deploy/main.js dist/deploy/main.css
+all: dist $(addprefix dist/test/,$(TEMPLATES)) dist/test/assets dist/test/main.js dist/test/main.css
+
+deploy: dist $(addprefix dist/deploy/,$(TEMPLATES)) dist/deploy/assets dist/deploy/main.js dist/deploy/main.css
rsync -av dist/deploy/ "pub.colonq.computer:~/public_html/"
dist:
@@ -20,17 +22,30 @@ dist/%/assets: $(shell find assets) dist
dist/%/main.js: main.js dist
cp $< $@
+dist/extension/main.css: extension/main.css dist
+ cp $< $@
+
dist/%/main.css: main.css dist
cp $< $@
dist/%/index.html: config-%.m4 dist index-template.html
sh -c "m4 $< >$@"
-extension: dist/extension/assets dist/extension/manifest.json dist/extension/background.js dist/extension/main.js dist/extension/main.css
+
+define GEN_RULE
+dist/%/$(template): config-%.m4 templates/$(template)
+ sh -c "m4 $$^ >$$@"
+endef
+$(foreach template,$(TEMPLATES), $(eval $(GEN_RULE)))
+
+extension: dist dist/extension/assets dist/extension/manifest.json dist/extension/background.js dist/extension/main.js dist/extension/main.css dist/extension/config.js
dist/extension/manifest.json: extension/manifest.dhall
dhall-to-json <$< >$@
+dist/extension/config.js: config-extension.js
+ cp $< $@
+
dist/extension/%: extension/%
cp $< $@
diff --git a/fig-frontend-client/config-deploy.m4 b/fig-frontend-client/config-deploy.m4
index 504bb3e..97fc61f 100644
--- a/fig-frontend-client/config-deploy.m4
+++ b/fig-frontend-client/config-deploy.m4
@@ -1,4 +1,4 @@
define(`CONFIG_SUBST', `
+globalThis.mode = 0;
globalThis.apiServer = "https://api.colonq.computer/api";
')
-include(`index-template.html')
diff --git a/fig-frontend-client/config-extension.js b/fig-frontend-client/config-extension.js
new file mode 100644
index 0000000..44b69d3
--- /dev/null
+++ b/fig-frontend-client/config-extension.js
@@ -0,0 +1,2 @@
+globalThis.mode = 1;
+globalThis.apiServer = "https://api.colonq.computer/api";
diff --git a/fig-frontend-client/config-test.m4 b/fig-frontend-client/config-test.m4
index f1e6c16..0b876e0 100644
--- a/fig-frontend-client/config-test.m4
+++ b/fig-frontend-client/config-test.m4
@@ -1,4 +1,4 @@
define(`CONFIG_SUBST', `
+globalThis.mode = 0;
globalThis.apiServer = "http://localhost:8000/api";
')
-include(`index-template.html')
diff --git a/fig-frontend-client/extension/main.css b/fig-frontend-client/extension/main.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fig-frontend-client/extension/main.css
diff --git a/fig-frontend-client/extension/manifest.dhall b/fig-frontend-client/extension/manifest.dhall
index 87c48f6..cf9e7a1 100644
--- a/fig-frontend-client/extension/manifest.dhall
+++ b/fig-frontend-client/extension/manifest.dhall
@@ -22,7 +22,7 @@
}
, content_scripts =
[ { matches = ["*://*.twitch.tv/*"]
- , js = ["main.js"]
+ , js = ["config.js", "main.js"]
, css = ["main.css"]
, run_at = "document_end"
}
diff --git a/fig-frontend-client/main.css b/fig-frontend-client/main.css
index 3305e19..7714273 100644
--- a/fig-frontend-client/main.css
+++ b/fig-frontend-client/main.css
@@ -16,7 +16,7 @@ html, body {
width: 100%;
}
-body {
+body.lcolonq-index {
font-family: "Iosevka Comfy";
font-weight: bold;
color: black;
@@ -29,6 +29,10 @@ body {
linear-gradient(to bottom, grey 1px, transparent 1px);
}
+body.lcolonq-obs {
+ background-color: rbga(0,0,0,0);
+}
+
#lcolonq-title {
position: absolute;
top: 2rem;
diff --git a/fig-frontend-client/main.js b/fig-frontend-client/main.js
index 67e726e..26c1be2 100644
--- a/fig-frontend-client/main.js
+++ b/fig-frontend-client/main.js
@@ -118,9 +118,9 @@ var $$void = function(dictFunctor) {
return map(dictFunctor)($$const(unit));
};
var voidRight = function(dictFunctor) {
- var map12 = map(dictFunctor);
+ var map13 = map(dictFunctor);
return function(x) {
- return map12($$const(x));
+ return map13($$const(x));
};
};
var functorArray = {
@@ -223,12 +223,32 @@ var EQ = /* @__PURE__ */ function() {
return EQ2;
}();
+// output/Data.Semigroup/foreign.js
+var concatArray = function(xs) {
+ return function(ys) {
+ if (xs.length === 0)
+ return ys;
+ if (ys.length === 0)
+ return xs;
+ return xs.concat(ys);
+ };
+};
+
// output/Data.Semigroup/index.js
+var semigroupArray = {
+ append: concatArray
+};
var append = function(dict) {
return dict.append;
};
// output/Data.Monoid/index.js
+var monoidArray = {
+ mempty: [],
+ Semigroup0: function() {
+ return semigroupArray;
+ }
+};
var mempty = function(dict) {
return dict.mempty;
};
@@ -296,15 +316,16 @@ var liftEffect = function(dict) {
// output/Audio/index.js
var playVoice = function(dictMonadEffect) {
- var liftEffect5 = liftEffect(dictMonadEffect);
+ var liftEffect6 = liftEffect(dictMonadEffect);
return function(b) {
return function(i) {
- return liftEffect5(_playVoice(b)(i));
+ return liftEffect6(_playVoice(b)(i));
};
};
};
// output/Config/foreign.js
+var mode = globalThis.mode;
var apiServer = globalThis.apiServer;
// output/Data.Array/foreign.js
@@ -335,6 +356,9 @@ var replicatePolyfill = function(count, value12) {
return result;
};
var replicateImpl = typeof Array.prototype.fill === "function" ? replicateFill : replicatePolyfill;
+var indexImpl = function(just, nothing, xs, i) {
+ return i < 0 || i >= xs.length ? nothing : just(xs[i]);
+};
// output/Control.Alt/index.js
var alt = function(dict) {
@@ -635,6 +659,7 @@ var unwrap = function() {
};
// output/Data.Foldable/index.js
+var identity5 = /* @__PURE__ */ identity(categoryFn);
var foldr = function(dict) {
return dict.foldr;
};
@@ -680,6 +705,15 @@ var foldableArray = {
return foldMapDefaultR(foldableArray)(dictMonoid);
}
};
+var foldMap = function(dict) {
+ return dict.foldMap;
+};
+var fold = function(dictFoldable) {
+ var foldMap2 = foldMap(dictFoldable);
+ return function(dictMonoid) {
+ return foldMap2(dictMonoid)(identity5);
+ };
+};
// output/Data.Function.Uncurried/foreign.js
var runFn2 = function(fn) {
@@ -698,9 +732,26 @@ var runFn3 = function(fn) {
};
};
};
+var runFn4 = function(fn) {
+ return function(a) {
+ return function(b) {
+ return function(c) {
+ return function(d) {
+ return fn(a, b, c, d);
+ };
+ };
+ };
+ };
+};
// output/Data.Array/index.js
var range2 = /* @__PURE__ */ runFn2(rangeImpl);
+var index = /* @__PURE__ */ function() {
+ return runFn4(indexImpl)(Just.create)(Nothing.value);
+}();
+var head = function(xs) {
+ return index(xs)(0);
+};
// output/Effect.Aff/foreign.js
var Aff = function() {
@@ -1215,7 +1266,7 @@ var Aff = function() {
var root = EMPTY;
function kill(error3, par2, cb2) {
var step2 = par2;
- var head = null;
+ var head2 = null;
var tail = null;
var count = 0;
var kills2 = {};
@@ -1236,14 +1287,14 @@ var Aff = function() {
};
});
}
- if (head === null) {
+ if (head2 === null) {
break loop;
}
- step2 = head._2;
+ step2 = head2._2;
if (tail === null) {
- head = null;
+ head2 = null;
} else {
- head = tail._1;
+ head2 = tail._1;
tail = tail._2;
}
break;
@@ -1252,10 +1303,10 @@ var Aff = function() {
break;
case APPLY:
case ALT:
- if (head) {
- tail = new Aff2(CONS, head, tail);
+ if (head2) {
+ tail = new Aff2(CONS, head2, tail);
}
- head = step2;
+ head2 = step2;
step2 = step2._1;
break;
}
@@ -1271,7 +1322,7 @@ var Aff = function() {
}
return kills2;
}
- function join2(result, head, tail) {
+ function join2(result, head2, tail) {
var fail2, step2, lhs, rhs, tmp, kid;
if (util.isLeft(result)) {
fail2 = result;
@@ -1289,30 +1340,30 @@ var Aff = function() {
if (interrupt !== null) {
return;
}
- if (head === null) {
+ if (head2 === null) {
cb(fail2 || step2)();
return;
}
- if (head._3 !== EMPTY) {
+ if (head2._3 !== EMPTY) {
return;
}
- switch (head.tag) {
+ switch (head2.tag) {
case MAP:
if (fail2 === null) {
- head._3 = util.right(head._1(util.fromRight(step2)));
- step2 = head._3;
+ head2._3 = util.right(head2._1(util.fromRight(step2)));
+ step2 = head2._3;
} else {
- head._3 = fail2;
+ head2._3 = fail2;
}
break;
case APPLY:
- lhs = head._1._3;
- rhs = head._2._3;
+ lhs = head2._1._3;
+ rhs = head2._2._3;
if (fail2) {
- head._3 = fail2;
+ head2._3 = fail2;
tmp = true;
kid = killId++;
- kills[kid] = kill(early, fail2 === lhs ? head._2 : head._1, function() {
+ kills[kid] = kill(early, fail2 === lhs ? head2._2 : head2._1, function() {
return function() {
delete kills[kid];
if (tmp) {
@@ -1332,24 +1383,24 @@ var Aff = function() {
return;
} else {
step2 = util.right(util.fromRight(lhs)(util.fromRight(rhs)));
- head._3 = step2;
+ head2._3 = step2;
}
break;
case ALT:
- lhs = head._1._3;
- rhs = head._2._3;
+ lhs = head2._1._3;
+ rhs = head2._2._3;
if (lhs === EMPTY && util.isLeft(rhs) || rhs === EMPTY && util.isLeft(lhs)) {
return;
}
if (lhs !== EMPTY && util.isLeft(lhs) && rhs !== EMPTY && util.isLeft(rhs)) {
fail2 = step2 === lhs ? rhs : lhs;
step2 = null;
- head._3 = fail2;
+ head2._3 = fail2;
} else {
- head._3 = step2;
+ head2._3 = step2;
tmp = true;
kid = killId++;
- kills[kid] = kill(early, step2 === lhs ? head._2 : head._1, function() {
+ kills[kid] = kill(early, step2 === lhs ? head2._2 : head2._1, function() {
return function() {
delete kills[kid];
if (tmp) {
@@ -1369,9 +1420,9 @@ var Aff = function() {
break;
}
if (tail === null) {
- head = null;
+ head2 = null;
} else {
- head = tail._1;
+ head2 = tail._1;
tail = tail._2;
}
}
@@ -1388,7 +1439,7 @@ var Aff = function() {
function run3() {
var status2 = CONTINUE;
var step2 = par;
- var head = null;
+ var head2 = null;
var tail = null;
var tmp, fid;
loop:
@@ -1399,31 +1450,31 @@ var Aff = function() {
case CONTINUE:
switch (step2.tag) {
case MAP:
- if (head) {
- tail = new Aff2(CONS, head, tail);
+ if (head2) {
+ tail = new Aff2(CONS, head2, tail);
}
- head = new Aff2(MAP, step2._1, EMPTY, EMPTY);
+ head2 = new Aff2(MAP, step2._1, EMPTY, EMPTY);
step2 = step2._2;
break;
case APPLY:
- if (head) {
- tail = new Aff2(CONS, head, tail);
+ if (head2) {
+ tail = new Aff2(CONS, head2, tail);
}
- head = new Aff2(APPLY, EMPTY, step2._2, EMPTY);
+ head2 = new Aff2(APPLY, EMPTY, step2._2, EMPTY);
step2 = step2._1;
break;
case ALT:
- if (head) {
- tail = new Aff2(CONS, head, tail);
+ if (head2) {
+ tail = new Aff2(CONS, head2, tail);
}
- head = new Aff2(ALT, EMPTY, step2._2, EMPTY);
+ head2 = new Aff2(ALT, EMPTY, step2._2, EMPTY);
step2 = step2._1;
break;
default:
fid = fiberId++;
status2 = RETURN;
tmp = step2;
- step2 = new Aff2(FORKED, fid, new Aff2(CONS, head, tail), EMPTY);
+ step2 = new Aff2(FORKED, fid, new Aff2(CONS, head2, tail), EMPTY);
tmp = Fiber(util, supervisor, tmp);
tmp.onComplete({
rethrow: false,
@@ -1436,21 +1487,21 @@ var Aff = function() {
}
break;
case RETURN:
- if (head === null) {
+ if (head2 === null) {
break loop;
}
- if (head._1 === EMPTY) {
- head._1 = step2;
+ if (head2._1 === EMPTY) {
+ head2._1 = step2;
status2 = CONTINUE;
- step2 = head._2;
- head._2 = EMPTY;
+ step2 = head2._2;
+ head2._2 = EMPTY;
} else {
- head._2 = step2;
- step2 = head;
+ head2._2 = step2;
+ step2 = head2;
if (tail === null) {
- head = null;
+ head2 = null;
} else {
- head = tail._1;
+ head2 = tail._1;
tail = tail._2;
}
}
@@ -1595,10 +1646,10 @@ var mapExceptT = function(f) {
};
};
var functorExceptT = function(dictFunctor) {
- var map12 = map(dictFunctor);
+ var map13 = map(dictFunctor);
return {
map: function(f) {
- return mapExceptT(map12(map2(f)));
+ return mapExceptT(map13(map2(f)));
}
};
};
@@ -1677,7 +1728,7 @@ var parallel = function(dict) {
};
// output/Control.Parallel/index.js
-var identity5 = /* @__PURE__ */ identity(categoryFn);
+var identity6 = /* @__PURE__ */ identity(categoryFn);
var parTraverse_ = function(dictParallel) {
var sequential2 = sequential(dictParallel);
var parallel3 = parallel(dictParallel);
@@ -1701,7 +1752,7 @@ var parSequence_ = function(dictParallel) {
return function(dictApplicative) {
var parTraverse_2 = parTraverse_1(dictApplicative);
return function(dictFoldable) {
- return parTraverse_2(dictFoldable)(identity5);
+ return parTraverse_2(dictFoldable)(identity6);
};
};
};
@@ -2681,11 +2732,8 @@ var fetch2 = function() {
// output/Model/foreign.js
var canvas = document.getElementById("lcolonq-canvas");
-var socket = new WebSocket("wss://colonq.computer/bullfrog/api/channel/listen/model");
+var socket = null;
var currentFrame = null;
-socket.addEventListener("open", (ev) => {
- console.log("connected");
-});
async function decompress(blob3) {
let ds = new DecompressionStream("gzip");
let stream = blob3.stream();
@@ -2743,7 +2791,7 @@ function readPacket(dv) {
}
}
function renderCellCanvas(ctx2, x, y, c) {
- if (c) {
+ if (c && c.type === "fg") {
let msg = c.g1 ? String.fromCodePoint(c.g0, c.g1) : String.fromCodePoint(c.g0);
if (msg.trim().length) {
ctx2.fillStyle = "black";
@@ -2772,6 +2820,10 @@ function renderCanvas() {
}
}
var _startModel = () => {
+ socket = new WebSocket("wss://colonq.computer/bullfrog/api/channel/listen/model");
+ socket.addEventListener("open", (ev) => {
+ console.log("connected");
+ });
socket.addEventListener("message", async (ev) => {
let arr = await decompress(ev.data);
let view = new DataView(arr);
@@ -2785,6 +2837,38 @@ var startModel = function(dictMonadEffect) {
return liftEffect(dictMonadEffect)(_startModel);
};
+// output/UI/foreign.js
+var _setInterval = (delay) => (f) => () => setInterval(f, delay);
+
+// output/UI/index.js
+var setInterval2 = function(dictMonadEffect) {
+ var liftEffect6 = liftEffect(dictMonadEffect);
+ return function(d) {
+ return function(f) {
+ return liftEffect6(_setInterval(d)(f));
+ };
+ };
+};
+
+// output/Web.DOM.DOMTokenList/foreign.js
+function add2(list) {
+ return function(token) {
+ return function() {
+ return list.add(token);
+ };
+ };
+}
+
+// output/Data.Nullable/foreign.js
+function nullable(a, r, f) {
+ return a == null ? r : f(a);
+}
+
+// output/Data.Nullable/index.js
+var toMaybe = function(n) {
+ return nullable(n, Nothing.value, Just.create);
+};
+
// output/Web.DOM.Document/foreign.js
var getEffProp = function(name15) {
return function(doc) {
@@ -2800,18 +2884,52 @@ var compatMode = getEffProp("compatMode");
var characterSet = getEffProp("characterSet");
var contentType = getEffProp("contentType");
var _documentElement = getEffProp("documentElement");
+function createElement(localName2) {
+ return function(doc) {
+ return function() {
+ return doc.createElement(localName2);
+ };
+ };
+}
+function createTextNode(data) {
+ return function(doc) {
+ return function() {
+ return doc.createTextNode(data);
+ };
+ };
+}
-// output/Data.Nullable/foreign.js
-function nullable(a, r, f) {
- return a == null ? r : f(a);
+// output/Web.Internal.FFI/foreign.js
+function _unsafeReadProtoTagged(nothing, just, name15, value12) {
+ if (typeof window !== "undefined") {
+ var ty = window[name15];
+ if (ty != null && value12 instanceof ty) {
+ return just(value12);
+ }
+ }
+ var obj = value12;
+ while (obj != null) {
+ var proto = Object.getPrototypeOf(obj);
+ var constructorName = proto.constructor.name;
+ if (constructorName === name15) {
+ return just(value12);
+ } else if (constructorName === "Object") {
+ return nothing;
+ }
+ obj = proto;
+ }
+ return nothing;
}
-// output/Data.Nullable/index.js
-var toMaybe = function(n) {
- return nullable(n, Nothing.value, Just.create);
+// output/Web.Internal.FFI/index.js
+var unsafeReadProtoTagged = function(name15) {
+ return function(value12) {
+ return _unsafeReadProtoTagged(Nothing.value, Just.create, name15, value12);
+ };
};
// output/Web.DOM.Document/index.js
+var toParentNode = unsafeCoerce2;
var toNonElementParentNode = unsafeCoerce2;
// output/Web.DOM.Element/foreign.js
@@ -2824,6 +2942,11 @@ var _namespaceURI = getProp("namespaceURI");
var _prefix = getProp("prefix");
var localName = getProp("localName");
var tagName = getProp("tagName");
+function classList(element) {
+ return function() {
+ return element.classList;
+ };
+}
// output/Web.DOM.ParentNode/foreign.js
var getEffProp2 = function(name15) {
@@ -2837,10 +2960,18 @@ var children = getEffProp2("children");
var _firstElementChild = getEffProp2("firstElementChild");
var _lastElementChild = getEffProp2("lastElementChild");
var childElementCount = getEffProp2("childElementCount");
+function querySelectorAll(selector) {
+ return function(node) {
+ return function() {
+ return node.querySelectorAll(selector);
+ };
+ };
+}
// output/Web.DOM.Element/index.js
var toNode = unsafeCoerce2;
var toEventTarget = unsafeCoerce2;
+var fromNode = /* @__PURE__ */ unsafeReadProtoTagged("Element");
// output/Web.DOM.Node/foreign.js
var getEffProp3 = function(name15) {
@@ -2868,6 +2999,20 @@ function setTextContent(value12) {
};
};
}
+function appendChild(node) {
+ return function(parent2) {
+ return function() {
+ parent2.appendChild(node);
+ };
+ };
+}
+
+// output/Web.DOM.NodeList/foreign.js
+function toArray2(list) {
+ return function() {
+ return [].slice.call(list);
+ };
+}
// output/Web.DOM.NonElementParentNode/foreign.js
function _getElementById(id2) {
@@ -2888,6 +3033,9 @@ var getElementById = function(eid) {
};
};
+// output/Web.DOM.Text/index.js
+var toNode2 = unsafeCoerce2;
+
// output/Web.Event.EventTarget/foreign.js
function eventListener(fn) {
return function() {
@@ -2925,30 +3073,89 @@ function document2(window2) {
// output/Main/index.js
var map6 = /* @__PURE__ */ map(functorEffect);
+var fold2 = /* @__PURE__ */ fold(foldableArray)(monoidArray);
+var map12 = /* @__PURE__ */ map(functorArray);
+var startModel2 = /* @__PURE__ */ startModel(monadEffectAff);
var bind4 = /* @__PURE__ */ bind(bindAff);
var fetch3 = /* @__PURE__ */ fetch2()()(/* @__PURE__ */ toCoreRequestOptionsRowRo()()(toCoreRequestOptionsHelpe));
-var discard2 = /* @__PURE__ */ discard(discardUnit)(bindAff);
-var startModel2 = /* @__PURE__ */ startModel(monadEffectAff);
+var discard2 = /* @__PURE__ */ discard(discardUnit);
+var discard1 = /* @__PURE__ */ discard2(bindAff);
+var liftEffect5 = /* @__PURE__ */ liftEffect(monadEffectAff);
var for_2 = /* @__PURE__ */ for_(applicativeAff)(foldableArray);
var show2 = /* @__PURE__ */ show(showInt);
var playVoice2 = /* @__PURE__ */ playVoice(monadEffectEffect);
+var setInterval3 = /* @__PURE__ */ setInterval2(monadEffectAff);
var setText5 = function(dictMonadEffect) {
- var liftEffect5 = liftEffect(dictMonadEffect);
+ var liftEffect1 = liftEffect(dictMonadEffect);
return function(e) {
return function(s) {
- return liftEffect5(setTextContent(s)(toNode(e)));
+ return liftEffect1(setTextContent(s)(toNode(e)));
};
};
};
var setText1 = /* @__PURE__ */ setText5(monadEffectAff);
+var maybeToArray = function(v) {
+ if (v instanceof Just) {
+ return [v.value0];
+ }
+ ;
+ if (v instanceof Nothing) {
+ return [];
+ }
+ ;
+ throw new Error("Failed pattern match at Main (line 35, column 1 - line 35, column 45): " + [v.constructor.name]);
+};
+var queryAll = function(dictMonadEffect) {
+ var Monad0 = dictMonadEffect.Monad0();
+ var bind22 = bind(Monad0.Bind1());
+ var liftEffect1 = liftEffect(dictMonadEffect);
+ var pure3 = pure(Monad0.Applicative0());
+ return function(q) {
+ return bind22(liftEffect1(windowImpl))(function(w) {
+ return bind22(liftEffect1(map6(toDocument)(document2(w))))(function(d) {
+ return bind22(liftEffect1(querySelectorAll(q)(toParentNode(d))))(function(nl) {
+ return bind22(liftEffect1(toArray2(nl)))(function(ns) {
+ return pure3(fold2(map12(function($95) {
+ return maybeToArray(fromNode($95));
+ })(ns)));
+ });
+ });
+ });
+ });
+ };
+};
+var query = function(dictMonadEffect) {
+ var Monad0 = dictMonadEffect.Monad0();
+ var bind22 = bind(Monad0.Bind1());
+ var queryAll1 = queryAll(dictMonadEffect);
+ var liftEffect1 = liftEffect(dictMonadEffect);
+ var pure3 = pure(Monad0.Applicative0());
+ return function(q) {
+ return bind22(queryAll1(q))(function($96) {
+ return function(v) {
+ if (v instanceof Nothing) {
+ return liftEffect1($$throw("could not find element matching query: " + q));
+ }
+ ;
+ if (v instanceof Just) {
+ return pure3(v.value0);
+ }
+ ;
+ throw new Error("Failed pattern match at Main (line 57, column 27 - line 59, column 21): " + [v.constructor.name]);
+ }(head($96));
+ });
+ };
+};
+var query1 = /* @__PURE__ */ query(monadEffectEffect);
+var mainObs = /* @__PURE__ */ launchAff_(startModel2);
var listen2 = function(dictMonadEffect) {
- var bind1 = bind(dictMonadEffect.Monad0().Bind1());
- var liftEffect5 = liftEffect(dictMonadEffect);
+ var bind22 = bind(dictMonadEffect.Monad0().Bind1());
+ var liftEffect1 = liftEffect(dictMonadEffect);
return function(e) {
return function(ev) {
return function(f) {
- return bind1(liftEffect5(eventListener(f)))(function(l) {
- return liftEffect5(addEventListener(ev)(l)(false)(toEventTarget(e)));
+ return bind22(liftEffect1(eventListener(f)))(function(l) {
+ return liftEffect1(addEventListener(ev)(l)(false)(toEventTarget(e)));
});
};
};
@@ -2957,22 +3164,22 @@ var listen2 = function(dictMonadEffect) {
var listen1 = /* @__PURE__ */ listen2(monadEffectAff);
var byId = function(dictMonadEffect) {
var Monad0 = dictMonadEffect.Monad0();
- var bind1 = bind(Monad0.Bind1());
- var liftEffect5 = liftEffect(dictMonadEffect);
+ var bind22 = bind(Monad0.Bind1());
+ var liftEffect1 = liftEffect(dictMonadEffect);
var pure3 = pure(Monad0.Applicative0());
return function(i) {
- return bind1(liftEffect5(windowImpl))(function(w) {
- return bind1(liftEffect5(map6(toDocument)(document2(w))))(function(d) {
- return bind1(liftEffect5(getElementById(i)(toNonElementParentNode(d))))(function(v) {
+ return bind22(liftEffect1(windowImpl))(function(w) {
+ return bind22(liftEffect1(map6(toDocument)(document2(w))))(function(d) {
+ return bind22(liftEffect1(getElementById(i)(toNonElementParentNode(d))))(function(v) {
if (v instanceof Nothing) {
- return liftEffect5($$throw("could not find element with id: " + i));
+ return liftEffect1($$throw("could not find element with id: " + i));
}
;
if (v instanceof Just) {
return pure3(v.value0);
}
;
- throw new Error("Failed pattern match at Main (line 32, column 80 - line 34, column 21): " + [v.constructor.name]);
+ throw new Error("Failed pattern match at Main (line 43, column 80 - line 45, column 21): " + [v.constructor.name]);
});
});
});
@@ -2984,19 +3191,19 @@ var updateSubtitle = /* @__PURE__ */ bind4(/* @__PURE__ */ byId1("lcolonq-subtit
return bind4(v.text)(setText1(subtitle));
});
});
-var main = /* @__PURE__ */ launchAff_(/* @__PURE__ */ discard2(/* @__PURE__ */ liftEffect(monadEffectAff)(/* @__PURE__ */ log("hi")))(function() {
- return discard2(startModel2)(function() {
+var mainHomepage = /* @__PURE__ */ launchAff_(/* @__PURE__ */ discard1(/* @__PURE__ */ liftEffect5(/* @__PURE__ */ log("hi")))(function() {
+ return discard1(startModel2)(function() {
return bind4(byId1("lcolonq-marquee"))(function(marq) {
return bind4(fetch3(apiServer + "/motd")({}))(function(v) {
- return discard2(bind4(v.text)(setText1(marq)))(function() {
- return discard2(updateSubtitle)(function() {
+ return discard1(bind4(v.text)(setText1(marq)))(function() {
+ return discard1(updateSubtitle)(function() {
return bind4(byId1("lcolonq-subtitle"))(function(subtitle) {
- return discard2(listen1(subtitle)("click")(function(_ev) {
+ return discard1(listen1(subtitle)("click")(function(_ev) {
return launchAff_(updateSubtitle);
}))(function() {
return for_2(range2(0)(6))(function(i) {
return bind4(byId1("lcolonq-letter-" + show2(i)))(function(letter) {
- return discard2(listen1(letter)("click")(function(_ev) {
+ return discard1(listen1(letter)("click")(function(_ev) {
return playVoice2(true)(i);
}))(function() {
return listen1(letter)("mouseover")(function(_ev) {
@@ -3013,6 +3220,89 @@ var main = /* @__PURE__ */ launchAff_(/* @__PURE__ */ discard2(/* @__PURE__ */ l
});
});
}));
+var appendText = function(dictMonadEffect) {
+ var bind22 = bind(dictMonadEffect.Monad0().Bind1());
+ var liftEffect1 = liftEffect(dictMonadEffect);
+ return function(parent2) {
+ return function(s) {
+ return bind22(liftEffect1(windowImpl))(function(w) {
+ return bind22(liftEffect1(map6(toDocument)(document2(w))))(function(d) {
+ return bind22(liftEffect1(createTextNode(s)(d)))(function(n) {
+ return liftEffect1(appendChild(toNode2(n))(toNode(parent2)));
+ });
+ });
+ });
+ };
+ };
+};
+var appendText1 = /* @__PURE__ */ appendText(monadEffectEffect);
+var appendElement = function(dictMonadEffect) {
+ var liftEffect1 = liftEffect(dictMonadEffect);
+ return function(parent2) {
+ return function(child) {
+ return liftEffect1(appendChild(toNode(child))(toNode(parent2)));
+ };
+ };
+};
+var appendElement1 = /* @__PURE__ */ appendElement(monadEffectEffect);
+var create3 = function(dictMonadEffect) {
+ var Monad0 = dictMonadEffect.Monad0();
+ var Bind1 = Monad0.Bind1();
+ var bind22 = bind(Bind1);
+ var liftEffect1 = liftEffect(dictMonadEffect);
+ var discard3 = discard2(Bind1);
+ var Applicative0 = Monad0.Applicative0();
+ var for_1 = for_(Applicative0)(foldableArray);
+ var appendElement2 = appendElement(dictMonadEffect);
+ var pure3 = pure(Applicative0);
+ return function(tag) {
+ return function(classes) {
+ return function(children2) {
+ return bind22(liftEffect1(windowImpl))(function(w) {
+ return bind22(liftEffect1(map6(toDocument)(document2(w))))(function(d) {
+ return bind22(liftEffect1(createElement(tag)(d)))(function(el) {
+ return bind22(liftEffect1(classList(el)))(function(cl) {
+ return discard3(for_1(classes)(function(c) {
+ return liftEffect1(add2(cl)(c));
+ }))(function() {
+ return discard3(for_1(children2)(function(c) {
+ return appendElement2(el)(c);
+ }))(function() {
+ return pure3(el);
+ });
+ });
+ });
+ });
+ });
+ });
+ };
+ };
+ };
+};
+var create1 = /* @__PURE__ */ create3(monadEffectEffect);
+var mainExtension = /* @__PURE__ */ launchAff_(/* @__PURE__ */ discard1(/* @__PURE__ */ liftEffect5(/* @__PURE__ */ log("hello from extension")))(function() {
+ return setInterval3(1e3)(function __do() {
+ var e = query1(".chat-scrollable-area__message-container")();
+ var $$new5 = create1("div")([".chat-line__message"])([])();
+ appendText1($$new5)("test")();
+ return appendElement1(e)($$new5)();
+ });
+}));
+var main = /* @__PURE__ */ function() {
+ if (mode === 0) {
+ return mainHomepage;
+ }
+ ;
+ if (mode === 1) {
+ return mainExtension;
+ }
+ ;
+ if (mode === 2) {
+ return mainObs;
+ }
+ ;
+ return $$throw("unknown mode");
+}();
// <stdin>
main();
diff --git a/fig-frontend-client/src/Config.js b/fig-frontend-client/src/Config.js
index 11a9792..0990a53 100644
--- a/fig-frontend-client/src/Config.js
+++ b/fig-frontend-client/src/Config.js
@@ -1 +1,2 @@
+export const mode = globalThis.mode;
export const apiServer = globalThis.apiServer;
diff --git a/fig-frontend-client/src/Config.purs b/fig-frontend-client/src/Config.purs
index b464803..3711d69 100644
--- a/fig-frontend-client/src/Config.purs
+++ b/fig-frontend-client/src/Config.purs
@@ -1,3 +1,4 @@
module Config where
+foreign import mode :: Int
foreign import apiServer :: String
diff --git a/fig-frontend-client/src/Main.purs b/fig-frontend-client/src/Main.purs
index cb06b86..8b132a7 100644
--- a/fig-frontend-client/src/Main.purs
+++ b/fig-frontend-client/src/Main.purs
@@ -4,7 +4,9 @@ import Prelude
import Audio as Audio
import Config as Config
+import Data.Array (head)
import Data.Array as Array
+import Data.Foldable (fold)
import Data.Maybe (Maybe(..))
import Data.Traversable (for, for_)
import Effect (Effect)
@@ -14,17 +16,26 @@ import Effect.Console (log)
import Effect.Exception (throw)
import Fetch (fetch)
import Model (startModel)
+import UI as UI
import Web.DOM as DOM
+import Web.DOM.DOMTokenList as DOM.DTL
import Web.DOM.Document as DOM.Doc
import Web.DOM.Element as DOM.El
import Web.DOM.Node as DOM.Node
+import Web.DOM.NodeList as DOM.NL
import Web.DOM.NonElementParentNode as DOM.NEP
+import Web.DOM.Text as DOM.Text
+import Web.DOM.ParentNode as DOM.P
import Web.Event.Event as Ev
import Web.Event.EventTarget as Ev.Tar
import Web.HTML as HTML
import Web.HTML.HTMLDocument as HTML.Doc
import Web.HTML.Window as HTML.Win
+maybeToArray :: forall a. Maybe a -> Array a
+maybeToArray (Just x) = [x]
+maybeToArray Nothing = []
+
byId :: forall m. MonadEffect m => String -> m DOM.Element
byId i = do
w <- liftEffect HTML.window
@@ -33,11 +44,47 @@ byId i = do
Nothing -> liftEffect $ throw $ "could not find element with id: " <> i
Just e -> pure e
+queryAll :: forall m. MonadEffect m => String -> m (Array DOM.Element)
+queryAll q = do
+ w <- liftEffect HTML.window
+ d <- liftEffect $ HTML.Doc.toDocument <$> HTML.Win.document w
+ nl <- liftEffect (DOM.P.querySelectorAll (DOM.P.QuerySelector q) (DOM.Doc.toParentNode d))
+ ns <- liftEffect $ DOM.NL.toArray nl
+ pure $ fold $ (maybeToArray <<< DOM.El.fromNode) <$> ns
+
+query :: forall m . MonadEffect m => String -> m DOM.Element
+query q = do
+ queryAll q >>= head >>> case _ of
+ Nothing -> liftEffect $ throw $ "could not find element matching query: " <> q
+ Just x -> pure x
+
listen :: forall m. MonadEffect m => DOM.Element -> String -> (Ev.Event -> Effect Unit) -> m Unit
listen e ev f = do
l <- liftEffect $ Ev.Tar.eventListener f
liftEffect $ Ev.Tar.addEventListener (Ev.EventType ev) l false $ DOM.El.toEventTarget e
+create :: forall m. MonadEffect m => String -> Array String -> Array DOM.Element -> m DOM.Element
+create tag classes children = do
+ w <- liftEffect HTML.window
+ d <- liftEffect $ HTML.Doc.toDocument <$> HTML.Win.document w
+ el <- liftEffect $ DOM.Doc.createElement tag d
+ cl <- liftEffect $ DOM.El.classList el
+ for_ classes \c ->
+ liftEffect $ DOM.DTL.add cl c
+ for_ children \c ->
+ appendElement el c
+ pure el
+
+appendElement :: forall m. MonadEffect m => DOM.Element -> DOM.Element -> m Unit
+appendElement parent child = liftEffect $ DOM.Node.appendChild (DOM.El.toNode child) (DOM.El.toNode parent)
+
+appendText :: forall m. MonadEffect m => DOM.Element -> String -> m Unit
+appendText parent s = do
+ w <- liftEffect HTML.window
+ d <- liftEffect $ HTML.Doc.toDocument <$> HTML.Win.document w
+ n <- liftEffect $ DOM.Doc.createTextNode s d
+ liftEffect $ DOM.Node.appendChild (DOM.Text.toNode n) (DOM.El.toNode parent)
+
setText :: forall m. MonadEffect m => DOM.Element -> String -> m Unit
setText e s = liftEffect $ DOM.Node.setTextContent s $ DOM.El.toNode e
@@ -47,8 +94,8 @@ updateSubtitle = do
{ text: catchphrase } <- fetch (Config.apiServer <> "/catchphrase") {}
catchphrase >>= setText subtitle
-main :: Effect Unit
-main = launchAff_ do
+mainHomepage :: Effect Unit
+mainHomepage = launchAff_ do
liftEffect $ log "hi"
startModel
marq <- byId "lcolonq-marquee"
@@ -66,3 +113,23 @@ main = launchAff_ do
Audio.playVoice true i
listen letter "mouseover" \_ev -> do
Audio.playVoice false i
+
+mainExtension :: Effect Unit
+mainExtension = launchAff_ do
+ liftEffect $ log "hello from extension"
+ UI.setInterval 1000.0 do
+ e <- query ".chat-scrollable-area__message-container"
+ new <- create "div" [".chat-line__message"] []
+ appendText new "test"
+ appendElement e new
+
+mainObs :: Effect Unit
+mainObs = launchAff_ do
+ startModel
+
+main :: Effect Unit
+main = case Config.mode of
+ 0 -> mainHomepage
+ 1 -> mainExtension
+ 2 -> mainObs
+ _ -> throw "unknown mode"
diff --git a/fig-frontend-client/src/Model.js b/fig-frontend-client/src/Model.js
index 299c645..797bae4 100644
--- a/fig-frontend-client/src/Model.js
+++ b/fig-frontend-client/src/Model.js
@@ -1,11 +1,7 @@
let canvas = document.getElementById("lcolonq-canvas");
-let socket = new WebSocket("wss://colonq.computer/bullfrog/api/channel/listen/model");
+let socket = null;
let currentFrame = null;
-socket.addEventListener("open", (ev) => {
- console.log("connected");
-});
-
async function decompress(blob) {
let ds = new DecompressionStream("gzip");
let stream = blob.stream();
@@ -68,7 +64,7 @@ function readPacket(dv) {
}
function renderCellCanvas(ctx, x, y, c) {
- if (c) {
+ if (c && c.type === "fg") {
let msg = c.g1 ? String.fromCodePoint(c.g0, c.g1) : String.fromCodePoint(c.g0);
if (msg.trim().length) {
ctx.fillStyle = "black";
@@ -99,6 +95,10 @@ function renderCanvas() {
}
export const _startModel = () => {
+ socket = new WebSocket("wss://colonq.computer/bullfrog/api/channel/listen/model");
+ socket.addEventListener("open", (ev) => {
+ console.log("connected");
+ });
socket.addEventListener("message", async (ev) => {
let arr = await decompress(ev.data);
let view = new DataView(arr);
diff --git a/fig-frontend-client/src/UI.js b/fig-frontend-client/src/UI.js
new file mode 100644
index 0000000..0b00e5d
--- /dev/null
+++ b/fig-frontend-client/src/UI.js
@@ -0,0 +1,2 @@
+export const _cheatLog = (a) => () => console.log(a);
+export const _setInterval = (delay) => (f) => () => setInterval(f, delay);
diff --git a/fig-frontend-client/src/UI.purs b/fig-frontend-client/src/UI.purs
new file mode 100644
index 0000000..49d797a
--- /dev/null
+++ b/fig-frontend-client/src/UI.purs
@@ -0,0 +1,13 @@
+module UI where
+
+import Prelude
+import Effect (Effect)
+import Effect.Class (class MonadEffect, liftEffect)
+
+foreign import _cheatLog :: forall a. a -> Effect Unit
+cheatLog :: forall m a. MonadEffect m => a -> m Unit
+cheatLog x = liftEffect $ _cheatLog x
+
+foreign import _setInterval :: Number -> Effect Unit -> Effect Unit
+setInterval :: forall m. MonadEffect m => Number -> Effect Unit -> m Unit
+setInterval d f = liftEffect $ _setInterval d f
diff --git a/fig-frontend-client/index-template.html b/fig-frontend-client/templates/index.html
index f793ddd..8827694 100644
--- a/fig-frontend-client/index-template.html
+++ b/fig-frontend-client/templates/index.html
@@ -11,7 +11,7 @@ CONFIG_SUBST
</script>
<script type="module" src="./main.js"></script>
</head>
- <body>
+ <body class="lcolonq-index">
<!-- RINGBEARER -->
<canvas id="lcolonq-canvas"></canvas>
<div id="lcolonq-title">
diff --git a/fig-frontend-client/templates/obs.html b/fig-frontend-client/templates/obs.html
new file mode 100644
index 0000000..999035a
--- /dev/null
+++ b/fig-frontend-client/templates/obs.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
+ <title>LCOLONQ Browser Source</title>
+ <link rel="icon" href="./assets/mrgreen.png">
+ <link rel="stylesheet" type="text/css" href="./main.css">
+ <script type="module">
+CONFIG_SUBST
+ globalThis.mode = 2;
+ </script>
+ <script type="module" src="./main.js"></script>
+ </head>
+ <body class="lcolonq-obs">
+ <canvas id="lcolonq-canvas"></canvas>
+ </body>
+</html>
diff --git a/fig-monitor-twitch/main/Main.hs b/fig-monitor-twitch/main/Main.hs
index 2232a03..05f3cdb 100644
--- a/fig-monitor-twitch/main/Main.hs
+++ b/fig-monitor-twitch/main/Main.hs
@@ -11,12 +11,14 @@ data Command
= Monitor
| Chatbot
| RedirectServer
+ | Validate
parseCommand :: Parser Command
parseCommand = subparser $ mconcat
[ command "monitor" $ info (pure Monitor) (progDesc "Launch the Twitch monitor")
, command "chatbot" $ info (pure Chatbot) (progDesc "Launch the Twitch chatbot")
, command "user-token-server" $ info (pure RedirectServer) (progDesc "Launch a web server to handle authentication redirects")
+ , command "validate-endpoint" $ info (pure Validate) (progDesc "Test Twitch authentication")
]
data Opts = Opts
{ busHost :: Text
@@ -43,3 +45,4 @@ main = do
Monitor -> twitchEventClient cfg (opts.busHost, opts.busPort)
Chatbot -> twitchChatClient cfg (opts.busHost, opts.busPort)
RedirectServer -> userTokenRedirectServer cfg
+ Validate -> twitchEndpointTest cfg
diff --git a/fig-monitor-twitch/src/Fig/Monitor/Twitch.hs b/fig-monitor-twitch/src/Fig/Monitor/Twitch.hs
index 1889545..17f2b8a 100644
--- a/fig-monitor-twitch/src/Fig/Monitor/Twitch.hs
+++ b/fig-monitor-twitch/src/Fig/Monitor/Twitch.hs
@@ -5,6 +5,7 @@
module Fig.Monitor.Twitch
( twitchEventClient
, twitchChatClient
+ , twitchEndpointTest
, userTokenRedirectServer
) where
@@ -233,6 +234,11 @@ shoutout souser user = do
unless (HTTP.statusIsSuccessful $ HTTP.responseStatus response) $ do
log $ "Failed to shoutout: error " <> tshow (HTTP.statusCode $ HTTP.responseStatus response)
+twitchEndpointTest :: Config -> IO ()
+twitchEndpointTest cfg = runAuthed cfg do
+ user <- loginToUserId "lcolonq"
+ log user
+
twitchEventClient :: Config -> (Text, Text) -> IO ()
twitchEventClient cfg busAddr = do
WS.runSecureClient "eventsub.wss.twitch.tv" 443 "/ws" \conn -> do
@@ -248,6 +254,7 @@ twitchEventClient cfg busAddr = do
log $ "Connected to Twitch API, session ID is: " <> sessionId
runAuthed cfg do
user <- loginToUserId cfg.userLogin
+ log "got user id"
subscribe sessionId "channel.channel_points_custom_reward_redemption.add" user
subscribe sessionId "channel.prediction.begin" user
subscribe sessionId "channel.prediction.end" user
@@ -255,6 +262,7 @@ twitchEventClient cfg busAddr = do
subscribe sessionId "channel.poll.end" user
subscribe sessionId "channel.subscribe" user
subscribe sessionId "channel.subscription.gift" user
+ log "finished subscribing"
subscribeFollows sessionId user
subscribeRaids sessionId user
busClient busAddr
@@ -275,7 +283,7 @@ twitchEventClient cfg busAddr = do
let parseEvent o = do
payload <- o .: "payload"
event <- payload .: "event"
- nm <- event .: "user_name"
+ nm <- event .: "user_login"
reward <- event .: "reward"
title <- reward .: "title"
minput <- event .:? "user_input"
@@ -312,7 +320,7 @@ twitchEventClient cfg busAddr = do
let parseEvent o = do
payload <- o .: "payload"
event <- payload .: "event"
- event .: "from_broadcaster_user_name"
+ event .: "from_broadcaster_user_login"
case Aeson.parseMaybe parseEvent res of
Just nm -> do
log $ "Incoming raid from: " <> nm
@@ -322,7 +330,7 @@ twitchEventClient cfg busAddr = do
let parseEvent o = do
payload <- o .: "payload"
event <- payload .: "event"
- event .: "user_name"
+ event .: "user_login"
case Aeson.parseMaybe parseEvent res of
Just nm -> do
log $ "New follower: " <> nm
@@ -332,7 +340,7 @@ twitchEventClient cfg busAddr = do
let parseEvent o = do
payload <- o .: "payload"
event <- payload .: "event"
- event .: "user_name"
+ event .: "user_login"
case Aeson.parseMaybe parseEvent res of
Just nm -> do
log $ "New subscriber: " <> nm
@@ -342,7 +350,7 @@ twitchEventClient cfg busAddr = do
let parseEvent o = do
payload <- o .: "payload"
event <- payload .: "event"
- nm <- event .: "user_name"
+ nm <- event .: "user_login"
bits <- event .: "bits"
pure (nm, bits)
case Aeson.parseMaybe parseEvent res of
@@ -354,7 +362,7 @@ twitchEventClient cfg busAddr = do
let parseEvent o = do
payload <- o .: "payload"
event <- payload .: "event"
- nm <- event .: "user_name"
+ nm <- event .: "user_login"
num <- event .: "total"
pure (nm, num)
case Aeson.parseMaybe parseEvent res of
diff --git a/fig-monitor-twitch/src/Fig/Monitor/Twitch/Utils.hs b/fig-monitor-twitch/src/Fig/Monitor/Twitch/Utils.hs
index f1d757c..59ba04c 100644
--- a/fig-monitor-twitch/src/Fig/Monitor/Twitch/Utils.hs
+++ b/fig-monitor-twitch/src/Fig/Monitor/Twitch/Utils.hs
@@ -78,7 +78,8 @@ authedRequestJSON :: (Aeson.ToJSON a, Aeson.FromJSON b) => Text -> Text -> a ->
authedRequestJSON method url val = do
resp <- authedRequest method url $ Aeson.encode val
case Aeson.eitherDecode resp of
- Left err -> throwM . FigMonitorTwitchException $ tshow err
+ Left err -> do
+ throwM . FigMonitorTwitchException $ tshow err
Right res -> pure res
runAuthed :: Config -> Authed a -> IO a