DEV Community

Cover image for 📹 Saving social media videos to your phone
Ryan Collins
Ryan Collins

Posted on • Originally published at on

📹 Saving social media videos to your phone

I happen to have a problem with scrolling through a lot of social media. In my travels, I’ll come across a lot of videos that I’d like to share or save. The problem with sharing the videos is that sometimes the site doesn’t make it very pleasant for a person without an account to view the video. Facebook, I’m looking at you. Another issue is that the video may get pulled for various reasons. Since I’m a big geek always looking for a way to overengineer a solution, I wrote a couple of scripts to make it easy to download videos from social media sites so I can share them.


If you’d like to try this yourself, here are the tools you’ll need:

  • An Unix based host that you can access publicly on the internet. I use a virtual private server, but you can use the free tier from Amazon or any VPS provider.
  • yt-dlp: This software is the magic that allows everything to happen. It’s a fork of youtube-dl and is a command line app that downloads videos from various services.
  • Telegram: Telegram is my instant messaging client of choice, and I use telegram-send to send me the movie file once it’s downloaded
  • sqlite3: I could probably queue up videos with a plain text file, but why do that when I can use a full blown database. Another bonus is that I’ve wanted a reason to use sqlite3 in a project.
  • tmux: tmux is a terminal multiplexer which allows you to have multiple windows open over a command line interface. You can also detach from the session and it stays running.

Installing the software

On your VPS you’ll need to install the software needed. You can follow the directions at each site for installing and configuring the software.

  • yt-dlp
  • telegram-send
  • sqlite3
  • tmux (or your favorite terminal multiplexer)

You don’t have to use Telegram, you can use something else, but I would recommend at least checking it out. It gives you unlimited storage with file sizes up to 2GB (however, telegram-send can only send videos up to 50MB, which isn’t a problem with short social media videos).

First up is a script to download the video. Yes, we could call yt-dlp directly, but I want control over where the videos are saved along with how they are named.


cd ${HOME}/Movies
filename=$(/usr/local/bin/yt-dlp --windows-filenames --get-filename "${1}")
file="${filename:0:33}-${filename: -24}"

/usr/local/bin/yt-dlp --windows-filenames -o "${file}" "${1}"

telegram-send --video "${file}" --caption "${filename}"

Enter fullscreen mode Exit fullscreen mode

You will have to adjust the paths to fit your situation. I store the downloaded videos in ~/Movies. Let me know how to improve the naming of the file. This way works well enough for me with Tik Tok videos, but I’m always ready for improvement.

Once we chmod +x we can call the script with one parameter, the url for the video. This could be the link to the tweet with the video, or the link from Tik Tok. The video will be downloaded and then sent to me in Telegram.

This is what my first iteration of downloading videos looked like. On my iPhone I made a Shortcut that would call the script over ssh. The problem was that once I initiated the Shortcut, I was stuck waiting for it to finish. Since that could take a minute or so, I needed to come up with a better solution. Enter a download queue in an sqlite3 database.

The database

The database will store a command and a variable to the command. I’m wanting to extend the queuing system into other areas, like scheduling tweets or Mastodon toots.

I use ~/Development as a place to store all of my scripts, so inside that folder I created a folder called gozcron. That will be where I save the database and any other scripts I may need.

sqlite3 is pretty cool, creating the database is as simple as sqlite3 gozcron.db. You will enter the sqlite3 prompt. Here is the create statement I used to create a table in the database called actions:

CREATE TABLE actions (id INTEGER PRIMARY KEY,action varchar(30),variable varchar(1024),due varchar(32),completed BYTE DEFAULT '0');

Enter fullscreen mode Exit fullscreen mode

There are 5 columns:

  • id: An autoincrementing field to use for delete or update actions
  • action: Denotes the steps to take with this record. Currently only supports getvideo but will support other tasks in the future.
  • variable: Stores the arguments for the action. For getvideo that would be the URL of the video.
  • due: In the future I want to be able to schedule when tasks happen. The date/time of the scheduled action will be stored in this field but for getvideo it is ignored.
  • completed: Once the task is done, this field will be set to 1.

After the create statement is ran, you can exit sqlite3 with .quit.

Now that we have a database, let’s add tasks to it. The script will take 3 arguments and add them as a record to the actions table.


cd ${HOME}/Development/gozcron


echo "${action}-${var}-${due}" >> addtask.log

sqlite3 gozcron.db <<EOF
insert into actions (action,variable,due)


Enter fullscreen mode Exit fullscreen mode

The echo line is used for debugging, I don’t know if I’ll leave it in the script, but it’s there for now. For downloading videos I run the script with only two arguments, getvideo https://MEDIAURL. This runs from an SSH step in an iOS Shortcut. Since it only adds one record to a database, it finishes a lot quicker on the phone.

We’ve got a script that will download the video, and a script to store which videos to download, now we need a script that will go through our queue in the database and download the videos. That’s where comes in.



now=$(date +"%Y-%m-%d %H:%M")
list=$(sqlite3 -batch -separator ',' gozcron.db "select id,action,variable from actions where completed=\"0\" AND (due < \"${now}\" OR due IS NULL)";)

while read -r line; do
    id=$(echo "${line}" | cut -d "," -f 1)
    action=$(echo "${line}" | cut -d "," -f 2)
    var=$(echo "${line}" | cut -d "," -f 3)

    #echo "id: ${id}, Action: ${action}, Variable: ${var}"

    case "${action}" in
            echo "Downloading movie ${var}"
            ${getvideo} ${var}            
            sqlite3 -batch gozcron.db "update actions set completed=\"1\" where id=\"${id}\";"

done <<<"${list}"

Enter fullscreen mode Exit fullscreen mode selects all of the tasks that aren’t completed and that are either past their due date or do not have a due date set. It then iterates through the list, and runs on any row that has getvideo as the action. If I run the script, it checks once and then exits. We don’t want to do that, so I run it with while TRUE; do ./; sleep 60; done. I probably should just incorporate the loop in the script, and maybe I will.

Running all the time

Since I get tired of looking up how to create services, I run the script in a window under tmux. I can then detach from my session and my script stays running.tmux is a terminal multiplexer, allowing you to run multiple windows or screens from one connection. It also lets you disconnect and leave your stuff running. for when you reconnect.

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.