#!/bin/bash # shellcheck disable=SC2164 # Defining variables PREFIX='/data/data/com.termux/files/usr' nerdfontsrepo='https://api.github.com/repos/ryanoasis/nerd-fonts' dist_dir="$PREFIX/share/termux-nf/fonts" down_dir="$HOME/share/termux-nf/Downloads" cache_dir="/data/data/com.termux/cache" TERMUX_DIR="$HOME/.termux/font.ttf" # Set the name of the file to store the release number release_file="$cache_dir/release.txt" # Define a file for the installed fonts names to be stored in installed_fonts_file="$cache_dir/installed.txt" aFontInstalled="False" keepZipFiles="False" update_fonts="False" force_update="False" # Set colors RED=$(tput setaf 1) GREEN=$(tput setaf 2) RESET=$(tput sgr0) # Help message usage() { cat << EOF Termux-NF: A Better way to install NerdFonts on Termux Usage: getnf [options] OPTIONS: -h print this help message and exit -f force reinstall an already installed font -k keep the downloaded fonts zip files -i directly install the specified fonts To install fonts using the menu: - Choose one or more fonts (by index/number) to install - Hit Return/Enter to install the selected fonts - Type 'q' to quit To install fonts directly: - Get the exact name of a font from the menu - Use 'getnf -i ""' to install a font - Use 'getnf -i ","' to install multiple fonts EOF } info() { printf "%s\n" "$1" } confirm() { printf "${GREEN}%b${RESET}\n" "$1" } alert() { printf "${RED}%b${RESET}\n" "$1" } error() { alert "$1" >&2 exit 1 } ensure_installed() { if ! command -v "$1" > /dev/null; then error "Dependency $1 is not installed on your system." fi } create_dir() { if [[ -d "$1" ]]; then info "$2 directory exists, good." else mkdir -p "$1" confirm "Created the $2 directory." fi } check_dependencies() { # Check if dependencies exist ensure_installed unzip ensure_installed curl # Check if the distDir and downDir exist, if they don't, create them create_dir "$dist_dir" "Fonts" create_dir "$down_dir" "Fonts Download" [[ -d "$cache_dir" ]] || mkdir -p "$cache_dir" } handle_release_version() { # Get the local release version [[ -f "$release_file" ]] && cached_release=$(cat "$release_file") # Get the latest release number from NerdFonts github repo release=$(curl --silent "$nerdfontsrepo/releases/latest" | awk -v RS=',' -F'"' '/tag_name/ {print $4}') # Compare the latest release number with the cached release number if [[ "$release" != "$cached_release" ]]; then update_fonts=True # Update the cached release number echo "$release" > "$release_file" fi } download_font() { info "$1 download started..." curl -LJO# "https://github.com/ryanoasis/nerd-fonts/releases/download/$release/$1.zip" confirm "$1 download finished" } extract_font() { info "$1 installation started..." unzip -qqo "$1.zip" -d "$dist_dir/$1" confirm "$1 installation finished" } remove_zip_files() { info "Removing downloaded zip files from $down_dir..." for font in "${SELECTED_FONTS[@]}"; do rm "$down_dir/$font.zip" done confirm "Downloaded zip files removal succeeded!" } install_font() { pushd "$down_dir" > /dev/null # Remove the zip file of the download font if it exists due to curl not having an overwrite function if [[ -f "$down_dir/$1.zip" ]]; then rm "$down_dir/$1.zip" fi download_font "$1" && extract_font "$1" && echo "$1" >> "$installed_fonts_file" aFontInstalled="True" popd > /dev/null } font_url_exists() { url="https://github.com/ryanoasis/nerd-fonts/releases/download/$release/$1.zip" curl --output /dev/null --silent --head --fail "$url" && return 0 || return 1 } direct_install() { for font_name in $(echo "$1" | tr ',' ' '); do if font_url_exists "$font_name"; then SELECTED_FONTS+=("$font_name") else error "Invalid font name: $font_name. Try again." fi done } post_install() { # Remove downloaded archives if the option -k was not passed if [[ "$keepZipFiles" == "False" ]]; then remove_zip_files else confirm "The downloaded zip files can be found in $down_dir" fi } menu() { local options=("$@") info "Select one or more fonts:" ( for i in "${!options[@]}"; do printf "%d) %s\n" "$((i + 1))" "${options[$i]}" done printf "q) Quit\n" ) | pr -3 -t -w "$(tput cols)" } # Parse input like 1-3 parse_range() { if ! [[ $1 =~ ^[0-9]+-[0-9]+$ ]]; then alert "Invalid input format: $1. Expected format: X-Y." return 1 fi IFS='-' read -ra range <<< "$1" range_start=${range[0]} range_end=${range[1]} for ((i = range_start; i <= range_end; i++)); do index=$((i - 1)) if ((index >= 0 && index < ${#font_options[@]})); then SELECTED_FONTS[index]=${font_options[index]} else alert "Invalid option: $i. Try again." return 1 fi done } menu_install() { # Download the file list and extract the font names font_list=$(curl -s "$nerdfontsrepo/contents/patched-fonts?ref=master" | awk -v RS=',' -F'"' '/name/ {print $4}') # Convert the list of fonts into an array of fonts declare -a all_fonts # Read the input string and populate the array #mapfile -t all_fonts <<< "$font_list" while IFS= read -r line; do all_fonts+=("$line") done <<< "$font_list" # Get the list of installed fonts if [[ -f "$installed_fonts_file" ]]; then installed_font_list=$(cat "$installed_fonts_file") # Convert the list of installed fonts into an array of fonts declare -a installed_fonts while IFS= read -r line; do installed_fonts+=("$line") done <<< "$installed_font_list" fi # Remove installed fonts from the list of all fonts if there is no new release # or if the user does not want to force the update if [[ "$update_fonts" == "False" && "$force_update" == "False" ]]; then declare -a font_options for font in "${all_fonts[@]}"; do if [[ " ${installed_fonts[*]} " != *" $font "* ]]; then font_options+=("$font") fi done else echo "" > "$installed_fonts_file" font_options=("${all_fonts[@]}") fi # Call the menu function to list the available fonts menu "${font_options[@]}" # Handle user input while true; do read -rp "Enter font number(s) (e.g. 1,2,3 or 1-3 or 1,3-5): " choices for choice in $(echo "$choices" | tr ',' ' '); do if [[ $choice == "q" ]]; then confirm "Goodbye!" exit # Choice is a range (e.g. 1-3) elif [[ $choice == *-* ]]; then parse_range "$choice" || continue 2 elif ((choice >= 1 && choice <= ${#font_options[@]})); then index=$((choice - 1)) SELECTED_FONTS[index]=${font_options[index]} else alert "Invalid option: $choice. Try again." continue 2 fi done echo "Selected fonts: ${SELECTED_FONTS[*]}" break done } # Applying font on termux termux() { cd $dist_dir arrange_files() { # Check if any .ttf files exist if ls *.ttf 1>/dev/null 2>&1; then # List only .ttf files if they exist files=(*.ttf) else # Otherwise, list all files files=(*) fi # List the files numerically echo "${BLUE}List of Installed Fonts:${RESET}" for i in "${!files[@]}"; do echo "${BLUE}$((i+1)). ${files[$i]}${RESET}" done } # activating the function arrange_files select_file() { # Prompt the user to select a file read -p "${BLUE}Enter the number of the file:${RESET} " choice # Validate the user input if [[ $choice =~ ^[0-9]+$ ]] && [ $choice -ge 1 ] && [ $choice -le ${#files[@]} ]; then selected_file="${files[$((choice-1))]}" # Check if the selected file is a directory if [ -d "$selected_file" ]; then cd "$selected_file" || { echo "${RED}Failed to enter directory $selected_file"${RESET}; exit 1; } arrange_files # Arrange files in the selected directory select_file # Prompt the user to select a file again else cp "$selected_file" "$HOME/.termux/font.ttf" || { echo "${RED}Failed to apply font"${RESET}; exit 1; } echo "${GREEN}Font Applied.${RESET}" fi else echo "${RED}Invalid choice. Please enter a valid number.${RESET}" select_file fi } # activating the function select_file echo " ${BLUE}[${RED}*${BLUE}] ${BLUE}Reloading Settings..." am broadcast --user 0 -a com.termux.app.reload_style com.termux > /dev/null { echo " ${BLUE}[${RED}*${BLUE}] ${GREEN}Applied Successfully."; echo; } } main() { # Setting flags while getopts ":hkfi:" option; do case "${option}" in h) usage && exit 0 ;; k) keepZipFiles="True" ;; f) force_update="True" ;; i) FONTNAMES="$OPTARG" ;; :) error "Option '-$OPTARG' requires at least one font name." ;; *) usage && exit 0 ;; esac done # Shift parsed options shift $((OPTIND - 1)) check_dependencies handle_release_version # List of selected fonts declare -a SELECTED_FONTS # Put the selected fonts into the list if [[ -n "$FONTNAMES" ]]; then direct_install "$FONTNAMES" else menu_install fi # Loop over the selected fonts and download them if ((${#SELECTED_FONTS[@]} > 0)); then for i in "${SELECTED_FONTS[@]}"; do install_font "$i" done else error "No fonts were selected, exiting." fi # If a font was installed if [[ "$aFontInstalled" == "True" ]]; then post_install fi # To check if Termux is being used if [ $(ps -ef| grep -c com.termux) -gt 0 ]; then termux fi } main "$@"