Jekyll2017-04-05T23:00:01+00:00/samhemann.comA place for my ideas, scripts, and inspirations.
Making high quality gifs with FFmpeg2017-03-29T00:03:47+00:002017-03-29T00:03:47+00:00/gifs/2017/03/29/mastering-gifs<p>It’s quite impressive how prevalent gifs are throughout the internet, considering the file format was introduced 30 years ago. That being said the lossless file format is just as inefficient as ever, and still a complete pain to work with.</p>
<p>It’s also clear that not all gifs are created equal. Tumblr’s 1MB limit for uploading size made it notorious for low resolution, borderline still image gifs like this:</p>
<div class="vidcenter">
<a href="http://imgur.com/TP9pRHC"><img src="http://i.imgur.com/TP9pRHC.gif" title="source: imgur.com" /></a>
</div>
<p>Whereas browsing /r/highqualitygifs on reddit reveals masterpieces like this 41 second, 624 pixel wide piece of art:</p>
<div class="vidcenter">
<video preload="auto" autoplay="autoplay" style="max-width: 100%; min-height: 409.5px;" muted="muted" loop="loop" webkit-playsinline="">
<source src="//i.imgur.com/E0l6vsB.mp4" type="video/mp4" />
</video>
</div>
<h2 id="the-problem">The problem</h2>
<p>You’d think a format introduced 30 years ago would be a breeze to work with at this point, but if you’ve ever tried to make one you were probably caught off guard by how frustrating the process is. Sites like gfycat and imgur offer to convert your videos to gifs, but there is a 10 second limit and ambiguous resolution changes.</p>
<p>If you want to make gifs manually, Photoshop is the most common choice for creators at /r/highqualitygifs, but that is a pretty expensive investment just to up your karma on reddit.</p>
<p>A while ago I found <a href="http://blog.pkh.me/p/21-high-quality-gif-with-ffmpeg.html">this post</a> which provided great insight into the gif’ing capabilities of FFmpeg - an open source, command-line video conversion program. I boiled down the essentials to a couple of bash scripts, and creating gifs went from hoping Photoshop won’t crash from using 16GB of RAM to a painless ~60 second process.</p>
<h2 id="getting-the-video-source-ready">Getting the Video Source Ready</h2>
<p>Assuming you have a source video that’s too long, FFmpeg can losslessly shorten it for you almost instantly with most video formats. All you have to do is update the variables in this script and voila!</p>
<div class="language-bash highlighter-rouge"><pre class="highlight"><code><span class="c">#! /bin/bash</span>
<span class="c"># Remove spaces from filenames!</span>
<span class="nv">input</span><span class="o">=</span><span class="s2">"input.mp4"</span>
<span class="nv">output</span><span class="o">=</span><span class="s2">"shortened.mp4"</span>
<span class="c"># Timestamps must be in HH:MM:SS.xxx format</span>
<span class="nv">timein</span><span class="o">=</span><span class="s2">"00:01:29.0"</span>
<span class="nv">length</span><span class="o">=</span><span class="s2">"00:00:16.0"</span>
ffmpeg -i <span class="nv">$input</span> -ss <span class="nv">$timein</span> -c copy -t <span class="nv">$length</span> <span class="nv">$output</span>
<span class="nb">echo</span> <span class="s2">"Finished."</span>
</code></pre>
</div>
<h2 id="creating-the-gif">Creating the gif</h2>
<p>Check to make sure your video looks good, then this next script should take you home:</p>
<div class="language-bash highlighter-rouge"><pre class="highlight"><code><span class="c">#! /bin/bash</span>
<span class="nv">input</span><span class="o">=</span><span class="s2">"shortened.mp4"</span>
<span class="nv">output</span><span class="o">=</span><span class="s2">"output.gif"</span>
<span class="nv">palette</span><span class="o">=</span><span class="s2">"./tmp/palette.png"</span>
<span class="c"># Update the fps and width here:</span>
<span class="nv">filters</span><span class="o">=</span><span class="s2">"fps=30,scale=720:-1:flags=lanczos"</span>
<span class="nb">echo</span> -ne <span class="s2">"Creating palette..."</span>
ffmpeg -v warning -i <span class="nv">$input</span> -vf <span class="s2">"</span><span class="nv">$filters</span><span class="s2">,palettegen"</span> -y <span class="nv">$palette</span>
<span class="nb">echo</span> -ne <span class="s2">"</span><span class="se">\r\0</span><span class="s2">33[KCreating gif..."</span>
ffmpeg -v warning -i <span class="nv">$input</span> -i <span class="nv">$palette</span> -lavfi <span class="s2">"</span><span class="nv">$filters</span><span class="s2"> [x]; [x][1:v] paletteuse"</span> -y <span class="nv">$output</span>
<span class="nb">echo</span> <span class="s2">" Finished."</span>
</code></pre>
</div>
<p>Typically this process takes around a minute, but if you’re attempting a particularly long gif you may be waiting a bit longer.</p>
<p>You can see the performance it has with high color variance and heavy animation in this example:</p>
<div class="vidcenter">
<video autoplay="" loop="" style="max-width: 100%; min-height: 360px;"><source type="video/mp4" src="//i.imgur.com/6JRoICb.mp4" /></video>
</div>
<p>As well as the clarity when using less complicated color pallets and lower frame rates:</p>
<div class="vidcenter">
<video autoplay="" loop="" style="max-width: 100%; min-height: 409.5px;"><source type="video/mp4" src="//i.imgur.com/oCrupnw.mp4" /></video>
</div>
<h2 id="notes">Notes</h2>
<p>Keep in mind the raw <code class="highlighter-rouge">.gif</code> file you create is usually larger than the source video itself (which is <em>insane</em>), so I recommend using imgur to host your gifs. They convert all gifs to HTML5 videos, which are a fraction of the size. This will keep mobile users happy as long as your remember to share the link ending in <code class="highlighter-rouge">.gifv</code>.</p>
<p>Since it looks like gifs won’t be going anywhere soon, I hope this post at least made it less stressfull for those without photoshop to create and share amazing memes.</p>It’s quite impressive how prevalent gifs are throughout the internet, considering the file format was introduced 30 years ago. That being said the lossless file format is just as inefficient as ever, and still a complete pain to work with.Building a Discord Bot with Node.js2017-03-28T00:03:47+00:002017-03-28T00:03:47+00:00/nodejs/2017/03/28/discord-bot-with-node<p>This guide will cover every step needed to get up and running with your own Discord bot,
aimed at anyone who is new to Node.js or just unsure of where to start.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Since we’ll be using Discord.js as our library for interacting with the Discord API, you
will need to have at least Node.js 6.0.0 or higher. If you are unsure of what version is
currently installed running <code class="highlighter-rouge">node -v</code> will let you know.</p>
<p>This tutorial assumes minimal knowledge of node.js. All of the code
used can be found in <a href="https://github.com/metasloth/discord-nodejs-demo">this repository</a>.</p>
<h2 id="creating-a-discord-application">Creating a Discord Application</h2>
<p>First you’ll need to create a Discord app. Head over to
https://discordapp.com/developers/applications/me and choose “New App”.
Once your app is created, you’ll want to click “Create App Bot User”.
This will give your bot a username and allow you to add it to servers.</p>
<p>Since Discord servers are free and easy to make, I recommend making one
specifically for testing the bot. Once you do this, you can add the bot to
your server by replacing “YOUR_CLIENT_ID” with the Client ID of your bot in
the following url:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>https://discordapp.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=bot&permissions=0
</code></pre>
</div>
<p>Finally, in the App Bot User section, click to reveal your token. This
token is used as the authentication for you bot to log in, so you’ll want
to keep it secret. If you are using git and want to keep it hidden in a
public repo, store it in a file named <code class="highlighter-rouge">secret.json</code>, which should look
something like this:</p>
<div class="language-js highlighter-rouge"><pre class="highlight"><code><span class="p">{</span> <span class="s2">"token"</span><span class="err">:</span> <span class="s2">"YOUR_BOT_TOKEN"</span> <span class="p">}</span>
</code></pre>
</div>
<p>Then in your <code class="highlighter-rouge">.gitignore</code> file you can add <code class="highlighter-rouge">secret.json</code> on it’s own line,
which will prevent git from staging the file. Using a json file will make
it super simple to reference our token later on.</p>
<h2 id="configuring-our-nodejs-project">Configuring our Node.js Project</h2>
<p>Head over to the directory for your project and run <code class="highlighter-rouge">npm init</code> to populate
a basic <code class="highlighter-rouge">package.json</code> file. Next we’ll install the npm packages needed
for this project:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>npm install --save discord.js@11.0.0 request@2.81.0 cheerio@0.22.0
</code></pre>
</div>
<p>Create a file named <code class="highlighter-rouge">main.js</code>, and add the following lines of code:</p>
<div class="language-js highlighter-rouge"><pre class="highlight"><code><span class="kr">const</span> <span class="nx">secret</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./secret.json'</span><span class="p">)</span>
<span class="kr">const</span> <span class="nx">Discord</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'discord.js'</span><span class="p">)</span>
<span class="kr">const</span> <span class="nx">client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Discord</span><span class="p">.</span><span class="nx">Client</span><span class="p">()</span>
<span class="nx">client</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'message'</span><span class="p">,</span> <span class="nx">msg</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">msg</span><span class="p">.</span><span class="nx">content</span> <span class="o">===</span> <span class="s1">'!hi'</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">msg</span><span class="p">.</span><span class="nx">reply</span><span class="p">(</span><span class="s1">'Hello there!'</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">})</span>
<span class="nx">client</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'ready'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="err">`</span><span class="nx">$</span><span class="p">{</span><span class="nx">client</span><span class="p">.</span><span class="nx">user</span><span class="p">.</span><span class="nx">username</span><span class="p">}</span> <span class="nx">is</span> <span class="nx">ready</span> <span class="nx">to</span> <span class="nx">chat</span><span class="o">!</span><span class="err">`</span><span class="p">)</span>
<span class="p">})</span>
<span class="c1">// This will let us know of any API errors encountered</span>
<span class="nx">client</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'error'</span><span class="p">,</span> <span class="nx">error</span> <span class="o">=></span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">error</span><span class="p">))</span>
<span class="nx">client</span><span class="p">.</span><span class="nx">login</span><span class="p">(</span><span class="nx">secret</span><span class="p">.</span><span class="nx">token</span><span class="p">)</span>
</code></pre>
</div>
<p>We can now start our bot with <code class="highlighter-rouge">node main.js</code>, and if everything is working properly
you should be off to a riviting conversation with your bot.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Hopefully this serves as a starting ground for anyone new to node.js and struggling
to get up and running. If you run into trouble as you add more complexity to your bot,
Discord.js has a pretty active Discord server wher you can usually get quick help!</p>
<p>I’ll be adding a bit more depth to this guide shortly, including deploying your bot
to a free AWS ec2 instance so your bot can be running 24/7.</p>This guide will cover every step needed to get up and running with your own Discord bot, aimed at anyone who is new to Node.js or just unsure of where to start.Welcome to samhemann.com!2017-03-21T01:44:47+00:002017-03-21T01:44:47+00:00/meta/2017/03/21/welcome<p>Hi There! This site is brand new and shiny, so it will be a few days
before I have it fully populated with content. In the mean time, you
can check out the source code on <a href="https://github.com/metasloth/metasloth.github.io">github</a>.</p>
<p>To make up for the lack of content, enjoy a sloth gif…</p>
<div class="vidcenter">
<video preload="auto" autoplay="autoplay" loop="loop" style="width: 300px;">
<source src="//i.imgur.com/hGcZAHs.webm" type="video/webm" /></source>
</video>
</div>Hi There! This site is brand new and shiny, so it will be a few days before I have it fully populated with content. In the mean time, you can check out the source code on github.