Nushell Example #2

I’ve been working with Nushell as a substitute for both a Unix shell and my usual tools for commandline data manipulation. All of my examples are at work though, so I’m writing up a few demonstrations.

A local charitable festival has a website but the schedule of events doesn’t lend itself well to printing. I’ll work with the data that drives it and generate a schedule that I can carry.

I’ve already inspected the front-end in Firefox’s web tools and identified the back-end API call. From its Javascript I’ve figured out that ‘797’ means “music”. Explaining the browser debugger and how I figured that out is beyond the scope of this post.

If you want to play with the data yourself, I have a gzipped copy here so you won’t abuse their API. Be nice.

# Get all the music events for the weekend from the API...
let music = (http get "https://opositivefestival.org/wp-admin/admin-ajax.php?action=wcs_get_events_json&content[wcs_type]=797&start=2023-10-05&end=2023-10-08")

# If I were using the dumped data above I'd do this to extract
# just the music events...
let music = (
  ^gzip -dc ~/repos/misc-demos/nushell/opositive.data.json.gz |
  from json | 
  where ($it.terms.wcs_type.0 | any {|x| $x.id == 797})
)

$music | columns
╭────┬────────────────╮
│  0 │ title          │
│  1 │ id             │
│  2 │ thumbnail      │
│  3 │ thumbnail_size │
│  4 │ multiday       │
│  5 │ ending         │
│  6 │ duration       │
│  7 │ terms          │
│  8 │ period         │
│  9 │ excerpt        │
│ 10 │ hash           │
│ 11 │ visible        │
│ 12 │ timestamp      │
│ 13 │ last           │
│ 14 │ start          │
│ 15 │ end            │
│ 16 │ future         │
│ 17 │ finished       │
│ 18 │ permalink      │
│ 19 │ buttons        │
│ 20 │ meta           │
╰────┴────────────────╯

Great. After a little exploring I know the fields I need: Name, Start, End, Location, and a description named “Excerpt”. Start and End are date and time, we’ve converted them in the previous example and will do the same. Excerpt is a HTML snippet. I’ll use the command line web browser lynx to render it as text. The first line is roughly the same as the Location, the second line is a summary, and the remainder is a free-form description. I’ll split lines and pull out the second.

let schedule = $music | 
  each {|r| {
      Name: $r.title,
      Start: $r.start,
      End: $r.end,
      Location: ($r.terms.wcs_room.0.name),
      Description: ($r.excerpt |
                 ^lynx --dump --force-html -stdin |
                 str trim |
                 split row -r '\n' |
                 get 2 |
                 str trim) 
      }
  } |
  group-by { get Start | format date "%Y-%m-%d" }

Let’s see what Friday’s events are:

let $friday = $schedule | get "2023-10-06"

$friday
╭────┬────────────────────────────────────────┬───────────────────────────┬───────────────────────────┬───────────────────────┬────────────────────────────────╮
│  # │                  Name                  │           Start           │            End            │       Location        │          Description           │
├────┼────────────────────────────────────────┼───────────────────────────┼───────────────────────────┼───────────────────────┼────────────────────────────────┤
│  0 │ O+ Kickoff Parade featuring Brasskill  │ 2023-10-06T17:45:00+00:00 │ 2023-10-06T18:30:00+00:00 │ Kingston Library      │ Lineup at 5pm – Parade at      │
│    │                                        │                           │                           │                       │ 5:45pm                         │
│  1 │ Banned Jezebel                         │ 2023-10-06T19:00:00+00:00 │ 2023-10-06T19:45:00+00:00 │ Keegan Ales           │ Funk, Blues, Rock & Soul       │
│  2 │ Molly Tigre                            │ 2023-10-06T19:00:00+00:00 │ 2023-10-06T19:45:00+00:00 │ SO+mewhere Stage      │ Ethopian Funk & Progressive    │
│    │                                        │                           │                           │                       │ Jazz                           │
│  3 │ The Goddess Party                      │ 2023-10-06T19:15:00+00:00 │ 2023-10-06T20:00:00+00:00 │ The Old Dutch Church  │ A cult worth joining           │
│  4 │ Reed Foehl                             │ 2023-10-06T19:30:00+00:00 │ 2023-10-06T20:15:00+00:00 │ Utility Bicycle Works │ Grammy Nominated               │
│    │                                        │                           │                           │                       │ Folk/Americana                 │
│  5 │ Brothers Choice                        │ 2023-10-06T20:00:00+00:00 │ 2023-10-06T20:45:00+00:00 │ SO+mewhere Stage      │ Rock and Roll!                 │
│  6 │ Pencildive                             │ 2023-10-06T20:00:00+00:00 │ 2023-10-06T20:45:00+00:00 │ Keegan Ales           │ Rock / Punk Power Trio         │
│  7 │ Gail Ann Dorsey                        │ 2023-10-06T20:15:00+00:00 │ 2023-10-06T21:15:00+00:00 │ The Old Dutch Church  │ Legendary Bassist              │
│  8 │ The Kondrat Sisters                    │ 2023-10-06T20:25:00+00:00 │ 2023-10-06T21:10:00+00:00 │ Utility Bicycle Works │ Harmony Driven Folk            │
│  9 │ Juma Sultan's Aboriginal Music Society │ 2023-10-06T21:00:00+00:00 │ 2023-10-06T22:00:00+00:00 │ SO+mewhere Stage      │ World-Beat Garage-Jazz         │
│ 10 │ Lulu Lewis                             │ 2023-10-06T21:00:00+00:00 │ 2023-10-06T22:00:00+00:00 │ Keegan Ales           │ Dance / Electronic Rock        │
│ 11 │ Bashful                                │ 2023-10-06T21:20:00+00:00 │ 2023-10-06T22:05:00+00:00 │ Utility Bicycle Works │ Emotionally Engineered         │
│    │                                        │                           │                           │                       │ Nostalgia                      │
│ 12 │ Carsie Blanton                         │ 2023-10-06T21:30:00+00:00 │ 2023-10-06T22:30:00+00:00 │ The Old Dutch Church  │ Protest Songs & Optimistic     │
│    │                                        │                           │                           │                       │ Singalongs!                    │
│ 13 │ Peter Boofit                           │ 2023-10-06T22:00:00+00:00 │ 2023-10-06T22:30:00+00:00 │ Keegan Ales           │ Original 8 bit                 │
│ 14 │ John Swan                              │ 2023-10-06T22:30:00+00:00 │ 2023-10-06T23:30:00+00:00 │ Keegan Ales           │ Dance Music Turntable DJ       │
╰────┴────────────────────────────────────────┴───────────────────────────┴───────────────────────────┴───────────────────────┴────────────────────────────────╯

Good. Now I can create a new column with just the start and end time and drop the columns Start and End. I’ll render it to HTML.

$friday | 
  upsert Time {|x| [ ($x.Start | format date "%H:%M"), ($x.End| format date "%H:%M" ) ] | str join " - "} | 
  reject Start End |
  to html out> /tmp/friday.html

Finally, I’ll use pandoc to convert the HTML table to a PDF with compact margins and small fonts that I can print.

pandoc -V geometry:landscape -V fontsize=8pt -V geometry:margin=.25in -f html -t pdf friday.html -o friday.pdf

It looks pretty good:

O+ Friday Schedule