summaryrefslogtreecommitdiffstats
path: root/.bin
diff options
context:
space:
mode:
authorRomain Gonçalves <me@rgoncalves.se>2024-05-14 18:53:03 +0200
committerRomain Gonçalves <me@rgoncalves.se>2024-05-14 18:53:03 +0200
commit612dbb6993c8a548744f29a4d15d6b31325357c8 (patch)
tree0d61cee0ea74ac811268d0ffc00d3d55f7174112 /.bin
parent23e2bfd987c430bb41bc7860c46c2f572e9e2db4 (diff)
downloaddots-trunk.tar.gz
Tue May 14 06:53:03 PM CEST 2024HEADtrunk
Diffstat (limited to '.bin')
-rwxr-xr-x.bin/cmus-consistency23
-rwxr-xr-x.bin/cmus-find-unused20
-rwxr-xr-x.bin/cmus-find-unused-dir24
-rwxr-xr-x.bin/config.ini8
-rwxr-xr-x.bin/dot-sync11
-rwxr-xr-x.bin/dslr-webcam27
-rwxr-xr-x.bin/dwm-start2
-rwxr-xr-x.bin/music175
-rwxr-xr-x.bin/python-chad15
-rwxr-xr-x.bin/ssh-personal14
-rwxr-xr-x.bin/synchronize-pub-dots5
-rwxr-xr-x.bin/undock1
-rwxr-xr-x.bin/x11-config3
-rwxr-xr-x.bin/x11-screen4
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
diff --git a/.bin/music b/.bin/music
index a14aae9..0c280ad 100755
--- a/.bin/music
+++ b/.bin/music
@@ -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
remember that computers suck.