Sort With Xslt By Version Number

There are this moments in my life where I get really excited about technology. The latest of these moments was when I found out that nginx autoindex supports xslt out of the box.

Lets go 2 steps back what does that even mean. Nginx autoindex is the feature which allows you to list all available files and folders in the web root of you server. So it's just a very simple web page listing all files as link. The config for that looks like this:

location /documentation {
	autoindex on;
}

The problem is, this list is really basic. Maybe this list is not good enough, maybe you want more than files just alphabetically sorted and listed. Maybe you want to sort them by date, alphabetically descending or something else. Maybe you want to style this list which some CSS. And that exactly what I want to do. I have folders with different versions like 2.07.03 and 3.0.0 and I want to sort them in a way that you see the latest version first. So that you see 3.0.0 > 2.07.03.

And here comes xslt (and my excitement) in to play. Nginx autoindex does also support three alternative output modes to html. Thats xml, json and jsonp. And when you use xml you can provide your own xslt file. So that is what we do:

location /documentation {
	autoindex on;
	autoindex_format xml;
	xslt_stylesheet /path/to/your/transform.xslt;
}

You find the full documentation for the xslt module here. And now we can use all the amazingness of xslt.

The plain xml autoindex generates looks like this:

<?xml version="1.0"?>
<list>
  <directory mtime="2018-08-23T09:40:02Z">2.12.01</directory>
  <directory mtime="2018-11-19T15:04:06Z">2.12.02</directory>
  <directory mtime="2018-09-05T14:07:04Z">3.0.0</directory>
  <directory mtime="2018-10-08T07:14:02Z">3.0.1</directory>
  <directory mtime="2018-11-29T17:06:58Z">3.0.12</directory>
  <directory mtime="2018-11-13T11:34:26Z">2.99.99</directory>
  <directory mtime="2018-11-29T17:06:58Z">latest</directory>
</list>

And here is how you sort with xslt by version.

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="utf-8" indent="yes"/>

<xsl:template match="/list">
    <html>
        <body>
            <table>
                <tr>
                    <th>name</th>
                    <th>date</th>
                </tr>
                <xsl:for-each select="directory">
                    <xsl:sort select="substring-before(., '.')" data-type="number" order="descending"/>
                    <xsl:sort select="substring-before(substring-after(., '.'), '.')" data-type="number" order="descending"/>
                    <xsl:sort select="substring-after(substring-after(., '.'), '.')" data-type="number" order="descending"/>
                    <tr>
                        <td>
                            <a href=".">
                                <xsl:value-of select="."/>
                            </a>
                        </td>
                        <td>
                            <xsl:value-of select="substring(@mtime, 9, 2)"/>
                            <xsl:text>-</xsl:text>
                            <xsl:value-of select="substring(@mtime, 6, 2)"/>
                            <xsl:text>-</xsl:text>
                            <xsl:value-of select="substring(@mtime, 1, 4)"/>
                            <xsl:text> </xsl:text>
                            <xsl:value-of select="substring(@mtime, 12, 8)"/>
                        </td>
                    </tr>
                </xsl:for-each>
            </table>
        </body>
    </html> 
</xsl:template>

</xsl:stylesheet>

As you can see this creates just a basic html table so I leave it up to to you to Style it in a way you like. And a big thanks to michael.hor257k on stackoverflow who created this readable version of the xslt based on my horrible hacky xslt.

Enjoy your new fancy autoindex pages!

Podcasting With Pulse

The goal is to create a simple solution to live stream a podcast. This means I need a audio stream which combines the thing I hear and the things I say.

To achieve this I mostly copied what makefu does. The first step is to figure out what the name of your input and output device is. You can find that with:

pacmd list-sources | grep -e device.string -e 'name:'

Which will provide you with output like this:

	name: <alsa_output.pci-0000_00_1b.0.analog-stereo.monitor>
		device.string = "0"
	name: <alsa_input.pci-0000_00_1b.0.analog-stereo>
		device.string = "front:0"
	name: <alsa_output.pci-0000_01_00.1.hdmi-stereo-extra1.monitor>
		device.string = "1"
	name: <alsa_output.usb-Focusrite_Scarlett_Solo_USB-00.analog-stereo.monitor>
		device.string = "2"
	name: <alsa_input.usb-Focusrite_Scarlett_Solo_USB-00.analog-stereo>
		device.string = "front:2"

As we can see here my output device is: alsa_output.usb-Focusrite_Scarlett_Solo_USB-00.analog-stereo.monitor and my input device is alsa_input.usb-Focusrite_Scarlett_Solo_USB-00.analog-stereo.

Now my problem is that my input device is stereo but my microphone only records in mono. But this is easy to fix, we can just remap our input to mono like this:

pactl load-module module-remap-source master=alsa_input.usb-Focusrite_Scarlett_Solo_USB-00.analog-stereo master_channel_map=front-left,front-right channels=2 channel_map=mono,mono

If we check the list of devices again we have a new input device called alsa_input.usb-Focusrite_Scarlett_Solo_USB-00.analog-stereo.remapped. And this will be the input device we use.

Now we can just create a new stream and map input and output to it:

# create stream
pactl load-module module-null-sink sink_name=stream sink_properties=device.description="Streaming"

# map input and output
pactl load-module  module-loopback source=alsa_output.usb-Focusrite_Scarlett_Solo_USB-00.analog-stereo.monitor sink=stream latency_msec=1
pactl load-module  module-loopback source=alsa_input.usb-Focusrite_Scarlett_Solo_USB-00.analog-stereo.remapped sink=stream latency_msec=1

The only thing left is to have a darkice which is compiled with mp3 support and then you can stream to any [icecast}(http://icecast.org/) server like this:

darkice -c stream.cfg

My config looks like this:

[general]
duration = 0
bufferSecs = 5
reconnect = yes
realtime = no
rtprio = 2

[input]
sampleRate = 44100
bitsPerSample = 16
channel = 2
device = pulseaudio
paSourceName = stream.monitor

[icecast2-0]
format=mp3
channel=2
bitrate=128
bitrateMode=cbr
quality=0.6
server=dns.name.or.ip.of.your.icecast.server
name=Testi test
description=Test test
public=yes
localDumpFile=dump.mp3
mountPoint=your_mountpoint.mp3
password=XXXXX
port=9000

And thats it, happy streaming!

Telegraf Snmp Hp Switch Monitoring

Monitore a HP 1810-24G Switch (J9450A) with telegraf, influxdb and grafana over snmp. Sounds complicated and convoluted but it's not I swear.

Basically you need to do two things. (Well if you have a running telegraf, influxdb and grafana setup and your HP switch has snmp enabled)

The plan was to use ifXTable but for a reason unknown to me it didn't work. So here is the inputs.snmp config I use:

[[inputs.snmp]]
    agents = [ "SWITCH_IP:161" ]
    community = "notpublic"
   [[inputs.snmp.field]]
     name = "hostname"
     oid = "SNMPv2-MIB::sysName.0"
     is_tag = true
   
    # Port 01
    [[inputs.snmp.field]]
       name = "if_01_name"
       oid = "IF-MIB::ifName.1" 
    [[inputs.snmp.field]]
       name = "if_01_speed"
       oid = "IF-MIB::ifSpeed.1" 
    [[inputs.snmp.field]]
       name = "if_01_in_octets"
       oid = "IF-MIB::ifInOctets.1" 
    [[inputs.snmp.field]]
       name = "if_01_out_octets"
       oid = "IF-MIB::ifOutOctets.1" 
    [[inputs.snmp.field]]
       name = "if_01_in_error"
       oid = "IF-MIB::ifInErrors.1" 
    [[inputs.snmp.field]]
       name = "if_01_out_error"
       oid = "IF-MIB::ifOutErrors.1" 

....     

    # Port 24
    [[inputs.snmp.field]]
       name = "if_24_name"
       oid = "IF-MIB::ifName.24" 
    [[inputs.snmp.field]]
       name = "if_24_speed"
       oid = "IF-MIB::ifSpeed.24" 
    [[inputs.snmp.field]]
       name = "if_24_in_octets"
       oid = "IF-MIB::ifInOctets.24" 
    [[inputs.snmp.field]]
       name = "if_24_out_octets"
       oid = "IF-MIB::ifOutOctets.24" 
    [[inputs.snmp.field]]
       name = "if_24_in_error"
       oid = "IF-MIB::ifInErrors.24" 
    [[inputs.snmp.field]]
       name = "if_24_out_error"
       oid = "IF-MIB::ifOutErrors.24"

The full config can be found here to copy & paste: fliiiix/2921c168182b27b27d8aca2bdb5f83b0

And then the second step is to create a the graph in grafana.

grafana config

Note: it's times 8 because the value you get over snmp is octets. And don't forget to change the Unit to bits/sec on the Units tab.

If you are lazy and need all 24 ports on one dashboard here you can find my config. Don't forget to search and replace my hostname (atlas.l33t.network) with your hostname.

Plexpy Is Now Tautulli

What is tautulli? From there site: "Tautulli is a 3rd party application that you can run alongside your Plex Media Server to monitor activity and track various statistics." And if you where already a plexpy user, it's the same but better. And here is how you migrate your existing plexpy installation to tautulli.

The first thing is to install it:

pkg install tautulli

Note: I'm not sure if this port is already in the quarterly package repos since I build my own packages.

Update the /etc/rc.conf to (tautulli_user is by default nobody):

tautulli_enable="YES"
tautulli_user="plex"

Stop plexpy and copy the config and database. Make sure config.ini and tautulli.db are owned by the tautulli_user you use!

service plexpy stop
cp /usr/local/plexpz/config.ini /var/db/tautulli/config.ini
cp /usr/local/plexpz/plexpy.db /var/db/tautulli/tautulli.db

And that's it you can start tautulli and enjoy the cool new interface.

service tautulli start

Hidpi Display Configuration

Apparently it is too hard to ship with a default configuration, that works well with HiDPI displays. And my Dell XPS 13 has a HiDPI display. But fear not, it's not that hard to configure when you know which files you should change. So here is what's working for me with i3 as window manager. (This should probably work for everything using XServer.)

The first file we need is ~/.Xresources

Xft.dpi: 192
Xft.autohint: 0
Xft.lcdfilter:  lcddefault
Xft.hintstyle:  hintfull
Xft.hinting: 1
Xft.antialias: 1
Xft.rgba: rgb

I don't think all these options are needed, but as I said, works for me™️.

To finally get ~/.Xresources loaded you need the ~/.xinitrc file.

xrdb -merge ~/.Xresources

Btw: this is also part of my dotfiles.