···55cowsay: A picture is worth a thousand words
66---
7788-I've recently been going down the path of madness known as customizing my desktop and
99-I figured I'd share some neat scripts and setups I've done along the way.
88+I've recently been going down the path of madness known as customizing my desktop and I figured I'd
99+share some neat scripts and setups I've done along the way.
10101111-Today I'll go into some scripts I've been working on to capture screen shots and recordings.
1212-They allow selecting regions of the screen and specific windows, and I also made it so you
1313-can edit them afterwards.
1111+Today I'll go into some scripts I've been working on to capture screen shots and recordings. They
1212+allow selecting regions of the screen and specific windows, and I also made it so you can edit them
1313+afterwards.
14141515## Background
16161717My entire system and home folder is managed by [NixOS](https://nixos.org), so I have a
1818-[configuration repository](https://github.com/Bwc9876/nix-conf) where all my scripts and configs
1919-can be found, I'll reference them throughout this post and provide links to the current version of each so you
2020-can see if I've updated them since this post.
1818+[configuration repository](https://github.com/Bwc9876/nix-conf) where all my scripts and configs can
1919+be found, I'll reference them throughout this post and provide links to the current version of each
2020+so you can see if I've updated them since this post.
21212222-Currently I use [Hyprland](https://hyprland.org) as my window manager, and have been duct-taping components together to make my own little Desktop Environment around it.
2222+Currently I use [Hyprland](https://hyprland.org) as my window manager, and have been duct-taping
2323+components together to make my own little Desktop Environment around it.
23242424-I also like to use [NuShell](https://nushell.sh) as my shell, and these scripts
2525-will be written in it. If you haven't checked out NuShell yet, I highly recommend it!
2525+I also like to use [NuShell](https://nushell.sh) as my shell, and these scripts will be written in
2626+it. If you haven't checked out NuShell yet, I highly recommend it!
26272728## Screenshots
28292929-First is the script to take screenshots. This is a relatively simple script as it simply builds
3030-on top of [grimblast](https://github.com/hyprwm/contrib/tree/main/grimblast) with some nice QoL
3030+First is the script to take screenshots. This is a relatively simple script as it simply builds on
3131+top of [grimblast](https://github.com/hyprwm/contrib/tree/main/grimblast) with some nice QoL
3132features.
32333334To install grimblast, all I have to do is add it to my `environment.systemPackages`:
···4243];
4344```
44454545-Grimblast will automatically save screenshots to `XDG_SCREENSHOTS_DIR`, I
4646-manually set this in my _home manager_ config with:
4646+Grimblast will automatically save screenshots to `XDG_SCREENSHOTS_DIR`, I manually set this in my
4747+_home manager_ config with:
47484849```nix
4950xdg.userDirs.extraConfig.XDG_SCREENSHOTS_DIR = "${config.home.homeDirectory}/Pictures/Screenshots";
···51525253Grimblast will name the screenshots with the current date and time, which works for me.
53545454-Now along to actually using grimblast, I'll create a new script and put in in my config somewhere, we'll
5555-call it `screenshot.nu`. I usually like to place any non-nix files in a folder called `res` at the root
5656-of my config, we'll get to actually calling this script once we're done writing it.
5555+Now along to actually using grimblast, I'll create a new script and put in in my config somewhere,
5656+we'll call it `screenshot.nu`. I usually like to place any non-nix files in a folder called `res` at
5757+the root of my config, we'll get to actually calling this script once we're done writing it.
57585859To start out we need to call grimblast, I like to use `copysave` as the action as I like having it
5960immediately in my clipboard, and having it saved for later. I'll also add `--freeze` which simply
···6364let file_path = grimblast --freeze copysave
6465```
65666666-grimblast will then return the path to the saved screenshot, which we save in `file_path`.
6767-If the user were to cancel the selection (press escape), `file_path` would be empty, so we want to make sure
6868-to check for that so we're not trying to open a non-existent file.
6767+grimblast will then return the path to the saved screenshot, which we save in `file_path`. If the
6868+user were to cancel the selection (press escape), `file_path` would be empty, so we want to make
6969+sure to check for that so we're not trying to open a non-existent file.
69707071```nushell
7172if $file_path == "" {
···8889let choice = notify-send --app-name=screengrab -i $file_path -t 7500 --action=open=Open --action=folder="Show In Folder" --action=edit=Edit --action=delete=Delete "Screenshot taken" $"Screenshot saved to ($file_path) and copied to clipboard"
8990```
90919191-A long command here, `notify-send` allows us to send a notification to the currently running notification daemon.
9292-In my case I'm using [swaync](https://github.com/ErikReider/SwayNotificationCenter).
9292+A long command here, `notify-send` allows us to send a notification to the currently running
9393+notification daemon. In my case I'm using
9494+[swaync](https://github.com/ErikReider/SwayNotificationCenter).
93959494-- `--app-name` is the name of the application that sent the notification, I say screengrab here so swaync will show an icon in addition to the image, also so I can play a camera shutter sound when the notification is sent.
9696+- `--app-name` is the name of the application that sent the notification, I say screengrab here so
9797+ swaync will show an icon in addition to the image, also so I can play a camera shutter sound when
9898+ the notification is sent.
9599- `-i` is the icon to display in the notification, in this case the screenshot we just took.
96100- `-t` is the time in milliseconds to show the notification
97101- `--action` is actions to display in the notification, `name=Text`
···101105102106
103107104104-Now we need to handle each action, the chosen action is returned by notify-send, so we can match on that.
108108+Now we need to handle each action, the chosen action is returned by notify-send, so we can match on
109109+that.
105110106106-- "Open" and "Open Folder" are pretty simple, just pass `$file_path` and `$file_path | path dirname` to `xdg-open`
107107-- "Edit" I'll simply pass the file path to my editor, I chose [swappy](https://github.com/jtheoof/swappy) because of it's simplicity and ease of use.
111111+- "Open" and "Open Folder" are pretty simple, just pass `$file_path` and `$file_path | path dirname`
112112+ to `xdg-open`
113113+- "Edit" I'll simply pass the file path to my editor, I chose
114114+ [swappy](https://github.com/jtheoof/swappy) because of it's simplicity and ease of use.
108115- "Delete" I'll just remove the file.
109116110117```nushell
···128135129136### Calling the Screenshot script
130137131131-Now in terms of actually calling it I'll be binding it to `Win` + `Shift` + `S` in Hyprland, as
132132-well as `PrintScreen`.
138138+Now in terms of actually calling it I'll be binding it to `Win` + `Shift` + `S` in Hyprland, as well
139139+as `PrintScreen`.
133140134141In home manager I simply have to add these strings to my Hyprland binds
135142···142149];
143150```
144151145145-Now by switching to my new config (and making sure to stage `screenshot.nu` of course),
146146-I can take screenshots with a keybind!
152152+Now by switching to my new config (and making sure to stage `screenshot.nu` of course), I can take
153153+screenshots with a keybind!
147154148155## Screen Recordings
149156150150-This will be a bit more involved mainly because something like grimblast doesn't exist for screen recordings.
151151-Looking at existing solutions I couldn't find any that I really liked, mostly because they involved
152152-some additional UI. To be clear this script will be for _simple_, _short_ recordings, long-term stuff
153153-I'll still prefer to use something like OBS.
157157+This will be a bit more involved mainly because something like grimblast doesn't exist for screen
158158+recordings. Looking at existing solutions I couldn't find any that I really liked, mostly because
159159+they involved some additional UI. To be clear this script will be for _simple_, _short_ recordings,
160160+long-term stuff I'll still prefer to use something like OBS.
154161155162For the actual screen recording I'll be using [wf-recorder](https://github.com/ammen99/wf-recorder).
156163···165172];
166173```
167174168168-First and foremost location, I chose to use `~/Videos/Captures` for my recordings. I didn't
169169-set an environment variable for this, it'll be hardcoded in the script.
175175+First and foremost location, I chose to use `~/Videos/Captures` for my recordings. I didn't set an
176176+environment variable for this, it'll be hardcoded in the script.
170177171178```nushell
172179let date_format = "%Y-%m-%d_%H-%M-%S"
···180187let out_name = date now | format date $"($captures_folder)/($date_format).mp4"
181188```
182189183183-This will handle determining the folder and name for the recordings,
184184-and creating the folder if it doesn't exist.
190190+This will handle determining the folder and name for the recordings, and creating the folder if it
191191+doesn't exist.
185192186193Next up I want to have a similar selection process to the screenshot script, to do this I'll use
187187-[slurp](https://github.com/emersion/slurp) to select areas of the screen,
188188-which is what grimblast uses under the hood.
194194+[slurp](https://github.com/emersion/slurp) to select areas of the screen, which is what grimblast
195195+uses under the hood.
189196190197In addition, grimblast does some communication with Hyprland to get window information such as
191191-position and size, this lets you select a window to take a screenshot of. I'll be getting that info manually from
192192-Hyprland using NuShell instead:
198198+position and size, this lets you select a window to take a screenshot of. I'll be getting that info
199199+manually from Hyprland using NuShell instead:
193200194201```nushell
195202let workspaces = hyprctl monitors -j | from json | get activeWorkspace.id
···208215}
209216```
210217211211-I do `complete` here to get the exit code of the slurp command, if it's 1 then the user cancelled the selection
212212-and similar to the screenshot script I'll exit.
218218+I do `complete` here to get the exit code of the slurp command, if it's 1 then the user cancelled
219219+the selection and similar to the screenshot script I'll exit.
213220214214-Now it's time to actually record, the stdout of `slurp` contains the geometry that we want to capture,
215215-so we'll pass that to `wf-recorder` with the `-g` flag:
221221+Now it's time to actually record, the stdout of `slurp` contains the geometry that we want to
222222+capture, so we'll pass that to `wf-recorder` with the `-g` flag:
216223217224```nushell
218225wf-recorder -g ($stat.stdout) -F fps=30 -f $out_name
219226```
220227221221-Pretty simple command, `-g` is the geometry to record, `-F` is the format options, and `-f` is the output file.
228228+Pretty simple command, `-g` is the geometry to record, `-F` is the format options, and `-f` is the
229229+output file.
222230223231Now we'll run into an issue if we run this script and start recording, there's no way to stop it!
224232I'll cover how we're going to get around that when it comes to setting up keybinds.
···231239232240
233241234234-Most arguments are the same here as the screenshot script, the only difference is the icon and app name.
235235-The actions are also basically the same, so I'll leave out the explanation and just show the handler:
242242+Most arguments are the same here as the screenshot script, the only difference is the icon and app
243243+name. The actions are also basically the same, so I'll leave out the explanation and just show the
244244+handler:
236245237246```nushell
238247match $action {
···252261253262Now to actually call the script, I'll bind it to `Win` + `Shift` + `R` in Hyprland.
254263255255-However, we're going to do something special with the `exec` line here. Instead of simply calling the script
256256-we're going to check if `wf-recorder` is already running, if this is the case we can send
257257-`SIGINT` to it to make it stop recording, meaning our script will continue and show the notification.
264264+However, we're going to do something special with the `exec` line here. Instead of simply calling
265265+the script we're going to check if `wf-recorder` is already running, if this is the case we can send
266266+`SIGINT` to it to make it stop recording, meaning our script will continue and show the
267267+notification.
258268259269```nix
260270wayland.windowManager.hyprland.settings.bindr = [
···264274];
265275```
266276267267-`pkill` here will exit with code `1` if it doesn't find any processes to kill, so the `||` will run our script if `pkill` fails.
277277+`pkill` here will exit with code `1` if it doesn't find any processes to kill, so the `||` will run
278278+our script if `pkill` fails.
268279269269-Note that I did this on `bindr`, this means the keybind will only happen once the R key is _released_ rather than
270270-pressed. This is to prevent a weird issue I ran into where the recording would stop immediately after starting.
280280+Note that I did this on `bindr`, this means the keybind will only happen once the R key is
281281+_released_ rather than pressed. This is to prevent a weird issue I ran into where the recording
282282+would stop immediately after starting.
271283272272-And that's it! We can now screen record with ease. It won't record audio
273273-(might do an additional keybind in the future) and it also doesn't copy the recording to the clipboard, but
274274-it works pretty well for short videos.
284284+And that's it! We can now screen record with ease. It won't record audio (might do an additional
285285+keybind in the future) and it also doesn't copy the recording to the clipboard, but it works pretty
286286+well for short videos.
275287276288## Full Scripts
277289