-
-
Save rafaelmaeuer/2321d1543c8e846b13fe38ea0b61b683 to your computer and use it in GitHub Desktop.
// Version 1.4.3 | |
// 30.05.2022 | |
// | |
// Mit Caching und Fallback | |
// Neue API mit TSV-Parsing | |
// Dark-Mode Unterstützung | |
const resetCache = false; | |
const cacheMinutes = 60; | |
const today = new Date(); | |
const neededTotalVaccinations = 83200000; | |
let result; | |
let resultDe; | |
let width = 100; | |
const h = 5; | |
const colorLightGreen = new Color("#47b881") | |
const colorDarkGreen = new Color("#00783e") | |
let widget = new ListWidget(); | |
widget.setPadding(6, 12, 8, 12); | |
widget.url = | |
"https://interaktiv.morgenpost.de/corona-impfungen-deutschland-bundeslaender-weltweit/"; | |
await getNumbers(); | |
await createWidget(); | |
Script.setWidget(widget); | |
Script.complete(); | |
if (config.runsInApp) { | |
widget.presentSmall(); | |
} | |
async function createWidget() { | |
// Add background color | |
widget.backgroundColor = new Color("ffffff"); | |
widget.backgroundColor = Color.dynamic(widget.backgroundColor, new Color("1c1c1c")); | |
widget.addSpacer(); | |
const dataFirst = { | |
text: "Erstimpfung", | |
quota: resultDe.vaccinations1_quota, | |
vaccination: resultDe.vaccinations1, | |
progress: createProgress(resultDe.vaccinations1), | |
}; | |
createProgressStack(dataFirst); | |
const dataSecond = { | |
text: "Zweitimpfung", | |
quota: resultDe.vaccinations2_quota, | |
vaccination: resultDe.vaccinations2, | |
progress: createProgress(resultDe.vaccinations2), | |
}; | |
createProgressStack(dataSecond); | |
const dataThird = { | |
text: "Booster", | |
quota: resultDe.vaccinations4_quota + " | " + resultDe.vaccinations3_quota, | |
vaccination: resultDe.vaccinations4 + " | " + resultDe.vaccinations3, | |
progress: createProgress(resultDe.vaccinations3, resultDe.vaccinations4), | |
}; | |
createProgressStack(dataThird); | |
widget.addSpacer(3); | |
let calendarStack = widget.addStack(); | |
const date = resultDe.date.split('-'); // destructure date | |
const lastUpdateDate = new Date(date[0], date[1]-1, date[2]); // fixes -1 day | |
const options = { year: 'numeric', month: '2-digit', day: '2-digit' }; | |
let description = widget.addText("Stand: " + lastUpdateDate.toLocaleDateString('de-DE', options)); | |
description.centerAlignText(); | |
description.font = Font.mediumSystemFont(9); | |
} | |
function createProgressStack(data) { | |
let firstDoseStack = widget.addStack(); | |
firstDoseStack.layoutHorizontally(); | |
let amountFirstText = firstDoseStack.addText(data.text); | |
amountFirstText.font = Font.boldSystemFont(12); | |
firstDoseStack.addSpacer(); | |
let percentFirstText = firstDoseStack.addText(data.quota + "%"); | |
percentFirstText.font = Font.boldSystemFont(12); | |
widget.addSpacer(2); | |
let progressStack = widget.addStack(); | |
progressStack.layoutVertically(); | |
let progressNumberStack = widget.addStack(); | |
progressNumberStack.layoutHorizontally(); | |
const progressText = progressNumberStack.addText(numberWithDots(data.vaccination)); | |
progressText.font = Font.mediumSystemFont(10); | |
progressStack.addImage(data.progress); | |
widget.addSpacer(3); | |
} | |
// get images from local storage or download them once (currently not used) | |
//async function getImage(image) { | |
// let fm = FileManager.local(); | |
// let dir = fm.documentsDirectory(); | |
// let path = fm.joinPath(dir, image); | |
// if (fm.fileExists(path)) { | |
// return fm.readImage(path); | |
// } else { | |
// // download once | |
// let imageUrl; | |
// switch (image) { | |
// case "vac-logo.png": | |
// imageUrl = "https://i.imgur.com/ZsBNT8E.png"; | |
// break; | |
// case "calendar-icon.png": | |
// imageUrl = "https://i.imgur.com/Qp8CEFf.png"; | |
// break; | |
// default: | |
// console.log(`Sorry, couldn't find ${image}.`); | |
// } | |
// let req = new Request(imageUrl); | |
// let loadedImage = await req.loadImage(); | |
// fm.writeImage(path, loadedImage); | |
// return loadedImage; | |
// } | |
//} | |
function numberWithDots(x) { | |
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "."); | |
} | |
async function getNumbers() { | |
// Set up the file manager. | |
const files = FileManager.local(); | |
// Set up cache | |
const cachePath = files.joinPath( | |
files.cacheDirectory(), | |
"api-cache-covid-vaccination-numbers-mopo-tsv" | |
); | |
const cacheExists = files.fileExists(cachePath); | |
const cacheDate = cacheExists ? files.modificationDate(cachePath) : 0; | |
// Get Data | |
try { | |
// If cache exists and it's been less than 60 minutes since last request, use cached data. | |
if ( | |
cacheExists && !resetCache && | |
today.getTime() - cacheDate.getTime() < cacheMinutes * 60 * 1000 | |
) { | |
console.log("Get from Cache"); | |
result = files.readString(cachePath); | |
} else { | |
console.log("Get from API"); | |
const req2 = new Request( | |
"https://cdn.fnki.de/corona-data/vaccinations.rki.tsv" | |
); | |
result = await req2.loadString(); | |
console.log("Write Data to Cache"); | |
try { | |
files.writeString(cachePath, result); | |
} catch (e) { | |
console.log("Creating Cache failed!"); | |
console.log(e); | |
} | |
} | |
} catch (e) { | |
console.error(e); | |
if (cacheExists) { | |
console.log("Get from Cache"); | |
result = files.readString(cachePath); | |
} else { | |
console.log("No fallback to cache possible. Due to missing cache."); | |
} | |
} | |
await setTotalVacNoForGermany(result); | |
} | |
async function setTotalVacNoForGermany(result) { | |
const cols = result.split(/\r?\n/); | |
const data = cols.map(col => col.split('\t')); | |
data.pop(); // remove last (empty) element | |
const name = data[0]; | |
const vals = data[data.length -1]; | |
const date = name.indexOf('date'); | |
const vac1 = name.indexOf('vaccinations1'); | |
const vac2 = name.indexOf('vaccinations2'); | |
const vac3 = name.indexOf('vaccinations3'); | |
const vac4 = name.indexOf('vaccinations4'); | |
const vac1Quota = name.indexOf('vaccinations1_quota'); | |
const vac2Quota = name.indexOf('vaccinations2_quota'); | |
const vac3Quota = name.indexOf('vaccinations3_quota'); | |
const vac4Quota = name.indexOf('vaccinations4_quota'); | |
resultDe = { | |
date: vals[date], | |
vaccinations1: vals[vac1], | |
vaccinations1_quota: vals[vac1Quota], | |
vaccinations2: vals[vac2], | |
vaccinations2_quota: vals[vac2Quota], | |
vaccinations3: vals[vac3], | |
vaccinations3_quota: vals[vac3Quota], | |
vaccinations4: vals[vac4], | |
vaccinations4_quota: vals[vac4Quota], | |
}; | |
} | |
function createProgress(firstVacNo, secondVacNo) { | |
const context = new DrawContext(); | |
context.size = new Size(width, h); | |
context.opaque = false; | |
context.respectScreenScale = true; | |
context.setFillColor(new Color("#d2d2d7")); | |
const path = new Path(); | |
path.addRoundedRect(new Rect(0, 0, width, h), 3, 2); | |
context.addPath(path); | |
context.fillPath(); | |
context.setFillColor(colorLightGreen); | |
const path1 = new Path(); | |
const path1width = | |
(width * firstVacNo) / neededTotalVaccinations > width | |
? width | |
: (width * firstVacNo) / neededTotalVaccinations; | |
path1.addRoundedRect(new Rect(0, 0, path1width, h), 3, 2); | |
context.addPath(path1); | |
context.fillPath(); | |
if (secondVacNo) { | |
const path2 = new Path(); | |
const path2width = | |
(width * secondVacNo) / neededTotalVaccinations > width | |
? width | |
: (width * secondVacNo) / neededTotalVaccinations; | |
path2.addRoundedRect(new Rect(0, 0, path2width, h), 3, 2); | |
context.addPath(path2); | |
context.setFillColor(colorDarkGreen) | |
context.fillPath(); | |
} | |
return context.getImage(); | |
} | |
// | |
// Bitte bis zum Ende kopieren | |
// |
Bekomme Fehlermeldung
Error on line 597:71:
TypeError:
undefined is not an
object (evaluating
l'amountBoosterPer
Cent.toLocaleString‘)
Jetzt bekomme ich die gleiche Fehlermeldung wie Spezial2K und das Datum der Daten ist der 27.4. und ohne 4. Impfung.
Merkwürdig, ich hatte das caching komplett deaktiviert, ist in v1.4.1 wieder aktiv - sonst Widget mal löschen und neu anlegen…
1.4.1 rennt! Danke.
v1.4.2: code refactoring + cleanup
Wunderbar, und wenn man in den Zeilen 81 und 84 die Fontgröße 11 statt 12 nimmt passt auch alles ins Fenster. Font.boldSystemFont(11)
Läuft! Danke! :-D
Super. Danke
Supi! Läuft! Vielen Dank!
Im DarkMode leider keine Schrift zu lesen…
hab die Zeile auskommentiert.
//if (Device.isUsingDarkAppearance()) { // widget.backgroundColor = new Color("1c1c1e"); //}
Interessant, bei mir macht das keine Probleme:
Edit: @princemaxwell probier mal v1.4.3, Chaos43925 hat diese Verbesserung vorgeschlagen: https://gist.github.com/marco79cgn/b5f291d6242a2c530e56c748f1ae7f2c#gistcomment-4184051
sag mal, kannst du die Texte so anpassen, dass man deren Farbe auch Manuell ändern kann? Dann könnte ich eine Methode vorschlagen, wie man einstellen kann, ob man dauerhaft den Darkmode oder dauerhaft den Lightmode haben will.
Edit: Vergiss es. Ich habe einen Weg gefunden. Ist aber eine menge Code, die Vorschlagen müsste...
um diesen Kommentar klein zu halten habe ich für den neuen Code einen Fork deines Forks erstellt und meinen Code dort untergebracht.
https://gist.github.com/Chaos53925/5617c8a70ddbaec918b2d6804755c92f
Hi, ist es möglich auch den zweiten Booster anzeigen zu lassen?
Hi, ist es möglich auch den zweiten Booster anzeigen zu lassen?
Wenn du fragst, ob das als eigener Balken machbar ist, dann würde ich aufgrund von Platzmangel bei der größe "small" sagen, dass das nicht praktikabel ist. Bei der Größe "medium" kann ich mir das schon eher vorstellen. Aber so wie meine Version davon aufgebaut ist, wird es etwas daueren bis ich eine alternative Ansicht gebaut habe.
Ich bin geduldig, Covid wird uns ja noch lange begleiten
Covid is over…
Hi, ist es möglich auch den zweiten Booster anzeigen zu lassen?
Es ist vollbracht. Die Medium Ansicht hat für jede Impfung einen eigenen Balken.
Zu finden ist die aktualisierte Verson hier:
https://gist.github.com/Chaos53925/5617c8a70ddbaec918b2d6804755c92f
Bei Problemen bitte einfach melden.
Hey, vielen Dank!
Es gibt übrigens eine alternative ansicht mit getrennten Balken:
Dafür musst du nur etwas als Parameter eintragen.
bei mir steht z.B. die 200 drin.
2 steht für geräteinstellungen abhängige anzeige zwischen Dark und Lightmode
0 ist dafür gedacht das öffnen der Website durch drauftippen zu verhindern
0 steht für die alternative Medium-Ansicht mit den 4 Balken
sollte nichts eingetragen sein sehen die Standarteinstellungen wie folgt aus: 211
Wenn du das Skript in der App ausführst kannst du einen Assistenten ausführen, der dir die Parameter gemäß der von dir gewünschten Einstellungen erstellt und in die Zwischenablage Kopiert. dann musst du die nur noch unter "Parameter" einsetzen
Ich muss zu meiner Schande gestehen, dass ich übersehen habe, dass in dem kleinen Widget ja bereits beide Booster angezeigt werden, nur halt in einem Balken! 😁
Das Widget updated sich seit 5.4. nicht mehr. Jemand eine Idee wo das Problem liegt?
Ja, das ist der Datenquelle geschuldet. Der letzte Stand der Datenquelle ist ebenfalls der 5.4.
Dort Heißt es:
2.467 Personen wurden am 05.04. geimpft.
Und deren Datenquelle aktualisiert zur Zeit auch nicht.
Dort heiße es:
Mit dem Auslaufen der CoronaImpfV am 07. April 2023 wird die tägliche Aktualisierung des COVID-19-Impfquotenmonitorings eingestellt und die Berichterstattung zunächst pausiert. Mit Inkrafttreten der COVID-19-VorsorgeV am 8. April 2023 wird das RKI die Aktualisierungsfrequenz des Impfquotenmonitorings an die Meldefrequenz in der COVID-19-VorsorgeV anpassen und voraussichtlich ab Mai das Update der Impfdaten in angepasster Form und Frequenz wieder aufnehmen.
Hmm bekomme den Fehler: „ Exception Occurred Error on line 286:24: The widget is
already presented.“