Skip to content

Instantly share code, notes, and snippets.

@KeironO
Created November 23, 2024 19:50
Show Gist options
  • Save KeironO/7d05bf5de7701662bad8b3437cd9fb56 to your computer and use it in GitHub Desktop.
Save KeironO/7d05bf5de7701662bad8b3437cd9fb56 to your computer and use it in GitHub Desktop.
sync-mp3.sh
#!/bin/bash
# Ensure dependencies are installed
if ! command -v rsync &> /dev/null; then
echo "rsync is required but not installed. Please install it with 'sudo apt install rsync'."
exit 1
fi
if ! command -v sqlite3 &> /dev/null; then
echo "sqlite3 is required but not installed. Please install it with 'sudo apt install sqlite3'."
exit 1
fi
# Prompt for the destination directory
read -rp "Enter the mount point of the MP3 player (destination directory): " mp3_mount
if [ ! -d "$mp3_mount" ]; then
echo "Directory $mp3_mount does not exist. Please provide a valid directory."
exit 1
fi
# Define source and destination directories
src_dir="$HOME/media/music"
dest_dir="$mp3_mount/"
db_file="$mp3_mount/.sync_metadata.db" # SQLite database file
# Create SQLite database and table if not exists
sqlite3 "$db_file" <<EOF
CREATE TABLE IF NOT EXISTS file_metadata (
relative_path TEXT UNIQUE,
size INTEGER,
last_modified INTEGER
);
EOF
# Function to get file size
get_file_size() {
local file_path="$1"
stat --format='%s' "$file_path"
}
# Function to get the last modification time of a file
get_file_mtime() {
local file_path="$1"
stat --format='%Y' "$file_path"
}
# Function to escape single quotes for SQLite
escape_sql() {
echo "$1" | sed "s/'/''/g"
}
# Sync function
sync_music() {
echo "Starting sync from $src_dir to $dest_dir..."
# Step 1: Create a list of all files in the source directory
temp_source_file_list=$(mktemp)
find "$src_dir" -type f > "$temp_source_file_list"
# Step 2: Iterate through the source files
total_files=$(wc -l < "$temp_source_file_list")
copied_files=0
while IFS= read -r source_file; do
relative_path="${source_file#$src_dir/}"
dest_file="$dest_dir$relative_path"
mkdir -p "$(dirname "$dest_file")"
# Get file metadata
file_size=$(get_file_size "$source_file")
file_mtime=$(get_file_mtime "$source_file")
escaped_relative_path=$(escape_sql "$relative_path")
# Check database for existing metadata
db_entry=$(sqlite3 "$db_file" "SELECT size, last_modified FROM file_metadata WHERE relative_path = '$escaped_relative_path';")
if [ -n "$db_entry" ]; then
db_size=$(echo "$db_entry" | awk -F'|' '{print $1}')
db_mtime=$(echo "$db_entry" | awk -F'|' '{print $2}')
else
db_size=""
db_mtime=""
fi
# Sync file if size or modification time has changed
if [ "$file_size" != "$db_size" ] || [ "$file_mtime" != "$db_mtime" ]; then
rsync -a "$source_file" "$dest_file"
sqlite3 "$db_file" <<EOF
INSERT OR REPLACE INTO file_metadata (relative_path, size, last_modified)
VALUES ('$escaped_relative_path', $file_size, $file_mtime);
EOF
echo "Transferred: $relative_path | Size: $(du -h "$source_file" | cut -f1) | Status: UPDATED"
((copied_files++))
else
echo "Skipped: $relative_path | Size: $(du -h "$source_file" | cut -f1) | Status: UP-TO-DATE"
fi
done < "$temp_source_file_list"
echo "Cleaning up removed files..."
sqlite3 "$db_file" "SELECT relative_path FROM file_metadata;" | while IFS= read -r relative_path; do
dest_file="$dest_dir$relative_path"
if [ ! -f "$dest_file" ]; then
escaped_relative_path=$(escape_sql "$relative_path")
echo "Removed stale file record: $relative_path | Status: DELETED"
sqlite3 "$db_file" "DELETE FROM file_metadata WHERE relative_path = '$escaped_relative_path';"
fi
done
rm "$temp_source_file_list"
echo "Sync complete! $copied_files files updated."
}
# Start syncing
sync_music
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment