Skip to content

Instantly share code, notes, and snippets.

@rileyjshaw
Last active April 19, 2024 21:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rileyjshaw/8b76099a4500c1bea3c6d0a755639e60 to your computer and use it in GitHub Desktop.
Save rileyjshaw/8b76099a4500c1bea3c6d0a755639e60 to your computer and use it in GitHub Desktop.
Run this from a local folder containing whatever you want to go on the Shokz OpenSwim
#!/bin/bash
# Shokz OpenSwim headphones (formerly AfterShokz Xtrainerz) have a bug where
# tracks are not played in alphabetical or track order. They are played in the
# order that they were copied to the device. Read more about the issue here:
#
# - https://en.help.shokz.com/s/article/How-to-list-the-track-order-on-OpenSwim-formerly-Xtrainerz-OPENSWIM1408
# - https://en.help.shokz.com/s/get-article?urlName=how-to-list-tracks-order-EN
#
# After extensive testing, it seems that specifying transmission order alone is
# not enough to get tracks playing in order. Otherwise, the following command
# would work:
#
# rsync -avr --delete --exclude=".*" --exclude="System Volume Information" --exclude="*.DS_Store" ./ /Volumes/XTRAINERZ
#
# It seems that adding a delay between each file allows the device to process
# file order correctly. Filenames also seem to matter, so files are renamed to
# sequential numbers before copying.
#
# This script also removes all track metadata to save space, and adds audible
# folder titles to assist with navigation.
#
# Other things I tried that didn’t work:
#
# - Adding --bwlimit=1024 to rsync to slow down the transfer.
# - Adding track number metadata tags. Source: `add-track-numbers.sh`:
# id3v2 -T "$((i + 1))/${#FILES[@]}" "${FILES[i]}"
# - Editing file modification and creation dates to match the track order:
# # Set the modification date.
# gtouch -d "+$i minutes" "/Volumes/XTRAINERZ/$d${FILES[i]}"
# # Copy the modification date to the creation date.
# SetFile -d "$(GetFileInfo -m "/Volumes/XTRAINERZ/$d${FILES[i]}")" "/Volumes/XTRAINERZ/$d${FILES[i]}"
# - Adding a random suffix to the end of each file name.
# for f in *.mp3; do
# mv "$f" "$(mktemp "${f%.mp3} - XXXX").mp3"
# done
# # mktemp creates some 0 byte files that we need to clean up.
# find . -type f ! -name '*.mp3' -delete
rsync -Rr . _tmp
cd _tmp
for d in */; do
if [ "$d" = "System Volume Information/" ]; then
continue
fi
cd "$d"
# Create title tracks in each directory. Source: `mp3titles.sh`.
say "$d" -o "00. Title.aiff"
lame -S -m m "00. Title.aiff" "00. Title.mp3"
rm "00. Title.aiff"
# Remove all track metadata.
id3v2 -D *.mp3
# Rename all files to sequential numbers.
ls -1p | grep -v "/$" | cat -n | while read n f; do mv -n "${f}" "$(printf "%03d" $n).mp3"; done
FILES=(*.mp3)
for i in "${!FILES[@]}"; do
echo -e "Copying from $d [$(($i + 1))/${#FILES[@]}]: \t${FILES[i]}"
# Copy the single file to the USB drive.
rsync -a --delete "${FILES[i]}" "/Volumes/XTRAINERZ/$d"
sleep 0.5
done
cd ..
done
cd ..
rm -rf _tmp
@rileyjshaw
Copy link
Author

Note: controlling load order doesn’t necessarily ensure proper song order. The way to be 100% sure is to use FATSort.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment