Skip to content

Instantly share code, notes, and snippets.

@aaronedev
Created August 8, 2025 09:12
Show Gist options
  • Save aaronedev/9d8b0076357882adc4742fd6df1f9702 to your computer and use it in GitHub Desktop.
Save aaronedev/9d8b0076357882adc4742fd6df1f9702 to your computer and use it in GitHub Desktop.
json to vcf contact creation designed for telegram export contact feature
#!/bin/bash
##############################################################################
# Script to convert a JSON file to VCF format
# was originally created for Telegram contacts when using
# export contact feature
##############################################################################
# Author: https://github.com/aaronedev
# Version: 1.0
# License: MIT
# 2025-08-08
# Dependencies: jq
# Usage: ./json2vcf.sh <input_json_file> [output_directory]
# Example: ./json2vcf.sh contacts.json
# Output: ./vcf_contacts/
##############################################################################
# Check if jq is installed
if ! command -v jq &>/dev/null; then
echo "Error: jq is required but not installed. Install with: pacman -S jq"
exit 1
fi
# Check if input file is provided
if [ $# -eq 0 ]; then
echo "Usage: $0 <json_file> [output_directory]"
echo "Example: $0 telegram_contacts.json ./vcf_contacts/"
exit 1
fi
JSON_FILE="$1"
OUTPUT_DIR="${2:-./vcf_contacts}"
# Check if JSON file exists
if [ ! -f "$JSON_FILE" ]; then
echo "Error: File '$JSON_FILE' not found"
exit 1
fi
# Create output directory
mkdir -p "$OUTPUT_DIR"
# Function to generate UID (using sha256 hash of contact info)
generate_uid() {
local first_name="$1"
local last_name="$2"
local phone="$3"
echo -n "${first_name}${last_name}${phone}" | sha256sum | cut -d' ' -f1
}
# Function to format phone number (convert to international format)
format_phone() {
local phone="$1"
# Remove leading zeros and add + if it starts with country code
if [[ $phone =~ ^00([0-9]+)$ ]]; then
echo "+${BASH_REMATCH[1]}"
else
echo "$phone"
fi
}
# Function to create safe filename from name
safe_filename() {
local name="$1"
# Replace spaces and special chars with underscores, remove multiple underscores
echo "$name" | sed 's/[^a-zA-Z0-9]/_/g' | sed 's/__*/_/g' | sed 's/^_\|_$//g'
}
# Parse JSON and create VCF files
jq -r '.contacts.list[] | @base64' "$JSON_FILE" | while read -r contact_b64; do
# Decode base64 and extract contact info
contact=$(echo "$contact_b64" | base64 --decode)
first_name=$(echo "$contact" | jq -r '.first_name // ""')
last_name=$(echo "$contact" | jq -r '.last_name // ""')
phone_number=$(echo "$contact" | jq -r '.phone_number // ""')
# Skip if no phone number
if [ -z "$phone_number" ]; then
echo "Warning: Skipping contact with no phone number"
continue
fi
# Create full name (FN field)
if [ -n "$first_name" ] && [ -n "$last_name" ]; then
full_name="$first_name $last_name"
elif [ -n "$first_name" ]; then
full_name="$first_name"
elif [ -n "$last_name" ]; then
full_name="$last_name"
else
full_name="Unknown Contact"
fi
# Create structured name (N field: Last;First;;;)
structured_name="${last_name};${first_name};;;"
# Generate UID
uid=$(generate_uid "$first_name" "$last_name" "$phone_number")
# Format phone number
formatted_phone=$(format_phone "$phone_number")
# Create safe filename
safe_name=$(safe_filename "$full_name")
filename="${OUTPUT_DIR}/${safe_name}_${uid:0:8}.vcf"
# Generate VCF content
cat >"$filename" <<EOF
BEGIN:VCARD
VERSION:3.0
UID:$uid
FN:$full_name
N:$structured_name
TEL;TYPE=CELL:$formatted_phone
CATEGORIES:myContacts
END:VCARD
EOF
echo "Created: $filename"
done
echo "VCF conversion completed. Files saved to: $OUTPUT_DIR"
# Optional: Create a combined VCF file
read -r -p "Create a single combined VCF file? (y/n): " create_combined
if [[ $create_combined =~ ^[Yy]$ ]]; then
combined_file="${OUTPUT_DIR}/all_contacts.vcf"
cat "${OUTPUT_DIR}"/*.vcf >"$combined_file"
echo "Combined VCF created: $combined_file"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment