Audiobooks

I listen to audiobooks while hiking solo, and have been fortunate enough to do a long hike each year since 2012– that is a lot of audio. I record links to each completed audiobook in my online hiking journals, first as a note to myself, and second a recommendation to anyone reading or crawling this blog, a shout-out to the work of authors and readers that I have enjoyed.

My preference is to avoid audiobooks with DRM Digital Rights Management, and unfortunately a monopoly controlling contemporary audiobooks insists on DRM as a condition for authors to be published with them. Luckily for me, LibriVox was started in 2005, a group of volunteer readers who record and distribute audiobooks of public domain books. In my youth I tended to read mostly science fiction, and missed out on many classics of literature, and LibriVox has allowed me to remedy that situation in some small part.

(Please be aware that book copyright duration differs according to country, and USA rules are different from everyone else. Nowadays I look forward to seeing what new books slip out of copyright January 1 of each year, for possible use on my next hike.)

Below are all the audiobooks completed on my long hikes to date, sometimes with short notes. Perhaps this might help other travelers on their audiobook journey. More notes below the list…

AT 2012

(no audiobooks on this trip, just podcasts)

CDT 2013

CDT 2015

CDT 2016

GET 2017

PCT 2018

NNML 2019

AZT 2020

MRT 2021

HDT 2022

CT 2023

GXL 2024

GET 2024

More Notes

When hiking, I only listen to audiobooks in one ear, at moderate volume, and take care to be aware of sounds around me. If I am in serious bear country, audiobooks can wait.

For USA copyright rules, in 2025 works published in 1929 or before move into the public domain. Due to a quirk in copyright law, many early science fiction whose copyright was not renewed by the publisher became public domain early, so I have recently been enjoying Golden Age SF.

I make a note of particularly good readers, and often seek out other books they have read. Some of my favorite LibriVox readers: Kara Shallenberg, Karen Savage, and the prolific Phil Chenevert. For the Girl Genius Agatha H series, Angela Dawe is excellent. For Cory Doctorow books, Wil Wheaton is super, though the author is also quite good. I avoid AI readers, for now. No narrators with uptalk, please.

On early hikes I also listened to contemporary audiobooks by Podiobooks.com, a site for mostly free downloads by self-published authors. Sadly that site has been absorbed by another website with a different business model, and links may not work.

During the lonely months between long hikes I keep up morale by searching for more audiobooks on LibriVox and elsewhere, and currently have more than 100 books downloaded for future hikes.

Trails and Graph Theory 22: Ground Truthiness

Ground Truth: Information known to be true by direct observation, rather than by inference. In GIS (Geographical Information Systems), ground truth refers to verifying or correcting data on a map database by going out and measuring.

Truthiness: Assertion that a statement is true based on opinion, without regard to evidence. (Coined by Stephen Colbert on the Colbert Report)

The 1.0 version of the Gila X Loop is not workable, and no one should attempt to hike this route in its present form. One key connector trail between Glenwood and Gila Hot Springs, Holt Apache Trail #181, is in questionable condition after a fire, likely very brushy with thorny locust. On my route #181 connects to Turkeyfeather Mountain Trail #102, which is completely removed from the USFS Gila Interactive Map, although it still appears on plenty of printed maps, CalTopo, GaiaGPS, and OpenStreetMap. Likely there are other trails on my route that are actually non-trails, permanently abandoned by the USFS due to serious damage after fire and subsequent erosion.

I will need to re-run my algorithm, after removing trails that are not on the Gila Interactive Map and no longer recognized by the USFS. Look for v2.0 of the Gila X Loop sometime in 2025-2026, along with an attempted thru-hike for even more Ground Truth.

On another matter, I encountered difficulty hiking on the Deloche/Winn Canyon Trail #179. My algorithm attempted to exclude “deloche and winn canyon” (case insensitive), but openstreetmap.org and most sources used the name “deloche/wynn canyon”. Computer programs typically look for an exact match when comparing strings. Oops.

Lessons Learned:

  • Programmers get caught up in the excitement of creating an algorithm, and do not allocate sufficient energy in vetting the input data. GIGO: garbage in, garbage out.
  • Geographical names may have slight variations. Do not use a string “equals” matching function for cases where a string “similar” function should be used.
Related Posts:

Trails and Graph Theory 21: More Databook

In a previous article we sketched out how to create a databook for our long hike, a text summary of the route, which can include waypoints, elevation, trail names, and intersections. Our first result was somewhat crude, so we are circling back to make a better effort.

In a recent post we described how to break apart trail sections that had been concatenated together as part of our algorithm to find a maximum length route. We also found a different way to add elevation to our network, using built-in OSMNx functions. We have so many nodes in our desimplified network graph that it is better to take steps to only add elevation to important nodes.

def add_elevation(Q):
    H = nx.MultiGraph()
    H.graph['crs'] = ox.settings.default_crs

    for node, dat in Q.nodes(data=True):
        if 'street_count' in dat:
            street_count = dat['street_count']
            if street_count > 2:
                H.add_node(node,**dat)
    ox.settings.elevation_url_template = \
        'https://api.open-elevation.com/api/v1/lookup?locations={locations}'
    ox.elevation.add_node_elevations_google(H, api_key=None,
        batch_size=350,
        pause=1.0,
            )
    print('Added elevation data for ',H.number_of_nodes(), ' nodes')
    for node,dat in H.nodes(data=True):
        Q.add_node(node,**dat)
    return Q

Another improvement we should make is to document any road crossing or trail crossing on the route. Along with our trail graph G, we use the graph of all trails and roads GTR. Whenever a G node has a ‘street_count’ attribute greater than 2, we expect a crossing, and go back to GTR to attempt to find the name of the road or trail that our route crosses.

def report_path(Q,Q_orig, txt='',freedom_units=False,lat_long=False):
    meters_to_mile = 0.0006213712
    meters_to_feet = 3.28084
    meters_to_km = 0.001
    
    if nx.is_eulerian(Q):
        total_length = 0
        data = []
        
        for u,v,k in nx.eulerian_circuit(Q, keys=True): #fix: use predefined circuit, not arbitrary
             data_line = []
             if freedom_units:
                 data_line.append(str(round(total_length*meters_to_mile,1)))
             else:
                 data_line.append(str(round(total_length*meters_to_km,1)))
                 
             d = Q.get_edge_data(u,v)[k]
            # print(d)
             length=0                 
             if 'length' in d:
                 length = d['length'] #meters
                 total_length += length
             node_attr = Q.nodes(data=True)[v]
            # print( node_attr )
            
             street_count = node_attr['street_count']
             if street_count == 2:
                 continue
             
             long = node_attr['x']
             lat = node_attr['y']
             if lat_long:
                 data_line.append(lat)
                 data_line_append(long)
             #elevation = get_elevation(lat,long) #in meters
             if 'elevation' in node_attr:
                 elevation = node_attr['elevation']
                 if freedom_units:
                     data_line.append(str(round(elevation*meters_to_feet)))
                 else:
                     data_line.append(str(round(elevation)))
             else:
                 data_line.append(' ')

             trail_name=''
             if 'name' in d:
                 trail_name = d['name']
                 if not isinstance(trail_name, str):
                     trail_name = ','.join(trail_name) #in case is a list
             
             data_line.append(trail_name)                     
             
             crossing = set()
             crossing_txt = ''
             for x,neighbor,k,d in Q_orig.edges(v,data=True, keys=True):
                 if 'name' in d:
                     name = d['name']
                     if not isinstance(name, str): #FIX with a foreach
                         name = ','.join(name) #in case is a list
                     if name != trail_name:
                         crossing.add(name)
                 elif 'highway' in d:
                     name = d['highway']
                     name = '<' + name + '>'
                     crossing.add(name)
             if len(crossing)>0:
                 crossing_txt = ','.join(crossing)
             data_line.append(crossing_txt)
                              
             data.append(data_line)                 
        header = []
        if freedom_units:
            header.append('MILE')
        else:
            header.append('KM')
        if lat_long:
            header.append('LAT')
            header.append('LONG')
        header.append('ELEVATION')
        header.append('TRAIL')
        header.append('INTERSECTION')
        table = columnar(data, header, no_borders=True,terminal_width=132)
        print(table)     
    else:
        print('The graph is not eulerian')

Ideally, it might be useful to automatically add nearby water sources. We did document a way to find water sources, but inserting them into our databook looks challenging, so perhaps we will add that feature at a later date. Algorithmically adding other features, such as post offices, stores, or established campsites, are left as an exercise for the reader. 😁

A short example excerpt from the databook shows the improvements:

  MILE   ELEVATION  TRAIL                                    INTERSECTION                                                      

234.6 8373 West Fork Trail #151 Iron Creek Trail #172
234.8 8376 West Fork Trail #151 Iron Creek Mesa Trail #171
237.4 7831 West Fork Trail #151 Cooper Trail #141
240.3 7841 Cooper Trail #141 Clayton Mesa Trail #175
242.6 7106 Clayton Mesa Trail #175 Middle Fork Trail #157
242.7 7090 Middle Fork Trail #157 Iron Creek Mesa Trail #171
246.0 7326 Middle Fork Trail #157 Snow Canyon Trail #142
246.6 7467 Snow Canyon Trail #142 <path>
246.8 7356 Snow Canyon Trail #142 <path>
246.9 7359 Snow Canyon Trail #142 <service>

Download source code and improved databook here.

Related Posts: