Skip to content

Instantly share code, notes, and snippets.

@cvn
Last active January 17, 2026 03:39
Show Gist options
  • Select an option

  • Save cvn/f24a0f228a9e42de955aaa867d40437d to your computer and use it in GitHub Desktop.

Select an option

Save cvn/f24a0f228a9e42de955aaa867d40437d to your computer and use it in GitHub Desktop.
Scripts to add arbitrary file types to QLStephenSwift
#!/bin/sh
# Add or remove file types from QLStephenSwift and rebuild
# Usage: sh qlss-add-filetype.sh <file_path> [file_path...]
# 2026-01-16 v1 - Prompted by Chad von Nau
# ============================================================================
# Setup
# ============================================================================
# 1. Install Xcode and sign in with your Apple account
# 2. Clone QLStephenSwift repository
# 3. Make sure the project can build. Try qlss-fix-build.sh
# 4. Update the variables below, or set them as environment variables
# 5. Run this script on a file you want to preview
# 6. Re-activate the extension (first time only):
# https://github.com/MyCometG3/QLStephenSwift#activation-required-for-both-methods
# Repository directory - Set here or via environment variable
# Example: REPO_DIR=/path/to/repo sh qlss-add-filetype.sh ...
REPO_DIR="${REPO_DIR:-$HOME/Repositories/QLStephenSwift}"
# The app will be rebuilt and saved here:
INSTALL_PATH="${INSTALL_PATH:-/Applications/QLStephenSwift.app}"
# ============================================================================
# Get the file types
# ============================================================================
# Exit on error
set -e
if [ $# -eq 0 ]; then
echo "Usage: sh $0 <file_path> [file_path...]"
echo "Example: sh $0 /path/to/file.yml"
exit 0
fi
# Track actions for verification
ANY_ERROR=0
# Collect unique UTIs from all files (newline-delimited)
UNIQUE_TYPES=""
for FILE_PATH in "$@"; do
# Check if file exists
if [ ! -f "$FILE_PATH" ]; then
echo "Error: File not found $FILE_PATH"
ANY_ERROR=1
continue
fi
# Get the UTI type
TYPE=$(mdls -name kMDItemContentType "$FILE_PATH" | sed -n 's/^kMDItemContentType = "\(.*\)"$/\1/p')
if [ -z "$TYPE" ]; then
echo "Error: Could not determine file type $FILE_PATH"
ANY_ERROR=1
continue
fi
if ! printf '%s\n' "$UNIQUE_TYPES" | grep -qx "$TYPE"; then
if [ -z "$UNIQUE_TYPES" ]; then
UNIQUE_TYPES="$TYPE"
else
UNIQUE_TYPES="${UNIQUE_TYPES}
$TYPE"
fi
fi
done
if [ $ANY_ERROR -eq 1 ]; then
exit 0
fi
if [ -z "$UNIQUE_TYPES" ]; then
exit 0
fi
# ============================================================================
# Modify the Info.plist
# ============================================================================
join_types() {
printf '%s\n' "$1" | awk 'NF{if(!first){printf "%s",$0; first=1} else {printf ", %s",$0}}'
}
INFO_PLIST="$REPO_DIR/QLStephenSwift/QLStephenSwiftPreview/Info.plist"
if [ ! -f "$INFO_PLIST" ]; then
echo "Error: Info.plist not found"
exit 0
fi
# Read existing types once
EXISTING_TYPES=$(plutil -p "$INFO_PLIST" | grep -A 10 "QLSupportedContentTypes" | grep -o '"[^"]*"' | tr -d '"')
# Decide action: remove all if all types already present, else add only missing
ACTION="add"
ALL_PRESENT=1
while IFS= read -r TYPE; do
[ -z "$TYPE" ] && continue
if ! printf '%s\n' "$EXISTING_TYPES" | grep -qx "$TYPE"; then
ALL_PRESENT=0
break
fi
done <<EOF
$UNIQUE_TYPES
EOF
if [ $ALL_PRESENT -eq 1 ]; then
ACTION="remove"
printf '%s' "Removing $(join_types "$UNIQUE_TYPES")... "
while IFS= read -r TYPE; do
[ -z "$TYPE" ] && continue
ESCAPED_TYPE=$(printf '%s\n' "$TYPE" | sed 's/\./\\./g')
sed -i '' "/<string>$ESCAPED_TYPE<\/string>/d" "$INFO_PLIST"
done <<EOF
$UNIQUE_TYPES
EOF
else
printf '%s' "Adding $(join_types "$UNIQUE_TYPES")... "
ADD_TYPES=""
while IFS= read -r TYPE; do
[ -z "$TYPE" ] && continue
if printf '%s\n' "$EXISTING_TYPES" | grep -qx "$TYPE"; then
# Skip already-present types when adding
continue
fi
if [ -z "$ADD_TYPES" ]; then
ADD_TYPES="$TYPE"
else
ADD_TYPES="${ADD_TYPES}
$TYPE"
fi
done <<EOF
$UNIQUE_TYPES
EOF
while IFS= read -r TYPE; do
[ -z "$TYPE" ] && continue
ARRAY_LENGTH=$(plutil -p "$INFO_PLIST" | grep -A 10 "QLSupportedContentTypes" | grep -E "^\s+[0-9]+\s+=>" | wc -l | tr -d ' ')
plutil -insert NSExtension.NSExtensionAttributes.QLSupportedContentTypes.$ARRAY_LENGTH -string "$TYPE" "$INFO_PLIST"
done <<EOF
$ADD_TYPES
EOF
fi
# ============================================================================
# Build the app
# ============================================================================
cd "$REPO_DIR"
# Pin destination to avoid xcodebuild "multiple matching destinations" warnings
BUILD_ARCH="$(uname -m)"
BUILD_DESTINATION="platform=macOS,arch=$BUILD_ARCH"
# Debug builds allow the app to be rebuilt without having to re-register the extension
BUILD_CONFIGURATION="Debug"
# Build with minimal console output
xcodebuild -project QLStephenSwift/QLStephenSwift.xcodeproj \
-scheme QLStephenSwift \
-configuration "$BUILD_CONFIGURATION" \
-destination "$BUILD_DESTINATION" \
-quiet \
clean build
# Find the built app - try to find the most recent DerivedData directory
BUILT_APP=$(find ~/Library/Developer/Xcode/DerivedData -name "QLStephenSwift.app" -type d -path "*/Build/Products/$BUILD_CONFIGURATION/*" -newer "$INFO_PLIST" 2>/dev/null | head -1)
# If not found with -newer, try without
if [ -z "$BUILT_APP" ]; then
BUILT_APP=$(find ~/Library/Developer/Xcode/DerivedData -name "QLStephenSwift.app" -type d -path "*/Build/Products/$BUILD_CONFIGURATION/*" | head -1)
fi
if [ -z "$BUILT_APP" ] || [ ! -d "$BUILT_APP" ]; then
echo "Error: Could not find built app"
exit 0
fi
# Verify the built app has necessary files
if [ ! -f "$BUILT_APP/Contents/Info.plist" ] || [ ! -d "$BUILT_APP/Contents/MacOS" ]; then
echo "Error: Built app appears incomplete"
exit 0
fi
# Copy to Applications using ditto (more reliable for app bundles)
rm -rf "$INSTALL_PATH"
ditto "$BUILT_APP" "$INSTALL_PATH"
# Verify the types were added/removed from the Info.plist in the copied app
APP_INFO_PLIST="$INSTALL_PATH/Contents/PlugIns/QLStephenSwiftPreview.appex/Contents/Info.plist"
if [ -f "$APP_INFO_PLIST" ]; then
APP_TYPES=$(plutil -p "$APP_INFO_PLIST" | grep -A 10 "QLSupportedContentTypes" | grep -o '"[^"]*"' | tr -d '"')
while IFS= read -r TYPE; do
[ -z "$TYPE" ] && continue
if printf '%s\n' "$APP_TYPES" | grep -qx "$TYPE"; then
if [ "$ACTION" = "remove" ]; then
echo "Error: Type still present after removal $TYPE"
ANY_ERROR=1
fi
else
if [ "$ACTION" = "add" ]; then
echo "Error: Type not found after addition $TYPE"
ANY_ERROR=1
fi
fi
done <<EOF
$UNIQUE_TYPES
EOF
fi
# Success message with checkmark
if [ $ANY_ERROR -eq 0 ]; then
echo "✓ OK"
fi
#!/bin/sh
# Set IDs in QLStephenSwift so local signing works, then test the build
# Usage: sh qlss-fix-build.sh /path/to/repo
# 2026-01-16 v1 - Prompted by Chad von Nau
# ============================================================================
# Setup
# ============================================================================
# Repository directory - first argument
REPO_DIR="$1"
# Development Team ID - set here or leave empty to auto-detect
DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM:-}"
# ============================================================================
# Main
# ============================================================================
set -e
if [ -z "$REPO_DIR" ]; then
echo "Usage: $0 /path/to/repo"
exit 0
fi
# Try to detect Development Team ID from Xcode preferences
detect_development_team() {
team_id=$(defaults read "$HOME/Library/Preferences/com.apple.dt.Xcode.plist" IDEProvisioningTeamByIdentifier 2>/dev/null | \
grep -A 3 "teamID" | \
grep "teamID" | \
head -1 | \
sed -n 's/.*teamID = \([A-Z0-9]*\);/\1/p')
if [ -n "$team_id" ] && [ ${#team_id} -eq 10 ]; then
echo "$team_id"
else
return 1
fi
}
if [ -z "$DEVELOPMENT_TEAM" ]; then
if ! DEVELOPMENT_TEAM=$(detect_development_team); then
echo "Error: Could not detect Development Team ID. Open Xcode and sign in, or set DEVELOPMENT_TEAM variable."
exit 0
fi
fi
# Validate team ID (typical 10-char Apple team ID)
if ! printf '%s' "$DEVELOPMENT_TEAM" | grep -Eq '^[A-Z0-9]{10}$'; then
echo "Error: DEVELOPMENT_TEAM must be 10 characters (A-Z, 0-9)"
exit 0
fi
# Replace author IDs with user's team ID
if grep -Eq "com\.mycometg3(\.[A-Z0-9]{10})?\.qlstephenswift" "$REPO_DIR/QLStephenSwift/QLStephenSwift.xcodeproj/project.pbxproj" 2>/dev/null && \
! grep -Fq "com.mycometg3.${DEVELOPMENT_TEAM}.qlstephenswift" "$REPO_DIR/QLStephenSwift/QLStephenSwift.xcodeproj/project.pbxproj" 2>/dev/null
then
find "$REPO_DIR/QLStephenSwift" -type f \( -name "*.entitlements" -o -name "AppConstants.swift" -o -name "project.pbxproj" \) \
-exec sed -i '' \
-E "s/com\.mycometg3(\.[A-Z0-9]{10})?\.qlstephenswift/com.mycometg3.$DEVELOPMENT_TEAM.qlstephenswift/g" \
{} +
echo "Updated IDs to com.mycometg3.$DEVELOPMENT_TEAM.qlstephenswift"
fi
# Persist DEVELOPMENT_TEAM in the project so other scripts can build
PROJECT_PBXPROJ="$REPO_DIR/QLStephenSwift/QLStephenSwift.xcodeproj/project.pbxproj"
if grep -q "DEVELOPMENT_TEAM" "$PROJECT_PBXPROJ" 2>/dev/null; then
sed -i '' -E "s/DEVELOPMENT_TEAM = [^;]+;/DEVELOPMENT_TEAM = $DEVELOPMENT_TEAM;/g" "$PROJECT_PBXPROJ"
echo "Updated DEVELOPMENT_TEAM to $DEVELOPMENT_TEAM"
else
echo "Warning: DEVELOPMENT_TEAM not found in project.pbxproj; not updated."
fi
cd "$REPO_DIR"
# Pin destination to avoid xcodebuild "multiple matching destinations" warnings
BUILD_ARCH="$(uname -m)"
BUILD_DESTINATION="platform=macOS,arch=$BUILD_ARCH"
printf '%s' "Testing build... "
# Build (same base flags as ql-add-filetype.sh, plus signing setup)
xcodebuild -project QLStephenSwift/QLStephenSwift.xcodeproj \
-scheme QLStephenSwift \
-configuration Debug \
-destination "$BUILD_DESTINATION" \
-quiet \
CODE_SIGN_STYLE=Automatic \
-allowProvisioningUpdates \
clean build
echo "✓ OK"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment