Junkyard

Documenting my personal set-up.

View on GitHub

homepage

I’m using gethomepage/homepage. This is a very aesthetic yet simple homepage.

Screenshot of my homepage

Service Widgets

I used customapi for three widgets:

Trilium

Trilium was the easiest to set up. It had a well-documented api (official, Trilium Rocks) and uses an app token.

        widget:
          type: customapi
          url: http://<address>:<port>/trilium/etapi/app-info
          refreshInterval: 9000000000   # random big number to avoid refreshing too often
          method: GET                   # not necessary
          headers:
            Authorization: <etapi_token>
          mappings:
            - field: appVersion
              label: Version

This simply displays the app version.

tt-rss

This one took me ages to figure out the error. I thought I was setting up my reverse proxy wrong, and I did technically. The tt-rss api endpoint requires a trailing slash, while homepage sanitises the trailing slash away. I couldn’t find out a better way to handle this, so my nginx config looks like this:

server{
    <server config>

    location /tt-rss/api {
        proxy_pass http://127.0.0.1:<port>/tt-rss/api/;
    }
}

tt-rss uses a session id (sid) to authenticate.

You can ‘login’ and get a sid using curl. Below is from tt-rss official api docs.

curl -d '{"op":"login","user":"you","password":"xxx"}' http://example.com/tt-rss/api/

This widget config shows the number of unread articles.

        widget:
          type: customapi
          url: http://<address>:<port>/tt-rss/api
          refreshInterval: 900000        # 15 min, tt-rss' refresh interval
          method: POST
          requestBody: 
            sid: <sid>                   # obtained using curl 
            op: getUnread
          mappings:
            - field: content.unread
              label: Unread
              format: number

calibre

Homepage has a built-in widget for calibre-web, but not one for the calibre content server. The difficulty with this is that I’m using digest authentication (because I’m not using https), which means that the authentication header requires constant update because the nonce becomes stale. The timeout for the nonce is an hour according to calibre’s source code [x].

# line 22 src/calibre/srv/auth.py
MAX_AGE_SECONDS = 3600

The API uses AJAX, defined in src/calibre/srv/ajax.py.

The following shows the numbers of books in the default Calibre library.

        widget:
          type: customapi
          url: http://<address>:<port>/calibre/ajax/search
          refreshInterval: 2629746000             # one month
          method: GET
          headers:
            Authorization: Digest username="<...> # obtained by putting the api url 
                                                  # in the browser and copying the 
                                                  # authorisation header
          mappings:
            - field: num_books_without_search
              label: '# of books'

To get the ‘Authorization’ header programmatically, I use a Bash script to run curl and extract the header into an .env file that will substitute the value in the service.yaml file i.e.:

headers:
  {{HOMEPAGE_FILE_CALIBRE}}

To set the substitution, the docker compose file needs to have:

   environment:
       HOMEPAGE_FILE_CALIBRE: ./config/.env

The Bash file is placed in the config folder and writes to the .env file [x, x, x, x]:

#!/bin/bash

curl -Lvso /dev/null 'http://<address>:<port>/calibre/ajax/search' --digest -u <username>:<password> 2> .tenv 
sed '/Authorization/!d' .tenv | cut -c 3- > .env

The Bash script will run every hour using systemd timers [x, x]. The service/timer files are in the repo. You place them in /etc/systemd/system and run systemctl enable homepage-calibre.service (to automatically restart on boot) and systemctl start homepage-calibre.service.