super idee, mit ai: plus webcam, ecet und ohnw schwarze balken:
// ----------------------------------------------------
// URLs
// ----------------------------------------------------
let urlMetar = "https://images.egelsbach-airport.com/METREPEgelsbach/metrep.jpg"
let urlCam = "https://images.egelsbach-airport.com/WebCamEgelsbach/Wetter.jpg"
let urlDWD = "https://www.dwd.de/DE/fachnutzer/luftfahrt/teaser/luftsportberichte/edfe/node.html"
// ----------------------------------------------------
// EINSTELLUNGEN
// ----------------------------------------------------
let cropWidget = 30
let cropFullscreen = 80
let safeAreaMargin = 00
// ----------------------------------------------------
// ----------------------------------------------------
// LOGIK
// ----------------------------------------------------
let isFullscreen = (args.queryParameters["fullscreen"] === "true")
let showWidget = config.runsInWidget || !isFullscreen
let activeCrop = showWidget ? cropWidget : cropFullscreen
let activeMargin = showWidget ? safeAreaMargin : 0
// ----------------------------------------------------
// WIDGET-GRÖSSE (IN PUNKTEN!)
// ----------------------------------------------------
let widgetWidthPt = 329
let widgetHeightPt = 155
let canvasW = widgetWidthPt
let canvasH = widgetHeightPt
// ----------------------------------------------------
// DATEN LADEN (Bilder & DWD BDE)
// ----------------------------------------------------
let reqMetar = new Request(urlMetar + "?t=" + Date.now())
let imgMetar = await reqMetar.loadImage()
let reqCam = new Request(urlCam + "?t=" + Date.now())
let imgCam = await reqCam.loadImage()
async function fetchBDE() {
try {
let req = new Request(urlDWD)
let html = await req.loadString()
let now = new Date()
let year = now.getFullYear()
let month = ("0" + (now.getMonth() + 1)).slice(-2)
let day = ("0" + now.getDate()).slice(-2)
let todayStr = year + "-" + month + "-" + day
let rows = html.split("\n")
for (let row of rows) {
if (row.includes(todayStr)) {
let cleanRow = row.replace(/<[^>]*>/g, " ").trim()
let parts = cleanRow.split(/\s+/).filter(p => p.length > 0)
// Index 5 ist 17:35
if (parts.length >= 6) {
// Wieder einzeilig
return "BDE: " + parts[5]
}
}
}
return "BDE: --"
} catch(e) {
return "BDE: Err"
}
}
let bdeText = await fetchBDE()
// ----------------------------------------------------
// DRAW CONTEXT
// ----------------------------------------------------
let ctx = new DrawContext()
ctx.size = new Size(canvasW, canvasH)
ctx.respectScreenScale = true
ctx.opaque = true
// ----------------------------------------------------
// 1. Webcam Hintergrund
// ----------------------------------------------------
let camW = imgCam.size.width
let camH = imgCam.size.height
let scaleCam = Math.max(canvasW / camW, canvasH / camH)
let drawCamW = camW * scaleCam
let drawCamH = camH * scaleCam
let drawCamX = (canvasW - drawCamW) / 2
let drawCamY = (canvasH - drawCamH) / 2
ctx.drawImageInRect(imgCam, new Rect(drawCamX, drawCamY, drawCamW, drawCamH))
// ----------------------------------------------------
// 2. METAR Overlay
// ----------------------------------------------------
let metarW = imgMetar.size.width
let metarH = imgMetar.size.height
let scaleMetar = canvasH / metarH
let drawMetW = metarW * scaleMetar
let drawMetH = canvasH
let shiftLeft = activeCrop * scaleMetar
let drawMetX = -shiftLeft + activeMargin
let drawMetY = 0
ctx.drawImageInRect(imgMetar, new Rect(drawMetX, drawMetY, drawMetW, drawMetH))
// ----------------------------------------------------
// 3. BDE Text Einblendung (Rechtsbündig unten)
// ----------------------------------------------------
if (bdeText) {
ctx.setFont(Font.boldSystemFont(10))
ctx.setTextColor(Color.white())
ctx.setTextAlignedRight()
// Unten rechts positionieren (Höhe des Canvas minus 30 Pixel)
let rectText = new Rect(canvasW - 110, canvasH - 30, 100, 20)
ctx.drawTextInRect(bdeText, rectText)
}
let compositeImg = ctx.getImage()
// ----------------------------------------------------
// AUSGABE
// ----------------------------------------------------
if (showWidget) {
let widget = new ListWidget()
widget.url =
"scriptable:///run?scriptName=" +
encodeURIComponent(Script.name()) +
"&fullscreen=true"
widget.backgroundImage = compositeImg
widget.refreshAfterDate = new Date(Date.now() + 5 * 60 * 1000)
if (config.runsInWidget) {
Script.setWidget(widget)
} else {
await widget.presentMedium()
}
Script.complete()
} else {
let view = new WebView()
let imgData = Data.fromPNG(compositeImg).toBase64String()
let base64Url = "data:image/png;base64," + imgData
let html = `
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
margin:0;
background:black;
display:flex;
justify-content:center;
align-items:center;
min-height:100vh;
}
img {
width:100%;
height:auto;
}
</style>
</head>
<body>
<img src="${base64Url}">
</body>
</html>
`
await view.loadHTML(html)
await view.present(true)
Script.complete()
}