Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ddnomad/2c76db2250359af1b2608849e747ac01 to your computer and use it in GitHub Desktop.
Save ddnomad/2c76db2250359af1b2608849e747ac01 to your computer and use it in GitHub Desktop.
A collection of quick and dirty scripts for automating installation of plugins and themes for Obsidian.md editor

Expected directory structure for getting utility scripts properly sourced:

.
├── install_obsidian_community_plugins.sh
├── install_obsidian_themes.sh
└── utils
    ├── check_has_commands.sh
    └── print.sh

Example plugins list file:

obsidian-minimal-settings
templater-obsidian
# some-other-plugin

# you can have empty lines and comments in this file and it is handled gracefully

Example themes list file:

Things
Minimal
# Last specified theme will be automatically set as a default one in Obsidian
#!/usr/bin/env bash
set -euo pipefail
function check_has_commands {
if test "$#" -lt 1; then
>&2 echo 'Usage: check_has_commands <command> [<command>...]'
exit 1
fi
local command
for command in "$@"; do
if ! command -v "${command}" &> /dev/null; then
>&2 echo "Error: Failed to detect that a command is installed: ${command}"
exit 1
fi
done
}
#!/usr/bin/env bash
set -euo pipefail
SOURCE_DIR="$(realpath "$(dirname "${BASH_SOURCE[0]:-$0}")")"
readonly SOURCE_DIR
readonly UTILS_DIR="${SOURCE_DIR}/utils"
# shellcheck source=/dev/null
source "${UTILS_DIR}"/check_has_commands.sh
# shellcheck source=/dev/null
source "${UTILS_DIR}"/print.sh
readonly OBSIDIAN_COMMUNITY_PLUGINS_INDEX_URL=https://raw.githubusercontent.com/obsidianmd/obsidian-releases/master/community-plugins.json
function install_obsidian_community_plugin {
if test "$#" -ne 3; then
print plain 'Usage: install_obsidian_community_plugin <plugin_id> <dot_obsidian_directory_path> <temp_directory_path>'
exit 1
fi
local plugin_id
plugin_id="$1"
local dot_obsidian_directory_path
dot_obsidian_directory_path="$(realpath "$2")"
local temp_dir
temp_dir="$(realpath "$3")"
local plugin_repo
plugin_repo="$(curl -s "${OBSIDIAN_COMMUNITY_PLUGINS_INDEX_URL}" | jq -r ".[] | select(.id == \"${plugin_id}\") | .repo")"
if test -z "${plugin_repo}"; then
print error "Failed to find Obsidian community plugin by ID: ${plugin_id}"
exit 1
fi
local line
local main_download_url
local manifest_download_url
local styles_download_url
while IFS= read -r line; do
local url
url="$(cut -f2- -d':' <<<"${line}" | tr -d '"' | xargs)"
local file_name
file_name="$(rev <<< "${url}" | cut -d'/' -f1 | rev)"
case "${file_name}" in
main.js )
main_download_url="${url}"
;;
manifest.json )
manifest_download_url="${url}"
;;
styles.css )
styles_download_url="${url}"
;;
* )
continue
;;
esac
done <<< "$(curl -s "https://api.github.com/repos/${plugin_repo}/releases/latest" | grep "browser_download_url")"
if test -z "${main_download_url}" || test -z "${manifest_download_url}"; then
print error "Failed to locate Obsidian community plugin download URL(s): ${plugin_id}"
exit 1
fi
local main_file_path
main_file_path="${temp_dir}/main.js"
local manifest_file_path
manifest_file_path="${temp_dir}/manifest.json"
curl -s -o "${main_file_path}" -L "${main_download_url}"
curl -s -o "${manifest_file_path}" -L "${manifest_download_url}"
local target_plugin_directory
target_plugin_directory="${dot_obsidian_directory_path}/plugins/${plugin_id}"
mkdir -p "${target_plugin_directory}"
cp "${main_file_path}" "${target_plugin_directory}/main.js"
cp "${manifest_file_path}" "${target_plugin_directory}/manifest.json"
if test -n "${styles_download_url}"; then
local styles_file_path
styles_file_path="${temp_dir}/styles.css"
curl -s -o "${styles_file_path}" -L "${styles_download_url}"
cp "${styles_file_path}" "${target_plugin_directory}/styles.css"
fi
local enabled_plugins_list_file_path
enabled_plugins_list_file_path="${dot_obsidian_directory_path}/community-plugins.json"
if ! test -f "${enabled_plugins_list_file_path}"; then
echo '[]' > "${enabled_plugins_list_file_path}"
fi
temp_file_path="$(mktemp)"
function delete_temp_file {
# shellcheck disable=SC2317
rm "${temp_file_path}" &> /dev/null || :
}
trap delete_temp_file EXIT
jq ". += [\"${plugin_id}\"]" "${enabled_plugins_list_file_path}" > "${temp_file_path}" && \
cp "${temp_file_path}" "${enabled_plugins_list_file_path}"
}
function main {
if test "$#" -ne 2; then
print plain "Usage: $0 <plugins_list_file_path> <dot_obsidian_directory_path>"
exit 1
fi
check_has_commands curl jq mktemp
local plugins_list_file_path
plugins_list_file_path="$(realpath "$1")"
local dot_obsidian_directory_path
dot_obsidian_directory_path="$(realpath "$2")"
if ! test -f "${plugins_list_file_path}"; then
print error "Provided community plugins list path does not exist or is not a regular file: ${plugins_list_file_path}"
exit 1
fi
if ! test -d "${dot_obsidian_directory_path}"; then
print error "Provided .obsidian directory path does not exist or is not a directory: ${dot_obsidian_directory_path}"
exit 1
fi
temp_dir="$(mktemp -d)"
function delete_temp_dir {
# shellcheck disable=SC2317
rm -r "${temp_dir}"
}
trap delete_temp_dir EXIT
local plugin_id
while read -r plugin_id; do
if [[ "${plugin_id}" == \#* ]] || test -z "${plugin_id}"; then
continue
fi
print info "Installing Obsidian community plugin: ${plugin_id}"
install_obsidian_community_plugin "${plugin_id}" "${dot_obsidian_directory_path}" "${temp_dir}"
done < "${plugins_list_file_path}"
print success 'All done'
}
main "$@"
#!/usr/bin/env bash
set -euo pipefail
SOURCE_DIR="$(realpath "$(dirname "${BASH_SOURCE[0]:-$0}")")"
readonly SOURCE_DIR
readonly UTILS_DIR="${SOURCE_DIR}/utils"
# shellcheck source=/dev/null
source "${UTILS_DIR}"/check_has_commands.sh
# shellcheck source=/dev/null
source "${UTILS_DIR}"/print.sh
readonly OBSIDIAN_THEMES_INDEX_URL=https://raw.githubusercontent.com/obsidianmd/obsidian-releases/master/community-css-themes.json
function install_obsidian_theme {
if test "$#" -ne 3; then
print plain 'Usage: install_obsidian_theme <theme_name> <dot_obsidian_directory_path> <temp_directory_path>'
exit 1
fi
local theme_name
theme_name="$1"
local dot_obsidian_directory_path
dot_obsidian_directory_path="$(realpath "$2")"
local temp_dir
temp_dir="$(realpath "$3")"
local theme_repo
theme_repo="$(curl -s "${OBSIDIAN_THEMES_INDEX_URL}" | jq -r ".[] | select(.name == \"${theme_name}\") | .repo")"
if test -z "${theme_repo}"; then
print error "Failed to find Obsidian theme by name: ${theme_name}"
exit 1
fi
local release_download_url
release_download_url="$(curl -s "https://api.github.com/repos/${theme_repo}/releases/latest" | jq -r .tarball_url)"
if test -z "${release_download_url}"; then
print error "Failed to retrieve Obsidian theme download URL: ${theme_name}"
exit 1
fi
local release_archive_file_path
release_archive_file_path="${temp_dir}"/release.tar.gz
curl -s -o "${release_archive_file_path}" -L "${release_download_url}"
tar -xf "${release_archive_file_path}" -C "${temp_dir}"
local theme_css_file_path
theme_css_file_path="$(ls -1 "${temp_dir}/${theme_repo/\//-}"*/theme.css)"
local manifest_file_path
manifest_file_path="$(ls -1 "${temp_dir}/${theme_repo/\//-}"*/manifest.json)"
local target_theme_directory
target_theme_directory="${dot_obsidian_directory_path}/themes/${theme_name}"
mkdir -p "${target_theme_directory}"
cp "${theme_css_file_path}" "${target_theme_directory}/theme.css"
cp "${manifest_file_path}" "${target_theme_directory}/manifest.json"
}
function main {
if test "$#" -ne 2; then
print plain "Usage: $0 <themes_list_file_path> <dot_obsidian_directory_path>"
exit 1
fi
check_has_commands curl jq mktemp
local themes_list_file_path
themes_list_file_path="$(realpath "$1")"
local dot_obsidian_directory_path
dot_obsidian_directory_path="$(realpath "$2")"
if ! test -f "${themes_list_file_path}"; then
print error "Provided themes list path does not exist or is not a regular file: ${themes_list_file_path}"
exit 1
fi
if ! test -d "${dot_obsidian_directory_path}"; then
print error "Provided .obsidian directory path does not exist or is not a directory: ${dot_obsidian_directory_path}"
exit 1
fi
temp_dir="$(mktemp -d)"
function delete_temp_dir {
# shellcheck disable=SC2317
rm -r "${temp_dir}"
}
trap delete_temp_dir EXIT
local line
local theme_name
while read -r line; do
if [[ "${line}" == \#* ]] || test -z "${line}"; then
continue
fi
theme_name="${line}"
print info "Installing Obsidian theme: ${theme_name}"
install_obsidian_theme "${theme_name}" "${dot_obsidian_directory_path}" "${temp_dir}"
done < "${themes_list_file_path}"
print info "Setting the last encountered theme as a default one: ${theme_name}"
temp_file_path="$(mktemp)"
function delete_temp_file {
# shellcheck disable=SC2317
rm "${temp_file_path}" &> /dev/null || :
}
trap delete_temp_file EXIT
local obsidian_appearance_config_file
obsidian_appearance_config_file="${dot_obsidian_directory_path}/appearance.json"
jq ".cssTheme = \"${theme_name}\"" "${obsidian_appearance_config_file}" > "${temp_file_path}" && \
cp "${temp_file_path}" "${obsidian_appearance_config_file}"
print success 'All done'
}
main "$@"
#!/usr/bin/env bash
set -euo pipefail
function print {
if test "$#" -ne 2; then
>&2 echo 'Usage: print error|info|plain|success|warning <message>'
exit 1
fi
local message_type
message_type="$1"
local message
message="$2"
case "${message_type}" in
error )
>&2 echo "$(tput setaf 1)Error: ${message}$(tput setaf 7)"
;;
info )
>&2 echo "$(tput setaf 4)---(i) INFO: ${message}$(tput setaf 7)"
;;
plain )
>&2 echo "${message}"
;;
success )
>&2 echo "$(tput setaf 2)---(+) OK: ${message}$(tput setaf 7)"
;;
warning )
>&2 echo "$(tput setaf 3)---(!) WARNING: ${message}$(tput setaf 7)"
;;
* )
print error "Unsupported message type: ${message_type}"
exit 1
;;
esac
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment