diff --git a/config/git/gitk b/config/git/gitk index 2041fb1..d0c1309 100644 --- a/config/git/gitk +++ b/config/git/gitk @@ -56,8 +56,8 @@ set geometry(main) 1920x1012+0+18 set geometry(state) normal set geometry(topwidth) 1920 set geometry(topheight) 225 -set geometry(pwsash0) "969 1" -set geometry(pwsash1) "1454 1" -set geometry(botwidth) 1202 +set geometry(pwsash0) "931 1" +set geometry(pwsash1) "971 1" +set geometry(botwidth) 951 set geometry(botheight) 782 set permviews {} diff --git a/config/scripts/install-arch b/config/scripts/install-arch index 29794a7..d9843e9 100755 --- a/config/scripts/install-arch +++ b/config/scripts/install-arch @@ -7,6 +7,7 @@ sudo pacman -S etckeeper --needed sudo etckeeper commit "install-arch script: begin" # Install yay +# TODO Use yay-bin sudo pacman -S base-devel --needed if ! pacman -Q yay &> /dev/null then diff --git a/config/scripts/picture_name_date b/config/scripts/picture_name_date index 5567f8e..f82a394 100755 --- a/config/scripts/picture_name_date +++ b/config/scripts/picture_name_date @@ -3,16 +3,18 @@ import os import re import typing +import datetime import PIL.ExifTags import PIL.Image import progressbar EXTENSION_PATTERN = re.compile(r'\.JPE?G', re.I) -COMMON_PATTERN = re.compile(r'(IMG|DSC[NF]?|100|P10)_?\d+', re.I) +COMMON_PATTERN = re.compile(r'(IMG|DSC[NF]?|100|P10|f|t)_?\d+', re.I) EXIF_TAG_NAME = 'DateTimeOriginal' EXIF_TAG_ID = list(PIL.ExifTags.TAGS.keys())[list( PIL.ExifTags.TAGS.values()).index(EXIF_TAG_NAME)] +EXIF_DATE_FORMAT = '%Y:%m:%d %H:%M:%S' def get_pictures(directory: str = ".", skip_renamed: bool = True) \ @@ -41,7 +43,10 @@ def main() -> None: exif_data = img._getexif() if exif_data and EXIF_TAG_ID in exif_data: date_raw = exif_data[EXIF_TAG_ID] - # print(date_raw, full_path) + date = datetime.datetime.strptime(date_raw, EXIF_DATE_FORMAT) + new_name = date.isoformat().replace(':', '-') + '.jpg' # For NTFS + print(full_path, new_name) + os.rename(full_path, new_name) # TODO FOLDER img.close() diff --git a/config/scripts/softwareList b/config/scripts/softwareList index 1d1d44f..1c53992 100755 --- a/config/scripts/softwareList +++ b/config/scripts/softwareList @@ -83,7 +83,7 @@ echo "Finding packages to install" # i A || i B: will try A for each installer, then B for each installer # Package managers (install first) -i yay +i yay-bin i python-pip python3-pip pip3 # TODO Install first and recharge installers @@ -107,7 +107,7 @@ i tmux # Terminal multiplexer i bash-completion # Shell completions i fzf # Fancy file finder i highlight # Syntax highlighter (TODO No termux) -i powerline-go # Nice prompt (potential problem: requires go-pie) +i powerline-go-bin powerline-go # Nice prompt (potential problem: requires go-pie) i zsh # Shell # TODO Arch only for the following but not a problem @@ -135,6 +135,7 @@ i socat # Multi-purpose relay i rsync # Remote file-copying tool i speedtest-cli # Network speed benchmarker (TODO No termux) i bind-tools dnsutils # DNS queryier +i whois # Domain name queryier # Archives utilities i unzip # Unarchive ZIP files @@ -203,6 +204,7 @@ then i man # Documentation i strace # Tracer i ctags universal-ctags exuberant-ctags # Tags generator + i perf # Allow verifying performance of software # C/C++ i cmake # C++ Build system @@ -250,6 +252,12 @@ then i inkscape # Vector image converter i optipng # Optimize PNG files i jpegtran libjpeg-turbo # Compress JPEG files + i libreoffice-fresh # Office suite + i hunspell-en_GB # Spell checker British english + i hunspell-en_US # Spell checker American english + # i libreoffice-extension-grammalecte-fr # Spell checker French + i libreoffice-extension-languagetool # Complimentary spell checker various + # TODO The last two can't cohabit fi if $INSTALL_IMAGE diff --git a/config/scripts/unziptree b/config/scripts/unziptree index 5cf5ab9..82b8e0c 100755 --- a/config/scripts/unziptree +++ b/config/scripts/unziptree @@ -2,33 +2,161 @@ import os import subprocess +import sys +import logging +import magic +import typing +import coloredlogs +import enum -for root, dirs, files in os.walk("."): - for name in files: - base, ext = os.path.splitext(name) - if name.endswith(".zip"): - cmd = ["unzip"] - elif name.endswith(".7z"): - cmd = ["7z", "e"] - elif name.endswith(".rar"): - cmd = ["unrar", "x"] - elif name.endswith('.tar'): - cmd = ["tar", "xf"] - elif name.endswith('.tar.gz'): - cmd = ["tar", "xzf"] - elif name.endswith('.tar.xz'): - cmd = ["tar", "xJf"] +# TODO Able to ignore extensions everywhere + +class ArchiveType(): + suffix: str = '' + dest_suffix: str = '' + mime: typing.Optional[str] = None + header: typing.Optional[bytes] = None + extract_cmd: typing.Optional[typing.List[str]] = None + single_file = False + append_dest = False + + def __init__(self) -> None: + self.log = logging.getLogger(self.__class__.__name__) + + def dest_name(self, archive: str) -> str: + return archive[:-len(self.suffix)] + self.dest_suffix + + def fits(self, name_lower: str, mime: str, header: bytes) -> bool: + if not name_lower.endswith(self.suffix): + return False + if self.mime is not None and mime != self.mime: + return False + if self.header is not None and not header.startswith(self.header): + return False + return True + + def _get_cmd(self, archive: str, dest: str) -> typing.List[str]: + assert self.extract_cmd + cmd = self.extract_cmd + [archive] + if self.append_dest: + cmd.append(dest) + return cmd + + def extract(self, archive: str, dest: str) -> None: + cmd = self._get_cmd(archive, dest) + if not self.single_file: + os.mkdir(dest) + self.log.info("Extracting '%s' into '%s'", archive, dest) + self.log.debug("%s", cmd) + if self.single_file: + r = subprocess.run(cmd) else: - continue - - filepath = os.path.join(root, name) - dirpath = os.path.join(root, base) - print(filepath) - - os.mkdir(dirpath) - - cmd.append(os.path.realpath(filepath)) - r = subprocess.run(cmd, cwd=dirpath) + r = subprocess.run(cmd, cwd=dest) r.check_returncode() + if self.single_file: + assert os.path.isfile(dest) + os.unlink(archive) - os.unlink(filepath) + + extract_fun: typing.Optional[typing.Callable[[str, str], None]] = None + +class ArchiveZip(ArchiveType): + suffix = '.zip' + mime = 'application/zip' + extract_cmd = ['unzip'] + +class Archive7z(ArchiveType): + suffix = '.7z' + mime = 'application/x-7z-compressed' + extract_cmd = ['7z', 'x'] + +class ArchiveRar(ArchiveType): + suffix = '.rar' + mime = 'application/x-rar' + extract_cmd = ['unrar', 'x'] + +class ArchiveTar(ArchiveType): + suffix = '.tar' + mime = 'application/x-tar' + extract_cmd = ['tar', '--extract', '--file'] + +class ArchiveTarGz(ArchiveType): + suffix = '.tar.gz' + mime = 'application/gzip' + extract_cmd = ['tar', '--extract', '--gzip', '--file'] + +class ArchiveTarXz(ArchiveType): + suffix = '.tar.xz' + mime = 'application/x-xz' + extract_cmd = ['tar', '--extract', '--xz', '--file'] + +class ArchiveGzip(ArchiveType): + suffix = '.gz' + mime = 'application/gzip' + single_file = True + extract_cmd = ['gunzip'] + +class TreeExtractor(): + ARCHIVE_TYPES: typing.List[ArchiveType] = [ + ArchiveZip(), + Archive7z(), + ArchiveRar(), + ArchiveTar(), + ArchiveTarGz(), + ArchiveTarXz(), + ArchiveGzip(), + ] + + def __init__(self) -> None: + self.log = logging.getLogger('TreeExtractor') + self.extensions = set() + for archive_type in self.ARCHIVE_TYPES: + suffixes = archive_type.suffix.split('.') + self.extensions.add('.' + suffixes[-1]) + + + def extract_tree(self, directory: str = '.') -> None: + for root, dirs, files in os.walk(directory): + real_root = os.path.realpath(root) + for name in files: + self.log.debug("Handling '%s' '%s'", real_root, name) + + # Initial filtering with extensions + extension = os.path.splitext(name)[1].lower() + if extension not in self.extensions: + self.log.debug("Extension not matched: %s", name) + continue + + name_lower = name.lower() + filepath = os.path.join(real_root, name) + with open(filepath, 'rb') as filedesc: + header = filedesc.read(1024) + mime = magic.from_buffer(header, mime=True) + + archive_type = None + for archtyp in self.ARCHIVE_TYPES: + if archtyp.fits(name_lower, mime, header): + archive_type = archtyp + break + if not archive_type: + self.log.debug("Not matched: %s", filepath) + continue + + dest_name = archive_type.dest_name(name) + dest = os.path.join(real_root, dest_name) + try: + archive_type.extract(filepath, dest) + except BaseException as e: + # TODO Parameters stop on error + self.log.error(e, exc_info=True) + + if os.path.isdir(dest): + self.extract_tree(dest) + + def main(self) -> None: + directory = sys.argv[1] if len(sys.argv) > 1 else '.' + self.extract_tree(directory) + +if __name__ == '__main__': + coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s') + TreeExtractor().main()