Skip to content

Instantly share code, notes, and snippets.

@ianchesal
Last active July 20, 2025 21:22
Show Gist options
  • Save ianchesal/34bb82dc5565eccd88f54c4f1c371d55 to your computer and use it in GitHub Desktop.
Save ianchesal/34bb82dc5565eccd88f54c4f1c371d55 to your computer and use it in GitHub Desktop.
Auto-Organize Your Fractal-Bot Backups
#!/usr/bin/env ruby
# ***USE***
# Drop this file into the folder where you have Fractal-Bot storing your
# backups. Name it whatever you like. Run it from time to time and it'll
# sort your backups into sub-folders based on file prefixes.
#
# If you're on a Mac you can use this code as a Folder Automation action and
# it should work just fine and run every time a new file is created in your
# backup folder.
#
# ***REQUIRES***
# Fractal-Bot v3.0.8 or newer
require 'fileutils'
# Add new devices you're backing up to this list
supported_devices = %w[FM3 III AX8 FM9 VP4]
supported_devices.each do |subdir|
next if File.directory? subdir
puts "Making ./#{subdir}"
FileUtils.mkdir_p subdir
end
Dir.glob('*.syx') do |sysexfile|
next unless File.file? sysexfile
subdir = sysexfile[0..2]
next unless supported_devices.include? subdir
puts "Moving #{sysexfile} to ./#{subdir}/"
FileUtils.mv(sysexfile, "./#{subdir}/#{sysexfile}")
end
#!/bin/bash
# Fractal-Bot Backup Group Zipper
#
# This script finds SYX files matching the pattern <dirname>-<timestamp>-*.syx
# or <timestamp>-*.syx (for older backups), groups them by timestamp,
# and creates zip archives named <dirname>-<timestamp>.zip or <timestamp>.zip
#
# Usage: Run this script in a device directory (e.g., III, FM9, VP4)
#
# CAUTION: This script DELETES the original .syx files after zipping them!
# set -eo pipefail
# Get current directory name (e.g., "III", "FM9")
DIRNAME=$(basename "$PWD")
# Color output for better visibility
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}Fractal-Bot Backup Group Zipper${NC}"
echo -e "Working in directory: ${YELLOW}$DIRNAME${NC}"
echo
# Check if we have any .syx files
if ! ls *.syx >/dev/null 2>&1; then
echo -e "${RED}No .syx files found in current directory.${NC}"
exit 1
fi
# Function to process files and group them
process_files() {
local pattern="$1"
local prefix="$2"
local description="$3"
echo -e "${BLUE}Processing $description files...${NC}"
# Find all unique timestamps for this pattern (extract before any files are deleted)
local timestamps
if [[ "$prefix" == "" ]]; then
# For older format files without prefix: YYMMDD-HHMMSS-*.syx
timestamps=$(ls $pattern 2>/dev/null | sed -E 's/^([0-9]{6}-[0-9]{6})-.*\.syx/\1/' | sort -u)
else
# For newer format files with prefix: DIRNAME-YYMMDD-HHMMSS-*.syx
timestamps=$(ls $pattern 2>/dev/null | sed -E 's/.*-([0-9]{6}-[0-9]{6})-.*\.syx/\1/' | sort -u)
fi
if [ -z "$timestamps" ]; then
echo -e " ${YELLOW}No $description files found.${NC}"
return
fi
local count=0
for timestamp in $timestamps; do
local files
files=$(ls ${prefix}${timestamp}-*.syx 2>/dev/null || true)
if [ -n "$files" ]; then
local zip_name
if [ -n "$prefix" ] && [ "$prefix" != "$DIRNAME-" ]; then
zip_name="${prefix%%-}${timestamp}.zip"
else
zip_name="${DIRNAME}-${timestamp}.zip"
fi
echo -e " ${GREEN}Creating ${zip_name}${NC}"
echo " Files: $(echo $files | wc -w) file(s)"
# Create the zip file
if zip -q "$zip_name" $files; then
echo -e " ${GREEN}✓ Archive created successfully${NC}"
# Delete the original files
rm $files
echo -e " ${GREEN}✓ Original files deleted${NC}"
((count++))
else
echo -e " ${RED}✗ Failed to create archive${NC}"
fi
fi
done
echo -e " ${GREEN}Processed $count timestamp group(s)${NC}"
echo
}
# Safety check: Ask user for confirmation
echo -e "${YELLOW}WARNING: This script will DELETE the original .syx files after zipping them!${NC}"
echo -e "${YELLOW}Files will be grouped by timestamp and zipped.${NC}"
echo
read -p "Do you want to continue? (y/N): " -r
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo -e "${RED}Operation cancelled.${NC}"
exit 1
fi
echo
# Count total files before processing
total_files=$(ls *.syx 2>/dev/null | wc -l)
echo -e "${BLUE}Found $total_files .syx files total${NC}"
echo
# Process newer format files: <DIRNAME>-YYMMDD-HHMMSS-*.syx
process_files "${DIRNAME}-[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]-*.syx" "${DIRNAME}-" "newer format (${DIRNAME}-YYMMDD-HHMMSS)"
# Process older format files: YYMMDD-HHMMSS-*.syx (without device prefix)
process_files "[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]-*.syx" "" "older format (YYMMDD-HHMMSS)"
# Count remaining files
if ls *.syx >/dev/null 2>&1; then
remaining_files=$(ls *.syx | wc -l)
else
remaining_files=0
fi
processed_files=$((total_files - remaining_files))
echo -e "${GREEN}✓ Processing complete!${NC}"
echo -e " Files processed: ${GREEN}$processed_files${NC}"
echo -e " Files remaining: ${YELLOW}$remaining_files${NC}"
if [ "$remaining_files" -gt 0 ]; then
echo
echo -e "${YELLOW}Remaining files (didn't match expected patterns):${NC}"
ls *.syx 2>/dev/null || true
fi
echo
echo -e "${BLUE}Created zip files:${NC}"
if ls *.zip >/dev/null 2>&1; then
ls *.zip
else
echo -e "${YELLOW}No zip files created.${NC}"
fi
#!/bin/bash
# Fractal-Bot Yearly Archive Creator
#
# This script finds SYX files with timestamp-based filenames and creates
# yearly archives (YYYY.zip) by grouping files with the same year.
# If a yearly archive already exists, new files are added to it.
#
# Supports both formats:
# - Newer: DIRNAME-YYMMDD-HHMMSS-*.syx
# - Older: YYMMDD-HHMMSS-*.syx
#
# Usage: Run this script in a device directory (e.g., III, FM9, VP4)
#
# CAUTION: This script DELETES the original .syx files after zipping them!
# Get current directory name (e.g., "III", "FM9")
DIRNAME=$(basename "$PWD")
# Try to detect the actual device prefix from existing files
DEVICE_PREFIX=""
if ls *-[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]-*.syx >/dev/null 2>&1; then
# Extract the device prefix from the first matching file
DEVICE_PREFIX=$(ls *-[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]-*.syx 2>/dev/null | head -1 | sed -E 's/^([^-]+)-[0-9]{6}-.*\.syx/\1/')
echo -e "Detected device prefix: ${YELLOW}$DEVICE_PREFIX${NC}"
else
DEVICE_PREFIX="$DIRNAME"
echo -e "Using directory name as device prefix: ${YELLOW}$DEVICE_PREFIX${NC}"
fi
# Color output for better visibility
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}Fractal-Bot Yearly Archive Creator${NC}"
echo -e "Working in directory: ${YELLOW}$DIRNAME${NC}"
echo
# Check if we have any .syx files
if ! ls *.syx >/dev/null 2>&1; then
echo -e "${RED}No .syx files found in current directory.${NC}"
exit 1
fi
# Function to process files and group them by year
process_yearly_files() {
local pattern="$1"
local prefix="$2"
local description="$3"
echo -e "${BLUE}Processing $description files...${NC}"
# Find all unique years for this pattern
local years
if [[ "$prefix" == "" ]]; then
# For older format files without prefix: YYMMDD-HHMMSS-*.syx
# Extract YY and convert to 20YY
years=$(ls $pattern 2>/dev/null | sed -E 's/^([0-9]{2})[0-9]{4}-.*\.syx/20\1/' | sort -u)
else
# For newer format files with prefix: DIRNAME-YYMMDD-HHMMSS-*.syx
# Extract YY from YYMMDD and convert to 20YY
years=$(ls $pattern 2>/dev/null | sed -E 's/^[^-]+-([0-9]{2})[0-9]{4}-.*\.syx/20\1/' | sort -u)
fi
if [ -z "$years" ]; then
echo -e " ${YELLOW}No $description files found.${NC}"
return
fi
local count=0
for year in $years; do
local files
local year_pattern
local yy="${year#20}" # Extract YY from 20YY
if [[ "$prefix" == "" ]]; then
# For older format: find files starting with YY
files=$(ls ${yy}[0-9][0-9][0-9][0-9]-*.syx 2>/dev/null || true)
else
# For newer format: find files with prefix-YY
files=$(ls ${prefix}${yy}[0-9][0-9][0-9][0-9]-*.syx 2>/dev/null || true)
fi
if [ -n "$files" ]; then
local zip_name="${year}.zip"
local file_count=$(echo $files | wc -w)
# Check if archive already exists
if [ -f "$zip_name" ]; then
local existing_count=$(unzip -l "$zip_name" 2>/dev/null | tail -1 | awk '{print $2}' || echo "0")
echo -e " ${BLUE}Adding to existing ${zip_name}${NC} (currently has $existing_count files)"
echo " Adding: $file_count file(s) from year $year"
else
echo -e " ${GREEN}Creating new ${zip_name}${NC}"
echo " Files: $file_count file(s) from year $year"
fi
# Add files to the zip file (creates new or adds to existing)
if zip -q "$zip_name" $files; then
if [ -f "$zip_name" ]; then
local final_count=$(unzip -l "$zip_name" 2>/dev/null | tail -1 | awk '{print $2}' || echo "unknown")
echo -e " ${GREEN}✓ Files added to archive successfully${NC} (archive now has $final_count files)"
else
echo -e " ${GREEN}✓ Files added to archive successfully${NC}"
fi
# Delete the original files
rm $files
echo -e " ${GREEN}✓ Original files deleted${NC}"
((count++))
else
echo -e " ${RED}✗ Failed to add files to archive${NC}"
fi
fi
done
echo -e " ${GREEN}Processed $count year(s)${NC}"
echo
}
# Safety check: Ask user for confirmation
echo -e "${YELLOW}WARNING: This script will DELETE the original .syx files after zipping them!${NC}"
echo -e "${YELLOW}Files will be grouped by year and added to YYYY.zip archives.${NC}"
echo
read -p "Do you want to continue? (y/N): " -r
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo -e "${RED}Operation cancelled.${NC}"
exit 1
fi
echo
# Count total files before processing
total_files=$(ls *.syx 2>/dev/null | wc -l)
echo -e "${BLUE}Found $total_files .syx files total${NC}"
echo
# Process newer format files: <DEVICE_PREFIX>-YYMMDD-HHMMSS-*.syx
process_yearly_files "${DEVICE_PREFIX}-[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]-*.syx" "${DEVICE_PREFIX}-" "newer format (${DEVICE_PREFIX}-YYMMDD-HHMMSS)"
# Process older format files: YYMMDD-HHMMSS-*.syx (without device prefix)
process_yearly_files "[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]-*.syx" "" "older format (YYMMDD-HHMMSS)"
# Count remaining files
if ls *.syx >/dev/null 2>&1; then
remaining_files=$(ls *.syx | wc -l)
else
remaining_files=0
fi
processed_files=$((total_files - remaining_files))
echo -e "${GREEN}✓ Processing complete!${NC}"
echo -e " Files processed: ${GREEN}$processed_files${NC}"
echo -e " Files remaining: ${YELLOW}$remaining_files${NC}"
if [ "$remaining_files" -gt 0 ]; then
echo
echo -e "${YELLOW}Remaining files (didn't match expected patterns):${NC}"
ls *.syx 2>/dev/null || true
fi
echo
echo -e "${BLUE}Created/updated yearly archives:${NC}"
if ls *.zip >/dev/null 2>&1; then
for zipfile in *.zip; do
if [[ "$zipfile" =~ ^[0-9]{4}\.zip$ ]]; then
file_count=$(unzip -l "$zipfile" 2>/dev/null | tail -1 | awk '{print $2}')
echo " ${GREEN}$zipfile${NC} (${file_count} files)"
fi
done
else
echo -e "${YELLOW}No yearly archives created.${NC}"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment