Version 1.0.1 of order script

Signed-off-by: Benny Samir Hierl <bennysamir@posteo.de>
This commit is contained in:
Benny Samir Hierl 2020-11-12 22:54:55 +01:00
parent c66ad6cbdc
commit 1e83dfd586
No known key found for this signature in database
GPG key ID: 69DE3C3C097DB7F7
2 changed files with 144 additions and 78 deletions

View file

@ -1,7 +1,7 @@
// Variables used by Scriptable. // Variables used by Scriptable.
// These must be at the very top of the file. Do not edit. // These must be at the very top of the file. Do not edit.
// icon-color: deep-blue; icon-glyph: shopping-cart; // icon-color: deep-blue; icon-glyph: shopping-cart;
// Version 1.0.0 // Version 1.0.1
const cacheMinutes = 60 * 2 const cacheMinutes = 60 * 2
const today = new Date() const today = new Date()
@ -36,34 +36,59 @@ const cacheExists = files.fileExists(path)
const cacheDate = cacheExists ? files.modificationDate(path) : 0 const cacheDate = cacheExists ? files.modificationDate(path) : 0
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
const parseDate = (stringDate) => { const localeText = {
const months = { default: ['Day', 'Days'],
'Januar': 0, en: ['Day', 'Days'],
'Februar': 1, de: ['Tag', 'Tage'],
'März': 2, fr: ['Jour', 'Jours'],
'April': 3, es: ['día', 'días'],
'Mai': 4, it: ['giorno', 'giorni']
'Juni': 5,
'Juli': 6,
'August': 7,
'September': 8,
'Oktober': 9,
'November': 10,
'Dezember': 11
}
const m = stringDate.match(/([\d]{1,2})[.\s]+([\w]+)[\s]?([0-9]{4})?/)
const monthKey = Object.keys(months).find((key) => {
return key === m[2] || key.substring(0,3) == m[2]
})
if (!m[3]) {
m[3] = new Date().getFullYear()
}
return new Date(m[3], months[monthKey], m[1])
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
function creatProgress(total,havegone){ const parseLongDate = (stringDate) => {
const months = {
'January': 0,
'February': 1,
'March': 2,
'April': 3,
'May': 4,
'June': 5,
'July': 6,
'August': 7,
'September': 8,
'October': 9,
'November': 10,
'December': 11
}
const m = stringDate.match(/([\w]+)[\s]([\d]{1,2}),[\s]([0-9]{4})/)
return new Date(m[3], months[m[1]], m[2])
}
const parseShortDate = (stringDate, orderMonth) => {
const months = {
'Jan': 0,
'Feb': 1,
'Mar': 2,
'Apr': 3,
'May': 4,
'Jun': 5,
'Jul': 6,
'Aug': 7,
'Sep': 8,
'Oct': 9,
'Nov': 10,
'Dec': 11
}
const m = stringDate.match(/([\d]{1,2}) ([\w]{3})/)
let year = new Date().getFullYear()
if (months[m[2]] < orderMonth) {
year += 1
}
return new Date(year, months[m[2]], m[1])
}
////////////////////////////////////////////////////////////
function creatProgress(total, havegone) {
const context = new DrawContext() const context = new DrawContext()
context.size= new Size(width, h) context.size = new Size(width, h)
context.opaque = false context.opaque = false
context.respectScreenScale = true context.respectScreenScale = true
context.setFillColor(new Color('#d2d2d7')) context.setFillColor(new Color('#d2d2d7'))
@ -73,19 +98,19 @@ function creatProgress(total,havegone){
context.fillPath() context.fillPath()
context.setFillColor(new Color('#008009')) context.setFillColor(new Color('#008009'))
const path1 = new Path() const path1 = new Path()
const path1width = (width*havegone/total > width) ? width : width*havegone/total const path1width = (width * havegone / total > width) ? width : width * havegone / total
path1.addRoundedRect(new Rect(0, 0, path1width, h), 3, 2) path1.addRoundedRect(new Rect(0, 0, path1width, h), 3, 2)
context.addPath(path1) context.addPath(path1)
context.fillPath() context.fillPath()
return context.getImage() return context.getImage()
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
const getTimeRemaining = function (endtime){ const getTimeRemaining = function (endtime) {
const total = Date.parse(endtime) - Date.parse(new Date()); const total = Date.parse(endtime) - Date.parse(new Date());
const seconds = Math.floor( (total/1000) % 60 ); const seconds = Math.floor((total / 1000) % 60);
const minutes = Math.floor( (total/1000/60) % 60 ); const minutes = Math.floor((total / 1000 / 60) % 60);
const hours = Math.floor( (total/(1000*60*60)) % 24 ); const hours = Math.floor((total / (1000 * 60 * 60)) % 24);
const days = Math.floor( total/(1000*60*60*24) ); const days = Math.floor(total / (1000 * 60 * 60 * 24));
return { return {
total, total,
@ -97,10 +122,55 @@ const getTimeRemaining = function (endtime){
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
const getOrderdetails = async (ordernumber, email) => { const getOrderdetails = async (ordernumber, email) => {
const req = new Request(`https://store.apple.com/xc/de/vieworder/${ordernumber}/${email}`) const reqSession = new Request('https://secure.store.apple.com/shop/order/list')
resSession = await reqSession.loadString()
const CookieValues = reqSession.response.cookies.map((v) => {
return v.name + "=" + v.value
})
const xAosStkMatch = resSession.match(/"x-aos-stk":"([\w]+)"/)
if (!xAosStkMatch) {
throw new Error('Needed x-aos-stk token not found')
}
const postUrl = (reqSession.response.url.replace('/np/', '/npx/')) + '&_a=guestUserOrderLookUp&_m=loginHomeOLSS.orderLookUp'
const postReq = new Request(postUrl)
postReq.headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': reqSession.response.url,
'x-aos-model-page': 'sentryLoginOlssNP',
'x-aos-stk': xAosStkMatch[1],
'X-Requested-With': 'XMLHttpRequest',
'Cookie': CookieValues.join('; ')
}
postReq.method = "POST";
postReq.addParameterToMultipart('loginHomeOLSS.orderLookUp.orderNumber', ordernumber)
postReq.addParameterToMultipart('loginHomeOLSS.orderLookUp.emailAddress', email)
const resPostReq = await postReq.loadString()
if (postReq.response.statusCode !== 200) {
throw new Error(`Got HTTP ${postReq.response.statusCode} from API.`)
}
let postResData
try {
postResData = JSON.parse(resPostReq)
} catch (e) {
throw new Error('Can\'t parse API response.')
}
if (postResData['head']['status'] !== 302) {
console.log(resPostReq)
throw new Error('Fetching the data failed. Got unexpected response. Please try it later.')
}
const req = new Request(postResData['head']['data']['url'])
const res = await req.loadString() const res = await req.loadString()
const rawJSON = res.match(/<script id="init_data" type="application\/json">(.*)<\/script>/) const rawJSON = res.match(/<script id="init_data" type="application\/json">(.*)<\/script>/)
if(!rawJSON) { if (!rawJSON) {
return null return null
} }
const data = JSON.parse(rawJSON[1]) const data = JSON.parse(rawJSON[1])
@ -119,16 +189,18 @@ if (cacheExists && (today.getTime() - cacheDate.getTime()) < (cacheMinutes * 60
console.log("Get from Website") console.log("Get from Website")
try { try {
orderDetails = await getOrderdetails(widgetInput[0], widgetInput[1]) orderDetails = await getOrderdetails(widgetInput[0], widgetInput[1])
if(orderDetails !== null) { if (orderDetails !== null) {
console.log("Write to Cache") console.log("Write to Cache")
files.writeString(path, JSON.stringify(orderDetails)) files.writeString(path, JSON.stringify(orderDetails))
} }
} catch (e) { } catch (e) {
console.error('Fetching data from website failed') console.error('Fetching data from website failed:')
console.error(e) console.error(e)
if (cacheExists) { if (cacheExists) {
console.warn('Fallback to Cache') console.warn('Fallback to Cache')
orderDetails = JSON.parse(files.readString(path)) orderDetails = JSON.parse(files.readString(path))
} else {
throw new Error('Fetching the data failed. Now data to show.')
} }
} }
} }
@ -145,13 +217,13 @@ if (!orderDetails) {
throw new Error(`No Item on position ${widgetInput[2]}`) throw new Error(`No Item on position ${widgetInput[2]}`)
} }
const itemPosition = orderDetails['orderDetail']['orderItems']['c'][(widgetInput[2] -1) || 0] const itemPosition = orderDetails['orderDetail']['orderItems']['c'][(widgetInput[2] - 1) || 0]
const itemDetails = orderDetails['orderDetail']['orderItems'][itemPosition]['orderItemDetails'] const itemDetails = orderDetails['orderDetail']['orderItems'][itemPosition]['orderItemDetails']
const orderDate = parseDate(orderDetails['orderDetail']['orderHeader']['d']['orderPlacedDate']) const orderDate = parseLongDate(orderDetails['orderDetail']['orderHeader']['d']['orderPlacedDate'])
const deliveryDate = parseDate(itemDetails['d']['deliveryDate']) const deliveryDate = parseShortDate(itemDetails['d']['deliveryDate'], orderDate.getMonth())
const itemName = itemDetails['d']['productName'] const itemName = itemDetails['d']['productName']
const itemImageUrl = itemDetails['d']['imageData']['src'].replace(/wid=[\d]+/, 'wid=200').replace(/hei=[\d]+/, 'hei=200') const itemImageUrl = itemDetails['d']['imageData']['src'].replace(/wid=[\d]+/, 'wid=200').replace(/hei=[\d]+/, 'hei=200')
const itemImage = await (new Request(itemImageUrl)).loadImage() const itemImage = await(new Request(itemImageUrl)).loadImage()
const remainingDays = getTimeRemaining(deliveryDate).days + 1; const remainingDays = getTimeRemaining(deliveryDate).days + 1;
widget.setPadding(10, 10, 10, 10) widget.setPadding(10, 10, 10, 10)
@ -160,7 +232,7 @@ if (!orderDetails) {
const headlineText = widget.addText(' Order Status') const headlineText = widget.addText(' Order Status')
headlineText.font = Font.regularSystemFont(14) headlineText.font = Font.regularSystemFont(14)
headlineText.textColor = Color.black() headlineText.textColor = Color.black()
widget.addSpacer() widget.addSpacer()
@ -174,28 +246,24 @@ if (!orderDetails) {
const itemNameText = productStack.addText(itemName) const itemNameText = productStack.addText(itemName)
itemNameText.font = Font.regularSystemFont(16) itemNameText.font = Font.regularSystemFont(16)
itemNameText.textColor = Color.black() itemNameText.textColor = Color.black()
itemNameText.minimumScaleFactor = 0.3 itemNameText.minimumScaleFactor = 0.3
itemNameText.lineLimit = 2 itemNameText.lineLimit = 2
widget.addSpacer() widget.addSpacer()
let postFix; const languageCode = Device.language().match(/^[\a-z]{2}/)
if(remainingDays === 1) { const t = (localeText[languageCode]) ? localeText[languageCode] : localeText.default
postFix = 'Day' let postFix = (remainingDays === 1) ? t[0] : t[1]
} else {
postFix = 'Days'
}
const remainingDayText = widget.addText(remainingDays + ' ' + postFix) const remainingDayText = widget.addText(remainingDays + ' ' + postFix)
remainingDayText.font = Font.regularSystemFont(28) remainingDayText.font = Font.regularSystemFont(28)
remainingDayText.textColor = Color.black() remainingDayText.textColor = Color.black()
remainingDayText.centerAlignText() remainingDayText.centerAlignText()
widget.addSpacer() widget.addSpacer()
const total = (deliveryDate - orderDate) / (1000*60*60*24) const total = (deliveryDate - orderDate) / (1000 * 60 * 60 * 24)
const daysGone = total - remainingDays const daysGone = total - remainingDays
widget.addImage(creatProgress(total, daysGone)) widget.addImage(creatProgress(total, daysGone))
@ -206,17 +274,17 @@ if (!orderDetails) {
footerStack.layoutHorizontally() footerStack.layoutHorizontally()
const orderDateText = footerStack.addDate(orderDate) const orderDateText = footerStack.addDate(orderDate)
orderDateText.textColor = Color.black() orderDateText.textColor = Color.black()
orderDateText.font = Font.regularSystemFont(8) orderDateText.font = Font.regularSystemFont(8)
footerStack.addSpacer() footerStack.addSpacer()
const deliveryDateText = footerStack.addDate(deliveryDate) const deliveryDateText = footerStack.addDate(deliveryDate)
deliveryDateText.textColor = Color.black() deliveryDateText.textColor = Color.black()
deliveryDateText.font = Font.regularSystemFont(8) deliveryDateText.font = Font.regularSystemFont(8)
} }
if(!config.runsInWidget) { if (!config.runsInWidget) {
await widget.presentSmall() await widget.presentSmall()
} else { } else {
// Tell the system to show the widget. // Tell the system to show the widget.

View file

@ -3,8 +3,6 @@
This widget shows you the status of your Apple Store order. It shows the remaining days until delivery, the product name, product image, order date and delivery date. This widget shows you the status of your Apple Store order. It shows the remaining days until delivery, the product name, product image, order date and delivery date.
_Notice_: The script is only working with order on the german Apple Store. You can provide me your order number + email, so that I'm able to add the support for your language.
[[Download]](https://raw.githubusercontent.com/ThisIsBenny/iOS-Widgets/main/Apple-Order-Status/Apple-Store-Order-Status.js) [[Download]](https://raw.githubusercontent.com/ThisIsBenny/iOS-Widgets/main/Apple-Order-Status/Apple-Store-Order-Status.js)
## Setup ## Setup