// dm Klopapier & Mehl Widget | |
// | |
// Copyright (C) 2020 by marco79 <marco79cgn@gmail.com> | |
// | |
// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL | |
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | |
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |
// IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | |
// OF THIS SOFTWARE. | |
// | |
// Wheat flour icon made by Freepik from www.flaticon.com and modified by achisto | |
// Toilet paper icon made by boettges | |
let country = 'de' // replace with 'at' for shops in Austria | |
let storeId = 251 | |
let param = args.widgetParameter | |
if (param != null && param.length > 0) { | |
storeId = param | |
} | |
const widget = new ListWidget() | |
const storeInfo = await fetchStoreInformation() | |
const storeCapacityPaper = await fetchAmountOfPaper() | |
const storeCapacityFlour = await fetchAmountOfWheatFlour() | |
await createWidget() | |
// used for debugging if script runs inside the app | |
if (!config.runsInWidget) { | |
await widget.presentSmall() | |
} | |
Script.setWidget(widget) | |
Script.complete() | |
// build the content of the widget | |
async function createWidget() { | |
const logoImg = await getImage('dm-logo.png') | |
widget.setPadding(6,6,6,6) | |
const titleFontSize = 12 | |
const detailFontSize = 36 | |
const logoStack = widget.addStack() | |
const shopStateStack = logoStack.addStack() | |
shopStateStack.layoutVertically() | |
shopStateStack.addSpacer(10) | |
let currentTime = new Date().toLocaleTimeString('de-DE', { hour: "numeric", minute: "numeric" }) | |
let currentDay = new Date().getDay() | |
let isOpen | |
if (currentDay > 0) { | |
const todaysOpeningHour = storeInfo.openingHours[currentDay-1].timeRanges[0].opening | |
const todaysClosingHour = storeInfo.openingHours[currentDay-1].timeRanges[0].closing | |
const range = [todaysOpeningHour, todaysClosingHour]; | |
isOpen = isInRange(currentTime, range) | |
} else { | |
isOpen = false | |
} | |
let shopStateText | |
if (isOpen) { | |
shopStateText = shopStateStack.addText('GEÖFFNET') | |
shopStateText.textColor = new Color("#00CD66") | |
logoStack.addSpacer(36) | |
} else { | |
shopStateText = shopStateStack.addText('GESCHLOSSEN') | |
shopStateText.textColor = new Color("#E50000") | |
logoStack.addSpacer(10) | |
} | |
shopStateText.font = Font.boldRoundedSystemFont(12) | |
const logoImageStack = logoStack.addStack() | |
logoStack.layoutHorizontally() | |
logoImageStack.backgroundColor = new Color("#ffffff", 1.0) | |
logoImageStack.cornerRadius = 8 | |
const wimg = logoImageStack.addImage(logoImg) | |
wimg.imageSize = new Size(32,32) | |
wimg.rightAlignImage() | |
widget.addSpacer(6) | |
// toilet paper | |
const toiletPaperIcon = await getImage('toilet-paper.png') | |
let row = widget.addStack() | |
row.layoutHorizontally() | |
row.addSpacer(2) | |
const toiletPaperImg = row.addImage(toiletPaperIcon) | |
toiletPaperImg.imageSize = new Size(30,30) | |
row.addSpacer(13) | |
let column = row.addStack() | |
column.layoutVertically() | |
const paperText = column.addText("KLOPAPIER") | |
paperText.font = Font.mediumRoundedSystemFont(11) | |
const packageCount = column.addText(storeCapacityPaper.toString()) | |
packageCount.font = Font.mediumRoundedSystemFont(18) | |
if (storeCapacityPaper < 30) { | |
packageCount.textColor = new Color("#E50000") | |
} else { | |
packageCount.textColor = new Color("#00CD66") | |
} | |
widget.addSpacer(4) | |
// wheat flour | |
const flourIcon = await getImage('wheat-flour.png') | |
let row2= widget.addStack() | |
row2.layoutHorizontally() | |
row2.addSpacer(3) | |
const flourImg = row2.addImage(flourIcon) | |
flourImg.imageSize = new Size(30,30) | |
row2.addSpacer(12) | |
let column2 = row2.addStack() | |
column2.layoutVertically() | |
const flourText = column2.addText("MEHL") | |
flourText.font = Font.mediumRoundedSystemFont(11) | |
const flourPackageCount = column2.addText(storeCapacityFlour.toString()) | |
flourPackageCount.font = Font.mediumRoundedSystemFont(18) | |
if (storeCapacityFlour < 30) { | |
flourPackageCount.textColor = new Color("#E50000") | |
} else { | |
flourPackageCount.textColor = new Color("#00CD66") | |
} | |
widget.addSpacer(4) | |
// shop info | |
const row3 = widget.addStack() | |
row3.layoutVertically() | |
const street = row3.addText(storeInfo.address.street) | |
street.font = Font.regularSystemFont(10) | |
const zipCity = row3.addText(storeInfo.address.zip + " " + storeInfo.address.city) | |
zipCity.font = Font.regularSystemFont(10) | |
} | |
// fetches the amount of toilet paper packages | |
async function fetchAmountOfPaper() { | |
let url | |
let counter = 0 | |
if (country.toLowerCase() === 'at') { | |
// Austria | |
const array = ["156754", "180487", "194066", "188494", "194144", "273259", "170237", "232201", "170425", "283216", "205873", "205874", "249881", "184204"] | |
for (var i = 0; i < array.length; i++) { | |
let currentItem = array[i] | |
url = 'https://products.dm.de/store-availability/AT/products/dans/' + currentItem + '/stocklevel?storeNumbers=' + storeId | |
let req = new Request(url) | |
let apiResult = await req.loadJSON() | |
if (req.response.statusCode == 200) { | |
counter += apiResult.storeAvailability[0].stockLevel | |
} | |
} | |
} else { | |
// Germany | |
url = 'https://products.dm.de/store-availability/DE/availability?dans=595420,708997,137425,28171,485698,799358,863567,452740,610544,846857,709006,452753,879536,452744,485695,853483,594080,504606,593761,525943,842480,535981,127048,524535&storeNumbers=' + storeId | |
const req = new Request(url) | |
const apiResult = await req.loadJSON() | |
for (var i in apiResult.storeAvailabilities) { | |
counter += apiResult.storeAvailabilities[i][0].stockLevel | |
} | |
} | |
return counter | |
} | |
// fetches the amount of wheat flour packages | |
async function fetchAmountOfWheatFlour() { | |
let url | |
let counter = 0 | |
if (country.toLowerCase() === 'at') { | |
// Austria | |
const array = ["178501", "178491", "178498", "178484", "171412", "178489", "295198"] | |
for (var i = 0; i < array.length; i++) { | |
let currentItem = array[i] | |
url = 'https://products.dm.de/store-availability/AT/products/dans/' + currentItem + '/stocklevel?storeNumbers=' + storeId | |
let req = new Request(url) | |
let apiResult = await req.loadJSON() | |
if (req.response.statusCode == 200) { | |
counter += apiResult.storeAvailability[0].stockLevel | |
} | |
} | |
} else { | |
// Germany | |
url = 'https://products.dm.de/store-availability/DE/availability?dans=488334,468120,706590,531500,468121,459912,468178&storeNumbers=' + storeId | |
const req = new Request(url) | |
const apiResult = await req.loadJSON() | |
for (var i in apiResult.storeAvailabilities) { | |
counter += apiResult.storeAvailabilities[i][0].stockLevel | |
} | |
} | |
return counter | |
} | |
// fetches information of the configured store, e.g. opening hours, address etc. | |
async function fetchStoreInformation() { | |
let url | |
if (country.toLowerCase() === 'at') { | |
url = 'https://store-data-service.services.dmtech.com/stores/item/at/' + storeId | |
widget.url = 'https://www.dm.at/search?query=toilettenpapier&searchType=product' | |
} else { | |
url = 'https://store-data-service.services.dmtech.com/stores/item/de/' + storeId | |
widget.url = 'https://www.dm.de/search?query=toilettenpapier&searchType=product' | |
} | |
let req = new Request(url) | |
let apiResult = await req.loadJSON() | |
return apiResult | |
} | |
// checks whether the store is currently open or closed | |
function isInRange(value, range) { | |
return value >= range[0] && value <= range[1]; | |
} | |
// get images from local filestore or download them once | |
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 'dm-logo.png': | |
imageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/50/Dm_Logo.svg/300px-Dm_Logo.svg.png" | |
break | |
case 'toilet-paper.png': | |
imageUrl = "https://i.imgur.com/Uv1qZGV.png" | |
break | |
case 'wheat-flour.png': | |
imageUrl = "https://i.imgur.com/gwWtMWn.png" | |
break | |
default: | |
console.log(`Sorry, couldn't find ${image}.`); | |
} | |
let iconImage = await loadImage(imageUrl) | |
fm.writeImage(path, iconImage) | |
return iconImage | |
} | |
} | |
// helper function to download an image from a given url | |
async function loadImage(imgUrl) { | |
const req = new Request(imgUrl) | |
return await req.loadImage() | |
} | |
// End of script | |
// Bitte bis zum Ende alles markieren und kopieren |
Seit ein paar Tagen wird für die Abfrage zum Toilettenpapier nur noch „NaN“ im Widget ausgegeben. Jemand eine Idee?
Seit ein paar Tagen wird für die Abfrage zum Toilettenpapier nur noch „NaN“ im Widget ausgegeben. Jemand eine Idee?
Hallo
Ändere die Zeile 161 so:
url = 'https://products.dm.de/store-availability/DE/availability?dans=595420,708997,137425,28171,485698,799358,452740,610544,709006,452753,485695,853483,525943,535981,127048&storeNumbers=' + storeId
Da sind wohl ein paar Artikelnummern nicht mehr gültig, und das Script kommt mit der Fehlermeldung nicht klar …
Mit freundlichen Grüßen Jochen
Hallo Jochen,
das klappt leider auch nicht (mehr).
Gruß
Hans
Hallo Hans
Bei mir klappt es noch mit der Zeile ...
Mit freundlichen Grüßen Jochen
Ich habe die storeID 2654 eingestellt, vielleicht liegt es daran.
Edit: Gerade festgestellt: deine Zeile bezieht sich auf Klopapier, bei mir wird aber bei Mehl NaN angezeigt.
Mit der wie folgt geänderten Zeile 191 funktioniert es bei mir wieder.
url = 'https://products.dm.de/store-availability/DE/availability?dans=468120,531500,468121,459912,468178,897927,461923,467198,755784,468119,721676&storeNumbers=' + storeId
Hallo
Zeile 189 ist bei mir noch original wie oben im Listing:
url = 'https://products.dm.de/store-availability/DE/availability?dans=488334,468120,706590,531500,468121,459912,468178&storeNumbers=' + storeId
Damit funktioniert es auch noch ...
Mit freundlichen Grüßen
Jochen
Apropos Windeln. Ich hab mal von dir kopiert und dieses Skript für die dm Ökowindeln angepasst. ;-)
https://gist.github.com/dakira/f3c7a138b0fac1212f832c103e10e0db