Last active
January 23, 2026 18:34
-
-
Save davidbb/871c2c1475326bb345235de6757e1d56 to your computer and use it in GitHub Desktop.
Fish shell script to create m4b-tool metadata from Libby audiobook metadata
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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/ / /g' | \ | |
| sed 's/</</g' | \ | |
| sed 's/>/>/g' | \ | |
| sed 's/&/\&/g' | \ | |
| sed 's/"/"/g' | \ | |
| sed "s/'/'/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