zip zip zip
This commit is contained in:
parent
a6755863dd
commit
c8aaa78f59
|
@ -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 {}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
r = subprocess.run(cmd, cwd=dest)
|
||||||
|
r.check_returncode()
|
||||||
|
if self.single_file:
|
||||||
|
assert os.path.isfile(dest)
|
||||||
|
os.unlink(archive)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
continue
|
||||||
|
|
||||||
filepath = os.path.join(root, name)
|
name_lower = name.lower()
|
||||||
dirpath = os.path.join(root, base)
|
filepath = os.path.join(real_root, name)
|
||||||
print(filepath)
|
with open(filepath, 'rb') as filedesc:
|
||||||
|
header = filedesc.read(1024)
|
||||||
|
mime = magic.from_buffer(header, mime=True)
|
||||||
|
|
||||||
os.mkdir(dirpath)
|
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
|
||||||
|
|
||||||
cmd.append(os.path.realpath(filepath))
|
dest_name = archive_type.dest_name(name)
|
||||||
r = subprocess.run(cmd, cwd=dirpath)
|
dest = os.path.join(real_root, dest_name)
|
||||||
r.check_returncode()
|
try:
|
||||||
|
archive_type.extract(filepath, dest)
|
||||||
|
except BaseException as e:
|
||||||
|
# TODO Parameters stop on error
|
||||||
|
self.log.error(e, exc_info=True)
|
||||||
|
|
||||||
os.unlink(filepath)
|
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()
|
||||||
|
|
Loading…
Reference in a new issue