Last active
May 11, 2024 18:55
-
-
Save meawoppl/74942f65438593e69b8747b10f53d8ac to your computer and use it in GitHub Desktop.
Nautilus Thumbnail Generator. Python 3 scalable and fast.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
import concurrent.futures | |
import hashlib | |
import os | |
import sys | |
import gi | |
gi.require_version('GnomeDesktop', '3.0') | |
from gi.repository import Gio, GnomeDesktop | |
def make_thumbnail(factory, filename, overwrite=False): | |
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() | |
# Already thumbnailed | |
path = factory.lookup(uri, mtime) | |
if overwrite and path is not None: | |
print("Removed:" + path) | |
os.remove(path) | |
if (not overwrite) and (path is not None): | |
return False | |
# Not thumbnailable | |
if not factory.can_thumbnail(uri, mime_type, mtime): | |
return False | |
# Error during thumb | |
thumbnail = factory.generate_thumbnail(uri, mime_type) | |
if thumbnail is None: | |
print("Error thumbnailing: " + str(uri)) | |
return False | |
factory.save_thumbnail(thumbnail, uri, mtime) | |
return True | |
def thumbnail_targets(factory, targets: list, overwrite=False): | |
tcount = os.cpu_count() * 2 | |
with concurrent.futures.ThreadPoolExecutor(max_workers=tcount) as tpe: | |
n_created = 0 | |
nails = tpe.map(lambda name: make_thumbnail(factory, name, overwrite=overwrite), targets) | |
for n, f in enumerate(nails): | |
update_txt = "Thumbnailing: {:.2%}".format((n + 1) / len(targets)) | |
print(update_txt, end="\r") | |
n_created += f | |
print("\nThumbnailed %i files." % n_created) | |
def gather_paths(targets: list, ignore_dot_prefixed=True): | |
file_names = [] | |
for target in targets: | |
if os.path.isdir(target): | |
for dirpath, folders, filenames in os.walk(target): | |
# Skip recursion into dotfiles if requested | |
# This helps with windows/osx FS/trash/etc | |
if ignore_dot_prefixed: | |
for folder in folders: | |
if folder.startswith("."): | |
folders.remove(folder) | |
# Append files found to list | |
for filename in filenames: | |
file_names.append(os.path.join(dirpath, filename)) | |
continue | |
if os.path.isfile(target): | |
file_names.append(target) | |
continue | |
raise ValueError("Don't know what to do with: " + target) | |
file_names.sort() | |
print(file_names) | |
return file_names | |
if __name__ == '__main__': | |
import argparse | |
ap = argparse.ArgumentParser( | |
description="A tool for generating Gnome thumbnails in parallel.") | |
ap.add_argument( | |
"paths", | |
help="The path(s) to thumbnail (typically one or more folders)", | |
nargs="+") | |
ap.add_argument( | |
"--overwrite", | |
help="Overwrite existing thumbnails.", | |
action="store_true") | |
ap.add_argument( | |
"--dotfiles", | |
help="Don't ignore directories prefixed with '.'", | |
action="store_false") | |
parsed = ap.parse_args() | |
factory = GnomeDesktop.DesktopThumbnailFactory() | |
targets = gather_paths(parsed.paths, ignore_dot_prefixed=parsed.dotfiles) | |
print("%i targets found" % len(targets)) | |
thumbnail_targets(factory, targets, overwrite=parsed.overwrite) |
I'm glad you like it. I'm surprised the default gnome config doesn't support any concurrency in this. Feel free to share, and lmk if it needs any improvements.
This is a very useful script. Thank you.
Here is a minor issue: running the script with no arguments generates a strange error, like this.
[x@localhost]$ python3 thumbnailer.py
usage: meawoppl thumbnailer.py [-h] [--overwrite] [--dotfiles] paths [paths ...]
meawoppl thumbnailer.py: error: the following arguments are required: paths
I'd recommend making argparse handle this a bit more smoothly (i.e. printing the --help output and exiting if the script's invoked with no arguments, rather than exiting without explaining what the help flag is); I may make a pull request for this later if I remember.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is exactly what I needed for previewing thousands of large images quickly. Thanks!