commit 682512320653dda166935023d6052b23f124b6ed Author: TreetopFlyer Date: Fri Apr 22 16:56:41 2022 -0400 init diff --git a/app.js b/app.js new file mode 100644 index 0000000..3e795e7 --- /dev/null +++ b/app.js @@ -0,0 +1,83 @@ +// @ts-check +/// + +import { h, html, render } from "https://esm.sh/htm/preact"; +import { createContext, Fragment } from 'https://esm.sh/preact'; +import { useReducer, useState, useEffect, useLayoutEffect, useMemo, useRef } from 'https://esm.sh/preact/hooks'; + + +/** @type {(props:{channel:string, interval:number})=>any} */ +const App = props => +{ + /** @type {Boxcast.StateBinding>} */ + const [ListGet, ListSet] = useState([]); + + /** @type {Boxcast.StateBinding} */ + const Selected = useState(false); + + useEffect(()=> + { + Ping(); + const timer = setInterval(Ping, props.interval); + return ()=>clearInterval(timer); + } + , []); + + /** @type {()=>Promise} */ + const Ping = async () => + { + const response = await fetch(`https://rest.boxcast.com/channels/${props.channel}/broadcasts?s=starts_at&l=1000`); + const json = await response.json(); + ListSet(json); + }; + + return html` +
+ ${ + ListGet.map(item => html`<${BroadcastItem} item=${item} active=${Selected} />`) + } +
+ `; +} + +/** @type {(props:{item:Boxcast.Broadcast, active:Boxcast.StateBinding})=>any} */ +const BroadcastItem = ({item, active}) => +{ + const startDate = useMemo(()=>DateParse(item.starts_at), [item.starts_at]); + + return html` +
active[1](item)}> + ${startDate.Month} ${startDate.Date} + ${item.name} + ${startDate.Hours}:${startDate.Minutes} ${startDate.M} + ${ + active[0]?.id == item.id ? html`
Active
` : null + } +
+ `; +}; + + +/** @type {(inDate:string)=>Boxcast.Date} */ +const DateParse = (inDateString) => +{ + let date = new Date(inDateString); + /** @type {Boxcast.Date} */ + let obj = { + Zone: date.toString().match(/\(([A-Za-z\s].*)\)/), + Day: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][date.getDay()], + Month: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][date.getMonth()], + Date: date.getDate(), + Hours: date.getHours(), + Minutes: date.getMinutes(), + }; + + obj.Zone = obj.Zone ? obj.Zone[1] : "local time"; + obj.M = obj.Hours >= 12 ? "PM" : "AM"; + obj.Hours %= 12; + if(obj.Hours == 0){ obj.Hours = 12; } + if(obj.Minutes < 10){ obj.Minutes = "0"+obj.Minutes; } + return obj; +}; + +export default App; \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..6447ec9 --- /dev/null +++ b/index.html @@ -0,0 +1,49 @@ + + + + + +
+
+ + + \ No newline at end of file diff --git a/types.d.ts b/types.d.ts new file mode 100644 index 0000000..72c5f3f --- /dev/null +++ b/types.d.ts @@ -0,0 +1,46 @@ +namespace Boxcast +{ + type Broadcast = + { + account_id:string + channel_id:string + description:string + id:string + name:string + poster:string + preview:string + starts_at:string + stops_at:string + tags:Array + timeframe: "future" | "preroll" | "current" | "past" + start?: Date + stop?: Date + } + + type Date = + { + Zone: string | RegExpMatchArray + Day: "Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday" | string + Month: "January" | "February" | "March" | "April" | "May" | "June" | "July" | "August" | "September" | "October" | "November" | "December" | string + Date: number + Hours: number + Minutes: string | number + M?: "AM" | "PM" + } + + type StateBinding = [T, (item:T)=>void]; +} + +namespace Store +{ + type State = + { + Channel:string, + List:Array, + Active:false | Boxcast.Broadcast + } + + type Action = ["ping-out"] | ["ping-back", Array] | ["select", Boxcast.Broadcast] + + type Reducer = (inState:State, inAction:Action) => inState +} \ No newline at end of file