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.
// These must be at the very top of the file. Do not edit.
// icon-color: deep-blue; icon-glyph: shopping-cart;
// Version 1.0.0
// Version 1.0.1
const cacheMinutes = 60 * 2
const today = new Date()
@ -36,34 +36,59 @@ const cacheExists = files.fileExists(path)
const cacheDate = cacheExists ? files.modificationDate(path) : 0
////////////////////////////////////////////////////////////
const parseDate = (stringDate) => {
const months = {
'Januar': 0,
'Februar': 1,
'März': 2,
'April': 3,
'Mai': 4,
'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])
const localeText = {
default: ['Day', 'Days'],
en: ['Day', 'Days'],
de: ['Tag', 'Tage'],
fr: ['Jour', 'Jours'],
es: ['día', 'días'],
it: ['giorno', 'giorni']
}
////////////////////////////////////////////////////////////
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()
context.size= new Size(width, h)
context.size = new Size(width, h)
context.opaque = false
context.respectScreenScale = true
context.setFillColor(new Color('#d2d2d7'))
@ -73,19 +98,19 @@ function creatProgress(total,havegone){
context.fillPath()
context.setFillColor(new Color('#008009'))
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)
context.addPath(path1)
context.fillPath()
return context.getImage()
}
////////////////////////////////////////////////////////////
const getTimeRemaining = function (endtime){
const getTimeRemaining = function (endtime) {
const total = Date.parse(endtime) - Date.parse(new Date());
const seconds = Math.floor( (total/1000) % 60 );
const minutes = Math.floor( (total/1000/60) % 60 );
const hours = Math.floor( (total/(1000*60*60)) % 24 );
const days = Math.floor( total/(1000*60*60*24) );
const seconds = Math.floor((total / 1000) % 60);
const minutes = Math.floor((total / 1000 / 60) % 60);
const hours = Math.floor((total / (1000 * 60 * 60)) % 24);
const days = Math.floor(total / (1000 * 60 * 60 * 24));
return {
total,
@ -97,10 +122,55 @@ const getTimeRemaining = function (endtime){
}
////////////////////////////////////////////////////////////
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 rawJSON = res.match(/<script id="init_data" type="application\/json">(.*)<\/script>/)
if(!rawJSON) {
if (!rawJSON) {
return null
}
const data = JSON.parse(rawJSON[1])
@ -119,16 +189,18 @@ if (cacheExists && (today.getTime() - cacheDate.getTime()) < (cacheMinutes * 60
console.log("Get from Website")
try {
orderDetails = await getOrderdetails(widgetInput[0], widgetInput[1])
if(orderDetails !== null) {
if (orderDetails !== null) {
console.log("Write to Cache")
files.writeString(path, JSON.stringify(orderDetails))
}
} catch (e) {
console.error('Fetching data from website failed')
console.error('Fetching data from website failed:')
console.error(e)
if (cacheExists) {
console.warn('Fallback to Cache')
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]}`)
}
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 orderDate = parseDate(orderDetails['orderDetail']['orderHeader']['d']['orderPlacedDate'])
const deliveryDate = parseDate(itemDetails['d']['deliveryDate'])
const orderDate = parseLongDate(orderDetails['orderDetail']['orderHeader']['d']['orderPlacedDate'])
const deliveryDate = parseShortDate(itemDetails['d']['deliveryDate'], orderDate.getMonth())
const itemName = itemDetails['d']['productName']
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;
widget.setPadding(10, 10, 10, 10)
@ -178,15 +250,11 @@ if (!orderDetails) {
itemNameText.minimumScaleFactor = 0.3
itemNameText.lineLimit = 2
widget.addSpacer()
let postFix;
if(remainingDays === 1) {
postFix = 'Day'
} else {
postFix = 'Days'
}
const languageCode = Device.language().match(/^[\a-z]{2}/)
const t = (localeText[languageCode]) ? localeText[languageCode] : localeText.default
let postFix = (remainingDays === 1) ? t[0] : t[1]
const remainingDayText = widget.addText(remainingDays + ' ' + postFix)
remainingDayText.font = Font.regularSystemFont(28)
@ -195,7 +263,7 @@ if (!orderDetails) {
widget.addSpacer()
const total = (deliveryDate - orderDate) / (1000*60*60*24)
const total = (deliveryDate - orderDate) / (1000 * 60 * 60 * 24)
const daysGone = total - remainingDays
widget.addImage(creatProgress(total, daysGone))
@ -216,7 +284,7 @@ if (!orderDetails) {
deliveryDateText.font = Font.regularSystemFont(8)
}
if(!config.runsInWidget) {
if (!config.runsInWidget) {
await widget.presentSmall()
} else {
// 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.
_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)
## Setup