Skip to content

Instantly share code, notes, and snippets.

@icsAT
Last active October 15, 2021 15:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save icsAT/23e5a5290f5b56eed277241964fbb4b8 to your computer and use it in GitHub Desktop.
Save icsAT/23e5a5290f5b56eed277241964fbb4b8 to your computer and use it in GitHub Desktop.
This Scriptable iOS Script displays the price of the selected Cryptocurrencies in a widget on your iPhone or iPad.
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: deep-brown; icon-glyph: magic;
// Crypto Coin Widget
// by icsAT (https://gist.github.com/icsAT)
// Version 0.81 from the 15th of Oktober 2021
// Data from Coin Market Cap Crypto API.
// Get your own privat API Key to use with this widget
// const cmcApiKey = "enter Your own API Key here xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
const cmcApiKey = "enter Your own API Key here xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
// With the Basic Plan you have a maximum of 333 API-Calls a Day and 10.000 API-Calls a Month.
// That means about 1 Call every 5 minutes.
// But be aware , that the refresh of a widget is regulated by iOS (approx. every 7 minutes afaik).
// Also be aware, that more than one widget means more API-Calls.
const cmcRefresh = 20
// The widget will dispay the actual price of the crypto currencies in the given reference value
// You may set what you want to see here in the script or in the widget parameters.
// The widget parameter has the format:
// referenceValue;crypto1,crypto2,crypto3,... f.e. EUR;BTC,ETH,ADA,SOL,DOT,DOGE,AVAX,LTC
// The widget parameter will overrule the values set here.
// Reference Value in wich the price is displayed f.e EUR, USD, BTC
var referenceValue = "EUR"
// Crypto Currencies to be displayed, seperated by "," f.e. BTC,ETH,ADA,SOL,DOT,DOGE,AVAX,LTC
// var cryptoCurrencies = "ADA,AVAX,BTC,DOGE,DOT,ETH,LTC"
var cryptoCurrencies = "ADA,AVAX,BTC,CHZ,DOGE,DOT,ETH,LINK,LTC,MIOTA,SOL,UNI,AMP,COMP,GRT,SXP,XLM"
// Maximum Number of Cryptocurrency Lines
// Depending on your device there are more or less lines possible
// small and medium
const maxLinesSM = 7
// large and extraLarge
const maxLinesLX = 17
// Widget Size to be displayed if running from Scriptable App
// Use 'small' (max. 8 values), 'medium' (max. 8 values), 'large' (max.21 values) or 'extraLarge' (iPad only, max.21 values)
config.widgetFamily = config.widgetFamily || 'large'
// Weitere Parameter
const COLOR_RED = new Color('#FF0000')
const COLOR_GREEN = new Color('#008000')
const COLOR_BLACK = new Color('#000000')
const COLOR_WHITE = new Color('#FFFFFF')
const COLOR_GREY90 = new Color('#E6E6E6')
const COLOR_GREY70 = new Color('#B3B3B3')
const COLOR_GREY50 = new Color('#808080')
const COLOR_GREY30 = new Color('#4D4D4D')
const COLOR_GREY10 = new Color('#1a1a1a')
// debugging (set to false or to true to disable or enable console logging)
const debug = false
// Script Name
const scriptName = Script.name().replace(".js","")
// running the script
let widget = await createWidget()
if (config.runsInWidget) {
Script.setWidget(widget)
} else {
switch (config.widgetFamily) {
case 'small': await widget.presentSmall(); break;
case 'medium': await widget.presentMedium(); break;
case 'large': await widget.presentLarge(); break;
case 'extraLarge': await widget.presentExtraLarge(); break;
}
}
Script.complete()
// create the widget
async function createWidget() {
if (debug) console.log("START async function crateWidget()")
if (args.widgetParameter) {
var parameters = args.widgetParameter.split(";")
referenceValue = parameters[0]
cryptoCurrencies = parameters[1]
}
referenceValue = referenceValue.trim()
referenceValue = referenceValue.replace(" ", "")
if (debug) console.log("referenceValue: " + referenceValue)
cryptoCurrencies = cryptoCurrencies.trim()
cryptoCurrencies = cryptoCurrencies.replace(" ", "")
if (debug) console.log("cryptoCurrencies: " + cryptoCurrencies)
numberCoins = 0
var coins = cryptoCurrencies.split(",")
for (coin of coins) {
numberCoins++
}
if (debug) console.log("numberCoins: " + numberCoins)
let listWidget = new ListWidget()
listWidget.backgroundColor = Color.clear()
listWidget.centerAlignContent
let darkMode = !(Color.dynamic(Color.white(),Color.black()).red)
if (debug) console.log("darkMode: " + darkMode)
const fm = FileManager.local()
let directoryPath = fm.joinPath(fm.documentsDirectory(), "Crypto")
if (debug) console.log("directoryPath: " + directoryPath)
const extension = scriptName + (darkMode ? "_dark" : "_light") + ".jpg"
if (debug) console.log("extension: " + extension)
const imagePath = fm.joinPath(directoryPath, extension)
if (debug) console.log("imagePath: " + imagePath)
if (!config.runsInWidget) {
changeBackground = !(await generatePrompt("Change Background?", "Would you like to change the background?",["Yes","No"]))
if (debug) console.log("setBackground: " + setBackground)
if (changeBackground) {
setBackground = !(await generatePrompt("New Background?", "Would you like to set a new image or erase the actual image?",["Set","Erase"]))
if (setBackground) {
if (!fm.fileExists(directoryPath) || !fm.isDirectory(directoryPath)) {
fm.createDirectory(directoryPath)
}
let newImage = await Photos.fromLibrary()
fm.writeImage(fm.joinPath(directoryPath, scriptName + "_light.jpg"), newImage)
let setBackgroundDark = !(await generatePrompt("Dark Background?", "Would you like to use a different image in dark mode?",["Yes","No"]))
if (debug) console.log("setBackgroundDark: " + setBackgroundDark)
if (setBackgroundDark) {
let newDarkImage = await Photos.fromLibrary()
fm.writeImage(fm.joinPath(directoryPath, scriptName + "_dark.jpg"), newImage)
} else {
fm.writeImage(fm.joinPath(directoryPath, scriptName + "_dark.jpg"), newImage)
}
} else {
if (fm.fileExists(fm.joinPath(directoryPath, scriptName + "_light.jpg"))) {
fm.remove(fm.joinPath(directoryPath, scriptName + "_light.jpg"))
}
if (fm.fileExists(fm.joinPath(directoryPath, scriptName + "_dark.jpg"))) {
fm.remove(fm.joinPath(directoryPath, scriptName + "_dark.jpg"))
}
}
}
}
if (fm.fileExists(imagePath)) {
if (fm.isFileStoredIniCloud(imagePath)) {
await fm.downloadFileFromiCloud(imagePath)
}
listWidget.backgroundImage = fm.readImage(imagePath)
if (debug) console.log("Background Image gesetzt.")
}
headLine = listWidget.addStack()
headLine.centerAlignContent
headLine.addSpacer()
headLineText = headLine.addText("Crypto Prices")
headLineText.font = Font.boldSystemFont(15)
headLineText.centerAlignText()
headLine.addSpacer()
stack = listWidget.addStack()
stack.layoutVertically()
stack.centerAlignContent
if ((numberCoins<maxLinesSM && (config.widgetFamily == 'small' || config.widgetFamily == 'medium')) || (numberCoins<maxLinesLX && (config.widgetFamily == 'large' || config.widgetFamily == 'extraLarge'))) {
stack.addSpacer(8)
}
lastUpdate = "1900-01-01T00:00:00.000Z"
if (debug) console.log("lastUpdate: "+ lastUpdate)
cmcUrlParameter = "?convert="+referenceValue+"&symbol="+cryptoCurrencies
if (debug) console.log("cmcUrlParameter: "+ cmcUrlParameter)
cryptoData = await getCryptoData(fm, cmcUrlParameter)
if (cryptoData && cryptoData.status.error_code == 0) {
if (config.widgetFamily == 'small') {
if (numberCoins <= maxLinesSM) {
await smallTable(coins, cryptoData)
} else {
errorLine = stack.addStack()
errorLine.layoutVertically()
fehlerText = errorLine.addText("Please use not more than " + maxLinesSM + " coins in a small widget!")
fehlerText.font = Font.boldSystemFont(8)
fehlerText.textColor = COLOR_RED
fehlerText = errorLine.addText("You tried to use " + numberCoins + " coins.")
fehlerText.font = Font.boldSystemFont(8)
fehlerText.textColor = COLOR_RED
}
}
if (config.widgetFamily == 'medium') {
if (numberCoins <= maxLinesSM) {
await wideTable(coins, cryptoData)
} else {
errorLine = stack.addStack()
errorLine.layoutVertically()
fehlerText = errorLine.addText("Please use not more than " + maxLinesSM + " coins in a medium widget!")
fehlerText.font = Font.boldSystemFont(15)
fehlerText.textColor = COLOR_RED
fehlerText = errorLine.addText("You tried to use " + numberCoins + " coins.")
fehlerText.font = Font.boldSystemFont(15)
fehlerText.textColor = COLOR_RED
}
}
if (config.widgetFamily == 'large') {
if (numberCoins <= maxLinesLX) {
await wideTable(coins, cryptoData)
} else {
errorLine = stack.addStack()
errorLine.layoutVertically()
fehlerText = errorLine.addText("Please use not more than " + maxLinesLX + " coins in a large widget!")
fehlerText.font = Font.boldSystemFont(15)
fehlerText.textColor = COLOR_RED
fehlerText = errorLine.addText("You tried to use " + numberCoins + " coins.")
fehlerText.font = Font.boldSystemFont(15)
fehlerText.textColor = COLOR_RED
}
}
if (config.widgetFamily == 'extraLarge') {
if (numberCoins <= maxLinesLX) {
await extraLargeTable(coins, cryptoData)
} else {
errorLine = stack.addStack()
errorLine.layoutVertically()
fehlerText = errorLine.addText("Please use not more than " + maxLinesLX + " coins in a extraLarge widget!")
fehlerText.font = Font.boldSystemFont(15)
fehlerText.textColor = COLOR_RED
fehlerText = errorLine.addText("You tried to use " + numberCoins + " coins.")
fehlerText.font = Font.boldSystemFont(15)
fehlerText.textColor = COLOR_RED
}
}
df = new DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm"
lastUpdate = df.string(new Date(cryptoData.status.timestamp))
if ((numberCoins<(maxLinesSM - 1) && (config.widgetFamily == 'small' || config.widgetFamily == 'medium')) || (numberCoins<(maxLinesLX - 1) && (config.widgetFamily == 'large' || config.widgetFamily == 'extraLarge'))) {
stack.addSpacer(8)
}
footerLine = listWidget.addStack()
footerLine.addSpacer()
footerLineText = footerLine.addText(lastUpdate)
footerLineText.font = Font.mediumSystemFont(8)
footerLineText.textColor = Color.dynamic(COLOR_GREY30, COLOR_GREY70)
footerLine.addSpacer()
} else {
errorLine = stack.addStack()
errorLine.layoutHorizontally()
if (cryptoData) {
errorText = errorLine.addText("Error Calling the Coin Market Cap API: "+cryptoData.status.error_message)
} else {
errorText = errorLine.addText("Not able to get Data from Coin Market Cap, nor from Cache. Try again.")
}
errorText.font = Font.boldSystemFont(15)
errorText.textColor = COLOR_RED
}
if (debug) console.log("END async function crateWidget()")
return listWidget
}
// small widget table
async function smallTable(coins, cryptoData) {
if (debug) console.log("START async function smallTable(coins, cryptoData)")
firstLine = stack.addStack()
firstLine.layoutHorizontally()
firstLine.centerAlignContent()
firstLine.backgroundColor = Color.dynamic(COLOR_BLACK, COLOR_WHITE)
firstLine.cornerRadius = 5
firstLine.addSpacer()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(50,0)
nameText = firstLineStack.addText("Name")
nameText.font = Font.mediumSystemFont(12)
nameText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
nameText.leftAlignText()
firstLineStack.addSpacer()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(70,0)
firstLineStack.addSpacer()
priceText = firstLineStack.addText("Price "+referenceValue)
priceText.font = Font.mediumSystemFont(12)
priceText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
priceText.rightAlignText()
firstLine.addSpacer()
lineCount = 1
for (coin of coins) {
if (debug) console.log("coin: "+ coin)
coinLine = stack.addStack()
coinLine.layoutHorizontally()
coinLine.centerAlignContent()
coinLine.addSpacer()
if (lineCount % 2 == 0) {
coinLine.backgroundColor = Color.dynamic(COLOR_GREY90, COLOR_GREY10)
}
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(50,0)
nameText = coinLineStack.addText(cryptoData.data[coin].symbol)
nameText.font = Font.mediumSystemFont(12)
nameText.leftAlignText()
coinLineStack.addSpacer()
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(70,0)
coinLineStack.addSpacer()
priceText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].price.toFixed(2)).toLocaleString())
priceText.font = Font.mediumSystemFont(12)
priceText.textColor = getTextColor("price", cryptoData.data[coin].quote[referenceValue].percent_change_1h)
priceText.rightAlignText()
coinLine.addSpacer()
lineCount++
}
if (debug) console.log("END async function smallTable(coins, cryptoData)")
}
// medium and large widget table
async function wideTable(coins, cryptoData) {
if (debug) console.log("START async function wideTable(coins, cryptoData)")
firstLine = stack.addStack()
firstLine.layoutHorizontally()
firstLine.centerAlignContent()
firstLine.backgroundColor = Color.dynamic(COLOR_BLACK, COLOR_WHITE)
firstLine.cornerRadius = 5
firstLine.addSpacer()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(115,0)
nameText = firstLineStack.addText("Name")
nameText.font = Font.mediumSystemFont(12)
nameText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
nameText.leftAlignText()
firstLineStack.addSpacer()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(70,0)
firstLineStack.addSpacer()
priceText = firstLineStack.addText("Price "+referenceValue)
priceText.font = Font.mediumSystemFont(12)
priceText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
priceText.rightAlignText()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(50,0)
firstLineStack.addSpacer()
dayText = firstLineStack.addText("24h %")
dayText.font = Font.mediumSystemFont(12)
dayText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
dayText.rightAlignText()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(50,0)
firstLineStack.addSpacer()
weekText = firstLineStack.addText("7d %")
weekText.font = Font.mediumSystemFont(12)
weekText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
weekText.rightAlignText()
firstLine.addSpacer()
lineCount = 1
for (coin of coins) {
if (debug) console.log("coin: "+ coin)
coinLine = stack.addStack()
coinLine.layoutHorizontally()
coinLine.centerAlignContent()
coinLine.addSpacer()
if (lineCount % 2 == 0) {
coinLine.backgroundColor = Color.dynamic(COLOR_GREY90, COLOR_GREY10)
}
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(115,0)
nameText = coinLineStack.addText(cryptoData.data[coin].symbol + "/" + cryptoData.data[coin].name)
nameText.font = Font.mediumSystemFont(12)
nameText.leftAlignText()
coinLineStack.addSpacer()
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(70,0)
coinLineStack.addSpacer()
priceText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].price.toFixed(2)).toLocaleString())
priceText.font = Font.mediumSystemFont(12)
priceText.textColor = getTextColor("price", cryptoData.data[coin].quote[referenceValue].percent_change_1h)
priceText.rightAlignText()
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(50,0)
coinLineStack.addSpacer()
dayText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].percent_change_24h.toFixed(2)).toLocaleString())
dayText.font = Font.mediumSystemFont(12)
dayText.textColor = getTextColor("day", cryptoData.data[coin].quote[referenceValue].percent_change_24h)
dayText.rightAlignText()
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(50,0)
coinLineStack.addSpacer()
weekText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].percent_change_7d.toFixed(2)).toLocaleString())
weekText.font = Font.mediumSystemFont(12)
weekText.textColor = getTextColor("week", cryptoData.data[coin].quote[referenceValue].percent_change_7d)
weekText.rightAlignText()
coinLine.addSpacer()
lineCount++
}
if (debug) console.log("END async function wideTable(coins, cryptoData)")
}
//extraLarge table
async function extraLargeTable(coins, cryptoData) {
if (debug) console.log("START async function extraLargeTable(coins, cryptoData)")
firstLine = stack.addStack()
firstLine.layoutHorizontally()
firstLine.centerAlignContent()
firstLine.backgroundColor = Color.dynamic(COLOR_BLACK, COLOR_WHITE)
firstLine.cornerRadius = 5
firstLine.addSpacer()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(125,0)
nameText = firstLineStack.addText("Name")
nameText.font = Font.mediumSystemFont(12)
nameText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
nameText.leftAlignText()
firstLineStack.addSpacer()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(75,0)
firstLineStack.addSpacer()
priceText = firstLineStack.addText("Price "+referenceValue)
priceText.font = Font.mediumSystemFont(12)
priceText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
priceText.rightAlignText()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(50,0)
firstLineStack.addSpacer()
hourText = firstLineStack.addText("1h %")
hourText.font = Font.mediumSystemFont(12)
hourText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
hourText.rightAlignText()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(50,0)
firstLineStack.addSpacer()
dayText = firstLineStack.addText("24h %")
dayText.font = Font.mediumSystemFont(12)
dayText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
dayText.rightAlignText()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(55,0)
firstLineStack.addSpacer()
weekText = firstLineStack.addText("7d %")
weekText.font = Font.mediumSystemFont(12)
weekText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
weekText.rightAlignText()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(125,0)
firstLineStack.addSpacer()
mcText = firstLineStack.addText("Market Cap "+referenceValue)
mcText.font = Font.mediumSystemFont(12)
mcText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
mcText.rightAlignText()
firstLineStack = firstLine.addStack()
firstLineStack.size = new Size(120,0)
firstLineStack.addSpacer()
csText = firstLineStack.addText("Circulating Supply")
csText.font = Font.mediumSystemFont(12)
csText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK)
csText.rightAlignText()
firstLine.addSpacer()
lineCount = 1
for (coin of coins) {
if (debug) console.log("coin: "+ coin)
coinLine = stack.addStack()
coinLine.layoutHorizontally()
coinLine.centerAlignContent()
coinLine.addSpacer()
if (lineCount % 2 == 0) {
coinLine.backgroundColor = Color.dynamic(COLOR_GREY90, COLOR_GREY10)
}
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(125,0)
nameText = coinLineStack.addText(cryptoData.data[coin].symbol + "/" + cryptoData.data[coin].name)
nameText.font = Font.mediumSystemFont(12)
nameText.leftAlignText()
coinLineStack.addSpacer()
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(75,0)
coinLineStack.addSpacer()
priceText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].price.toFixed(2)).toLocaleString())
priceText.font = Font.mediumSystemFont(12)
priceText.textColor = getTextColor("price", cryptoData.data[coin].quote[referenceValue].percent_change_1h)
priceText.rightAlignText()
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(50,0)
coinLineStack.addSpacer()
hourText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].percent_change_1h.toFixed(2)).toLocaleString())
hourText.font = Font.mediumSystemFont(12)
hourText.textColor = getTextColor("hour", cryptoData.data[coin].quote[referenceValue].percent_change_1h)
hourText.rightAlignText()
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(50,0)
coinLineStack.addSpacer()
dayText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].percent_change_24h.toFixed(2)).toLocaleString())
dayText.font = Font.mediumSystemFont(12)
dayText.textColor = getTextColor("day", cryptoData.data[coin].quote[referenceValue].percent_change_24h)
dayText.rightAlignText()
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(55,0)
coinLineStack.addSpacer()
weekText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].percent_change_7d.toFixed(2)).toLocaleString())
weekText.font = Font.mediumSystemFont(12)
weekText.textColor = getTextColor("week", cryptoData.data[coin].quote[referenceValue].percent_change_7d)
weekText.rightAlignText()
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(125,0)
coinLineStack.addSpacer()
mcText = coinLineStack.addText(Math.round(cryptoData.data[coin].quote[referenceValue].market_cap).toLocaleString())
mcText.font = Font.mediumSystemFont(12)
mcText.rightAlignText()
coinLineStack = coinLine.addStack()
coinLineStack.size = new Size(120,0)
coinLineStack.addSpacer()
csText = coinLineStack.addText(Math.round(cryptoData.data[coin].circulating_supply).toLocaleString())
csText.font = Font.mediumSystemFont(12)
csText.rightAlignText()
coinLine.addSpacer()
lineCount++
}
if (debug) console.log("END async function extraLargeTable(coins, cryptoData)")
}
// get crypto data from API
async function getCryptoData(fm, mcUrlParameter) {
if (debug) console.log("START async function getCryptoData(fm, cmcUrlParameter)")
let directoryPath = fm.joinPath(fm.libraryDirectory(), scriptName + ".cache")
if (debug) console.log("directoryPath: "+ directoryPath)
let cmcApiData = getCache(fm, directoryPath, cmcRefresh)
if (!cmcApiData || cmcApiData.length == 0 || cmcApiData.cacheExpired) {
try {
const cmcApiUrl = "https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest" + cmcUrlParameter
if (debug) console.log("cmcApiUrl: "+ cmcApiUrl)
let cmcApiRequest = new Request(cmcApiUrl)
cmcApiRequest.headers = { 'X-CMC_PRO_API_KEY': cmcApiKey, 'Accept': 'application/json' }
cmcApiData = await cmcApiRequest.loadJSON()
if (!cmcApiData || cmcApiData.length == 0) { throw 0 }
fm.writeString(directoryPath, JSON.stringify(cmcApiData, null, 2))
} catch(e) {
cmcApiData = getCache(fm, directoryPath, cmcRefresh)
}
}
if (debug) console.log("Return cmcApiData: "+ JSON.stringify(cmcApiData, null, 2))
if (debug) console.log("END async function getCryptoData(fm, cmcUrlParameter)")
return cmcApiData
}
// get text color
function getTextColor(object, value) {
if (debug) console.log("START function getTextColor(object, value)")
let textColor = Color.dynamic(COLOR_BLACK, COLOR_WHITE)
if ((object=="price" && value>=1) || (object=="hour" && value>=1) || (object=="day" && value>=5) || (object=="week" && value>=10)) {
textColor = COLOR_GREEN
} else if ((object=="price" && value<=-1) || (object=="hour" && value<=-1) || (object=="day" && value<=-5) || (object=="week" && value<=-10)) {
textColor = COLOR_RED
}
if (debug) console.log("Return textColor: "+ textColor)
if (debug) console.log("END function getTextColor(object, value)")
return textColor
}
// get cache
function getCache(fm, path, minAge = -1, maxAge) {
if (debug) console.log("START function getCache(fm, path, minAge = -1, maxAge)")
if (debug) console.log("path: "+ path)
if (debug) console.log("minAge: "+ minAge)
if (debug) console.log("maxAge: "+ maxAge)
if (!fm.fileExists(path)) {
if (debug) console.log("Cache File does not exists. Return null")
return null
}
const cache = JSON.parse(fm.readString(path))
if (debug) console.log("cache: "+ JSON.stringify(cache, null, 2))
now = new Date()
if (debug) console.log("now: "+ now)
const age = (now.getTime() - fm.modificationDate(path).getTime())/60000
if (debug) console.log("age: "+ age)
if (Number.isInteger(maxAge) && age > maxAge) {
if (debug) console.log("Age is grater than maxAge. Return null.")
return null
}
if (minAge != -1 && (!minAge || age > minAge)) cache.cacheExpired = true
if (debug) console.log("Return cache: "+ JSON.stringify(cache, null, 2))
if (debug) console.log("END function getCache(fm, path, minAge = -1, maxAge)")
return cache
}
// generate prompt.
async function generatePrompt(title,message,options) {
if (debug) console.log("START async function generatePrompt(title,message,options)")
if (debug) console.log("title: "+ title)
if (debug) console.log("message: "+ message)
if (debug) console.log("options: "+ options)
let alert = new Alert()
alert.title = title
if (message) alert.message = message
let buttons = options || ["OK"]
for (button of buttons) {
alert.addAction(button)
}
if (debug) console.log("END async function generatePrompt(title,message,options)")
return await alert.presentAlert()
}
@icsAT
Copy link
Author

icsAT commented Oct 12, 2021

IMG_2981

@icsAT
Copy link
Author

icsAT commented Oct 12, 2021

First of all you have to get a free API key from Coin Market Cap an put it in the code.

image

@icsAT
Copy link
Author

icsAT commented Oct 12, 2021

You may set the minimum refresh interval in minutes here to get along with the free plan at Coin Market Cap.

image

@icsAT
Copy link
Author

icsAT commented Oct 12, 2021

You are able to set the reference currency and the displayed cryptocurrencies in the code or as a script parameter. The script parameter overrules the setting in the code. If you use the script parameter, you have write the reference currency first followed by a semicolon. Then you have to write all the cryptocurrencies to be shown, separated by comma. Do not use any spaces.
Script parameter example: EUR;ADA,BTC,ETH,LTC,UNI,DOGE

If you want to setup more than one crypto widget on one device with different reference currencies and/or different cryptocurrencies you need to have one Scriptable script for each Widget. This is because otherwise one widget would set the cache an the other widget would not find the needed information in this cache.

Code:
image

Script parameter:
IMG_2992

@icsAT
Copy link
Author

icsAT commented Oct 12, 2021

Because different generations of devices are able to display a different amount of lines in the same size widget, you are free to set the maximum number lines for the widget types. If you set up more coins an error will occur.

Setting:
image

Error:
IMG_2993

@icsAT
Copy link
Author

icsAT commented Oct 12, 2021

Version 0.81 (10/15/2021)

  • added possibility to remove background.

Version 0.80 (10/12/2021)

  • Very first version.

@icsAT
Copy link
Author

icsAT commented Oct 12, 2021

Small:
IMG_2983IMG_2991

Medium:
IMG_2981
IMG_2990

Large:
IMG_2982
IMG_2988

Extra Large:
IMG_0162
IMG_0161

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment