diff options
Diffstat (limited to '.bin')
-rwxr-xr-x | .bin/cmus-consistency | 23 | ||||
-rwxr-xr-x | .bin/cmus-find-unused | 20 | ||||
-rwxr-xr-x | .bin/cmus-find-unused-dir | 24 | ||||
-rwxr-xr-x | .bin/config.ini | 8 | ||||
-rwxr-xr-x | .bin/dot-sync | 11 | ||||
-rwxr-xr-x | .bin/dslr-webcam | 27 | ||||
-rwxr-xr-x | .bin/dwm-start | 2 | ||||
-rwxr-xr-x | .bin/music | 175 | ||||
-rwxr-xr-x | .bin/python-chad | 15 | ||||
-rwxr-xr-x | .bin/ssh-personal | 14 | ||||
-rwxr-xr-x | .bin/synchronize-pub-dots | 5 | ||||
-rwxr-xr-x | .bin/undock | 1 | ||||
-rwxr-xr-x | .bin/x11-config | 3 | ||||
-rwxr-xr-x | .bin/x11-screen | 4 |
14 files changed, 270 insertions, 62 deletions
diff --git a/.bin/cmus-consistency b/.bin/cmus-consistency new file mode 100755 index 0000000..dae667b --- /dev/null +++ b/.bin/cmus-consistency @@ -0,0 +1,23 @@ +#!/bin/sh + +set -xe + +music_urls_file="${HOME}/.config/music/urls" +music_path="${HOME}/music" +music_album_list_file="$(mktemp)" + +find "${music_path}" -maxdepth 1 -type d -not -path "${music_path}" -not -name ".*" \ + | sort \ + | xargs -I {} basename {} \ + > "${music_album_list_file}" + +grep -v "^http" "${music_urls_file}" \ + | grep -v "^#" \ + | tr -s "\n" \ + | sort \ + | uniq \ + | diff - "${music_album_list_file}" \ + | grep -e "^>" -e "^<" \ + | sort -V + +rm "${music_album_list_file}" diff --git a/.bin/cmus-find-unused b/.bin/cmus-find-unused new file mode 100755 index 0000000..2fd5f1c --- /dev/null +++ b/.bin/cmus-find-unused @@ -0,0 +1,20 @@ +#!/bin/sh +# Find tracks in no playlist + +set -xe + +cmus_path="${HOME}/.config/cmus" +music_path="${HOME}/music" +cmus_playlist_files="$(mktemp)" + +cat "${cmus_path}/playlists/"* \ + | sort \ + | uniq \ + > "${cmus_playlist_files}" + +find "${music_path}" -type f -not -name ".*" \ + | sort \ + | uniq \ + | comm -23 - "${cmus_playlist_files}" + +rm "${cmus_playlist_files}" diff --git a/.bin/cmus-find-unused-dir b/.bin/cmus-find-unused-dir new file mode 100755 index 0000000..189bb12 --- /dev/null +++ b/.bin/cmus-find-unused-dir @@ -0,0 +1,24 @@ +#!/bin/sh + +set -xe + +cmus_path="${HOME}/.config/cmus" +music_path="${HOME}/music" +cmus_playlist_files="$(mktemp)" + +cat "${cmus_path}/playlists/"* \ + | xargs -d "\n" -I {} dirname {} \ + | xargs -I {} basename {} \ + | sort \ + | uniq \ + > "${cmus_playlist_files}" + +cmus-find-unused \ + | xargs -d "\n" -I {} dirname {} \ + | grep -v -e "^${music_path}$" -e "\." \ + | xargs -I {} basename {} \ + | sort \ + | uniq \ + | comm -23 - "${cmus_playlist_files}" + +rm "${cmus_playlist_files}" diff --git a/.bin/config.ini b/.bin/config.ini new file mode 100755 index 0000000..9f4986e --- /dev/null +++ b/.bin/config.ini @@ -0,0 +1,8 @@ +[AAAA-aaa] + +a = "a" + +[bbb] +bb +cc +dd diff --git a/.bin/dot-sync b/.bin/dot-sync index f12f878..f41b936 100755 --- a/.bin/dot-sync +++ b/.bin/dot-sync @@ -4,11 +4,11 @@ set -xe export GIT_SSH_COMMAND="ssh -o ConnectTimeout=1 -o ConnectionAttempts=1" -yadm stash -yadm pull --rebase -yadm stash pop +yadm stash || true +yadm pull --rebase || true +yadm stash pop || true -yadm add -u +yadm add -u || true yadm add \ "${HOME}/.bin" \ "${HOME}/.config/cmus/playlists" \ @@ -28,7 +28,8 @@ yadm add \ "${HOME}/.config/yadm" \ "${HOME}/.config/waybar" \ "${HOME}/.config/zk" \ - "${HOME}/.public-keys" + "${HOME}/.public-keys" \ + || true yadm push diff --git a/.bin/dslr-webcam b/.bin/dslr-webcam new file mode 100755 index 0000000..a1c9084 --- /dev/null +++ b/.bin/dslr-webcam @@ -0,0 +1,27 @@ +#!/bin/sh + +set -xe + +VIDEO_INDEX="${1:-1}" + +# gphoto2 --stdout --capture-movie | ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -f v4l2 "/dev/video${VIDEO_INDEX}" + +gphoto2 --stdout --capture-movie | + ffmpeg \ + -threads:v 2 \ + -threads:a 8 \ + -filter_threads 2 \ + -thread_queue_size 512 \ + -hwaccel opencl \ + -fflags nobuffer \ + -flags low_delay \ + -strict experimental \ + -probesize 819200 \ + -analyzeduration 0 \ + -i - \ + -vcodec rawvideo \ + -preset ultrafast \ + -tune zerolatency \ + -pix_fmt yuv420p \ + -f v4l2 "/dev/video${VIDEO_INDEX}" \ + -framerate 30 diff --git a/.bin/dwm-start b/.bin/dwm-start index b42252a..e2dcc00 100755 --- a/.bin/dwm-start +++ b/.bin/dwm-start @@ -22,7 +22,7 @@ while true; do # x11 configuration x11-config - . ~/.bin/x11-screen + ag-autorandr # dwm dwm 2> ~/.dwm.log @@ -1,63 +1,37 @@ #!/usr/bin/python3 +import logging import os import sys -import yt_dlp -from dataclasses import dataclass - - -def _match_filter(info: dict, *, incomplete) -> str | None: - _duration = info.get("duration") - _duration_min = 60 - - if _duration and int(_duration) < _duration_min: - return "Duration too short: < _duration_min" - return None +import yt_dlp # type: ignore[import] +from dataclasses import dataclass -@dataclass(frozen=True) -class Collection: - """A music collection.""" - - title: str - links: frozenset[str] - - def __eq__(self, other) -> bool: - if isinstance(other, Collection): - return self.title == other.title - raise NotImplementedError - +logging.basicConfig() +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) -def parse_raw_to_collections(raw_data: list[str]) -> frozenset[Collection]: - collections: set[Collection] = set() - _collection_data: list[str] = [] - for index, line in enumerate(raw_data): - if line.startswith("#"): - continue - elif line == "" or index + 1 == len(raw_data): - if len(_collection_data) == 0: - continue +def get_ytdlp_options(output_dir: str) -> dict: + """yt_dlp download and convertion options.""" - collections.add( - Collection(_collection_data[0], frozenset(_collection_data[1:])) - ) - _collection_data.clear() - else: - _collection_data.append(line) + def match_filter(info: dict, *, incomplete) -> str | None: + duration = info.get("duration") + duration_min = 60 - return frozenset(collections) + if duration is not None and int(duration) < duration_min: + return "Duration too short: < _duration_min" + return None -def get_ytdlp_options(output_dir: str) -> dict: return { "format": "bestaudio/best", - "match_filter": _match_filter, + "match_filter": match_filter, "postprocessors": [ { "key": "FFmpegExtractAudio", - #"preferredcodec": "m4a", + # "preferredcodec": "m4a", }, { "key": "FFmpegMetadata", @@ -71,31 +45,128 @@ def get_ytdlp_options(output_dir: str) -> dict: "outtmpl": f"{output_dir}/%(title)s.%(ext)s", "restrictfilenames": True, "ignoreerrors": True, + "writethumbnail": True, } -def download_collection(collection: Collection, parent_dir: str) -> None: - output_dir = os.path.join(parent_dir, collection.title) +def parse_raw_lines(lines: list[str]) -> list[list[str]]: + """Parse collections of name + link(s) + + (Usually stored in a text file). + """ + entries: list[list[str]] = list() + entry: list[str] = list() + + for index, line in enumerate(lines): + + # entries are separated by an empty line. + if line == "": + entries.append(entry) + entry = list() + continue + + entry.append(line) - if os.path.isdir(output_dir): - return + # handle the last entry when reaching the end of the file. + if index + 1 == len(lines): + entries.append(entry) + entry = list() - os.makedirs(output_dir, exist_ok=True) + return entries - with yt_dlp.YoutubeDL(get_ytdlp_options(output_dir)) as downloader: - downloader.download(collection.links) + +@dataclass(frozen=True) +class Link: + """A music link.""" + + url: str + is_enabled: bool + + +@dataclass(frozen=True) +class Collection: + """A music collection.""" + + name: str + links: tuple[Link, ...] + is_enabled: bool + + def __eq__(self, other) -> bool: + if isinstance(other, Collection): + return self.name == other.name + + raise NotImplementedError + + +def sanitize_entry_informations( + entry: str, indicator: str = "#" +) -> tuple[str, bool]: + + is_comment = entry.startswith(indicator) + + if is_comment: + entry = entry.split(indicator, 1)[1].lstrip() + + return entry, not is_comment + + +def create_link(entry: str) -> Link: + url, is_enabled = sanitize_entry_informations(entry) + return Link(url=url, is_enabled=is_enabled) + + +def create_collection(entry: list[str]) -> Collection: + """Create a collection from a raw entry.""" + name, is_enabled = sanitize_entry_informations(entry[0]) + links = [create_link(_link) for _link in entry[1:]] + + return Collection( + name=name, + links=tuple(links), + is_enabled=is_enabled + ) + + +def get_collection_dir(collection: Collection, parent_dir: str) -> str: + return os.path.join(parent_dir, collection.name) + + +def download_collection(collection: Collection, directory: str) -> None: + """Download a music collection to the local filesystem.""" + + # create directory and download/convert with opinionated settings. + os.makedirs(directory, exist_ok=True) + + with yt_dlp.YoutubeDL(get_ytdlp_options(directory)) as downloader: + for link in collection.links: + if not link.is_enabled: + logger.info(f"Skipping {collection.name}, {link}") + continue + + logger.info(f"Downloading {collection.name}, {link}") + downloader.download(link.url) def main() -> int: - # input handling + """Main entrypoint.""" + + # argument handling if len(sys.argv) != 2: return 1 with open(sys.argv[1], "r") as file: filedata = file.read().splitlines() - for collection in parse_raw_to_collections(filedata): - download_collection(collection, os.getcwd()) + for entry in parse_raw_lines(filedata): + collection = create_collection(entry) + output_dir = get_collection_dir(collection, os.getcwd()) + + if os.path.isdir(output_dir) or not collection.is_enabled: + logger.info(f"Skipping {collection.name}") + continue + + logger.info(f"Handling {collection.name}") + download_collection(collection, output_dir) return 0 diff --git a/.bin/python-chad b/.bin/python-chad new file mode 100755 index 0000000..3fc230e --- /dev/null +++ b/.bin/python-chad @@ -0,0 +1,15 @@ +#!/bin/sh + +set -e + +venv_path=$(poetry env info -p || true) + +if [ "${?}" -eq 0 ]; then + export PATH="${venv_path}/bin:${PATH}" +fi + +set -x + +isort "${1:-.}" +black "${1:-.}" +flake8 "${1:-.}" diff --git a/.bin/ssh-personal b/.bin/ssh-personal new file mode 100755 index 0000000..e99764c --- /dev/null +++ b/.bin/ssh-personal @@ -0,0 +1,14 @@ +#!/bin/sh +# Used for work laptop. +# Add personal key and start the ssh-agent with it. + +set -xe + +ssh_personal_key="${HOME}/.ssh/id_personal" + +test -f "${ssh_personal_key}" + +eval "$(ssh-agent)" +ssh-add "${ssh_personal_key}" + +set +xe diff --git a/.bin/synchronize-pub-dots b/.bin/synchronize-pub-dots index 8c7a9c4..852a75c 100755 --- a/.bin/synchronize-pub-dots +++ b/.bin/synchronize-pub-dots @@ -2,8 +2,11 @@ set -e +# perform pre-flight checks command -v yadm git git rev-parse --is-inside-work-tree +[ "$(yadm rev-parse --show-toplevel)" != "$(git rev-parse --show-toplevel)" ] + allowed_patterns="-e ^.bin -e ^.config/alacritty/ @@ -39,8 +42,6 @@ allowed_patterns="-e ^.bin -e ^.zshrc " -[ "$(yadm rev-parse --show-toplevel)" != "$(git rev-parse --show-toplevel)" ] - # retrieve existing files upstream_files=$(cd "${HOME}" && yadm ls-files) local_files=$(find . -not -path "./.git*" -not -path ".") diff --git a/.bin/undock b/.bin/undock index c592fbf..4a9c14f 100755 --- a/.bin/undock +++ b/.bin/undock @@ -3,4 +3,5 @@ set -xe dock +xrandr --output eDP1 --mode 1920x1080 --primary xrandr -s 0 diff --git a/.bin/x11-config b/.bin/x11-config index 554f00c..d304547 100755 --- a/.bin/x11-config +++ b/.bin/x11-config @@ -7,7 +7,8 @@ synclient_options="TapButton1=1 \ TapButton2=3 \ TapButton3=2 \ PalmDetect=1 \ - TouchpadOff=0" + TouchpadOff=0 \ + VertScrollDelta=111" # synaptic if command -v syndaemon; then diff --git a/.bin/x11-screen b/.bin/x11-screen index 38ee006..82f8650 100755 --- a/.bin/x11-screen +++ b/.bin/x11-screen @@ -1,5 +1,7 @@ #!/bin/sh +set -x + __hidpi() { xrdb -merge ~/.Xresources.hidpi @@ -25,7 +27,7 @@ if [ "${hostname}" = "ws-xps01" ]; then __hidpi fi -if [ "${hostname}" = "work-01" ]; then +if [ "${hostname}" = "ws-work01" ]; then xrandr --output eDP1 --mode 1920x1080 xrandr --output DP3 --off xrandr --addmode DP3 1920x1080 |