# @name YouTube # @desc Subscriber count of a YouTube channel # @author Blueforcer # @version 2.0 # @config chan text "Channel ID" default="UCpGLALzRO0uaasWTsm9M99w" maxlen=32 help="The UC... part of youtube.com/channel/UC..., not the @handle" class YouTube var url, chan, period var subs, label, full, err var ticks, busy var ramp def init() self.chan = store.get("chan") self.url = "https://api.socialcounts.org/youtube-live-subscriber-count/" + self.chan self.period = 3600 # once an hour self.subs = store.get("who") == self.chan ? store.get("n") : nil self.label = self.subs == nil ? nil : self.human(self.subs) self.full = self.subs == nil ? nil : str(self.subs) self.err = false self.ticks = 21 self.busy = false self.ramp = [0xFF0000, 0xFF6666] end def human(n) if n < 1000 return str(n) end var d = 1000 var suf = "K" if n >= 1000000000 d = 1000000000 suf = "B" elif n >= 1000000 d = 1000000 suf = "M" end var v = n / (d + 0.0) if v >= 10 return str(round(v)) + suf end var t = round(v * 10) return str(int(t / 10)) + "." + str(t % 10) + suf end def on_body(body, status) self.busy = false shared.set("f", 0) if status != 200 || body == nil self.err = true return end var m = re.search("(\\d+)", body) if m == nil self.err = true return end var n = num(m[1]) if n == nil return end self.err = false if n == self.subs return end self.subs = n self.full = str(n) self.label = self.human(n) # built here, not per frame store.set("n", n) store.set("who", self.chan) end def tls_busy() for k : shared.keys() if size(k) > 2 && k[size(k) - 2 .. size(k) - 1] == ".f" && shared.get(k) == 1 var a = shared.age(k) if a != nil && a < 20000 return true end end end return false end def loop() if self.ticks <= 0 if !self.busy && !self.tls_busy() self.ticks = self.period self.busy = true shared.set("f", 1) # The first hit in the body is the live estimate. http.get(self.url, / b, st -> self.on_body(b, st), {'find': "\"subscriberCount\":", 'keep': 32}) end end self.ticks -= 1 end def draw() clear() rect_fill(0, 1, 8, 6, 0xFF0000) line(1, 0, 6, 0, 0xFF0000) line(1, 7, 6, 7, 0xFF0000) line(3, 2, 3, 6, 0xFFFFFF) line(4, 3, 4, 5, 0xFFFFFF) pixel(5, 4, 0xFFFFFF) if self.label != nil var avail = width() - 9 var s = self.full var w = text_ink_width(s) if w > avail s = self.label w = text_ink_width(s) end ramp_text(9 + (avail - w) / 2, 6, s, self.ramp) return end var s = self.err ? "?" : "..." var w = text_ink_width(s) text(9 + (width() - 9 - w) / 2, 6, s, self.err ? 0xCC7722 : 0x555555) end end return YouTube()