Taking video snapshots quickly: KDE VLC Snapper

Some of the oldest readers of this blog are well aware of a certain hobby of mine. Over the years I’ve always wanted to write more about that, including the stuff I’m viewing nowadays, but I found a hassle to collect snapshots from videos / DVDs, selecting them, and so on. 

Recently I learnt that VLC has some rather complete Python bindings, and I thought, why not make the process automated? Yesterday I had some free time on my hands and a quick session of hacking brought some results already.
As the stuff is somewhat past prototypal stage, I thought I would push somewhere for others to use.  Lo and behold, here I present you KDE VLC Snapper.
As you can see, it’s a minimal dialog: just select your source video file (any file supported by VLC will do), the number of screencaps, the destination directory, and the program will do the rest. Currently it works somewhat OK (see caveats below) and is good enough for my use cases.

How do I get it?

Just clone this repository:
git clone http://git.gitorious.org/kde-vlc-snapper/kde-vlc-snapper.git

followed by

sudo python setup.py install

You can then invoke the program with

kdevlcsnapper
Requirements include PyKDE4 (tested on KDE Dev Platform 4.6), numpy (just for its “linspace” function, alternatives are welcome) and VLC installed (you don’t need the bindings, however: I provide a local copy).
What about bugs? Well, currently there are two issues that I’m unsure on how to fix: the first is a crash on exit, the second is that certain media files make VLC crash in the background when called from the bindings.
In any case, if you try it out, let me know what you think in the comments!

Improvements to the Git hooks

As you may already know, recently the KDE sysadmins completely overhauled the commit hooks used with the Git infrastructure. Written in Python, they have already brought significant improvements to the current workflows. These hooks include keywords that when specified trigger particular actions: the most used are  to CC specific email addresses (CCMAIL), to CC bug reports (CCBUG) or to close bug reports (BUG).

With the adoption of Review Board to facilitate code reviews, there were also requests for a REVIEW keyword that could close the review requests without asking the submitters to do so manually (which is slow and not always effective). Since the hooks for Git were written in Python, I thought I could give a hand there.

I looked into the Review Board API, which is a simple REST API: tasks are performed with HTTP GET, POST, or PUT. As I didn’t want to dive too much into the technicalities, I decided to use a wrapper that would make things easier: python-rest-client. Once that was in place, it was just a matter of adding some sugar to handle replies, errors and logging. All in 78 lines of code.

Now that the “field tests” passed with flying colors, I’m happy to announce that such a hook exists and is operational for KDE’s Git infrastructure. By using the REVIEW keyword at the start of a line, followed by a number, the hook will notify the Review Board instance and close the request. It will also publish a comment stating the commit’s SHA1 and the person who did it.

You can take a look at the finished results in this review request.

Credits for this also go to Ben “bcooksley” Cooksley for helping with testing and fixes, and Eike “Sho” Hein for helpful suggestions.

PyKDE4: Retrieve data using KIO

One of the greatest strengths of KDE is undoubtedly the asynchronous and network-transparent I/O access, employed by the so-called “I/O” slaves, part of the KIO class. If you are developing an application that requires file or network access, those classes make things incredibly simple to do, and they don’t freeze your GUI when you are in the middle of a process.

In this post I’ll show how to use KIO to retrieve files from network resources using PyKDE4. The whole example is also available in the kdeexamples module.

Our first step is to create a simple UI to show how KIO works. It will be a text edit along with two buttons to retrieve and clear items. Here’s how it looks in Designer (the ui file and its compiled Python version are available at the above link):

Image of the example form

Once this is done, we turn our attention to code. We start customary imports:

#!/usr/bin/env python
import sys
import PyQt4.QtCore as QtCore
import PyQt4.QtGui as QtGui
import PyKDE4.kdecore as kdecore
import PyKDE4.kdeui as kdeui
from PyKDE4.kio import KIO

These will provide for everything we need. Then we set up our widget:


from ui_textbrowser import Ui_Form

class TextArea(QtGui.QWidget, Ui_Form):

    """Example class used to show how KIO works."""

    def __init__(self, parent=None):

        super(TextArea, self).__init__(parent)
        self.setupUi(self)

        self.downloadButton.clicked.connect(self.start_download)
        self.clearButton.clicked.connect(self.textWidget.clear)

Nothing strange in the initializer here. We simply make two connections, one to the clear() slot of the clear button, and the other to start the KIO process, that is the retrieval of the index from www.kde.org. Let’s take a look at the start_download slot:

    def start_download(self):
        kdeui.KMessageBox.information(self.parent(),
                                      "Now data will be retrieved from "
                                      "www.kde.org using KIO")

        # KIO wants KUrls
        data_url = kdecore.KUrl("http://www.kde.org")
        retrieve_job = KIO.storedGet(data_url, KIO.NoReload, KIO.HideProgressInfo)
        retrieve_job.result.connect(self.handle_download)

What do we do here? We show a KMessageBox, just for informational purposes. Once this is done, we prepare the actual KIO  job. KIO wants KUrls so we first of all wrap the URL we want to download from in that. Then we create the actual job: in this case it’s KIO.storedGet, that is we retrieve the data in full from our URL and store it in a QByteArray. This is a common use case, but you have to keep in mind that for large files this may be impractical. In such a case, we would be better off using KIO.get followed by a connection to the “data” signal, to get the data in chunks.

A KIO job can have many flags: here we set to remove the progress information, so that you won’t get a notification in the Plasma notifier. For small operations, this should be always present. For longer downloads, it’s likely not a good idea. More information are available in the KIO namespace page (C++ version).

As a last step, we connect the result signal (emitted when the job is complete) to a slot to handle the download. This is what makes KIO useful, because it’s asynchronous, so you can perform long downloads without blocking the user interface of your program

Lastly, we see the “handle_download” slot:


    def handle_download(self, job):

        # Bail out in case of errors
        if job.error():
            return

        print "This slot has been called. The job has finished its operation."

        data = job.data()
        self.textWidget.setPlainText(QtCore.QString(data))

This slot’s signature include a KJob instance, that is what we’ll use to get the data. In fact, using the data() function we can obtain the QByteArray containing what we have retrieved. Then, in this case we simply use setPlainText to put the downloaded data into the text edit.

What if something goes wrong? We can check for errors if job.error() returns True: in that case we can perform recovery, or simply tell our user that something went wrong. Especially with networked resources, this should always be present in your code.

So that’s all for now. As you can see, it was pretty simple, and also very effective.

PyKDE4: Tag and annotate files using Nepomuk

Some time has passed since I last blogged… this was not only due to lack of time but also due to motivation (writing long texts can be discouraging at times). In any case, I’d like to rectify for that. In this post, I’ll talk about Nepomuk, and in particular how to use it to tag and annotate arbitrary files using its API in PyKDE4.

Before starting, let me say that creating this tutorial was only possible thanks to the help of Sebastian Trueg, who helped me by pointing out some mistakes I was doing.

The example here is not showing the extra methods to set up a KApplication, etc.: the full code for this tutorial is available in the kdeexamples module.

Let’s start with the basics.

import sys
from PyQt4 import QtCore
from PyKDE4 import kdecore
from PyKDE4 import kdeui
from PyKDE4.nepomuk import Nepomuk

This will import all the bits needed to test our experiment. As a second step, we’ll create a dummy empty file.

dummy_file = open("dummy.txt", "w")
dummy_file.write("Some text\n")
dummy_file.close()

Or, if we have Python 2.6+ (as pointed out in the comments):

with open("dummy.txt", "w") as handle:
    handle.write("Some text\n")

Now that we have our file, it’s time to do something productive with it. But first and foremost, we have to ensure that Nepomuk is running. To do so, we make a simple check (EDIT: fixed the syntax):

result = Nepomuk.ResourceManager.instance().init()
if result != 0:
     return

Neomuk.instance().init() must return 0 if Nepomuk is properly set up. Once this is taken care of, we can manipulate the semantic information of our file. Thus, Nepomuk needs to be made aware of it: this is done by creating a resource that points to the actual file:

file_info = QtCore.QFileInfo("dummy.txt")
absolute_path = file_info.absoluteFilePath()
resource = Nepomuk.Resource(kdecore.KUrl(absolute_path)

Notice that we must use an absolute file path, or the resource will be not created properly and although no errors will happen when tagging, changes will not be made. Let’s now create a tag, which is done by simply constructing a Nepomuk.Tag instance:

tag = Nepomuk.Tag("test_example")
tag.setLabel("test_example")

In the first line we create the tag, then we associate it with a label, so that it will be displayed in applications such as Dolphin. The nice thing is that if the Tag already exists, it will be recycled: no duplicates will occur. A simple call to addTag to the resource we created earlier will now tag it:

resource.addTag(tag)

We can also add comments that can show up in Dolphin as well by using the setDescription method:

resource.setDescription("This is an example comment.")

What if we want to remove tags and descriptions? To wipe them all, we can use the remove() method of the Resource, otherwise we can strip elements by using removeProperty along with the tagUri() or descriptionUri() methods of the resource:

resource.remove() # strip everything
resource.removeProperty(resource.descriptionUri()) # remove comment
resource.removeProperty(resource.tagUri()) # remove tags

That’s it. As you can see, adding semantic information from PyKDE4 isn’t that hard. Sooner or later I’ll try my hand at queries and report back my findings.