Last active
September 7, 2021 22:12
-
-
Save v4lli/b123fd0c766ad6a8f92a0df374c965bc to your computer and use it in GitHub Desktop.
Scriptable.app Fit Star Capacity Status Widget Fork
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Variables used by Scriptable. | |
// These must be at the very top of the file. Do not edit. | |
// icon-color: yellow; icon-glyph: star; | |
// copied & adapted from: https://gist.github.com/kevinkub/46caebfebc7e26be63403a7f0587f664 | |
class LineChart { | |
constructor(width, height, values, ymin, ymax, len, padding = 0) { | |
this.ctx = new DrawContext() | |
this.ctx.size = new Size(width, height) | |
this.values = values; | |
this.ymin = ymin; | |
this.ymax = ymax; | |
this.padding = padding; | |
this.len = len || this.values.length; | |
} | |
_calculatePath() { | |
let difference = this.ymax - this.ymin; | |
let step = (this.ctx.size.width - this.padding) / (this.len - 1); | |
let points = this.values.map((current, index, all) => { | |
let x = step*index | |
let y = (this.ctx.size.height - this.padding) - (current - this.ymin) / difference * (this.ctx.size.height - this.padding); | |
return new Point(x, y) | |
}); | |
return this._getSmoothPath(points); | |
} | |
_getSmoothPath(points) { | |
let path = new Path() | |
path.move(new Point(0, this.ctx.size.height-this.padding)); | |
path.addLine(points[0]); | |
for(var i = 0; i < points.length-1; i ++) { | |
let xAvg = (points[i].x + points[i+1].x) / 2; | |
let yAvg = (points[i].y + points[i+1].y) / 2; | |
let avg = new Point(xAvg, yAvg); | |
let cp1 = new Point((xAvg + points[i].x) / 2, points[i].y); | |
let next = new Point(points[i+1].x, points[i+1].y); | |
let cp2 = new Point((xAvg + points[i+1].x) / 2, points[i+1].y); | |
path.addQuadCurve(avg, cp1); | |
path.addQuadCurve(next, cp2); | |
} | |
if (points.length === this.len) { | |
path.addLine(new Point(this.ctx.size.width - this.padding, this.ctx.size.height - this.padding)) | |
path.closeSubpath(); | |
} | |
return path; | |
} | |
configure(fn) { | |
let path = this._calculatePath() | |
if(fn) { | |
fn(this.ctx, path); | |
} else { | |
this.ctx.addPath(path); | |
this.ctx.fillPath(path); | |
} | |
return this.ctx; | |
} | |
} | |
let url = 'https://www.fit-star.de/fitnessstudio/muenchen-giesing' | |
const currentGymCapacity = await fetchGymStats() | |
const widget = new ListWidget() | |
await createWidget() | |
if (!config.runsInWidget) { | |
await widget.presentSmall() | |
} | |
Script.setWidget(widget) | |
Script.complete() | |
async function createWidget() { | |
widget.backgroundColor = new Color("333333", 1) | |
let lastWeekPath = new LineChart(512, 512, currentGymCapacity["full"]["last_week"].map(parseFloat).map((v) => v + 7), 0, 100, 12)._calculatePath(); | |
let chart = new LineChart(512, 512, currentGymCapacity["full"]["today"].map(parseFloat).map((v) => v + 7), 0, 100, 12).configure((ctx, path) => { | |
ctx.opaque = false; | |
ctx.setFillColor(new Color("ffffff", .35)); | |
ctx.addPath(lastWeekPath); | |
ctx.fillPath(lastWeekPath); | |
ctx.setStrokeColor(new Color("ffff00", 0.8)); | |
ctx.setLineWidth(8); | |
ctx.addPath(path); | |
ctx.strokePath(path); | |
}).getImage(); | |
widget.setPadding(-5,8,-5,-3) | |
widget.backgroundImage = chart | |
widget.addSpacer(7) | |
const capacityText = widget.addText(parseFloat(currentGymCapacity["full"]["percentage"]).toFixed(0) + "%") | |
capacityText.font = Font.mediumRoundedSystemFont(28) | |
if (currentGymCapacity < 10) { | |
capacityText.textColor = new Color("#33cc33") | |
} else if (currentGymCapacity < 30){ | |
capacityText.textColor = new Color("#ff9900") | |
}else{ | |
capacityText.textColor = new Color("#ff3300") | |
} | |
const available = parseInt(currentGymCapacity["full"]["available"], 10); | |
const assumedCurrent = Math.round(0.8*parseFloat(currentGymCapacity["full"]["percentage"])); | |
const assumedTotal = assumedCurrent + available; | |
const toPeople = widget.addText( | |
`± ${assumedCurrent} / ${assumedTotal}\nLive: ${currentGymCapacity["count"].toString()}` | |
); | |
toPeople.font = Font.regularSystemFont(12) | |
toPeople.textColor = Color.white() | |
widget.addSpacer(75) | |
let df = new DateFormatter() | |
df.dateFormat = 'HH:mm' | |
const lastupdate = widget.addText(`${df.string(new Date())} `); | |
lastupdate.font = Font.regularSystemFont(10) | |
lastupdate.textColor = Color.white() | |
lastupdate.centerAlignText(); | |
} | |
async function fetchGymStats() { | |
const req = new Request(url + "?t=" + (new Date()).toISOString()) | |
const result = await req.loadString() | |
const r1 = new RegExp("studios.*JSON.parse\\(JSON.stringify\\((.*)\\)\\)","g") | |
const matches1 = r1.exec(result); | |
if (matches1.length < 2) return null; | |
const r2 = new RegExp("live.*JSON.parse\\(JSON.stringify\\((.*)\\)\\)","g") | |
const matches2 = r2.exec(result); | |
if (matches2.length < 2) return null; | |
return {full: JSON.parse(matches1[1].replaceAll('\\"', '"'))[0], count: JSON.parse(matches2[1])[0][0]}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Still contains a few code smells (especially regarding layouting in Scriptable, which I didn't look into at all). Also, the total capacity is an educated guess.