Slightly too much Kodi for fun#
Wed Aug 4 21:02:24 2021
I'd been vacillating for a while about buying a new monitor, but
eventually I pulled the hammer (is that the idiom?) on a spangly new
Dell S2721SQ, which arrived yesterday and provided the incentive to
look at NixElec again. Because it
(the monitor) has speakers, which means I have the hardware to fix the
audio issues without having to commandeer the family TV.
Second rate
I don't claim to understand how ALSA works, and Kodi's approach to
ALSA is even more weird,
but I did eventually make it work for 44.1kHz sources: define an
ALSA fixed-rate pcm
for Kodi that is hardcoded to S16_LE
format, and then tell Kodi
about it in
advancedsettings.xml
A sticky GUI mess
To the extent that Kodi can be configured through files, they're XML
files. There is a
toXML
builtin
in Nix, but it only generates a particular XML representation that
would need XSLT to turn into files that Kodi likes - and XSLT for me
is assigned firmly to into the same "tried it once, not going back to
that" bucket as are m4 and Java applet programming.
What I really wanted is something that would let me write out (or
generate!) a nested attrset describing the structure I want, and turn
it, possibly via JSON, into XML. Python's
dict2xml is very nearly it, but
has no support for XML attributes, so I had to invent something
slightly more complicated.
Sadly, the extent that Kodi can be configured through files is not the
full extent. Although the sources are defined in XML, the content of
each source (tv shows? movies? music?) seems to be set in a Sqlite
database, which is another level of complexity to manage. So there's
still manual twattery on the GUI to deal with.
Hard pass#
Sat Aug 14 20:31:26 2021
I've got the key
I've got the secret
-- From the Urban Cookie Collective's guide to password management
For reasons that seemed good at the time, I've written a password
manager. It's a lot like pass ("the
standard unix password manager") - which I have been using up 'til
now - but it uses age instead of GPG to
do the heavy lifting.
moss, the Maybe-Ok Secrets Store,
is a 400-line Ruby script that uses only libraries provided by a
default Ruby installation, plus 520 lines of testing code (Cucumber
and RSpec).
Some random observations follow:
-
almost all of it was test-driven, but the tests are for the most
part end-to-end Cucumber tests that run the script in a subshell
instead of calling classes/functions/methods directly. I was not
expecting to get that far with end-to-end tests, but when all's said
and done it's a pretty small system.
-
There are certain deficiencies in the Cucumber step definition
language that get more annoying as the test suite grows. Most
notably, the use of ad hoc @var
to pass state from one step to the
next. I don't have a solution here, I'm just complaining about the
problem.
-
I don't claim to be a security expert, which might make me not a
good person to attempt this kind of project. I have carefully
avoided rolling my own crypto by using a third party program for
that, and I am quite pleased with my use of the various affordances
of Kernel.system
, IO.popen
, Kernel.spawn
and Tempfile
to
avoid even passing plaintext or passphrases in or out of the Ruby
process. There's a lot of flexibility in that family of methods if
you read the docs. More information about my security-related design choices in the relevant section of the README
-
I am simultaneously proud and ashamed of the
command line parser I
created by using various metaprogramming features in ways that may
or may not be generally recommended. (Don't try this at work, kids -
at least, not if you work for my employer, metaprogramming in
company code is firmly in the "presumption of bad" bucket).
-
I didn't know, but now I do, that there is support in the Ruby
standard library ('Fiddle') for calling C libraries without having
to write extensions and needing a C compiler. I didn't actually
need to - I thought I was going to need mlock(2) before I realised it
wouldn't help and found a way to use a temporary file instead -
but it's nice to know it's there.
-
It's a single script with no dependencies other than a Ruby
installation, and this is intentional: it means you can easily
install it anywhere just by copying the script. I might reconsider
the "single script" constraint if/when it passes 500 lines. I am
less likely to renege on "no external dependencies", because I've too
often had trouble running programs that require Bundler
from inside a project with its own Gemfile.
It's been a long time since I wrote more than about 5 lines of Ruby
for anything outside of a work context: for 'fun' projects I tend to
pick languages which I don't get a chance to use 9-5. Ruby for this
task was definitely less than awful, though.