zip zip zip

This commit is contained in:
Geoffrey Frogeye 2020-03-12 17:56:10 +01:00
parent a6755863dd
commit c8aaa78f59
5 changed files with 175 additions and 33 deletions

View file

@ -56,8 +56,8 @@ set geometry(main) 1920x1012+0+18
set geometry(state) normal set geometry(state) normal
set geometry(topwidth) 1920 set geometry(topwidth) 1920
set geometry(topheight) 225 set geometry(topheight) 225
set geometry(pwsash0) "969 1" set geometry(pwsash0) "931 1"
set geometry(pwsash1) "1454 1" set geometry(pwsash1) "971 1"
set geometry(botwidth) 1202 set geometry(botwidth) 951
set geometry(botheight) 782 set geometry(botheight) 782
set permviews {} set permviews {}

View file

@ -7,6 +7,7 @@ sudo pacman -S etckeeper --needed
sudo etckeeper commit "install-arch script: begin" sudo etckeeper commit "install-arch script: begin"
# Install yay # Install yay
# TODO Use yay-bin
sudo pacman -S base-devel --needed sudo pacman -S base-devel --needed
if ! pacman -Q yay &> /dev/null if ! pacman -Q yay &> /dev/null
then then

View file

@ -3,16 +3,18 @@
import os import os
import re import re
import typing import typing
import datetime
import PIL.ExifTags import PIL.ExifTags
import PIL.Image import PIL.Image
import progressbar import progressbar
EXTENSION_PATTERN = re.compile(r'\.JPE?G', re.I) 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_NAME = 'DateTimeOriginal'
EXIF_TAG_ID = list(PIL.ExifTags.TAGS.keys())[list( EXIF_TAG_ID = list(PIL.ExifTags.TAGS.keys())[list(
PIL.ExifTags.TAGS.values()).index(EXIF_TAG_NAME)] 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) \ def get_pictures(directory: str = ".", skip_renamed: bool = True) \
@ -41,7 +43,10 @@ def main() -> None:
exif_data = img._getexif() exif_data = img._getexif()
if exif_data and EXIF_TAG_ID in exif_data: if exif_data and EXIF_TAG_ID in exif_data:
date_raw = exif_data[EXIF_TAG_ID] 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() img.close()

View file

@ -83,7 +83,7 @@ echo "Finding packages to install"
# i A || i B: will try A for each installer, then B for each installer # i A || i B: will try A for each installer, then B for each installer
# Package managers (install first) # Package managers (install first)
i yay i yay-bin
i python-pip python3-pip pip3 i python-pip python3-pip pip3
# TODO Install first and recharge installers # TODO Install first and recharge installers
@ -107,7 +107,7 @@ i tmux # Terminal multiplexer
i bash-completion # Shell completions i bash-completion # Shell completions
i fzf # Fancy file finder i fzf # Fancy file finder
i highlight # Syntax highlighter (TODO No termux) 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 i zsh # Shell
# TODO Arch only for the following but not a problem # 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 rsync # Remote file-copying tool
i speedtest-cli # Network speed benchmarker (TODO No termux) i speedtest-cli # Network speed benchmarker (TODO No termux)
i bind-tools dnsutils # DNS queryier i bind-tools dnsutils # DNS queryier
i whois # Domain name queryier
# Archives utilities # Archives utilities
i unzip # Unarchive ZIP files i unzip # Unarchive ZIP files
@ -203,6 +204,7 @@ then
i man # Documentation i man # Documentation
i strace # Tracer i strace # Tracer
i ctags universal-ctags exuberant-ctags # Tags generator i ctags universal-ctags exuberant-ctags # Tags generator
i perf # Allow verifying performance of software
# C/C++ # C/C++
i cmake # C++ Build system i cmake # C++ Build system
@ -250,6 +252,12 @@ then
i inkscape # Vector image converter i inkscape # Vector image converter
i optipng # Optimize PNG files i optipng # Optimize PNG files
i jpegtran libjpeg-turbo # Compress JPEG 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 fi
if $INSTALL_IMAGE if $INSTALL_IMAGE

View file

@ -2,33 +2,161 @@
import os import os
import subprocess import subprocess
import sys
import logging
import magic
import typing
import coloredlogs
import enum
for root, dirs, files in os.walk("."): # TODO Able to ignore extensions everywhere
for name in files:
base, ext = os.path.splitext(name) class ArchiveType():
if name.endswith(".zip"): suffix: str = ''
cmd = ["unzip"] dest_suffix: str = ''
elif name.endswith(".7z"): mime: typing.Optional[str] = None
cmd = ["7z", "e"] header: typing.Optional[bytes] = None
elif name.endswith(".rar"): extract_cmd: typing.Optional[typing.List[str]] = None
cmd = ["unrar", "x"] single_file = False
elif name.endswith('.tar'): append_dest = False
cmd = ["tar", "xf"]
elif name.endswith('.tar.gz'): def __init__(self) -> None:
cmd = ["tar", "xzf"] self.log = logging.getLogger(self.__class__.__name__)
elif name.endswith('.tar.xz'):
cmd = ["tar", "xJf"] 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: else:
continue r = subprocess.run(cmd, cwd=dest)
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.check_returncode() 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()