Hey everyone,
I’m sharing a shortcut with you that I spent an inexcusable amount of time on for no apparent reason.
https://www.icloud.com/shortcuts/f239906999ba40cb832f11bb2ac3514f
It saves a video to your Recents photo album from the Instagram page that you are currently browsing. You activate the shortcut from the Share sheet.
-0-0-0- Step by step overview of the Shortcut -0-0-0-
The shortcut is straightforward, except for some gotchas:
First, it accepts a URL as input from the Share sheet;
Then, it checks if the URL contains the string ://www.instagram.com/p/
- the substring that all Instagram post pages share.
With that, Scriptable does its magic. I use the Scriptable inline JavaScript module to get an id and a key from downloadgram.com
, where I send a request for the download link of the video displayed at the URL from the Share sheet, which I inject as a Magic Variable. Downloadgram’s response is an HTML snippet that includes the URL, which Scriptable parses and returns as the outcome of the script.
let url = "https://downloadgram.com"
let wv = new WebView()
await wv.loadURL(url)
let id = "document.getElementsByName('build_id')[0].value"
let key = "document.getElementsByName('build_key')[0].value"
let myId = await wv.evaluateJavaScript(id)
let myKey = await wv.evaluateJavaScript(key)
let myURL = 'Shortcut Input'
url = "https://downloadgram.com/process.php"
let req = new Request(url);
req.method = "post";
req.addParameterToMultipart("url", myURL)
req.addParameterToMultipart("build_id", myId)
req.addParameterToMultipart("build_key", myKey)
let res = await wv.loadRequest(req)
let video = "document.getElementsByTagName('a')[0].href"
let myVideo = await wv.evaluateJavaScript(video)
return myVideo
Shortcuts accepts the outcome of the script, the URL, and downloads the contents - the video, if all goes well.
In the second to last step, we save the video to the Recents library of the Photos app.
Finally, the Shortcut throws a notification to confirm that it saved the video to the Recent Album.
-0-0-0- End of overview -0-0-0-
Alright, you don’t need to read further if all you want is to start downloading Instagram videos. Get the shortcut here and go wild. Of course, if you spot issues or come up with improvements, I’ll be grateful if you share them with us here on the forum.
I want to get something out of the way: I’m not a developer, haven’t been for ages, and JavaScript is new territory for me.
I’m aware at a high level of how web sites process requests, which is how I dug my way into figuring out how to use the download service without using a browser. I’d seen friends use Postman and installed various apps on my iPad that helped me stumble through an approximate understanding of what I need to do to obtain a download URL.
This forum helped me grasp with the lack of a Document Object Model at the entry level of a script. The solution is elegant and actually much more conceptually satisfying than the traditional JavaScript way - you instantiate a WebView object that loads the page and from that moment on, the WebView is aware of the DOM of that page. Neat.
I do find it hard to debug a Scriptable module inside of a Shortcut; as far as I can tell, you cannot use alert sheets (something to do with Siri not being able to work with them) and QuickLook has so many layers of heuristics in how it presents information that I can’t use it as a plain log of the data that the script is handling.
Downloadgram is one of many services that enable you to download videos from Instagram. I’m not even sure why I stuck with this one instead of Downloadvideosfrom, Insta-downloader or one of the myriads of other such services. Their magic is all in a cryptic PHP file that parses its way through the Instagram web arcana to present you with the piece of media that you’re after. I tried to grok what it is they’re doing, but they cover their traces well. I failed.
Then, passing messages between Shortcuts and Scriptable. Oh. My. God. After this whole exercise where I managed to automate downloading Instagram videos from the Share sheet, I can confidently say: I am none the wiser.
I wrote how I used a Scriptable in-line JavaScript module. That’s because I was finally unable to get the two to work together like adults. The URL that I wanted to pass from Shortcuts to Scriptable as an argument, arrived as a snippet of the URL.
https://instagram.com/p/Xd5hg62-6asdf
in ShortCuts becomes 6asdf
in Scriptable.
I spent hours figuring out that that is what was happening (knowing of no way to debug properly). And when I hard coded the URL in Scriptable, I was unable to align the response type coming out of Scriptable with whatever it is that ShortCuts expect. Paraphrasing, here is the ShortCuts error message:
Expecting type String, received type [String]
. Yeah.
Oh, and the clipboard? Fagedaboudit: it gets cleared before Scriptable can take a look at it. Empty. Nothing.
So, input into Scriptable unsuccessful, output into Shortcuts unsuccessful. I was ready to blow it all up, except that I fell foul to the Sunk Cost fallacy. It was one in the morning and there is no way I’m going to admit defeat.
Dr. Drang to the rescue. Serendipitously, I happened upon this gem of a blog post from last month
where Dr. Drang walks you through the use of the Run Inline Scipt action. At one in the morning, I felt this could be my ticket out of Purgatory, even though I wasn’t yet sure how.
I’ll cut it short: at four thirty I hit the sack, having successfully downloaded videos from instagram automatically through the Share sheet. Have at it.