Skip to content

Instantly share code, notes, and snippets.

@davidbb
Last active January 23, 2026 18:34
Show Gist options
  • Select an option

  • Save davidbb/871c2c1475326bb345235de6757e1d56 to your computer and use it in GitHub Desktop.

Select an option

Save davidbb/871c2c1475326bb345235de6757e1d56 to your computer and use it in GitHub Desktop.
Fish shell script to create m4b-tool metadata from Libby audiobook metadata
#!/usr/bin/env fish
# Check if jq is installed
if not command -v jq &> /dev/null
echo "Error: jq is required but not installed. Please install it first."
exit 1
end
# Check if metadata.json exists in ./metadata/
if not test -f ./metadata/metadata.json
echo "Error: ./metadata/metadata.json not found"
exit 1
end
set -l metadata_file ./metadata/metadata.json
# Extract book title
set -g booktitle (jq -r '.title' $metadata_file)
echo "Fish variable booktitle set to \"$booktitle\""
# Extract authors (only creators with role "author")
set -l authors (jq -r '.creator[] | select(.role == "author") | .name' $metadata_file)
set -g author (string join ", " $authors)
echo "Fish variable author set to \"$author\""
# Look up publication year using Open Library API
echo "Looking up publication year..."
set -l search_query (string escape --style=url "$booktitle $author")
set -l api_response (curl -s "https://openlibrary.org/search.json?q=$search_query&limit=1")
set -l pub_year (echo $api_response | jq -r '.docs[0].first_publish_year // empty')
if test -n "$pub_year"
set -g year $pub_year
echo "Fish variable year set to \"$year\""
else
echo "No publication year found - variable year not set"
end
# Extract description and create description.txt
# Remove HTML tags and decode HTML entities, preserving line breaks
jq -r '.description.full' $metadata_file | \
sed 's/<br>/\n/g' | \
sed 's/<\/p>/\n\n/g' | \
sed 's/<p>//g' | \
sed 's/<[^>]*>//g' | \
sed 's/&nbsp;/ /g' | \
sed 's/&lt;/</g' | \
sed 's/&gt;/>/g' | \
sed 's/&amp;/\&/g' | \
sed 's/&quot;/"/g' | \
sed "s/&apos;/'/g" | \
sed 's/Â/ /g' > description.txt
echo "Created description.txt"
# Process chapters and create chapters.txt
set -l chapters_output ""
# Get chapters array
set -l chapters (jq -c '.chapters[]' $metadata_file)
for chapter in $chapters
set -l title (echo $chapter | jq -r '.title')
set -l spine_index (echo $chapter | jq -r '.spine')
set -l offset (echo $chapter | jq -r '.offset')
# Calculate cumulative duration up to this spine
set -l cumulative_seconds 0
# Sum durations of all previous spine entries
if test $spine_index -gt 0
for i in (seq 0 (math $spine_index - 1))
set -l duration (jq -r ".spine[$i].duration" $metadata_file)
set cumulative_seconds (math $cumulative_seconds + $duration)
end
end
# Add the offset within the current spine
set cumulative_seconds (math $cumulative_seconds + $offset)
# Convert to hours:minutes:seconds.milliseconds
set -l hours (math -s0 "floor($cumulative_seconds / 3600)")
set -l minutes (math -s0 "floor(($cumulative_seconds % 3600) / 60)")
set -l seconds (math -s0 "floor($cumulative_seconds % 60)")
set -l milliseconds (math -s0 "floor(($cumulative_seconds - floor($cumulative_seconds)) * 1000)")
# Format timestamp
set -l timestamp (printf "%02d:%02d:%02d.%03d" $hours $minutes $seconds $milliseconds)
# Append to output
set chapters_output "$chapters_output$timestamp $title\n"
end
# Write chapters.txt
printf $chapters_output > chapters.txt
echo "Created chapters.txt"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment