Scripting with Fast video cataloger

Fast video cataloger has support for automating and extending the software through C# scripting.

Scripting in Fast video cataloger is extremely powerful but it can be a bit intimidating if you have no previous experience from scripting.

We prepared a guide to help you get started with scripting in Fast video cataloger, download it here

We also prepared a quick high-level video about scripting.

Using TMDB Web API ( The Movie DataBase )

TMDB (The Movie DataBase ) is a large open internet database you can use to search for movies, tv shows, and people in movies. It also has a web API.

Fast video cataloger is a software to organize video clips so you can quickly search, browse, and find what you are looking for.

This example will show how to use the scripting support in Fast video cataloger to integrate with the web API in TMDB. My goal is to show you have to integrate a search for actors using the TMDB web API and then add the metadata to Fast video cataloger. With this start, I hope you can expend it to what you need and perhaps use other functions in the TMDB API.

Script demo

Getting started

If you do not already have Fast video cataloger installed you can download a free trial from here

Before we can start you also need to create a free account at TMDB that you can get from here, When you have your account to go your profile, click settings and find the API tab and request a developer API key.

The script we show here can be downloaded from our sample git hub repository

Place the downloaded scripts get_actor.xaml and get_actor.xaml.cs in the script folder of your fast video cataloger installation.

Open the get_actor.xaml.cs and fine the line near the top that reads

static string api_key = "";

and replace the empty api_key string with your TMDB API key.

Running the script

To run the script in Fast video cataloger open the Script console window. In the window click on the Load button and load the get_actor.xaml.cs script. Click run and you should see a window like this:

tmdb actor search

Integrating with tmdb people search

Search for an actor and you should see something like this

tmdb search results

results of a search in the movie database

You can then click “Add to catalog” to add the actor to your Fast video cataloger database

Script overview

The C# script that is running uses WPF for the user interface. The user interface is defined in the XAML file. We use the rest API for TMDB. You can find full documentation for it here

Note that this sample just uses a minimal subset of the TMDB API. But, the principles are the same for the whole API, and it should be pretty easy to extend this with more functionality. For example, getting poster images or searching for movies.

Another difference to most other Fast video cataloger samples is that this one uses async programming which is needed for the web APIs.

Script walkthrough

You can find the full xaml file here and the full source file here

References

At the very top of the script we need to add our external references. This is what normally would go into “references” in a visual studio c# project. In a Fast video cataloger script you use a comment in the format of :”//css_ref [dependency]”.

//css_ref WindowsBase;
//css_ref PresentationCore;
//css_ref PresentationFramework;
//css_ref System.Runtime;
//css_ref System.ObjectModel;

WindowsBase, PresentationCore, and PresentationFramework are needed for the WPF user interface. System.Runtime and System.ObjectModel has the c# code we need to access and parse the web API.

Static variables

At the top of the script, we have a few static variables. The important one here is again the api_key variable, here you need to fill in your key as mentioned earlier.

Entry point

Run is the entry point of all scripts running from Fast Video cataloger:

static public async Task Run(IScripting scripting, string argument)

The only thing we do in the entry function is to save the passed in scripting interface and then create the GetActors WPF window and show it. We intentionally call Show() and not ShowDialog() since we want to be able to bring up the actor window in Fast video cataloger when we have this window open.

Constructor

In this example, we have put all code in the HelloWindow class. This has the same structure as the basic HelloWpf.cs sample.
The constructor loads the XAML interface definition and sets up the window. It also establishes the connection between the buttons and their click functions (unfortunately we do not support binding directly in the XAML as the XAML file is loaded through the script engine ).

Searching

When the search button is clicked we will get a callback to Search_Click(…). This is the main function that performs the search. We first fetch the text the user entered in the search box.

Then we call SearchActors asynchronously and expect to get a CPersonSearchResult back, more on that later.

private async Task SearchActors( string query )
{
  string encoded_query = System.Net.WebUtility.UrlEncode( query );
  string search_line = api_base_url + "search/person?api_key=" + api_key + /
         "&language=en-US&query=" + encoded_query + "&include_adult=true&page=1";
  CPersonSearchResult header_result = await GetFromJSON(search_line);
  return header_result;
}

After that, we have to check if we got a search hit. In this example, we only care about the first result but you can of course list all the results and let the user pick one of them.

We have our first actor and pick the name. We then call MakeProfileImageUrl(…) to generate a URL for the profile image. We call GetImageData(…) to get the image from that URL.

At this point, we have most of the data we need.

We create a new Actor class in the Fast video cataloger format and store that in m_CurrentActor. We fill in the data members with data from the search and the downloaded portrait data.

Next, we call GetPerson() with the TMDB id for the first actor. Once we have done that we have all the data we need from TMDB.
We create a WPF image from the downloaded image data and call SetActorToUI() to update the user interface.

SetActorToUI()

This function simply updates the user interface from the variable we have designed. The portrait is set to the image, the name and the description is set. The XAML file defines the whole layout of the user interface including size and positions of elements and fonts.

Adding to Fast Video cataloger catalog

If you click add to catalog after you have searched and found an actor you will get a callback to AddToCatalog_Click(…). Here we simply get the interface to the video catalog and call AddActorToDB() with the m_CurrentActor we filled in earlier when we got the search result.

GetConfiguration()

GetConfiguration() is a wrapper to load the TMDB configuration. You only need to call this once in your application and it is needed to among other things figure out the path to any image resource. The configuration is stored globally in m_Configuration. This is a very short function and it is a good example of how to use the TMDB rest API.

First, we create the URL that we will use to access TMDB. It always starts with the base URL and then the API we want to use and some arguments. Among the arguments, you always pass in your API key. We then use this URL and call one a utility function, GetFromJSON(), we have in the sample code. This function takes a class argument, which is of type of the JSON file we want to get from the URL. And, it returns an object of that class or null if it fails.
Let us take a closer look at that utility function.

GetFromJSON()

GetFromJSON() is an asynchronous function that you pass the class of what you want to read from the query string. There is some initial setup and then we call GetAsync( query ) that will asynchronously call the URL and get the result. Once we have the result we read the data from the response message as a string. We then create a memory stream to the string data and create a DataContractJsonSerializer object to parse our data from the JSON data and create the C# object.

public async Task GetFromJSON(string query)
{
  T parsed_stuct = default(T);
  var handler = new HttpClientHandler();
  handler.AllowAutoRedirect = false;
  var client = new HttpClient(handler);
  try
  {
    var videoGetIndexRequestResult = await client.GetAsync(query);
    var result = videoGetIndexRequestResult.Content.ReadAsStringAsync().Result;
    var ms = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(result));
    var serializer = new DataContractJsonSerializer(typeof(T));
    parsed_stuct = (T)serializer.ReadObject(ms);
    ms.Close();
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex.Message);
  }
  return parsed_stuct;
}

If you want to use other parts of the TMDB API you need to create classes for the data that are returned by the functions.

SearchActors( string query )

The SearchActors() function is very similar to the GetConfiguration() function but it uses the search/person API. We pass the api_key but also some extra arguments.

One of the arguments is a query string, this needs to be URL encoded to handle special characters like spaces.

Then again, once we have our URL, we simply use the GetFromJSON() utility to read the result into the CPersonSearchResult class. This class includes info about how many results you have from your query and some basic information about each result returned in an array of class CActorResult. Here you have the name of the actor, an id that we can use in other API calls and a profile_path. Profile_path is needed when you want to create an URL to fetch the profile picture.

MakeProfileImageUrl()

MakeProfileImageUrl() is a utility function that is used to generate an URL to a profile image. For this, we need the configuration data where you have the base_url for all profile images. We need to decide on the size of the image, the different types of sizes are also listed in the profile image, and then finally we need the part of the URL that is unique for every actor. Once we have this URL we can just get the data.

GetImageData()

GetImageData() takes the URL from MakeProfileImageUrl() or really any image URL in the TMDB image URL format. We again use the WebClient API and call DownloadDataTaskAsync(). This function will asynchronously download the image data to an array. This is the right format we need to pass to Fast video cataloger. But we need one more step to display it in the WPF user interface.

private async Task GetImageData(string url)
{
  byte[] image_data = null;
  try
  {
    Uri image_url = new Uri(url);
    var webClient = new System.Net.WebClient();
    image_data = await webClient.DownloadDataTaskAsync(image_url);
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex.Message);
  }
  return image_data;
}

LoadImageFromStream()

LoadImageFromStream() takes a memory stream to the bytes we loaded with GetImageData() and create a BitmapImage object from it. This object can then later be assigned as a source to any Image element we have in our XAML user interface.

Conclusion

I have shown how you can expand on the functionality of Fast video cataloger with web API. In this example we used TMDB but there are tons of other web APIs that might be useful and my hope is that this sample will make it easier for you to get started.

Build your custom video solution with a WPF user interface

Custom video solution

If you want to develop a custom video solution in Fast video cataloger you will need a user interface. This article will show you how to build a WPF user interface in a Fast video cataloger script.

What is WPF

WPF stands for Windows Presentation Foundation and is a Windows technology to create user interfaces. In WPF you defined your user interface in an XAML file. The whole user interface in Fast video cataloger is built with WPF.

XAML to define the user interface

In WPF you specify the layout of the user interface in an XML file. This file defines what standard controls you want on your page and how the layout is going to be arranged. Separating the user interface from the code like this makes it possible to hand over the design and layout of the user interface to an artist and let the programmer focus on the actual code of the application. Well at least in theory. Even if you are doing both the code and the user interface it is a nice separation to have your layout defined in a separate file. You can also use programs like Blend or Visual studio to design your user interface without touching the code of your application.

Problems with WPF in scripts

If you want to use WPF to build a user interface for a script in Fast video cataloger there are a few problems we need to solve. First, when compiling a WPF applicaton there are actually different compilers compiling the XAML code that defines the user interface and the C# code that is the program. The scripting in Fast video cataloger has no XAML compiler so that’s one problem. Another problem is that you do not specify a list of files to load, you only load your main C# script file. So to be able to define a user interface in XAML we need to load the file dynamically from our C# script. Luckily there is a function in .net to do just that System.Windows.Markup.XamlReader.Load(...).

Referencing external scripts

To be able to use WPF we need to bring in a number of external references. In a Visual studio solution you would add these these as references to the soluton. Again, in Fast video cataloger we load one script file. To solve this Fast video cataloger does special parsing of comments to let you use comments to bring in external references. css_ref is the syntax to bring in an external reference. To bring in everything you need for WPF in your script just add these lines to the top of your script:

//css_ref WindowsBase;
//css_ref PresentationCore;
//css_ref PresentationFramework;
//css_ref System.Runtime
//css_ref System.ObjectModel

Once we have the references we also need to add the “using” clause as usual in “.net”. Adding the following at the top of your script should bring in all we need for WPF.

using System;
using System.Xaml;
using System.Windows;
using System.IO;
using System.Windows.Controls;

Visual studio solution

The sample solution provided with the Fast video cataloger has all the references set up so you can add your XAML files and C# files there and use the UI editor to design your user interface. You are even able to compile the user interface even though the compilation in the solution works in a completely different way compared to the script. Even so, this is a good way to quickly catch errors. I highly recommend you use the provided sample solution and continue to build on the provided WPF sample.

Step by step through the script

This sample starts with a class that inherits from the Window class. This is the main window for the user interface. In the constructor we can set the size and title of the window.

Width = 320;
Height = 200;
Title = "Dynamic WPF window";

The next step is to load the actual xaml file that defines our user interface. Here is the code to do this:

string current_folder = Directory.GetCurrentDirectory();
string path = current_folder + "\\scripts\\samples\\hello_wpf.xaml";
using (FileStream fs = new FileStream( path, FileMode.Open))
{
m_RootElement = (DependencyObject) System.Windows.Markup.XamlReader.Load(fs);
}

XAML and the user interface definition

and if we look at the XAML file that defines the user interface it looks like this:


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Foreground="Black"
Background="White"
UseLayoutRounding="True">
<StackPanel>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<Label Foreground="Black">Enter message:</Label>
<TextBox Width="100" Name="input1" Margin="10"/>
</StackPanel>
<Button Name="button1"
Margin="10"
Width="96"
BorderThickness="2"
Content="Click Me" />
</StackPanel>
</Page>

The first lines are standard XAML for creating a page for a Window.

Next, a <StackPanel> controls the layout saying that everything below will be stacked vertically. Next, we have another <StackPanel> that says anything in it will be stacked horizontally. In there we add a <Label>, i..e. a text line and then a <TextBox> that accepts input from the user. Below the <StackPanel> we have a <Button>.

Connecting the button

We have now seen the definition of the user interface. Loading a XAML file dynamically like we do unfortunately mean that bindings does not work. Because of this we need to connect the button from the C# side and we do that like this:


Button btn = (Button)LogicalTreeHelper.FindLogicalNode(m_RootElement, "button1");
btn.Click += button1_Click;

The LogicalTreeHelper.FindLogicalNode function helps us find a UI element with the Name property set as “button1”, and we give the root of the loaded XAML file to search from. The function will return our Button and then we only need to hook up the Click event to the function we want to be called when the user clicks the button i.e. button1_Click

The last thing we do in the main window constructor is to set the content of the window to the loaded root element.
this.Content = m_RootElement;
This is what actually sets the loaded user interface to be displayed in the Window.

The script

The script starts as always at the static Run function. Here we create an object of our class and just call ShowDialog to show the window. When you run the script you will see the user interface. If you click the button we take what text has been input in the text box and shows that in a popup window.

The last thing to explain is the Main function. It is only needed because WPF expects the Main function when you compile in Visual Studio, it is never called or needed when running the C# file as a script in Fast Video cataloger.

WPF is a great option for building user interface and is highly recommended when you build a custom video solution on top of Fast video cataloger.

Complete XAML file


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Foreground="Black"
Background="White"
UseLayoutRounding="True">
<StackPanel>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<Label Foreground="Black">Enter message:</Label>
<TextBox Width="100" Name="input1" Margin="10"/>
</StackPanel>
<Button Name="button1"
Margin="10"
Width="96"
BorderThickness="2"
Content="Click Me" />
</StackPanel>
</Page>

Complete C# file


//css_ref WindowsBase;
//css_ref PresentationCore;
//css_ref PresentationFramework;
//css_ref System.Runtime
//css_ref System.ObjectModel

using System;
using System.Xaml;
using System.Windows;
using System.IO;
using System.Windows.Controls;

namespace VideoCataloger
{

public partial class HelloWindow : Window
{
DependencyObject m_RootElement;

public HelloWindow()
{
Width = 320;
Height = 200;
Title = "Dynamic WPF window";

string current_folder = Directory.GetCurrentDirectory();
string path = current_folder + "\\scripts\\samples\\hello_wpf.xaml";
using (FileStream fs = new FileStream( path, FileMode.Open))
{
m_RootElement = (DependencyObject) System.Windows.Markup.XamlReader.Load(fs);
}

Button btn = (Button)LogicalTreeHelper.FindLogicalNode(m_RootElement, "button1");
btn.Click += button1_Click;

this.Content = m_RootElement;
}

private void button1_Click(object sender, RoutedEventArgs e)
{
TextBox textbox = (TextBox) LogicalTreeHelper.FindLogicalNode(m_RootElement, "input1");
MessageBox.Show("Message is: " + textbox.Text);
}

[STAThread]
public static void Main()
{
}

static public void Run(IScripting scripting, string argument)
{
HelloWindow wnd = new HelloWindow();
wnd.ShowDialog();
}

}
}

Guide to recent How To articles about Fast video cataloger

Recent article overview about how to use Fast video cataloger

The last months we have added lots of information on how to use Fast video cataloger. Here is a quick guide to help you quickly find what might be useful for you.

New articles about how to use the software

Learn how you can use Fast video cataloger as a video library when you are live streaming in “video library for live streams”

Learn how to find identical or similar videos to save some space and clutter in “easy-way-to-find-similar-videos”

Learn how you can use the integrated companion image features in Fast video cataloger in “Managing photos and video images for your video files/”.

Fast video cataloger has an integrated file organizer. Learn how to organize your actual video files using this functionality in “How to work efficient with video folders/”.

This text, “How to work faster with videos in Fast video cataloger/”, is a favorite of mine. It goes through a bunch of small features that can save lots of time if you are a frequent user of Fast video cataloger.

“Video wall” is one of the unique features in Fast video cataloger. In “video-wall in Fast video cataloger/” we explain the feature in more detail. If you have not tested it already you owe it to yourself.

Learn how to get highest quality videoplayback in Fast video cataloger by reading “Using madvr for high quality video playback/”.

New articles about how to use the scripting functionalities

Scripting is not for everyone, there is a learning curve. But, if you are interested in automating tasks or extending the software we have added a bunch of new articles for you. And we have more text planned for the coming month. Maybe you know someone that is a programmer who would like to try it out?

In “Exporting thumbnail files from videos using c#” we show how you export the video thumbnails to jpeg files on disk. This will be useful when you want to use the images in another software or perhaps a web page.

In “Import videos from all my movies by Boildesoft” we show how you write a script that reads data from a standard Access database.

In “c# for all the really advanced video searches” we show how you may extend the search function to fit your specific need. This can be combining search criteria from external data or just be outside of what you can do with the user interface in Fast video cataloger.

Exporting thumbnail files from videos using c#

Saving thumbnails

Sometimes you need a video thumbnail for use outside of Fast video cataloger. You can easily just right click the thumbnail and select “save as”. This is fast and easy if its a single thumbnail you want to save but it will be very time consuming if you want to save all thubmnails for a video, or for several videos.

This is a good example of where the scripting support in Fast video cataloger can help, and it is really easy.

Exporting thumbnails from C# script

This example shows how to export out all thumbnails for the currently selected videos as files.

For each video we create a foder called thumbnails in the same folder as the video file. Then we get all the thumbnails for the selected video by calling GetThumbnailsForVideo(video_id, true );
we get all the thumbnails and only need to go through them all, generate a filename and call System.IO.File.WriteAllBytes(filename, image_data);
to write out the image to file.

using System;
using System.IO;
using System.Collections.Generic;
using VideoCataloger;
using VideoCataloger.RemoteCatalogService;

class ExportThumbnails
{
    static public void Run(IScripting scripting, string arguments)
    {
        scripting.GetConsole().Clear();

        var service = scripting.GetVideoCatalogService();
        ISelection selection = scripting.GetSelection();
        List selected = selection.GetSelectedVideos();
        foreach (long video_id in selected)
        {
            var video_file_entry = service.GetVideoFileEntry(video_id);
            string target_folder = video_file_entry.FilePath; 
            int path_end = target_folder.LastIndexOf('\\');
            target_folder = target_folder.Substring(0, path_end+1);
            target_folder += "Thumbnails\\";
            try
            {
                DirectoryInfo info = Directory.CreateDirectory(target_folder);
            }
            catch (Exception ex)
            {
                scripting.GetConsole().WriteLine( ex.Message );
            }

            long image_no = 1;
            Dictionary thumbnails = service.GetThumbnailsForVideo(video_id, true );
            foreach (KeyValuePair thumbnail_entry in thumbnails )
            {
                byte[] image_data = thumbnail_entry.Value.Image;

                string filename = target_folder + image_no.ToString() + ".jpg";
                scripting.GetConsole().WriteLine("Saving image to : " + filename);
                System.IO.File.WriteAllBytes(filename, image_data);
                image_no++;
            }
        }
    }
}