Mattermost Recipe: Previewing videos in a channel

Here’s another installment of a new series of posts we’re doing on the Mattermost blog: Mattermost Recipes.

The goal of these posts is to provide you with solutions to specific problems, as well as a discussion about the details of the solution and some tips about how to customize it to suit your needs perfectly.

If there’s a Recipe you want us to cook up in the future, drop us a line on our forum.

 

Problem:

You have video files being added to a fileserver, but you don’t know what’s in them. They’re stored remotely, so you can’t just download them to see what’s in them. You also need to share these files to the web, mobile, and desktop via automated transcoding.

Solution:

First, set up your Mattermost server. If you’re running it on the same machine you’re hosting the webhook on, you’ll need to modify the config.json file to include your local hostname:

"AllowedUntrustedInternalConnections": "192.168.1.100 127.0.0.1"

Then, install the following items on your server.

  • ffmpeg
  • mediainfo
  • webhook
  • incron
  • RestClient Gem
  • Mediainfo

Next, configure your Mattermost server to allow incoming and outgoing webhooks. To do this, go into the system console and enable incoming and outgoing webhooks. It’s under Settings -> Custom Integrations:

Custom Integrations Screenshot

After that’s done, check out the project and set up the configuration for your video preview file. Make sure to name the file video_preview_config.yaml and put it in the same directory as the Ruby script.

Then, test the preview by running a command against an existing file. I’ve included a video file:

$ mattermost_video_preview.rb preview clouds.mov

Now that you’ve got it running, configure your webhooks to call the server when it’s run. Modify the file web hooks.example.conf to use the appropriate paths and then run this command to set it up:

# cp webhooks.example.conf /etc/webhooks.conf
# service webhooks restart

Finally, configure incron to watch the directory and trigger the script when it’s run. To do this, first add your username to the incrontab:

$ sudo echo $USER >> /etc/incron.allow

Then run incrontab -e to add the following rule:

/directory/to/watch IN_CREATE /path/to/mattermost-video-preview/mattermost-video-preview.rb preview $@/$#

And that’s it! Now, when a video file is placed in the watch directory it will generate a preview, and you’ll be able to click one of the buttons to run a command on the file.

Discussion

This script is made up of two main functions: generate_previews and run_command.

As you can imagine, the first generates the preview images and posts it to the Mattermost channel and the latter runs the command and sends updates to the Mattermost channel. The call_mattermost function is used to send information to the Mattermost incoming webhook and the upload_file function moves the previewed image to the web server.

generate_previews

There are a couple of interesting things about this function. First is this bit, which calculates the screen grab interval based on the number of images needed and the duration of the clip

if framegrab_interval.to_i == 0
        total_images = 1
        framegrab_grid.split('x').each do |x|
            total_images *= x.to_i
        end
        framegrab_interval = file_info.duration / total_images
end

Outputting information in a human-readable format is important, so there are two sections that generate human-compatible file sizes and durations. This is something I think I can refactor into a more general, possibly recursive function that will work for more than just file sizes and durations:

count = 0
    units = ['bytes', 'KB', 'MB', 'GB', 'TB']
    loop do
        break if filesize < 1024.0
        count += 1
        filesize /= 1024.0
    end

    pretty_filesize = filesize.round(2).to_s + ' ' + units[count]

    duration = file_info.duration
    remainder = 0
    count = 0
    units = ['sec','min','h']
    loop do
        break if duration < 60
        count += 1
        remainder = duration % 60
        duration /= 60
    end

    pretty_duration = duration.round(0).to_s + ' ' + units[count]

The message posted to Mattermost makes use of Markdown-compatibility to present things in a nice table. It also iterates over the valid file operations, so you can configure different operations and have the included automatically.

message = "![#{base_filename}](#{uploaded_file_url})\n\n"
message+= "|#{base_filename}|[(preview)](#{uploaded_file_url})|\n"
message+= "|-|-:|\n"
message+= "|File Size| **#{pretty_filesize}**|\n"
message+= "|Duration| **#{pretty_duration}**|\n"
message+= "|Format| **#{file_info.format}**|"

actions = Config['FileOperations']
attachments_actions = []
actions.keys.each do |key|
    action_hash = {
        'name': key,
        'integration': {
            'url': [Config['Webhook']['url'], 'run-command'].join('/'),
            'context': {
                'command': key,
                'filename': File.realpath(filename)
            }
        }
    }

    attachments_actions.push(action_hash)
end

run_command

This function is also pretty straightforward. First it checks to see that the user is passing a valid file operation. Then it runs that command on the file. Because the file operations are stored in a config file, you don’t have to worry about running unauthorized commands.

The operations can be configured with a few different options:

  • command: The command to run. You can specify the input and output filenames.
  • text: Changes the default text that’s reported to Mattermost. Can include the input and output filenames in this as well.
  • location: Changes the default location where the new file is stored.

Applications

I wrote this to handle ripping DVDs. But anyone who’s handling a lot of video files can appreciate having relatively small previews of the videos for organizing them. Connecting them to Mattermost means you’re not having to manually watch a directory for new files or move around large movie files just to see what’s in them.

If you have an application where users are uploading video you’re going to need to moderate, or at least check out ones reported by other users, this could come in really handy. Putting the previews into Mattermost and giving the team there the ability to approve or deny them with a click would greatly speed up the moderation process.

Another use for this would be to curate videos generated by another department. For instance, your marketing department may have people generating video assets like screencasts that put the finished product in a specific folder. This script will generate a preview for it so you can see when it’s done and then run whatever commands you want.

(Editor’s noteThis post was written by Paul Rothrock, Customer Community Manager at Mattermost, Inc. If you have any feedback or questions about Mattermost Recipe: Previewing videos in a channel, please let us know.)

mm

Paul Rothrock is the Customer Community Manager at Mattermost, Inc. Prior to joining Mattermost, he served as a support product manager for Oracle. Paul also worked in tech support and as a publisher advocate for AddThis and has held several other software development roles over the years. Paul holds a bachelor of science degree in information sciences and technology from Penn State University.