How can I instruct Nautilus to pre-generate thumbnails?

13,876

Solution 1

Nautilus's thumbnailing routines actually come from the libgnome-desktop library, so it is possible to run the same thumbnailers outside of the file manager.

The API is a little complex, but the following Python script should help:

#!/usr/bin/python
import os
import sys

from gi.repository import Gio, GnomeDesktop

def make_thumbnail(factory, filename):
    mtime = os.path.getmtime(filename)
    # Use Gio to determine the URI and mime type
    f = Gio.file_new_for_path(filename)
    uri = f.get_uri()
    info = f.query_info(
        'standard::content-type', Gio.FileQueryInfoFlags.NONE, None)
    mime_type = info.get_content_type()

    if factory.lookup(uri, mtime) is not None:
        print "FRESH       %s" % uri
        return False

    if not factory.can_thumbnail(uri, mime_type, mtime):
        print "UNSUPPORTED %s" % uri
        return False

    thumbnail = factory.generate_thumbnail(uri, mime_type)
    if thumbnail is None:
        print "ERROR       %s" % uri
        return False

    print "OK          %s" % uri
    factory.save_thumbnail(thumbnail, uri, mtime)
    return True

def thumbnail_folder(factory, folder):
    for dirpath, dirnames, filenames in os.walk(folder):
        for filename in filenames:
            make_thumbnail(factory, os.path.join(dirpath, filename))

def main(argv):
    factory = GnomeDesktop.DesktopThumbnailFactory()
    for filename in argv[1:]:
        if os.path.isdir(filename):
            thumbnail_folder(factory, filename)
        else:
            make_thumbnail(factory, filename)

if __name__ == '__main__':
    sys.exit(main(sys.argv))

Save this to a file and mark it executable. You may also need to install the gir1.2-gnomedesktop-3.0 package if it is not already installed.

After that, simply invoke the script with the files or folders you want to thumbnail as arguments. Thumbnails will be saved to ~/.thumbnails where applications like Nautilus expect to find them.

Solution 2

The script below should do the job. It uses evince-thumbnailer which - as far as I know - comes with every gnome installation and is the default thumbnailer.
Save as pdfthumbnailer.sh and make it executable.
Usage: pdfthumbnailer.sh dir1 [dir2, ...]

#!/bin/bash

F1=$HOME/.thumbnails/normal
F2=$HOME/.cache/thumbnails/normal
SAVE_FOLDER=$F1
[ -e $F2 ] && SAVE_FOLDER=$F2

# the thumbnailing function
evincethumb() {
    outname=$(echo -n "$(readlink -f "$0")" | \
    perl -MURI::file -MDigest::MD5=md5_hex -ne 'print md5_hex(URI::file->new($_));')
    # no work if thumbnail already present
    [ ! -e $SAVE_FOLDER/${outname}.png ] && {
        echo "$0"
        #uncomment only one of both thumbnailers
        #convert -thumbnail 128x128 "$0"[0] $SAVE_FOLDER/${outname}.png 2>/dev/null
        evince-thumbnailer -s 128 "$0" $SAVE_FOLDER/${outname}.png 2>/dev/null
    }
}

# make our function visible to the subshell in "find -exec" below
export -f evincethumb

# loop through all given folders
for folder in "$@" ; do
    find "$folder" -type f -exec bash -c evincethumb {} \;
done

Restriction:

  • does not add Thumb::URI and Thumb::MTime attributes to the thumbnails as pointed out by James Henstridge. So far I have seen no evidence that the default evince-thumbnailer is doing so. In other words..as long as nautilus does not regenerate the thumbnails the script can be used for the job.

Notes:

  • prints the name of the file when generating a new thumbnail, skips generation if existing
  • speed: 37 pdf files tested with both evince-thumbnailer and convert (from imagemagick): 3seconds for evince-thumbnailer and 14seconds for convert.
  • generates thumbnails recognized by nautilus
  • path names handled by the perl URL:file module (spaces and other characters are correctly translated into a file uri)
  • needs perl, present in a default installation
  • files unhandled by evince-thumbnailer will simply output an error - muted with 2>/dev/null
  • look at the MimeType line in /usr/share/thumbnailers/evince.thumbnailer to see a list of handled file types
  • updates: starting from 12.04 the thumbnail folder seems to be ~/.cache/thumbnails.
    More robust paths using readlink.

Inspiration:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=683394

Solution 3

Got distracted for a while and rosch beat me to it :) Didn't know evince-thumbnailer existed (I'm not a Gnome user) but anyway, since I've already written it, here it goes. It requires imagemagick installed, check and install if not there with:

which convert || sudo apt-get install imagemagick

Save as mkthumb.sh (for instance), chmod +x mkthumb.sh it and execute it with absolute paths as arguments (you can use -s as its first paramterer to skip generating thumbnails that already exist) i.e.:

user@host $ ./mkthumb.sh -s /home/user/Downloads /home/user/blah
Processing directory /home/user/Downloads/pics/
OK   /home/user/Downloads/pics/FeO08.jpg
OK   /home/user/Downloads/pics/UrOCu.jpg
OK   /home/user/Downloads/pics/34ATZ.gif
OK   /home/user/Downloads/pics/WBRE3.jpg
OK   /home/user/Downloads/pics/LjLdH.jpg
OK   /home/user/Downloads/pics/xvvae (1).jpg
SKIP /home/user/Downloads/pics/itcrowd.jpg
OK   /home/user/Downloads/pics/76180344.jpg
OK   /home/user/Downloads/pics/fgk5N.jpg
....

The script (I've modified it slightly to support most images, you can add more extensions if you need them):

#!/bin/bash

# USAGE: mkthumb.sh [-s] <abs_path> [abs_path]
# create nautilus thumbnails for images and PDFs in the directories (and their
# sub-directories) given as parameters.
# -s is used to skip generating thumbnails that already exist

skip_existing=0
if [[ "${1}" == "-s" ]]; then
  skip_existing=1
  shift
fi

mkthumb() {
  file="${1}"
  dest="${2}"
  convert -thumbnail 128x128 "${file}[0]" "${dest}" &>/dev/null
  if (( $? == 0 )); then
    echo "OK   ${file}"
  else
    echo "FAIL ${file}"
  fi
}

OLDIFS="${IFS}"
IFS=$'\n'
for dir in $@; do
  realdir=`realpath "${dir}"`
  echo "Processing directory ${realdir}"
  for file in $(find "${realdir}" -regextype posix-egrep -iregex \
  '.*\.(pdf|png|jpg|gif|jpeg)'); do
    md5=$(echo -n "${file}" | perl -MURI::file -MDigest::MD5=md5_hex -ne \
          'print md5_hex(URI::file->new($_));')
    dest="${HOME}/.thumbnails/normal/${md5}.png"
    if [[ -f "${dest}" ]]; then
      if [[ "${skip_existing}" == "0" ]]; then
        mkthumb "${file}" "${dest}"
      else
        echo "SKIP ${file}"
      fi
    else
      mkthumb "${file}" "${dest}"
    fi
  done
done
IFS="${OLDIFS}"

It handles files with spaces in their names without issues.

A bit of testing here:

user@host $ find .thumbnails/
.thumbnails/
.thumbnails/fail
.thumbnails/fail/gnome-thumbnail-factory
.thumbnails/normal

# ok - no thumbnails present.

user@host $ ./mkthumb.sh -s /home/user/Downloads/pdf/test/
Processing directory /home/user/Downloads/pdf/test/
OK   /home/user/Downloads/pdf/test/800pdf.pdf
OK   /home/user/Downloads/pdf/test/3_TO_pricelist.pdf
OK   /home/user/Downloads/pdf/test/111011-speisekarte-mit-desserts.pdf
OK   /home/user/Downloads/pdf/test/1186157_r4f3a355eb104a (1).pdf

user@host $ touch tstamp

user@host $ ./mkthumb.sh -s /home/user/Downloads/pdf/test/
Processing directory /home/user/Downloads/pdf/test/
SKIP /home/user/Downloads/pdf/test/800pdf.pdf
SKIP /home/user/Downloads/pdf/test/3_TO_pricelist.pdf
SKIP /home/user/Downloads/pdf/test/111011-speisekarte-mit-desserts.pdf
SKIP /home/user/Downloads/pdf/test/1186157_r4f3a355eb104a (1).pdf

# running nautilus once now to see if it generates new thumbnails

# checking for new thumbnails:

user@host $ find .thumbnails/ -newer tstamp

# None.

Solution 4

I wrote a package that modified James' script to include multiprocessing and the option to recursively generate thumbnails. The package is pip-installable. Check here for installation instructions.

An example of usage is:

thumbgen -w 4 -r -d your_directory
  • -r: recursively generate thumbnails

  • -w: number of cores to use

Solution 5

The thumbnail specification includes shared thumbnail repositories , which allow for pre-generating thumbnails to be distributed along with the associated files rather than have every user generate their own thumbnail. So in theory you could generate thumbnails and then add them to a shared repository thus removing the need to generate them in future if you cleared out your thumbnails directory, or moved them all to a different machine or whatever.

http://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html#DIRECTORY

This Ask Ubuntu page come up in the results of a search when I was trying to find out if any application supports shared thumbnail repositories. Sadly it appears that no application supports them.

Share:
13,876

Related videos on Youtube

Glutanimate
Author by

Glutanimate

Medical student, hobbyist programmer. https://www.youtube.com/c/glutanimate

Updated on September 18, 2022

Comments

  • Glutanimate
    Glutanimate almost 2 years

    I have a large library of PDF documents (papers, lectures, handouts) that I want to be able to quickly navigate through. For that I need thumbnails.

    At the same time however, I see that the ~/.thumbnails folder is piling up with thumbs I don't really need. Deleting thumbnail junk without removing the important thumbs is impossible. If I were to delete them, I'd have to go to each and every folder with important PDF documents and let the thumbnail cache regenerate.

    I would love to be able to automate this process. Is there any way I can tell nautilus to pre-cache the thumbs for a set of given directories?

    Note: I did find a set of bash scripts that appear to do this for pictures and videos, but not for any other documents. Maybe someone more experienced with scripting might be able to adjust these for PDF documents or at least point me in the right direction on what I'd have to modify for this to work with PDF documents as well.


    Edit:

    The response to this question has been quite overwhelming. Let me first thank everyone who participated in solving this. The question, its answers and all the discussion around it are a great example of how the collaborative effort of many parties can lead to an optimal solution. This is exactly what makes Linux and Open Source so great.

    All of the provided answers would deserve the bounty I originally put up for this question. Still, there's only one bounty to award. I owe it to all future readers to choose the answer that solves the problem in the most efficient way. To determine which solution that is, I did a final test run, comparing the three scripts in compatibility, speed and output quality. Here are the results:


    Thumbnailer 1, by rosch:

    Compatibility: ✔ spaces in file name ; ✔ spaces in directory name ; ✘ freedesktop compliant

    Speed: 95 PDFs in 12,6 sec

    Quality: stock nautilus quality

    Additional Perks: 1.) automatically skips files with preexisting thumbs ; 2.) No additional packages needed

    Thumbnailer 2, by Martin Orda:

    Compatibility: ✔ spaces in file name ; ✔ spaces in directory name ; ✘ freedesktop compliant

    Speed: 95 PDFs in 70,0 sec

    Quality: significantly better scaling than the stock images.

    Additional Perks: 1.) automatically skips files with preexisting thumbs 2.) compatible with a wide range of image formats besides PDF 3.) platform-independent, does not rely on GNOME-components

    Thumbnailer 3, by James Henstridge:

    Compatibility: ✔ spaces in file name ; ✔ spaces in directory name ; ✔ freedesktop compliant

    Speed: 95 PDFs in 10,8 sec

    Quality: stock nautilus quality

    Additional Perks: 1.) automatically skips files with preexisting thumbs 2.) compatible with all file formats that are identified by the preinstalled thumbnailers


    All three scripts are excellent. Each has its distinct set of advantages and disadvantages. Rosch's solution works out of the box and might be the right choice for users with a minimal installation.

    Marcin Kaminski created a very versatile script that works with a variety of file formats and is DE-independent. It excels at thumbnail quality but does so at the expense of speed.

    In the end it was James' solution that fit my use case best. It's fast, versatile and offers the options to skip over files with preexisting thumbnails.


    Overall winner: James Henstridge


    Additional information: All three scripts are fully compatible with nautilus-scripts. You can easily install them following this tutorial.


    Edit 2: Updated review with improved script by rosch.

  • Glutanimate
    Glutanimate over 11 years
    Your script works absolutely great. It's exactly what I was looking for, so I awarded you with the bounty. I did encounter some error messages while doing my final test run, but they did not seem to hamper thumbnail generation. The errors might be related to the fact that some of the file names included German Umlauts ("ä,ü,ö"). Thank you, again, for providing this excellent solution. It will make my life much easier from now on.
  • James Henstridge
    James Henstridge over 11 years
    Those errors are coming from an XML parser being used by one of the thumbnailers, so would be related to the content of some file rather than its name. The above thumbnailer script will process all files in the directory, so it might not be a PDF it is having trouble with.
  • krasnaya
    krasnaya over 8 years
    I'm unable to create thumbnails for plain text files. Is there something I need to configure to make this work?
  • jacderida
    jacderida about 5 years
    This is fantastic, thanks! On Fedora 29 I had to use Python3 (so changed the shebang to /usr/bin/python3) and then turn the print statements into method calls, but other than that, it works perfectly!
  • jacderida
    jacderida about 5 years
    It's also worth noting that this only generates 'normal' sized thumbnails. There's also a 'large' thumbnail type. You can also generate large thumbnails by using the size argument of GnomeDesktop.DesktopThumnailFactory(). Documentation here: lazka.github.io/pgi-docs/GnomeDesktop-3.0/classes/…
  • nealmcb
    nealmcb over 3 years
    Wow - very good point. I hope someone fills this gap!
  • Jamie Hutber
    Jamie Hutber almost 3 years
    I seem to be getting an error, I assume as this answser is now 9 years old: UNSUPPORTED %s Traceback (most recent call last): File "./thumbnailGen.py", line 50, in <module> sys.exit(main(sys.argv)) File "./thumbnailGen.py", line 45, in main thumbnail_folder(factory, filename) File "./thumbnailGen.py", line 39, in thumbnail_folder make_thumbnail(factory, os.path.join(dirpath, filename)) File "./thumbnailGen.py", line 24, in make_thumbnail print ("UNSUPPORTED %s") % uri TypeError: unsupported operand type(s) for %: 'NoneType' and 'str'