There are so many great GIFs out there and I want to have copies of them. Twitter makes that harder than it should be by converting them to MP4 and not providing access to the source material. To make it easier, I made a bash pipeline that takes a tweet URL and a filename, extracts the MP4 from that tweet and uses ffmpeg to convert back to GIF.
- ffmpeg
- macOS:
brew install ffmpeg
- Ubuntu/Debian:
apt install ffmpeg
- macOS:
Stick this in your ~/.profile
:
video-url-from-tweet() {
if [ "$1" ]; then
url=$1
else
echo "Must provide a url"
return 1
fi
curl --silent $url |\
# should find the <meta> tag with content="<thumbnail url>"
(grep -m1 "tweet_video_thumb" ||\
echo "Could not find video" && return 1) |\
# from: <meta property="og:image" content="https://pbs.twimg.com/tweet_video_thumb/xxxxxxxxxx.jpg">
# to: https://pbs.twimg.com/tweet_video_thumb/xxxxxxxxxx.jpg
cut -d '"' -f 4 |\
# from: https://pbs.twimg.com/tweet_video_thumb/xxxxxxxxxx.jpg
# to: https://video.twimg.com/tweet_video/xxxxxxxxxx.mp4
sed 's/.jpg/.mp4/g' |\
sed 's/pbs.twimg.com\/tweet_video_thumb/video.twimg.com\/tweet_video/g'
}
video-from-tweet() {
if [ "$1" ]; then
url=$1
else
echo "Must provide a url"
return 1
fi
curl $(video-url-from-tweet $url)
}
video-to-gif() {
# derived from https://engineering.giphy.com/how-to-make-gifs-with-ffmpeg/
if [ "$2" ]; then
input=$1
output=$2
else
echo "Must provide an input file and output file"
return 1
fi
ffmpeg -i $input \
-filter_complex "[0:v] split [a][b];[a] palettegen [p];[b][p] paletteuse" \
-f gif \
$output
}
gif-from-tweet() {
if [ "$2" ]; then
url=$1
output=$2
else
echo "Must provide a url and an output filename"
return 1
fi
video-from-tweet $url | video-to-gif - $output
}
video-url-from-tweet <url>
: takes a tweet URL and returns the MP4 embedded in that tweet, or fails if no video is found.video-from-tweet <url>
: returns the raw data of the video that is embedded in the tweetvideo-to-gif <input> <output>
: converts a video to a GIFgif-from-tweet <url> <output>
: takes a tweet URL and an output filename and saves the MP4 embedded in that tweet as a GIF.
$ video-url-from-tweet https://twitter.com/tsunamino/status/1003318804619804672
https://video.twimg.com/tweet_video/DeyBINOUwAAbuif.mp4
# creates `wink.mp4'
$ video-from-tweet https://twitter.com/tsunamino/status/1003318804619804672 > wink.mp4
# creates `wink.gif' from `wink.mp4'
$ video-to-gif wink.mp4 wink.gif
<...a bunch of ffmpeg output...>
# or use this, which pipelines the above and doesn't create intermediate MP4
$ gif-from-tweet https://twitter.com/tsunamino/status/1003318804619804672 wink.gif
@aulisius it’s because that media content isn’t a gif but rather a video. With the
sed
command replacing the extension from jpg to mp4, it looks like Twitter doesn’t store pure videos in the same way. To get things to work with a true video tweet to gif you’d have to figure how these are stored in the Twitter backend to get at the video. Viewing the source of the tweet could help you figure it out.https://pbs.twimg.com/ext_tw_video_thumb/1005574542151028736/pu/img/-WtqAkKG4PmvMIzz.mp4 Results in a 404/unplayable video