Skip to content

Instantly share code, notes, and snippets.

@u-haru
Created November 11, 2024 16:23
Show Gist options
  • Save u-haru/afaf3c2b0ec70420e2f94fef090f5c30 to your computer and use it in GitHub Desktop.
Save u-haru/afaf3c2b0ec70420e2f94fef090f5c30 to your computer and use it in GitHub Desktop.
WindowsのExplorerのサムネイルを再帰的に取得するpythonスクリプト
#!/usr/bin/env python
import argparse
import os
import ctypes
import traceback
import comtypes
from ctypes import wintypes
import glob
import concurrent.futures
import tqdm
OLE32 = ctypes.OleDLL('ole32')
SHELL32 = ctypes.WinDLL('shell32')
IID_IShellItem = comtypes.GUID('{43826D1E-E718-42EE-BC55-A1E261C37BFE}')
SIZE = wintypes.SIZE(256, 256)
class IShellItemImageFactory(comtypes.IUnknown):
_iid_ = comtypes.GUID('{bcc18b79-ba16-442f-80c4-8a59c30c463b}')
_methods_ = [
comtypes.STDMETHOD(
ctypes.HRESULT,
"GetImage",
[
wintypes.SIZE, # size
wintypes.DWORD, # flags
ctypes.POINTER(wintypes.HANDLE) # phbmp
]
)
]
def cache_thumbnail(file_path: str):
shell_item = ctypes.c_void_p()
hr = SHELL32.SHCreateItemFromParsingName(
file_path,
None,
IID_IShellItem,
ctypes.byref(shell_item)
)
if hr != 0:
raise ctypes.WinError(hr)
shell_item = comtypes.cast(shell_item, comtypes.POINTER(IShellItemImageFactory))
shell_item_image_factory = shell_item.QueryInterface(IShellItemImageFactory) # type: ignore
hBitmap = wintypes.HANDLE()
hr = shell_item_image_factory.GetImage(SIZE, 0, ctypes.byref(hBitmap))
if hr != 0:
raise ctypes.WinError(hr)
def cache_thumbnail_com(file_path: str):
OLE32.CoInitialize(None)
try:
cache_thumbnail(file_path)
except Exception:
tqdm.tqdm.write(traceback.format_exc())
OLE32.CoUninitialize()
def generate_thumbnails_in_folder(folder_paths: list[str], recursive=True, threads=4):
files = [
os.path.abspath(file_path)
for folder_path in folder_paths
for file_path in glob.glob(os.path.join(folder_path, '**', '*.*'), recursive=recursive)
if os.path.isfile(file_path)
]
with concurrent.futures.ProcessPoolExecutor(max_workers=threads) as executor:
try:
for _ in tqdm.tqdm(executor.map(cache_thumbnail_com, files), total=len(files)):
pass
except KeyboardInterrupt:
print("Interrupted")
executor.shutdown(wait=True, cancel_futures=True)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Cache thumbnails for files in a directory')
parser.add_argument("target_dir", nargs="+", help="Target directory", default=[])
parser.add_argument("-t", "--threads", type=int, default=8, help="Number of threads")
args = parser.parse_args()
generate_thumbnails_in_folder(args.target_dir, threads=args.threads)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment