Audiobook reading system

376adfa Add tests

~naglis pushed to ~naglis/lytte git

3 days ago

1491c69 Update dependencies

~naglis pushed to ~naglis/lytte git

3 days ago

builds.sr.ht status


Basic audiobook reading system for Raspberry Pi, based on GStreamer.


  • Remember last playback position / volume / speed
  • Seek back when continuing playback with clamping to nearest past chapter
  • Contiguous seeking (e.g. seeking 5s backwards while on 2s in the second audio resource will seek to -3s from the end of the first audio resource)
  • Chapter navigation
  • Variable playback speed with maintained pitch
  • Automated position storage every minute


lytte --config /path/to/config.toml /path/to/publication/


A Debian package for Raspberry Pi 1 is available on individual release pages.

#Cargo features

Is default? Feature Description Dependencies
Yes bbl Custom audiobook formatxkcd serde_json
Yes gpio Allow controlling lytte via GPIO pins gpiocdev
Yes ffprobe Load chapters (if available) and/or audio resource duration for single audio resource publications using ffprobe (if available) serde_json
Yes played_at Store the datetime of when the publication was last played in the SQLite database. Not very useful if there is no RTC on the device. chrono

#Playback control

lytte can be controlled via GPIO pins. A pin can be mapped to a lytte action that will be executed when a rising edge is detected on the pin.

To allow for more actions/less pins, there is also support for (modifier pin, action pin) actions, where the action is only executed once a rising edge is detected on the modifier pin and then on an action pin.

A pin can be both a modifier to an action pin and action pin without a modifier, but not an action pin with modifier, e.g. (1+2 and 1, but not 1+2 and 3+1).

If a pin is used as both modifier and action pin without modifier, the action of it used as action pin without modifier is executed on falling edge on that pin.

#Supported actions


Start (unpause) playback, apply seek back (if applies, e.g. playback was paused a while ago).

The seek back amount depends on the configured seek back levels ([seek_back_levels] section in the configuration file).

lytte will also clamp to the nearest past chapter if such exists within the seek back duration.

#navigate <target>

Navigate to the <target> in the publication. <target> is a navigation target expression, e.g. +#1 to go to the next chapter.

#cycle_volume <step>

Increase/decrease volume by <step> intervals. <step> can be an integer between -25 and 25, excluding 0.

Volume is a value between 0 and 100. If the new volume value goes outside this range, the value will wrap, e.g. 104 will become 4.

#cycle_speed <direction>

Increase/decrease playback speed by 0.05, where 1.0 is normal playback speed. <direction> can be up (to increase playback speed) or down (to decrease playback speed).

Playback speed can be a value between 0.5 and 2.0. If the new playback speed exceeds this range, the value will wrap, e.g. 2.05 will become 0.55.


Reset playback speed to normal (1.0).


Store current playback position.


Store current playback volume.


Stop playback.


Exit lytte. Stores playback position.


lytte uses TOML for its configuration.

#Example configuration

# Path to lytte SQLite database file.
store_path =  "/var/lib/lytte/store"

# Path to the GPIO device.
chip_path = "/dev/gpiochip0"
# GPIO button click debounce duration.
debounce_duration = "25ms"

# Mapping of GPIO pin combinations to lytte actions.
# A combination can be a single pin (e.g. `"1"`) or a modifier + pin (e.g.
# `"1+2"`), where the modifier is pressed first and then the action pin.
"1" = "toggle_play_pause"
"2" = "cycle_volume 5"
"1+2" = "cycle_volume -5"

# Default volume for new publications (i. e. those that have no stored status).
# The value should be an integer between 1 and 100 (inclusive).
default_volume = 50

# Pause playback on startup. If set to false, lytte can be used as a zero button
# audiobook player.
start_paused = true

# When navigating backwards using the `#` (chapter) or `#|$` (chapter or audio
# resource) targets, use this as the duration since the beginning of the current
# chapter during which to allow navigating to the previous chapter (instead of
# going to the beginning of the current chapter).
# Note that the value is multiplied by the playback speed, e.g. if the current
# playback speed is 1.25x, then given 2s500ms the final threshold will be
# 2s500ms * 1.25 = 3s125ms.
chapter_merge_threshold = "2s 500ms"

# Maps duration since last playback to the duration to seek backwards when
# playback is resumed.
"250ms" = "1s"
"5m" = "10s"
"30m" = "30s"
"2h" = "1m"
"24h" = "2m"