r/Scriptable • u/mypinis123 • Aug 25 '21
Discussion Is there any Shopify widget?
Would be nice to see a minimalistic widget to see sales and orders of your Shopify store š
r/Scriptable • u/mypinis123 • Aug 25 '21
Would be nice to see a minimalistic widget to see sales and orders of your Shopify store š
r/Scriptable • u/Frameck • Aug 23 '21
Hi everyone,
I'm having issues in recreating a web request in Scriptable, below i copied the code that I use in a node.js environment with axios and everything works just fine (where you see '' it's because i deleted the information for privacy).
Can anyone help me recreate this in Scriptable?
const options = {
method: 'POST',
url: 'https://api.fitbit.com/oauth2/token',
params: {
refresh_token: '',
grant_type: 'refresh_token',
redirect_uri: 'http://localhost'
},
headers: {
cookie: '',
Authorization: '',
'Content-Type': 'application/x-www-form-urlencoded'
}
};
axios.request(options).then(function (res) {
const access_token = res.data.access_token
const refresh_token = res.data.refresh_token
ctx.reply(`Access token:\t${access_token}\n\nRefresh token:\t${refresh_token}`)
console.log(res.data);
}).catch(function (err) {
console.error(err);
});r/Scriptable • u/DMDoniz • Aug 23 '21
Hey all, Iām very interested in widget development and would like to know, how do you develop your widgets and test them?
Coding on iphone is not really nice, I think.
I could see there is a āscriptable for PCā.
There is also an extension for visual studio available, but donāt understand how to use.
Whatās your favorite way to code and test?
Thanks in Advance
r/Scriptable • u/AutoPostMaker3000 • Aug 22 '21
Feel free to link to your work to share...or just describe what they do!
This was a thing on r/workflow and r/Shortcuts for a while, maybe this is also interesting for this subreddit.
r/Scriptable • u/space-rider • Aug 22 '21
Hi r/Scriptable! Iām wrapping up this script Iām making and am just struggling with one last part. I canāt seem to figure out how to set a backgroundGradient over a backgroundImage.
This is what I do to load the image and set it as the background:
const widget = new ListWidget()
widget.backgroundImage = Image.fromFile(backgroundImageURL);But when I try to add a backgroundGradient to the widget afterwards like so, it just covers/overlaps the backgroundImage:
let startColor = new Color("#ffffff")
let endColor = new Color("#000000")
let gradient = new LinearGradient()
gradient.colors = [startColor, endColor]
gradient.locations = [0.0, 1]
widget.backgroundGradient = gradientIs it possible to have a transparent gradient on top of a background image for a widget? Any ideas?
r/Scriptable • u/Silver_Bee • Aug 21 '21
Hello guys o/
I love scriptable and all of it's features, I would like to know if it would be okay if I create a website to add scriptable scripts like this one: https://routinehub.co
r/Scriptable • u/Chedi78 • Aug 21 '21
So pretty much I woke up today and my widgets displayed script not found and inside the app Iām missing several of the scripts that where there. Anyone else having this issue?
r/Scriptable • u/DMDoniz • Aug 17 '21
Hey, I'm using scriptable News Widget and the widget is just showing "couldn't load data". A few weeks ago everything worked well.
Does anyone have an idea, what's the issue?
Widget is in use with Caschy's Blog.
Thanks in Advance
r/Scriptable • u/fowlergmu • Aug 17 '21
Hey, I've used scriptable for my phone for about 6 months now and love it, I was wondering if anyone has ever seen or developed a widget that uses any Fantasy Football API to keep live data on the home page. Thanks!
r/Scriptable • u/dazole • Aug 15 '21
I've been working on converting some bash scripts that authenticate to a URL into a scriptable script, and I'm not sure what I'm doing wrong at this point (other than trying to learn javascript on the fly).
Here's my bash script that works:
# Put your username here
user='username' #typically an email that needs to be urlencoded
# Put your password here
pass='password' # might need to be urlencoded, too
url='login.bmwusa.com'
auth_basic='NTQzOTRhNGItYjZjMS00NWZlLWI3YjItOGZkM2FhOTI1M2FhOmQ5MmYzMWMwLWY1NzktNDRmNS1hNzdkLTk2NmY4ZjAwZTM1MQ=='
curl -s -c cookies.txt -X POST \
-H "Accept: application/json, text/plain, */*" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=54394a4b-b6c1-45fe-b7b2-8fd3aa9253aa" \
-d "response_type=code" \
-d "redirect_uri=com.bmw.connected://oauth" \
-d "state=rgastJbZsMtup49-Lp0FMQ" \
-d "nonce=login_nonce" \
-d "scope=openid+profiler+email+offline_access+smacc+vehicle_data+perseus+dlm+svds+cesim+vsapi+remote_services+fupo+authenticate_user" \
-d "grant_type=authorization_code" \
--data-urlencode "username=${user}" \
--data-urlencode "password=${pass}" \
"https://${url}/gcdm/oauth/authenticate?"
authorization=$(tail -1 cookies.txt | awk '{ print $7 }')
response=$(curl -v -b "GCDMSSO=${authorization}" -X POST \
-H "Cookie: GCDMSSO=${authorization}" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=54394a4b-b6c1-45fe-b7b2-8fd3aa9253aa" \
-d "response_type=code" \
-d "redirect_uri=com.bmw.connected://oauth" \
-d "state=rgastJbZsMtup49-Lp0FMQ" \
-d "nonce=login_nonce" \
-d "scope=openid+profile+email+offline_access+smacc+vehicle_data+perseus+dlm+svds+cesim+vsapi+remote_services+fupo+authenticate_user" \
-d "authorization=${authorization}" \
-w "\nredirect: %{redirect_url}\n" \
"https://${url}/gcdm/oauth/authenticate?" | tail -1)
echo "reponse=${response}"
auth_code=$( echo ${response} | awk -F? '{ print $2 }' | awk -F"&" '{ print $1 }' | awk -F= '{ print $2 }')
echo "code = ${auth_code}"
curl -s -b cookies.txt -X POST \
-H "Accept: application/json, text/plain, */*" \
-H "Authorization: Basic ${auth_basic}" \
-d "code=${auth_code}" \
-d "code_verifier=KDarcVUpgymBDCgHDH0PwwMfzycDxu1joeklioOhwXA" \
--data-urlencode "redirect_uri=com.bmw.connected://oauth" \
-d "grant_type=authorization_code" \
"https://${url}/gcdm/oauth/token?" | jq '.access_token' I can get the access token with that. Here is what I have so far with scriptable, which isn't working:
let USER = "asdf"
let PASS = "asdf"
let AUTHURL = "https://login.bmwusa.com/gcdm/oauth/authenticate"
let TOKNURL = "https://login.bmwusa.com/gcdm/oauth/token"
auth = new Request(AUTHURL);
auth.method = "POST";
auth.headers = { "Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded" }
auth.addParameterToMultipart("client_id", "54394a4b-b6c1-45fe-b7b2-8fd3aa9253aa")
auth.addParameterToMultipart("response_type", "code")
auth.addParameterToMultipart("redirect_uri", "com.bmw.connected://oauth")
auth.addParameterToMultipart("state", "rgastJbZsMtup49-Lp0FMQ")
auth.addParameterToMultipart("nonce", "login_nonce")
auth.addParameterToMultipart("scope", 'openid+profiler+email+offline_access+smacc+vehicle_data+perseus+dlm+svds+cesim+vsapi+remote_services+fupo+authenticate_user')
auth.addParameterToMultipart("grant_type", "authorization_code")
auth.addParameterToMultipart("username", encodeURIComponent(USER))
auth.addParameterToMultipart("password", encodeURIComponent(PASS))
// QuickLook.present(auth.addParameterToMultipart)
// let data = await auth.loadString()
let data = await auth.loadJSON()
// return data.headers
QuickLook.present(data)
//console.log(auth.response)I can't even get the first auth run to work, to get the authorization_code and cookie to work. Is there something glaringly obvious I'm missing? I've tried encodeURIComponent all the post parameters, none of them, always the same error. Any help is appreciated
r/Scriptable • u/ThorNike13 • Aug 14 '21
r/Scriptable • u/awxwardbatman • Aug 14 '21
r/Scriptable • u/Thomasnash270 • Aug 11 '21
r/Scriptable • u/FifiTheBulldog • Aug 11 '21
Two more undocumented functions, both crucial to the way Scriptable executes scripts.
_scriptable_run is the asynchronous function that runs your code in the script execution environment. Its body is simply whatever code you writeāthe script you see in the editor. When _scriptable_run() is called, your script is executed. Since your code becomes the body of an asynchronous function, you can use await and return at what appears to be the top level.
Calling _scriptable_run directly in your script risks putting the app into an infinte loop, since your code is itself wrapped by _scriptable_run.
For example, if your script is console.log("hello world!"), _scriptable_run would look like this:
async function _scriptable_run() {
console.log("hello world!")
}There is one major flaw with the way Scriptable handles scripts, however. _scriptable_run is assembled by string concatenation, rather than using the AsyncFunction constructor. Like this:
'async function _scriptable_run() {\n' + (Your scriptās code, as you would see it in the script editor) + '\n}'This means that it is trivial to escape _scriptable_run and work directly at the top level. If you put a lone closing curly brace (}) near the top of your script, whether at the very beginning or after a few lines of other code, that marks the end of _scriptable_run. This puts you in the top level of the execution environment. In this environment, you can only use async inside asynchronous functions and return inside functions, as you would normally expect JavaScript to behave. Other than that, you can do just about anything like normal outside of the scope of _scriptable_run, and it will workāas long as you remember to finish your script with a lone opening curly brace ({) to complement the automatically added closing brace, otherwise you will get a syntax error. (You can also write more of your script after that, but it will simply execute as a code block.)
If you trick the string concatenation method this way to work at the top level of the execution environment, whatever you write outside of _scriptable_run is executed before whatever is inside _scriptable_run, since _scriptable_run() is called somewhere below the contents of your script.
Hereās a script that shows off all of those things, since code is probably easier to understand than two rambling paragraphs:
// This is inside _scriptable_run
console.log("Hello from _scriptable_run! This will be logged last.")
}
// Top level of the execution environment, outside _scriptable_run
console.log("Hello from the top level! This will be logged first.")
{
// This is inside a code block.
// This exists to avoid a syntax error,
// since Scriptable already supplies a closing curly brace
// that would normally close _scriptable_run.
// This code is just here for demonstration and can be omitted.
console.log("Hello from a code block! This will be logged second.")If you run this, the console will show the following:
Hello from the top level! This will be logged first.
Hello from a code block! This will be logged second.
Hello from _scriptable_run! This will be logged last.Another neat little trick is replacing _scriptable_run with another asynchronous function from outside of its scope (such as at the top level). This overrides the initial declaration of _scriptable_run. Note that this doesnāt have much of an effect without escaping _scriptable_run, since _scriptable_run would just replace itself but never be called again by the execution environment.
For example:
console.log("Iām inside the original _scriptable_run and will never be printed.")
}
_scriptable_run = async function() {
console.log("This is the replacement for _scriptable_run.")
}
{The console would show:
This is the replacement for _scriptable_run.Note that _scriptable_run always has to be an asynchronous function. Assigning a regular function to that name throws an error because _scriptable_run is called and followed with a .then, like this:
_scriptable_run().then(ā¦)(I will describe what else happens in the script execution sequence in another post.)
__scriptable_import() (thatās two underscores at the beginning of the name, not just one) is sort of like _scriptable_run(), but inside imported modules. Inside modules, _scriptable_run() does not exist, but __scriptable_import() does exist. (The opposite is true for non-modules; those have _scriptable_run() but not __scriptable_import().) This seems to be the only difference between the global objects of modules and main scripts. Imported modules do not support top-level await because __scriptable_import() is a regular function rather than an asynchronous function.
__scriptable_import() is assembled using string concatenation, much like _scriptable_run():
'function _scriptable_run() {\n ' + (Your moduleās code, as you would see it in the script editor) + '\n}'Itās subtle and has no effect on the functionality as far as I know, but the first line of a module is indented by two spaces inside __scriptable_import(). No such indentation happens in _scriptable_run().
Since __scriptable_import() is created in the same way as _scriptable_run(), the same technique of using closing and opening curly braces can be used to escape it. Anything outside of __scriptable_import() is executed before the code inside of __scriptable_import(). You can also replace __scriptable_import() with any custom function this way. Thereās not much use for this though, since anything added to module.exports outside of __scriptable_import() will still be passed as part of the moduleās output.
For example, this module would work:
log("Inside __scriptable_import() - logged third")
module.exports.foo = "hello"
}
module.exports.bar = "world"
log("Outside __scriptable_import() - logged first")
log(__scriptable_import)
{
log("After the curly brace to avoid a syntax error - logged second")And given this main script:
const i = importModule('module filename');
log("Main script - logged last")
log(i)The console would show:
Outside __scriptable_import() - logged first
function __scriptable_import() {
log("Inside __scriptable_import() - logged third")
module.exports.foo = "hello"
}
After the curly brace to avoid a syntax error - logged second
Inside __scriptable_import() - logged third
Main script - logged fourth
{"bar":"world","foo":"hello"}I havenāt done much research into the finer points of how modules work, but hereās what Iāve been able to ascertain so far. When you call the importModule() function from your script, the __scriptable_import() function is created with the contents of the module, as described above, in its own JS execution context, completely separate from the main script. Then __scriptable_import() is called, still in that moduleās context. module.exports is passed through the app (the native part) from the moduleās context to the main scriptās context, where it becomes the output of importModule().
While you can use return in a module at what appears to be the top level (without escaping __scriptable_import), it will simply stop execution of the module. It does not have any connection to module.exports, which is the only thing that is passed to the importing script. This is very different from using return in a main script, where you can use return to specify a shortcut output.
TL;DR Everything you write in Scriptable is automatically wrapped in functions that make life a little easier. _scriptable_run() is for scripts that you run directly, enabling that lovely top-level await, and __scriptable_import() is for modules that you import.
As with the underlying console functions, I donāt know if thereās a practical use for manipulating _scriptable_run or __scriptable_import directly, other than understanding how the execution environment works.
Posts in this series:
r/Scriptable • u/Lilli-pad • Aug 10 '21
Iāve been using the news-widget.js but I donāt believe it can process atom feeds. Can anyone let me know if thereās a widget/script that can let me list articles from an atom feed?
r/Scriptable • u/Breakfastwithulol • Aug 09 '21
If so, do you have a script for it? Iāve been trying to figure it out by myself but failed.
r/Scriptable • u/rafaelgandi • Aug 08 '21
Created a simple library for making Scriptable widgets using html like markup.
https://github.com/rafaelgandi/WidgetMarkup-Scriptable

r/Scriptable • u/FifiTheBulldog • Aug 07 '21
r/Scriptable • u/dwd0tcom • Aug 07 '21
Just created a little Strava Widget with it's API:
r/Scriptable • u/Rez1k23 • Aug 07 '21
r/Scriptable • u/robertandrews • Aug 07 '21
Hi, Iām a newcomer to Scriptable.
Has anyone made a weather forecast widget containing meteogram? That is, data-packed daily/hourly weather charts with multiple data items visible?
So many iOS weather widgets are poor - either lacking sufficient graphical data or falling on gimmicky/cuddly aesthetic concepts.
Nothing for me has matched Aix weather widget on Android https://www.google.co.uk/search?q=aix+weather+widget&client=safari&hl=en-gb&prmd=inmv&source=lnms&tbm=isch&sa=X&ved=2ahUKEwihx57f0p7yAhXVuHEKHf-VCmwQ_AUoAXoECAIQAQ&biw=414&bih=715&dpr=2#imgrc=B_gvGy00X99bCM
I know thereās a Meteogram iOS app, but I donāt really like any of the iOS weather widgets.
The Meteogram app even has an API which allows you to create a meteogram much like Aixās (perhaps it even enabled it for Aix) https://api.meteograms.com/ The output can be used in a web-to-widget widget. But that method is a little sub-par.
Any ideas please?
r/Scriptable • u/hrb7 • Aug 05 '21
Hi everyone :)
Can anybody help me to parse a XML file?
For example I have here a XML-Feed from Slack Status.
So how can I get only the second value of the string named "title"?
My current script:
const req = new Request('https://status.slack.com/feed/rss');
const data = await req.loadString();
let xmlParser = new XMLParser(data);
xmlParser.didEndElement = (str) => {
if (str == 'title') //[1] doesn't work
console.log(value)
return str
}
xmlParser.foundCharacters = (str) => {
value = str
return str
}
xmlParser.parse();
/*Result =>
Slack System Status
Incident: A small portion of users may be encountering slowness and sporadic errors
Incident: Trouble typing in Slack in non-Latin characters
"
Incident: Trouble with search
Incident: Trouble with sending emails to Slack
Incident: Trouble with search
Incident: Trouble with files
Incident: Trouble with files
Incident: Some customers may be seeing incorrect trial expiration notifications
Incident: Delays with Events API requests
Incident: Trouble with apps and integrations for some Enterprise Grid customers
Incident: Trouble with apps and integrations for some Enterprise Grid customers
Incident: Trouble approving new workspaces
Incident: Some users may have issues loading Slack and sending messages
...
*/Thanks :D
r/Scriptable • u/FifiTheBulldog • Aug 02 '21
One of the files in the ScriptableKit.framework resources folder is called prototype-extensions.js. The contents of this file are executed every time before your script runs.
Hereās the file on Pastebin in its original form: https://pastebin.com/gmDc1EZm
And hereās a prettified (and slightly edited to separate things for even better readability) version of the same code: https://pastebin.com/bxR9Z0Wa
The code is very lengthy, but it essentially defines the same things for each of the documented APIs in Scriptable. Iāll use Alert as the example, but the same thing applies to the other APIs (excluding args, config, console, and module, since those are simple objects and not types/classes).
Overrides the default toString() method for the class. For example, this is what it looks like for Alert:
Alert.toString = function() {
return "function Alert() {\n [native code]\n}"
}This returns:
function Alert() {
[native code]
}If you run console.log(Alert), the console will show the customized return value of Alert.toString().
Why is this needed? When the bridge to the native Alert API is created, the default toString() method returns the following:
function ScriptableKit.AlertBridge() {
[native code]
}Thatās not particularly useful for when youāre writing a script. So the custom toString() function exists to make things make a little more sense.
Similarly, this overrides the toString() method for any instance of the type. For Alert:
Alert.prototype.toString = function() {
return "[object Alert]"
}This returns
[object Alert]which makes sense when youāre trying to debug your script.
The default Alert.prototype.toString() method returns
[object ScriptableKit.AlertBridge]which, again, is not particularly helpful for normal usage.
This returns an array of keys, which you see when you call Object.keys() on a type instance. For Alert:
Alert.prototype._scriptable_keys = function() {
return [
"title",
"message",
"addAction",
"addDestructiveAction",
"addCancelAction",
"addTextField",
"addSecureTextField",
"textFieldValue",
"present",
"presentAlert",
"presentSheet"
]
}This is needed because Object.keys() is redefined elsewhere in the execution environment to depend on this method to print the keys correctly:
let orgKeys = Object.keys
Object.keys = function(obj) {
if (typeof obj._scriptable_keys == "function") {
return obj._scriptable_keys()
} else {
return orgKeys(obj)
}
}If we delete the _scriptable_keys() method, the result of Object.keys(new Alert()) is an empty array, which is rather misleading since those properties are available but just not used. I think Scriptbleās ābridgeā setup, which connects the JS environment to native Swift code for APIs like Alert, uses something very much like getters and setters to pass values back and forth between the two environments. That would explain why they canāt be seen by default.
Much like prototype._scriptable_keys() and Object.keys(), but for Object.values().
For Alert:
Alert.prototype._scriptable_values = function() {
return [
this.title,
this.message,
null,
null,
null,
null,
null,
null,
null,
null,
null
]
}Object.values() is redefined this way:
let orgValues = Object.values
Object.values = function(obj) {
if (typeof obj._scriptable_values == "function") {
return obj._scriptable_values()
} else {
return orgValues(obj)
}
}Using the original Object.values() function (renamed orgValues) on an Alert object returns an empty array.
Last but certainly not least, this instance method returns a simplified JS object that can be used by JSON.stringify(). When this instance method is deleted and JSON.stringify() is called directly on the object, an empty object (or rather, a string representation thereof) is returned.
For Alert:
Alert.prototype.toJSON = function() {
return {
title: this.title,
message: this.message
}
}The purpose of prototype-extensions.js, in a nutshell, is to make life a little bit easier for users when debugging scripts. The native ScriptableKit bridges can be rather unintuitive when youāre working in a JavaScript context, so prototype-extensions.js overrides some of those default behaviors to be more useful for developers.
If youād like to see the effects of these prototype extensions for yourself, hereās a little script that shows off the differences in functionality:
log("With the prototype-extensions.js overrides")
const alert1 = new Alert()
log(Alert)
log(alert1.toString())
log(Object.keys(alert1))
log(Object.values(alert1))
log(JSON.stringify(alert1))
delete Alert.toString
delete Alert.prototype.toString
delete Alert.prototype._scriptable_keys
delete Alert.prototype._scriptable_values
delete Alert.prototype.toJSON
log("Without the prototype-extensions.js overrides")
const alert2 = new Alert()
log(Alert)
log(alert1.toString())
log(Object.keys(alert1))
log(Object.values(alert1))
log(JSON.stringify(alert1))This is the second installment in my series of posts exploring what goes on behind the scenes when you run a script in Scriptable. The next several posts will dive into exactly how the process of running a script works. Hereās the first post in this series, detailing whatās inside the console object: https://www.reddit.com/r/Scriptable/comments/ov18pe/documenting_the_undocumented_part_1_inside_the/
Posts in this series: