Download Video using iOS Shortcuts -> Dropbox -> Downie

On Mac Power Users #493 I made an off-hand reference to a script-and-shortcut that I use to save YouTube videos from my iOS device into a Dropbox folder that I later view on my Apple TV using Infuse.

There has been approximately 4,371% more interest in this script than anything I have written on the Internet in the past 20 years, so I thought I should publish it somewhere I can point people to.

Here’s the overview

I always like to explain the “concept” before I get into the nitty-gritty details of how it’s done.

  1. On my iPhone or iPad, send a URL to a Shortcut.

  2. The Shortcut saves the URL to a text file in Dropbox.

  3. Somewhere, a Mac notices that the file has been created/modified.

  4. A shell script is triggered which looks for URLs in the text file.

  5. Those URLs are passed to Downie which has been previously configured to save videos to a different Dropbox folder.

  6. When the script is finished, it deletes the original text file and waits for it to be re-created.

  7. A push notification is sent to tell me the video has been downloaded

There’s more than one way to do it.

I’m not going to describe the only way to do this, because there are lots of ways to do this.

In step #2, you could use iCloud instead of Dropbox. If you use ShellFish you could probably use Shortcuts to save the file directly to your Mac via SFTP, rather than using any cloud storage at all. Heck, you could probably use Shortcuts’ built-in “Run SSH Command” to send the URL to a text file directly. I chose Dropbox because that was the easiest way for me to do it, and I know that even if my Mac is offline for some reason (which is almost never is) or if Dropbox isn’t running on my Mac (which it almost always is), this will still work.

In step #3 you could use launchd or Hazel.

In step #5, you could use youtube-dl instead of Downie.

It’s not foolproof

If you ask Downie to download something that isn’t a video, it probably won’t work right. I make no attempt to determine whether or not the URL is actually a video URL or not.

If you run the shortcut twice in rapid succession, it’s possible that your second URL might get added to the text file in the split-second after it is processed and before it is deleted, and your URL would be lost. That’s why I have the push notification in step #7, so I know when it’s safe to send another URL.

Here are the pieces. Some assembly required.

Shortcut on iPhone/iPad

This is pretty straight-forward. I’ll include a screenshot because it might help some folks understand how to make it, but it’s about as simple as shortcuts get:

  1. The shortcut accepts anything (note: I should probably make this less “receptive” because in iOS 13 shortcuts appear in a lot of places they don’t always belong, but I’m not re-writing anything until iOS 13 officially ships.) Right away this is a big assumption because we are trusting the user to give us the correct kind of data (specifically, a URL).

  2. The shortcut “expands” the URL. This is not strictly necessary, but I want to save the actual URL rather than a bit.ly URL.

  3. The user is “Ask”-ed “Is this what you want to add?” This presents the “expanded” URL to the user before it is saved. Tip: If what you really wanted to do was to save a video URL that you have on the clipboard, this is a good time to do that. You can just tap on the alert and paste the clipboard into it. This URL will not be expanded, which is a drawback. A better shortcut would ask the user if they want to use the shortcut input or the clipboard right from the start. Maybe I’ll improve it someday.

  4. Will take URLs from the input the user has given us. I use this step because it would theoretically let me throw a big block of text with a bunch of URLs at the shortcut and have all of them parsed out properly, but in actual practice I use this to send one URL about 99% of the time.

  5. The URLs are “appended” to a file in Dropbox. In reality, that file won’t exist 99.99% of the time, but it might – for example, if the Mac has crashed, or one of the “pieces” on the Mac has failed to run properly. Worst-case scenario you will end up with a text file with a bunch of URLs that you need to process. Note the “Make New Line” which should ensure that every URL is on its own line in the text file. That makes processing on the Mac easier. Finally the file path is relative to ~/Dropbox/ on your Mac. So ~/Dropbox/Action/downie-get.txt on my Mac becomes /Action/downie-get.txt for the purposes of this shortcut.

I think I originally borrowed the idea of an “Action” folder from David. I actually have two, one is ~/Action/ for things I want to do locally on my Mac, and the other is ~/Dropbox/Action/ for things that I want to do via Dropbox. This folder should always be empty. If there is something in it, the Mac should be trying to take some “action” on it. When that action is finished, the file should end up somewhere else (either filed or deleted).

One of the nice things about using Dropbox for this is that you can go back at least 30 days and “un-delete” previous versions of the file, if you need to for some reason. I’ve never needed that, but I like know it is there.

The shell script on the Mac

All of the hard work is done with a shell script on my Mac which is called /usr/local/bin/downie-get.sh. You can call it whatever you want on your Mac, just make sure you edit the launchd plist below to use the proper path.

My script should work for most people in most cases without (m)any changes, but I’ll try to describe what each step does in case you want to modify it.

Note that you may need to scroll the box to see the whole script.

#!/usr/bin/env zsh -f

	# This tells the script to get the $PATH from the ~/.path file if it exists
	# otherwise it will use the second $PATH in the "else" clause
if [[ -e "$HOME/.path" ]]
then
	source "$HOME/.path"
else
	PATH='/usr/local/scripts:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin'
fi

	# This is the same file that we created in the Shortcut,
	# except that we need to make sure we include the "$HOME/Dropbox" part of it
	# if you change the filename in the Shortcut, change it here too
INPUT="$HOME/Dropbox/Action/downie-get.txt"

if [[ ! -e "$INPUT" ]]
then
		# What happens if the script is run but the file does not exist?
		# We should just quit immediately
	echo "$NAME: The input file does not exist."
	exit 0
fi

if [[ ! -s "$INPUT" ]]
then
		# What happens if the script is run and the file exists but it is
		# zero bytes? We should just quit immediately
	echo "$NAME: The input file is empty."
	exit 0
fi

## Ok, so if we get here, the file exists and is not empty.

## Now, is Downie installed? We'll check two places:
##
## '/Applications/Downie 3.app'
##
## 			and
##
##

######## DOWNIE-CHECK-BEGIN
if [[ -d '/Applications/Setapp/Downie.app' ]]
then
	APPNAME='Downie'

elif [[ -d '/Applications/Downie 3.app' ]]
then
	APPNAME='Downie 3'
else
		# If Downie isn't installed, there's really no point in going on, is there?
	echo "$NAME: I did not find Downie at '/Applications/Downie 3.app' or at '/Applications/Setapp/Downie.app'!"
	exit 0
fi
######## DOWNIE-CHECK-END

	# we're going to use this so we can remove the original file ASAP
	# in case another URL gets sent by another invocation of the Shortcut
TEMPFILE="$HOME/.Trash/downie-get.$$.$RANDOM.txt"

	# This will rename the original file to this temp file in the trash
mv -vf "$INPUT" "$TEMPFILE"

	# the 'egrep' line will look for any line that starts with 'http'
	# which will also match 'https' URLs, of course
	# and then it will process each line that starts with https
	# and ignore all of the other lines, including any blank lines.
egrep '^http' "$TEMPFILE" | while read line
do
		##  This will tell "Downie" or "Downie 3" to open the "$line" (which is a variable
		##  containing a URL, assuming any were found)
		##  The `-g` and the `-j` tell Downie to stay in the background and
		##  stay hidden, so the app won't jump up in front of me if I happen
		##  to be using it while it is trying to do this

	open -g -j -a "$APPNAME" "$line"

done

exit 0

That’s pretty much it. I have previously configured Downie’s “General” preferences so it will:

  • Save videos to ~/Dropbox/Video/Infuse/
  • “Add .part extension to incomplete downloads”
  • “Automatically start download when added”
  • when multiple qualities are available: “Automatically select best quality” and “Prefer mp4 downloads”

If you want to test this on your own before trying the script, try this in Terminal:

open -a 'Downie 3' "https://www.youtube.com/watch?v=289v_gKJjWU"

or if you use Downie via Setapp:

open -a 'Downie' "https://www.youtube.com/watch?v=289v_gKJjWU"

If the video immediately starts downloading, you’re good to go. Add in the -g and -j before the -a if you want Downie to stay in the background.

"But I want to use youtube-dl not Downie!

Ok, well, as I said, there are lots of ways to do this, but if you want to use youtube-dl then:

  1. Delete the lines from “######## DOWNIE-CHECK-BEGIN” to “######## DOWNIE-CHECK-END”

  2. replace open -g -j -a "$APPNAME" "$line" with these lines:

	cd ~/Dropbox/Video/Infuse/

	youtube-dl --add-metadata --restrict-filenames --continue --format mp4 \
	--output "%(title)s-(%(id)s).%(ext)s" "$line"

The cd line in cd ~/Dropbox/Video/Infuse/ means “save the files in the folder ~/Dropbox/Video/Infuse/” which must already exist. Change that to wherever you want the videos to be saved.

Obviously you can use whatever arguments to youtube-dl that you want, I just used the ones that I most often use.

Other than that, the script should work just the same.

launchd or Hazel on the Mac.

As I mentioned above, you could use Hazel or launchd for this part. There’s really not a “right” choice. Hazel is definitely more user-friendly, but launchd plists are easier to back up than Hazel rules. Plus I have LaunchControl which makes writing launchd plists very easy. YMMV. Use what you like. I’m going to describe the launchd way because that’s what I use. If you want to use Hazel and don’t know how, leave a reply and I’ll help if I can.

Here is the .plist file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>com.tjluoma.downie-get</string>
	<key>Program</key>
	<string>/usr/local/bin/downie-get.sh</string>
	<key>RunAtLoad</key>
	<true/>
	<key>WatchPaths</key>
	<array>
		<string>/Users/luomat/Dropbox/Action/downie-get.txt</string>
	</array>
</dict>
</plist>

Save that to ~/Library/LaunchAgents/com.tjluoma.downie-get.plist

  • Change the /usr/local/bin/downie-get.sh to point to wherever you saved the shell script we created above.

  • Change the /Users/luomat/Dropbox/Action/downie-get.txt path to the same path that you used in the Shortcut. Make sure that you include the path to the Dropbox folder, so, for example:

  • /Action/downie-get.txt in the Dropbox Shortcut becomes

  • ~/Dropbox/Action/downie-get.txt

Except that launchd doesn’t always like it when you use ~ (I can never remember when it’s OK to use and when it isn’t, so I just try to avoid it altogether) so use /Users/YourShortNameHere instead of /Users/luomat.

Once you have the file edited properly, you need to tell launchd to “load” it. If you aren’t using LaunchControl you can do this in Terminal.app:

launchctl load ~/Library/LaunchAgents/com.tjluoma.downie-get.plist

If you ever want to stop using this, just delete the ~/Library/LaunchAgents/com.tjluoma.downie-get.plist file and reboot your Mac.

“What about that push notification?”

Yeah, I mentioned that I also get a push notification when the file is finished. That’s done with Hazel looking in ~/Dropbox/Video/Infuse/ for new video files and then it uses Pushover to send me a push notification.

This uses po.sh which I’ve written about separately, so I won’t repeat it here, but I will say that po.sh is super useful and I use it for dozens of things. If you want to get notifications on your iPhone/iPad for things that happen on your Mac, checkout Pushover.

(I think the app is $5 but the free service tier is all I’ve ever needed, and I paid them that $5 about 6 years ago.)

Infuse on the AppleTV

I use Infuse on the AppleTV to play videos from that Dropbox folder on the Apple TV, which, as Stephen pointed out, also has the benefit of keeping me out of the YouTube app on the Apple TV, which is Not Good.™

Questions? Comments? Concerns?

Let me know if there are parts of this that I need to explain better.

12 Likes

This is great, thank you.

In terms of using it with Hazel, I just set a Hazel rule to run when it detects the url file, and the action it performs is to run an embedded shell script - this shell script which only required some minor tweaking so that the file paths matched where my url file is saved.

1 Like

great writeup! thanks TJ!

any chance of also doing a writeup for the “grey area” itunes movies? :slight_smile:

Well, to be honest, I’m not doing that as much anymore, for a couple reasons:

  1. When I was doing it, we were on a heavily-metered Internet connection (20GB per month) and I wanted to make sure that I could download the video once and play it anywhere.

  2. I’ve gotten into the habit of waiting as long until movies come out on Blu-Ray and then waiting until the price drops from its initial level (watching via https://camelcamelcamel.com). 99% of all Blu-Rays now come with a digital code, so I can stream them on my iOS devices/Apple TV, and I have the Blu-Ray which I can convert into a restriction-free MKV if I want to, but in practice I rarely do.

  3. The app that I used NoteBurner M4V Converter Plus for Mac does not work on anything later than “macOS Sierra 10.12 and iTunes 12.8” which, at this point, means that I’d have to run the conversion on my 2007 iMac with 6GB of RAM… which is pretty darn slow. Which is a shame, because the app worked well, and even supported subtitles.

If I’ve purchased something via iTunes but not on Blu-Ray, I’m more inclined to check the back some of Internet trucks than try to deal with converting the iTunes file directly. For example, when Into the Spider-Verse came out, I bought it on iTunes the day that it was released. I wanted to take a screenshot of it, but the iPad won’t allow that… because piracy? :roll_eyes: Who TF knows… anyway, ~20 minutes later I had an MKV and took the screenshot in VLC on my Mac instead.

I also saw the movie 4 times in the theater and also bought it on Blu-Ray the day it came out, because sometimes I’m terrible at following my own advice. Of course it came with a digital code… which I no longer needed, because I had already bought it on iTunes… {can someone explain to me why movies come out on iTunes before Blu-Ray? I really don’t understand that at all, but it’s usually a 2-week delay, which seems ridiculously stupid. Then again, it’s Hollywood and technology, so I should expect stupidity, I suppose.} Anyway, I didn’t feel much guilt about acquiring a DRM-free version of a movie I’d paid for about 6 different times.

This worked amazingly well, thanks @tjluoma, you are the bomb diggity!

Thanks for sharing! I love it when the directions are clear. Hazel works perfectly. Now if Shortcut extensions would show up every time I share a URL, that’d be great.

sigh

Thanks for this - I’ll definitely give this a try.

I would be really interested to read about how you have done that. Could you share a link?

There is a basic write-up about it at https://github.com/tjluoma/po.sh:

If there’s anything you don’t understand, feel free to post a reply here (so we can keep related info together) and I’ll do my best to explain it better.

Hmmm… Thanks for this!

I’ve got to try to figure out how to do this from my work Mac. iCloud and Dropbox are out due to company security policy (Well, I guess technically I get could away with iCloud, but that’s more a personal choice to separate my data and the company’s data). I’m sure I could email the URL home and have something monitoring it back on my server at home.

This is the most fun game.

I would use homebrew and youtube-DL

Homebrew is macOS.

There’s a way to do it on iOS with Pythonista, Shortcuts and youtube-dl.

1 Like

@bocciaman and @bowline

Sorry, I’m saying use my work Mac to trigger my Home Mac to do the download, rather than trigger it from my phone.

Right now, I’m seeing the latest movie trailer I want to watch, airdropping the link to my phone, running the shortcut, and watching the trailer later at home on Plex.

I’d like to think out a way to send the link directly from my computer at work – where I don’t have access to cloud file services – to my computer at home. Email probably works for this as I can keep Mail.app running.

You could fairly easily¹ modify what I have to work with Send to Dropbox which is a free service (with paid upgrades that you would not need for this) which will give you a special email address.

All you’d have to do is set the Send To Dropbox address to save the text of your emails to a certain folder and set either Hazel or launchd to watch that folder, and then look for URLs in the text files that it finds.

¹ Well, that might be easy for me to say, since I wrote it, but I’d be glad to help if this is something that you want to pursue.

1 Like

BTW if you are interested in getting Downie, it’s part of the latest BundleHunt promo¹ for only $3.50

There’s also iStat Menus and iMazing and a bunch of others.

¹ {That’s my referral link, BTW. I think it’s clear that I recommended this app long before the deal came along :slight_smile: }

1 Like

@tjluoma Thank you so much for this! I’m using this constantly when I’m on the go and I encounter a video worth archiving.

Have you by any chance updated your script to work with Downie 4?

I’m so glad to hear that it’s been useful to you!

Updating this for Downie 4 should be fairly easy.

Just look for this:

elif [[ -d '/Applications/Downie 3.app' ]]
then
	APPNAME='Downie 3'
else

and change it to this:

elif [[ -d '/Applications/Downie 4.app' ]]
then
	APPNAME='Downie 4'
else

and that should be all you need to do.

If that doesn’t work, let me know and I can post a new script. (I can’t edit the original post anymore.)

Thank you very much! I changed it and it works. :+1: :smiley:

Also make sure you have the latest update for Downie. I use this through Setapp and the developer has released an update to fix a crash when the app launched. The bug would not allow the application to start at all and kept producing an error report to send to the developer. Once the report was sent then Downie would just close. The Setapp team only approved it this morning and after the app updated the errors have gone and the application is working fine.

If you use the non-Setapp version then I think this was fixed a few days ago. However, the update only reached Setapp subscribers this morning.

2 Likes

This is a fantastic setup that I use a lot. It works flawlessly for me when using Downie, but I would prefer YouTube-dl as it is more customisable. YouTube-dl doesn’t seem to allow simultaneous downloads, which Downie does easily. Has anyone else had that problem?

I’ve updated the script and posted it below using youtube-dl instead of Downie.

I have not tried this myself, so let me know if it doesn’t work and I’ll take a closer look.

(Note that there are still some references to Downie in various filenames, but that should not matter.)

I’ve also put it in a proper gist, so it should be easier to download, and easier for others to fork if they wish.

Note:

Despite the name of the gist, you should still save this to /usr/local/bin/downie-get.sh or else you’ll have to change these two lines in the plist:

	<key>Program</key>
	<string>/usr/local/bin/downie-get.sh</string>