Skip to content

Instantly share code, notes, and snippets.

View henrik's full-sized avatar

Henrik Nyh henrik

View GitHub Profile
@henrik
henrik / photos_app_zeropad.scpt
Last active June 22, 2021 17:48
Photos.app: Rename albums to zeropad numbers. Use case: Relying on sorted events and migrating from iPhoto which sorted "100" after "2" to Photos which didn't.
tell application "Photos"
repeat with theAlbum in albums of folder "Events"
set theName to name of theAlbum
-- Zeropad initial numbers, e.g. turning "12.3 Hi" into "0012.3 Hi".
set newName to (do shell script "ruby -e 'n = ARGV.first; num, rest = n.split(%{.}, 2); puts num.match?(/\\A\\d+\\z/) && rest ? [ num.rjust(4, %{0}), rest ].join(%{.}) : n' " & (quoted form of theName))
set name of theAlbum to newName
end repeat
end tell
@henrik
henrik / README.md
Created May 7, 2021 23:33
Export Plex library titles via Node

I wanted to export all titles from the Plex library on my Mac and couldn't find a good tool.

This is a tiny, quick-and-dirty Node JS script, using node-plex-api.

It assumes you have node and npm installed.

Then just download this "script.js" and run:

npm install plex-api --save

node script.js your_plex_username your_plex_password > plex.txt

@henrik
henrik / each_in_thread_pool.rb
Last active February 2, 2021 16:55
Run a block on a list of things in a limited number of concurrent threads. Mostly for the fun of it – there are more featureful libs like https://github.com/grosser/parallel.
# Lets you call a block for each item in a list, just like `each`.
# But instead of running serially, it runs in a limited number of parallel threads.
# This is useful when you don't just want one thread per item, e.g. to avoid rate limiting or network saturation.
class EachInThreadPool
def self.call(inputs, pool_size:, &block)
queue = Queue.new
inputs.each { queue << _1 }
pool_size.times.map {
@henrik
henrik / README.md
Created January 1, 2021 19:05
IRCC codes for Sony Bravia KD55XH9296BU. For my own reference for future automation.
@henrik
henrik / pathname_extras.rb
Last active December 8, 2020 19:48
Ruby code to check if a pathname is contained within another pathname (e.g. "/foo/bar/baz" within "/foo/bar") without being tricked by "..". Written with @olleolleolle.
class PathnameExtras
def self.in_dir?(path, dir:)
path_parts = path.expand_path.each_filename.to_a
dir_parts = dir.expand_path.each_filename.to_a
return false if path_parts == dir_paths
dir_parts.zip(path_parts).all? { |x, y| x == y }
end
end
@henrik
henrik / toggle_zoom_mute.scpt
Created November 21, 2020 23:24
AppleScript proof-of-concept for toggling Zoom mute. Gracefully handles Zoom not being installed, or not running, or not currently being in a meeting.
-- Based on: https://devforum.zoom.us/t/easiest-way-to-get-mute-status/18462/7
tell application "System Events"
if exists window 1 of process "zoom.us" then
tell application process "zoom.us"
if exists (menu 1 of menu bar item "Meeting" of menu bar 1) then
set meetingMenu to menu 1 of menu bar item "Meeting" of menu bar 1
set canMute to exists menu item "Mute audio" of meetingMenu
set canUnmute to exists menu item "Unmute audio" of meetingMenu
@henrik
henrik / README.md
Last active August 24, 2022 21:15
AWS Lambda Ruby script to get cat status from the SureFlap cat flap. Very rough-and-ready. Intended to be used with an iOS shortcut to get cat status.

AWS Lambda Ruby script to get cat status from the SureFlap cat flap. Very rough-and-ready.

Intended to be used with an iOS shortcut to get cat status – see https://twitter.com/henrik/status/1321201656822943745 for a screenshot of the shortcut.

This is not a tutorial, just some public notes for my own future use.

Setup hints

Create this as a AWS Lambda running on Ruby.

@henrik
henrik / example.ex
Created August 29, 2020 20:14
Elixir "@foo bar" macro example
defmodule MyMacro do
defmacro @{name, _meta, [arg]} do
IO.inspect "Your #{name} is a #{arg}"
end
defmacro __using__(_) do
quote do
import Kernel, except: [@: 1]
import unquote(__MODULE__)
end
@henrik
henrik / app.js
Last active March 27, 2021 21:07
Phoenix LiveView hook that makes links with a "phx-click" still trigger the default navigation event, and also prevents clicks on buttons inside these links from doing the same.
// Fixes two issues:
// - Clicking a link with a `phx-click` attribute did not cause the link default (navigation) to trigger.
// - Clicking a button inside the link *would* cause the link default to trigger.
Hooks.AllowLinkDefaultAndPreventNestedDefault = {
mounted() {
this.el.addEventListener("click", (e) => {
// `closest` in case we click an element inside a button, e.g. an icon.
if (e.target.closest("button")) {
e.preventDefault()
} else {
@henrik
henrik / Z_payloads.md
Last active May 26, 2020 19:57
LiveView rendering lab

Lab (LiveView 0.13.0, Phoenix 1.5.3)

A - straight for loop

First render, 8233 bytes

["4","4","lv:phx-FhF6gwiU2cjuXjoB","phx_reply",{"response":{"rendered":{"0":"<a class="tabs__tab " data-phx-link="patch" data-phx-link-state="push" href="/"><i class="fas fa-eye mr-1">\nCommits\n","1":"<a class="tabs__tab " data-phx-link="patch" data-phx-link-state="push" href="/comments"><i class="fas fa-comments mr-1">\nComments\n","2":"<a class="tabs__tab " data-phx-link="patch" data-phx-link-state="push" href="/settings"><i class="fas fa-cog mr-1">\nSettings\n","3":"","4":"","5":{"0":{"d":[["1","Item 1","1"],["2","Item 2","2"],["3","Item 3","3"],["4","Item 4","4"],["5","Item 5","5"],["6","Item 6","6"],["7","Item 7","7"],["8","Item 8","8"],["9","Item 9","9"],["10","Item 10","10"],["11","Item 11","11"],["12","Item 12","12"],["13","Item 13","13"],["14","Item 14","14"],["15","Item 15","15"],["16","Item 16","16"],["17","Item 17","17"],["18","Item 18","18"],["19