Last active
May 31, 2021 18:22
-
-
Save rcarmo/7d2746c4d91e03754184e01f3fec1411 to your computer and use it in GitHub Desktop.
TrueType Font Organizer
This file contains hidden or 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
from contextlib import redirect_stderr | |
from itertools import chain | |
from os import makedirs | |
from os.path import exists, join | |
from pathlib import Path | |
from shutil import move | |
from typing import Generator | |
from fontTools import ttLib # also requires brotli for some font formats | |
FONT_ROOT = '/Volumes/fonts' | |
def iter_fonts(path: str) -> chain: | |
p = Path(path) | |
return chain( | |
p.glob('**/*.ttf'), | |
p.glob('**/*.TTF'), | |
p.glob('**/*.otf'), | |
p.glob('**/*.OTF'), | |
p.glob('**/*.woff'), | |
p.glob('**/*.woff2'), | |
#p.glob('**/*.ttc') | |
) | |
def iter_paths(path: str) -> Generator: | |
p = Path(path) | |
return p.glob('**') | |
def font_name(font_path: Path): | |
print(font_path) | |
font = ttLib.TTFont(font_path, ignoreDecompileErrors=True) | |
with redirect_stderr(None): | |
names = font['name'].names | |
details = {} | |
for x in names: | |
if x.langID == 0 or x.langID == 1033: | |
try: | |
details[x.nameID] = x.toUnicode() | |
except UnicodeDecodeError: | |
details[x.nameID] = x.string.decode(errors='ignore') | |
return details[4], details[1], details[2] | |
def move_and_rename(src: Path, dst: Path, ordinal: int=0): | |
if not ordinal and exists(dst): | |
move_and_rename(src, dst, ordinal+1) | |
return | |
if ordinal: | |
numbered = Path(join(dst.parent, dst.stem) + f" ({ordinal})" + dst.suffix) | |
if exists(numbered): | |
move_and_rename(src, dst, ordinal+1) | |
return | |
dst = numbered | |
if not exists(dst.parent): | |
makedirs(dst.parent) | |
print(f"{src} -> {dst}") | |
move(src, dst) | |
def process_fonts() -> None: | |
for font_path in iter_fonts(FONT_ROOT): | |
if '_duplicates' in str(font_path): | |
continue | |
full_name, family, variation = font_name(font_path) | |
target_path = Path(join(FONT_ROOT, family, full_name) + font_path.suffix.lower()) | |
if(target_path == font_path): | |
continue | |
if(exists(target_path)): | |
target_path = Path(join(FONT_ROOT, '_duplicates', family, full_name) + font_path.suffix.lower()) | |
move_and_rename(font_path, target_path) | |
#print(font_name(filename)) # ('Century Bold Italic', 'Century', 'Bold Italic') – name, family, style | |
def cleanup_folders() -> None: | |
for test_path in list(iter_paths(FONT_ROOT)): | |
files = list(test_path.iterdir()) | |
if not len(files): | |
try: | |
test_path.rmdir() | |
except: | |
pass | |
if __name__=='__main__': | |
process_fonts() | |
cleanup_folders() |
This file contains hidden or 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
fonttools>=4.24.4 | |
brotli>=1.0.9 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment