Hacking Wishlist

This is a to-do list of sorts, but also a public invitation for others to share solutions for the given problems.

If you know how to solve any of these problems, email me at luke@lukesmith.xyz

Guidelines

  1. Solutions should be elegant and should ideally be done with core utilities or common programs. My goal is typically keep system depdendencies at a minimum (in my own computer and in LARBS).
  2. Bad solutions are done with several megabytes of Python packages. Ideal solutions are so simple I feel like an utter moron for not having thought of them before.
  3. Test your solution before you give it to me (unless I'm asking something that cannot be tested). I get a lot of bogus advice/pull requests/answers because people want to be "helpful" and don't actually test to see if their solution actually works. These people are wasting my time by leading me on wild goose chases. You can, however, give me non-solutions which are still good information and I will appreciate it.

2. An easy way to detect all mailboxes on an IMAP server

As you may know, I have a mutt-wizard that automatically generates mutt/terminal-based email system with mail accessible offline with offlineIMAP.

While running the wizard is easy, it is extremely difficult for those people who refuse to read the directions, readme or other documentation. That's because installing it comes in three steps:

The reason this is not one automated step is because the only consistent way I have for detecting all mailboxes is simply running offlineimap and letting it find them all. The mailbox names/locations are needed to finish the wizard.

A little hack like this will also help in the future, as I'm contemplating changing the wizard's backend from offlineIMAP to isync/mbsync. isync does not automatically detect all mailboxes at all, instead you have to put them in one by one. While isync is more minimal and better for other reasons, you have to manually specify each of the mail folders and their corresponding remote equivalents before a successful sync (so far as I know).

1. Pausing all instances of mpv with one command/script

In LARBS, super+shift+p is a "pause all" shortcut that pauses mpd and mpv instances. It's a pretty important shortcut, but I also have the same commands run when you lock the screen so you don't have to manually pause everything.

Pausing mpd via cli is easy, pausing mpv videos I've figured out, but I'm still trying to find a fool-proof way to pause mpv audio-only instances. Let me show you the video pause command now:

xdotool search --class mpv | xargs -I % xdotool key --window % comma

In other words, it uses xdotool to find all mpv windows and sends a , key to each. The comma is officially a shortcut for "one frame back", but also pauses the video. The reason I don't send p is because p toggles pause, and I need a command that won't unpause paused mpv instances.

Now this doesn't work on audio instances because (1) xdotool search won't find terminal instances running mpv and (2) even if it did, the ,/comma shortcut doesn't work!

I do have this, which doesn't do what I want, but might be helpful if you want to figure it out. By using pstree -p and coreutils, you can get all the PIDs of the terminal windows mpv is running in. Here I do that then send the key p to all of them.

pstree -p | grep "$TERMINAL.*{mpv}" | sed "s/.*$TERMINAL(\([0-9]*\)).*/\1/" | xargs -I @ xdotool search --pid @ | xargs -I % xdotool key --window % p

This will toggle pause on all mpv instances, video and audio. Close, but this line will toggle pause on all mpv instances. I want it to force pause, and again, ,/comma doesn't work on the audio instances.

Potential solution with servers

Zach O. sent in a working solution which does the job elegantly, although requires all instances of mpv to be run with servers. He suggests aliasing mpv as follows so it will have a server accessible in /tmp/mpvsoc*:

alias mpv='mpv --input-ipc-server=/tmp/mpvsoc$(date +%s)'

You can do the same in the ranger (rifle.conf) config, as follows:

mime ^video,       has mpv,      X, flag f = mpv --input-ipc-server=/tmp/mpvsoc$(date +%s) -- "$@"

But then, running the command below will pause all audio and video instances:

for i in $(ls /tmp/mpvsoc*); do
	echo '{ "command": ["set_property", "pause", true] }' | socat - $i;
done

This also requires socat, which is a very minor dependency (0.56MiB), but it's not in LARBS by default.

Anyway, this is a good working solution, although I'd like to have one that doesn't require aliasing in every program that you can run mpv. I'm going to keep this issue "open" in case someone sends an even more elegant solution without aliasing, but if that doesn't come, I might just push an update like this to the voidrice repository soon.

Potential solution with interprocess communication

siga suggested a similar solution which also requires aliasing, but uses IPC.

  1. Set up a pipe at a desired location: mkfifo /tmp/mpvipc.
  2. Then alias mpv to use that file as an input file: alias mpv='mpv --input-file=/tmp/mpvipc'
  3. Once you have that, run echo '{ "command": ["set_property", "pause", true] }' > /tmp/mpvipc to pause all instances.

This solution does not quite work as expected though, as the pause command typically only pauses the most recent instance.

✔ SOLVED 3. Use awk, sed etc. to move all text before regex to end

I wanted to have a little wrapper for opening image files in sxiv in a file browser. Specifically, I want to open the selected file first, but also open all other images as a list. The use isn't too important.

Anyway, let's say the input is this:

apple.png
banana.png
coconut.png
durian.png
eggplant.png
fruit_medly.png
grapes.png

And let's say the regex we're matching (i.e. the main file to be opened) is eggplant.png I want the output to be like this:

eggplant.png
fruit_medly.png
grapes.png
apple.png
banana.png
coconut.png
durian.png

That is, all the lines that originally appeared before the regex have been moved in the same order to the end. I was toying around with sed last night and it's not to difficult to get almost there: i.e. to have the matches before including the match to the end, but that's not what I want. I'd like to be able to do this in one elegant command. I feel like the answer is obvious and right in front of me, but you might see it clearer.

Anyway, once I have this output, I can feed it to sxiv which will open the main selected file and then you can key through the files in the order they are in the directory.

Solution (found by Maciej S.)

Maciej S. designed an awk script which works perfectly for this. Thanks again, Maciej! Here's it in one line:

awk 'BEGIN { lines = ""; m = 0; } /^eggplant\.png$/ { m = 1; } { if (!m) { if (lines) { lines = lines"\n"; } lines = lines""$0; } else { print $0; } } END { print lines; }'

Here's the awk script formatted more readably. It should make good sense even if you're like me and haven't really done anything too programmatic in awk before.

BEGIN {
  lines = "";
  m = 0;
}

/^eggplant\.png$/ {
  m = 1;
}

{
  if (!m) {
    if (lines) {
      lines = lines"\n";
    }
    lines = lines""$0;
  }
  else {
    print $0;
  }
}

END {
  print lines;
}

This will be added to my dotfiles repo as the rotdir (rotate directory) script. For use with sxiv, but probably eventually other programs.


Luke Return to main page