Jakob Gillich Personal blog

The state of video production on Linux

As a regular listener of the Linux Action Show and similar shows JB produces, I’ve always known video production on Linux isn’t the best experience ever. Never would I have imagined how bad things really are.

I had a really simple task. Record a video, add a few titles, done. Doesn’t sound hard, does it? Well, apparently it is - on Linux. I tried pretty much all editing software that is available:

Pitivi

Pitivi looks like a modern GNOME 3 app, great. Adding titles was very simple, unfortunately the app freezes every two clicks and you have to kill it.

Blender

Blender can actually do video editing, but Fedora does not compile it with ffmpeg support, so it supports zero formats. From what I’ve read its really not the best editing sofware anyway, so I didn’t bother building it myself.

Kdenlive

Great features, but some of them hidden at odd places. It has the potential to be really great, but sadly I also experienced a lot of crashes - less than Pitivi, but still, does anyone really work with this stuff?

OpenShot

OpenShot is missing some basic features any program should have. The actual video editing part is ok (yes, I had issues, but not as bad as with the others), but you can not ever move any of the files used in a project because they hard code a million paths in the project file. Paths to python, the local configuration directory and even the desktop. Open a project file after moving anything and OpenShot just crashes right away.

Lightworks

The only closed source app here. They announced they would go open source in 2011, I doubt it’s ever going to happen. It seems to be a pretty good software overall, but the free version is basically demo mode - adding titles requires the paid version, which I’m not really willing to get at this point.

What now?

I was able to get the results I wanted with OpenShot. But I don’t think I am ever going to use it again because it is impossible to share the project files with anyone. Renaming a single folder alone breaks your project, that’s just not acceptable.

I have to agree with others that video production on Linux is nowhere near being viable, unless you buy Lightworks. Kdenlive is probably the best open source editor out there, but you still have to deal with it crashing, a lot.

Using GitHub Pages and Travis for automatically deployed web sites

Due to some issues with upgrading my Ghost installation, and considering that I’m not blogging that much anyway, I’ve decided to move this blog over to GitHub Pages using the Middleman static site generator.

To write a blog post, all I have to do is to push it to GitHub. Travis then builds it and pushes it to the gh-pages branch, from where GitHub serves it, and thanks to Cloudflare I even get free SSL. Zero cost, zero maintenance required.

Now, on how to do that. Obviously you need a GitHub repository that contains your sources. This method works with pretty much anything that can output a static site, it is not limited to Middleman. Anyway, create your repository and add two files.

One, .travis.yml:

language: ruby
script: bundle exec middleman build
sudo: false
after_success: |
  export PATH=$HOME/.local/bin:$PATH &&
  [ $TRAVIS_BRANCH = master ] &&
  [ $TRAVIS_PULL_REQUEST = false ] &&
  pip install ghp-import --user `whoami` &&
  ghp-import -n build &&
  git push -fq https://${TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
env:
  global:
    - secure: YOUR_ENCRYPTED_GITHUB_TOKEN

This tells Travis to build the site and uses ghp-import to push the build folder back to GitHub. For authentication, you need a token from GitHub, then encrypt it using the Travis command line client (gem install travis) from within your repository:

travis encrypt TOKEN=YOUR_GITHUB_TOKEN

One more file you will need is a CNAME file. It tells GitHub pages that incoming requests from your domain belong to that repository. All it contains is your domain, in my case:

www.jakobgillich.com

Note that this has to be in the root path of your gh-pages branch, in the case of Middleman you would put it under source/CNAME. Once you have created these two files, you can enable Travis for your repository and your site should be automatically deployed to GitHub Pages whenever you push to your repository.

To set up your domain, go to Cloudflare and add two DNS records to your domain:

CNAME   @     jgillich.github.io
CNAME   www   jgillich.github.io

You can also set SSL to Full, Cloudflare will then always communicate with GitHub over SSL.

At this point, we are pretty much done, but one more thing. Since we got free SSL from Cloudflare, there is no reason not to use it. You can force HTTPS by going to Page Rules and checking Always use https for the URL pattern http://*jakobgillich.com/*.

How To Install Redmine on CentOS 7

The following describes the process to get the Redmine project management application running on CentOS (RHEL) 7 with a MariaDB database.

Install dependencies:

# yum install @development mariadb-server mariadb-devel ruby ruby-devel ImageMagick ImageMagick-devel rubygem-rake rubygem-bundler

Enable and start MariaDB:

# systemctl enable mariadb
# systemctl start mariadb

Configure database:

# mysql
> CREATE DATABASE redmine CHARACTER SET utf8;
> CREATE USER 'redmine'@'localhost' IDENTIFIED BY 'my_password';
> GRANT ALL PRIVILEGES ON redmine.* TO 'redmine'@'localhost';
> exit

Create user to run redmine under:

# adduser redmine

Download and extract redmine:

# curl -O http://www.redmine.org/releases/redmine-2.5.2.tar.gz
# tar xvf redmine-2.5.2.tar.gz
# mv redmine-2.5.2/ /home/redmine/
# mv /home/redmine/redmine-2.5.2 /home/redmine/redmine
# chown -R redmine:redmine /home/redmine/redmine

Setup redmine:

# su redmine
$ cd ~/redmine

$ cp config/database.yml.example config/database.yml
$ vi config/database.yml # set user & password for production

$ bundle install --without development test
$ rake generate_secret_token
$ RAILS_ENV=production rake db:migrate
$ # load default data (optional):
$ RAILS_ENV=production rake redmine:load_default_data

$ mkdir -p tmp tmp/pdf public/plugin_assets
$ chown -R redmine:redmine files log tmp public/plugin_assets
$ chmod -R 755 files log tmp public/plugin_assets

To start redmine with Ruby’s own webserver, run:

$ ruby script/rails server webrick -e production

You can also add -p PORTNUMBER to set a port other than the default (3000). If you want to access redmine over the network, you have to add a firewall rule:

# firewall-cmd --add-port=3000/tcp --permanent
# firewall-cmd --reload

Gulp, Yet Another JavaScript Build Tool

Grunt is unarguably the most popular build tool for web projects. I like a lot of things about it, but dislike a few others like the configuration syntax and its performance.

So I’ve finally tried Gulp and I’m impressed. Porting my Gruntfile was very easy because Gulp is just so simple to use, it took me maybe 30 minutes to port around 80 lines of Grunt configuration, resulting in 60 lines of gulp tasks. And it doesn’t just run faster (build time down to 2 seconds from 3 seconds; much more important however is that the watcher reacts faster), it is also more readable.

There are a few differences of course; Gulp doesn’t try to be the best tool for everything. Tasks run in parallel by default, which doesn’t work very well when one of them wipes the build directory while another one writes into it. Workarounds are available though.

Still, if you know how streams in Node work, you almost know how to use Gulp. Grunt on the other hand is a complex beast that does everything you want, but requires you to have some patience while learning and running it.

CentOS 7

[root@centos7 ~]# yum install nginx
No package nginx available.

Yes, they are dead serious. But they ship nginx in RHSCL 1.1, which sadly isn’t available on CentOS yet.

Redirecting Ctrl+A with JavaScript

While building a simple paste service, I wanted to catch Ctrl+A and redirect it to only select a single element. This does exactly that:

document.addEventListener('keydown', function (event) {
    if(event.ctrlKey && event.keyCode == 65) {
        var range = document.createRange();
        range.selectNode(document.getElementsByTagName('main')[0]);
        window.getSelection().addRange(range);
        event.preventDefault();
    }
});

What it does:

  • Attach a keydown handler to document to get all key presses
  • Make sure Ctrl+A have been pressed (A is keyCode 65)
  • Add a selection to an element (<main> in this case)
  • Call preventDefault to make sure the event is ignored by the browser

StartSSL & Heartbleed

Until today, I used StartCom’s StartSSL for all of my domains. While their web interface is terrible, they are probably the only company that offers free certificates. But in reality, they are not really free (anymore).

You surely heard of the Heartbleed bug, which allowed anyone to get access to the private certificate keys, making encryption totally useless. Since I was affected by this as well, there were two things I had to do:

  1. Update OpenSSL. By the time I heard about the vulnerability, FreeBSD did already provide an updated port. Easy.
  2. Replace all certificates. Turns out that in order to generate a new certificate at StartSSL, the old either has to expire or you have to revoke it - which costs $25.

Considering almost all of their customers need a new certificate, their free certificate effectively costs $25 now. I guess a lot of their customers aren’t willing to pay this fee and will rather risk leaked keys. That’s just irresponsible - if you are not able to offer free certificates that are actually secure, then don’t.

MProgress, a slim progress bar written in Vanilla JS

MProgress is a small JavaScript library I’ve been working on last weekend. If you know NProgress, my project is a much smaller (70 lines vs. 300+ lines) clone that has no dependency on jQuery. To be fair, it also has fewer features and only works on more modern (ES5-compatible) browsers.

I have never done a lot of DOM stuff without jQuery so this has been quite interesting. I had to look up how to do really basic things like inserting an element, but I also realized that there are very few cases where I will ever want to prefer Vanilla JS over jQuery. For example, to remove a element from the DOM, you have to call removeChild on the parent:

el.parentNode.removeChild(el);

Now the same code in jQuery:

$(el).remove()

The latter is not only shorter, it also easier to understand.

Anyway, in this case it made a lot of sense to write vanilla JavaScript: You can load it, show a progress bar and then start loading the huge chunk of minified scripts that your application consists of. Users with a slow (mobile) connection will then see a progress bar that informs them the page is being loaded instead of just a blank page.

To find out more, I’ve put a small page together that includes a live example of the library.

Smaller Moment.js

Moment.js is a great JavaScript library that makes working with time a lot easier. I totally love it, but there is one problem: It is huge! That is because moment-with-langs.js includes all supported languages, and they support a lot of them!

Now the good news is that you can build a custom version of Moment.js with just the languages you need. To do this, you need Git, Node.js and Grunt - but you have these already, right?

Let’s start by fetching the repository and installing dependencies:

git clone https://github.com/moment/moment.git
cd moment
git checkout master
npm install

Now simply run the below command with a comma seperated list of all languages you need (German and French in this example) - all languages in the lang/ folder can be embedded.

grunt release --embed_languages=de,fr

Note that english is always included and there is not way to change that. When the command finishes, you’ll find your custom version at min/moment-with-customlangs.js.

The resulting file size is around 70 KB with a single language - much better than the default 270 KB.

My First FreeBSD Port

I’ve recently created a FreeBSD port for Ghost. Overall, it was a pretty frustrating experience. The biggest issue was that there’s just so few resources on the web about it.

Yes, the official documentation is pretty good. But on the other hand, it actually answered very few of my questions. One example: Ports contain a plist file that lists all files that belong to it. There is documentation about it and it also has a section about dynamic plists. It tells you when you can use a dynamic plist, but it’s missing any instructions on how you actually implement one.

Since FreeBSD is not as popular as Linux, there are a lot less forum/blog posts and mailing list entries. You really can’t blame FreeBSD for that, but it makes finding solutions a lot harder. That’s also one of the reasons why I’m writing this.

But there is one thing that has helped me a lot: Reading other ports. You will gain a lot from that as most ports are written by experienced contributors. And if you struggle too much, there are a lot of helpful people hanging around on the forums and mailing lists.

Challenges

There were a few challenges I had to face. Once I even fixed a issue by switching to a fresh jail and abandoning the old. So please - if you are a newbie, use a jail so you don’t mess up your production system!

Extract to Subdirectory

The Ghost source code is a zip file that contains no sub folder. Doesn’t sound like a big deal, right? Actually, it is. If the source code extracts directly into ${WRKDIR}, it is pretty hard moving it into ${STAGEDIR} without specifying every single file because the latter directory is inside the former.

But this can be solved by using a custom do-extract:

do-extract:
    ${MKDIR} ${WRKSRC}
    ${LOCALBASE}/bin/unzip -d ${WRKSRC} ${DISTDIR}/${DISTFILES}

Set correct permissions

After extracting the files, they were set to 100. Not very useful, but using @mode 755 in the plist fixed it. You can also use @owner somebody and @group somegroup if you want to.

Dynamic plist

Implementing a dynamic plist wasn’t that hard. You simply need to specify PLIST= ${WRKDIR}/plist and then generate this file in the pre-install target like this:

cd ${WRKSRC}; ${FIND} . -type f | cut -c2- \
    | ${SED} 's|^|www/ghost|' \
    | ${SORT} -r >> ${PLIST}
${ECHO_CMD} "@comment directories" >> ${PLIST}
cd ${WRKSRC}; ${FIND} . -type d | cut -c2- \
    | ${SED} 's|^|@dirrm www/ghost|' \
    | ${SORT} -r >> ${PLIST}

This uses find to get a list of files, corrects the path and appends them to the plist. That’s all you have to do.

Learn from me

You can find the full code of my port in the Ghost-Config repository. Feel free to check it out, study it and send me your improvements.