Merge branch 'master' of github.com:steveokard/stevset

This commit is contained in:
Stefen Auris 2023-04-12 22:16:21 -04:00
commit 3eee731b00
3 changed files with 1077 additions and 0 deletions

407
config/dot-gallery-dl.conf Normal file
View file

@ -0,0 +1,407 @@
{
"extractor":
{
"base-directory": "~/gallery-dl/",
"#": "set global archive file for all extractors",
"archive": "~/gallery-dl/archive.sqlite3",
"#": "add two custom keywords into the metadata dictionary",
"#": "these can be used to further refine your output directories or filenames",
"keywords": {"bkey": "", "ckey": ""},
"#": "make sure that custom keywords are empty, i.e. they don't appear unless specified by the user",
"keywords-default": "",
"#": "replace invalid path characters with unicode alternatives",
"path-restrict": {
"\\": "",
"/" : "",
"|" : "",
":" : "",
"*" : "",
"?" : "",
"\"": "″",
"<" : "﹤",
">" : "﹥"
},
"#": "write tags for several *booru sites",
"postprocessors": [
{
"name": "metadata",
"mode": "tags",
"whitelist": ["danbooru", "moebooru", "sankaku"]
}
],
"pixiv":
{
"cookies": "$HOME/.gallery-dl/cookies-pixiv-net.txt"
},
"danbooru":
{
"ugoira": true,
"postprocessors": ["ugoira-webm"]
},
"exhentai":
{
"#": "use cookies instead of logging in with username and password",
"cookies":
{
"ipb_member_id": "12345",
"ipb_pass_hash": "1234567890abcdef",
"igneous" : "123456789",
"hath_perks" : "m1.m2.m3.a-123456789a",
"sk" : "n4m34tv3574m2c4e22c35zgeehiw",
"sl" : "dm_2"
},
"#": "wait 2 to 4.8 seconds between HTTP requests",
"sleep-request": [2.0, 4.8],
"filename": "{num:>04}_{name}.{extension}",
"directory": ["{category!c}", "{title}"]
},
"sankaku":
{
"#": "authentication with cookies is not possible for sankaku",
"username": "user",
"password": "#secret#"
},
"furaffinity": {
"#": "authentication with username and password is not possible due to CAPTCHA",
"cookies": {
"a": "7766e97d-cadf-4803-b354-a24a90fd0c56",
"b": "ec52df4c-6e67-4758-8f82-acdb0fa4c503"
},
"descriptions": "html",
"postprocessors": ["content"]
},
"deviantart":
{
"#": "download 'gallery' and 'scraps' images for user profile URLs",
"include": "gallery,scraps",
"#": "use custom API credentials to avoid 429 errors",
"client-id": "98765",
"client-secret": "0123456789abcdef0123456789abcdef",
"refresh-token": "0123456789abcdef0123456789abcdef01234567",
"#": "put description texts into a separate directory",
"metadata": true,
"postprocessors": [
{
"name": "metadata",
"mode": "custom",
"directory" : "Descriptions",
"content-format" : "{description}\n",
"extension-format": "descr.txt"
}
]
},
"flickr":
{
"access-token": "1234567890-abcdef",
"access-token-secret": "1234567890abcdef",
"size-max": 1920
},
"mangadex":
{
"#": "only download safe/suggestive chapters translated to English",
"lang": "en",
"ratings": ["safe", "suggestive"],
"#": "put chapters into '.cbz' archives",
"postprocessors": ["cbz"]
},
"reddit":
{
"#": "only spawn child extractors for links to specific sites",
"whitelist": ["imgur", "redgifs", "gfycat"],
"#": "put files from child extractors into the reddit directory",
"parent-directory": true,
"#": "transfer metadata to any child extractor as '_reddit'",
"parent-metadata": "_reddit"
},
"imgur":
{
"#": "use different directory and filename formats when coming from a reddit post",
"directory":
{
"'_reddit' in locals()": []
},
"filename":
{
"'_reddit' in locals()": "{_reddit[id]} {id}.{extension}",
"" : "{id}.{extension}"
}
},
"tumblr":
{
"posts" : "all",
"external": false,
"reblogs" : false,
"inline" : true,
"#": "use special settings when downloading liked posts",
"likes":
{
"posts" : "video,photo,link",
"external": true,
"reblogs" : true
}
},
"twitter":
{
"#": "write text content for *all* tweets",
"text-tweets": true,
"cookies": "$HOME/.gallery-dl/twitter.com_cookies.txt",
"postprocessors": ["content"]
},
"patreon":
{
"cookies": "$HOME/.gallery-dl/cookies-patreon-com.txt"
},
"mastodon":
{
"#": "add 'tabletop.social' as recognized mastodon instance",
"#": "(run 'gallery-dl oauth:mastodon:tabletop.social to get an access token')",
"tabletop.social":
{
"root": "https://tabletop.social",
"access-token": "513a36c6..."
},
"#": "set filename format strings for all 'mastodon' instances",
"directory": ["mastodon", "{instance}", "{account[username]!l}"],
"filename" : "{id}_{media[id]}.{extension}"
},
"foolslide": {
"#": "add two more foolslide instances",
"otscans" : {"root": "https://otscans.com/foolslide"},
"helvetica": {"root": "https://helveticascans.com/r" }
},
"foolfuuka": {
"#": "add two other foolfuuka 4chan archives",
"fireden-onion": {"root": "http://ydt6jy2ng3s3xg2e.onion"},
"scalearchive" : {"root": "https://archive.scaled.team" }
},
"gelbooru_v01":
{
"#": "add a custom gelbooru_v01 instance",
"#": "this is just an example, this specific instance is already included!",
"allgirlbooru": {"root": "https://allgirl.booru.org"},
"#": "the following options are used for all gelbooru_v01 instances",
"tag":
{
"directory": {
"locals().get('bkey')": ["Booru", "AllGirlBooru", "Tags", "{bkey}", "{ckey}", "{search_tags}"],
"" : ["Booru", "AllGirlBooru", "Tags", "_Unsorted", "{search_tags}"]
}
},
"post":
{
"directory": ["Booru", "AllGirlBooru", "Posts"]
},
"archive": "~/gallery-dl/custom-archive-file-for-gelbooru_v01_instances.db",
"filename": "{tags}_{id}_{md5}.{extension}",
"sleep-request": [0, 1.2]
},
"gelbooru_v02":
{
"#": "add a custom gelbooru_v02 instance",
"#": "this is just an example, this specific instance is already included!",
"tbib":
{
"root": "https://tbib.org",
"#": "some sites have different domains for API access",
"#": "use the 'api_root' option in addition to the 'root' setting here"
}
},
"instagram":
{
"api": "auto",
"cookies": "$HOME/.gallery-dl/cookies-instagram-com.txt",
"include": "posts",
"sleep-request": [8.0, 12.0],
"videos": true
},
"tbib": {
"#": "the following options are only used for TBIB",
"#": "gelbooru_v02 has four subcategories at the moment, use custom directory settings for all of these",
"tag":
{
"directory": {
"locals().get('bkey')": ["Other Boorus", "TBIB", "Tags", "{bkey}", "{ckey}", "{search_tags}"],
"" : ["Other Boorus", "TBIB", "Tags", "_Unsorted", "{search_tags}"]
}
},
"pool":
{
"directory": {
"locals().get('bkey')": ["Other Boorus", "TBIB", "Pools", "{bkey}", "{ckey}", "{pool}"],
"" : ["Other Boorus", "TBIB", "Pools", "_Unsorted", "{pool}"]
}
},
"favorite":
{
"directory": {
"locals().get('bkey')": ["Other Boorus", "TBIB", "Favorites", "{bkey}", "{ckey}", "{favorite_id}"],
"" : ["Other Boorus", "TBIB", "Favorites", "_Unsorted", "{favorite_id}"]
}
},
"post":
{
"directory": ["Other Boorus", "TBIB", "Posts"]
},
"archive": "~/gallery-dl/custom-archive-file-for-TBIB.db",
"filename": "{id}_{md5}.{extension}",
"sleep-request": [0, 1.2]
}
},
"downloader":
{
"#": "restrict download speed to 1 MB/s",
"rate": "5M",
"#": "show download progress indicator after 2 seconds",
"progress": 2.0,
"#": "retry failed downloads up to 3 times",
"retries": 3,
"#": "consider a download 'failed' after 8 seconds of inactivity",
"timeout": 8.0,
"#": "write '.part' files into a special directory",
"part-directory": "/tmp/.download/",
"ytdl":
{
"#": "use yt-dlp instead of youtube-dl",
"module": "yt_dlp"
}
},
"output":
{
"log": {
"level": "info",
"#": "use different ANSI colors for each log level",
"format": {
"debug" : "\u001b[0;37m{name}: {message}\u001b[0m",
"info" : "\u001b[1;37m{name}: {message}\u001b[0m",
"warning": "\u001b[1;33m{name}: {message}\u001b[0m",
"error" : "\u001b[1;31m{name}: {message}\u001b[0m"
}
},
"#": "shorten filenames to fit into one terminal line",
"#": "while also considering wider East-Asian characters",
"shorten": "true",
"#": "enable ANSI escape sequences on Windows",
"ansi": true,
"#": "write logging messages to a separate file",
"logfile": {
"path": "~/gallery-dl/log.txt",
"mode": "w",
"level": "debug"
},
"#": "write unrecognized URLs to a separate file",
"unsupportedfile": {
"path": "~/gallery-dl/unsupported.txt",
"mode": "a",
"format": "{asctime} {message}",
"format-date": "%Y-%m-%d-%H-%M-%S"
},
"skip": true
},
"postprocessor":
{
"#": "write 'content' metadata into separate files",
"content":
{
"name" : "metadata",
"#": "write data for every post instead of each individual file",
"event": "post",
"filename": "{post_id|tweet_id|id}.txt",
"#": "write only the values for 'content' or 'description'",
"mode" : "custom",
"format": "{content|description}\n"
},
"#": "put files into a '.cbz' archive",
"cbz":
{
"name": "zip",
"extension": "cbz"
},
"#": "various ugoira post processor configurations to create different file formats",
"ugoira-webm":
{
"name": "ugoira",
"extension": "webm",
"ffmpeg-args": ["-c:v", "libvpx-vp9", "-an", "-b:v", "0", "-crf", "30"],
"ffmpeg-twopass": true,
"ffmpeg-demuxer": "image2"
},
"ugoira-mp4":
{
"name": "ugoira",
"extension": "mp4",
"ffmpeg-args": ["-c:v", "libx264", "-an", "-b:v", "4M", "-preset", "veryslow"],
"ffmpeg-twopass": true,
"libx264-prevent-odd": true
},
"ugoira-gif":
{
"name": "ugoira",
"extension": "gif",
"ffmpeg-args": ["-filter_complex", "[0:v] split [a][b];[a] palettegen [p];[b][p] paletteuse"]
},
"ugoira-copy": {
"name": "ugoira",
"extension": "mkv",
"ffmpeg-args": ["-c", "copy"],
"libx264-prevent-odd": false,
"repeat-last-frame": false
}
},
"#": "use a custom cache file location",
"cache": {
"file": "~/gallery-dl/cache.sqlite3"
}
}

670
scripts/lan/betterdiscordctl Executable file
View file

@ -0,0 +1,670 @@
#!/usr/bin/env bash
set -ueo pipefail
shopt -s dotglob extglob nullglob
# Constants
VERSION=2.0.1
SOURCE=$(readlink -f "${BASH_SOURCE[0]}")
DISABLE_SELF_UPGRADE=
# Options
cmd=
verbosity=0
d_flavors=('' canary ptb development)
d_modules=
bd_remote=github
bd_remote_dir=
bd_remote_url=
bd_remote_github_owner=BetterDiscord
bd_remote_github_repo=BetterDiscord
bd_remote_github_release=latest
bd_remote_asar=betterdiscord.asar
d_install=traditional
flatpak_bin=flatpak
snap_bin=snap
self_upgrade_url='https://github.com/bb010g/betterdiscordctl/raw/master/betterdiscordctl'
# Variables
d_flavor=
d_core=
xdg_config=
bdc_data=${XDG_DATA_HOME:-$HOME/.local/share}/betterdiscordctl
d_config=
bd_config=
bd_asar=
bd_asar_escaped=
bd_asar_name=
show_help() {
cat << EOF
Usage: ${0##*/} [-f d_flavors] \\
[-D <bd_r_dir>|-U <bd_r_url>|-H <bd_r_github>] \\
[-i (traditional|flatpak|snap)] <command>
Manage BetterDiscord installations on Linux.
Options:
-V, --version display version info and exit
-h, --help display this help message and exit
-v, --verbose increase verbosity
-q, --quiet decrease verbosity
-f, --d-flavors <d_flavors> discover Discord installations with the
colon-separated list of suffixes <d_flavors>.
Defaults to ':canary:ptb:development'. Flavors
must be lowercase. Stable is flavor '', as
it's unsuffixed. Flavors shouldn't include
spaces.
-m, --d-modules <d_modules> use Discord modules in directory <d_modules>.
Defaults to discovery. Discord's user-specific
storage directory should contain <d_modules>.
-D, --bd-remote-dir reference BetterDiscord files at directory
<bd_r_dir> <bd_r_dir>. Overrides earlier --bd-remote-url
or --bd-remote-github. An empty string keeps a
previous value.
-U, --bd-remote-url download BetterDiscord files at base URL
<bd_r_url> <bd_r_url>. Overrides earlier --bd-remote-dir
or --bd-remote-github. An empty string keeps a
previous value. Works like --bd-remote-dir
with files downloaded into BetterDiscord's
data directory.
-H, --bd-remote-github download BetterDiscord files at GitHub
<bd_r_github> repository release <bd_r_github>, of form
[~<owner>][/<repo>][#<release>]. Defaults to
'~BetterDiscord/BetterDiscord#latest'. Overrides
earlier --bd-remote-dir or --bd-remote-github.
An omitted part keeps a previous value.
<owner> and <repo> must not contain '~', '/',
or '#'. Works like --bd-remote-url with a
GitHub repository release download base URL.
--bd-remote-asar <bd_r_asar> finds "betterdiscord.asar" at path <bd_r_asar>
relative to remote. Defaults to
'betterdiscord.asar'.
-i, --d-install traditional use a traditional Discord install. Default.
-i, --d-install flatpak use a Discord Flatpak app
-i, --d-install snap use a Discord Snap app
--flatpak-bin <flatpak> invoke Flatpak executable <flatpak>. Defaults
to 'flatpak'.
--snap-bin <snap> invoke Snap executable <snap>. Defaults to
'snap'.
--self-upgrade-url query <self_upgrade_url> for self-upgrades
<self_upgrade_url>
Commands:
status show the current Discord patch state
install install BetterDiscord
reinstall reinstall BetterDiscord
uninstall uninstall BetterDiscord
self-upgrade upgrade this program
EOF
}
verbose() {
if (( verbosity >= $1 )); then
shift
>&2 printf '%s\n' "$1"
fi
}
die() {
while (( $# > 0 )); do
>&2 printf '%s\n' "$1"
shift
done
exit 1
}
die_with_help() {
die "$@" "Use \`${0##*/} --help\` for more information."
}
die_option() {
die_with_help "ERROR: \"$1\" requires an option argument."
}
die_non_empty_option() {
die_with_help "ERROR: \"$1\" requires a non-empty option argument."
}
die_non_empty_option_part() {
die_with_help "ERROR: \"$1\" requires a non-empty $2 option argument part."
}
# arg parsing: top-level: options
while :; do
if [[ -z ${1+x} ]]; then break; fi
case $1 in
-V|--version)
>&2 printf 'betterdiscordctl %s\n' "$VERSION"
exit
;;
-h|-\?|--help)
show_help; exit
;;
-v|--verbose)
((verbosity++)) || :
;;
-q|--quiet)
((verbosity--)) || :
;;
-f|--d-flavors)
if [[ ${2+x} ]]; then
if [[ $2 != "${2,,}" ]]; then
die_with_help "ERROR: Discord flavors list must be lowercase: $2"
else
IFS=':' read -ra d_flavors <<< "$2:"; shift
fi
else die_option "$1"; fi
;;
-m|--d-modules)
if [[ ${2:+x} ]]; then d_modules=$2; shift
else die_non_empty_option "$1"; fi
;;
-D|--bd-remote-dir)
bd_remote=dir
if [[ ${2+x} ]]; then [[ ${2:+x} ]] && bd_remote_dir=$2; shift
else die_option "$1"; fi
;;
-U|--bd-remote-url)
bd_remote=url
if [[ ${2+x} ]]; then [[ ${2:+x} ]] && bd_remote_url=$2; shift
else die_option "$1"; fi
;;
-H|--bd-remote-github)
bd_remote=github
if [[ ${2+x} ]]; then
if [[ ! $2 =~ (~?[^~/#]*)(/?[^~/#]*)(#?.*) ]]; then
die_with_help "ERROR: \"$1\" requires a valid option argument."
fi
if [[ ${BASH_REMATCH[1]} ]]; then
[[ ${BASH_REMATCH[2]} != '~' ]] || die_non_empty_option_part "$1" '<owner>'
bd_remote_github_owner=${BASH_REMATCH[1]:1}
fi
if [[ ${BASH_REMATCH[2]} ]]; then
[[ ${BASH_REMATCH[2]} != '/' ]] || die_non_empty_option_part "$1" '<repo>'
bd_remote_github_repo=${BASH_REMATCH[2]:1}
fi
if [[ ${BASH_REMATCH[3]} ]]; then
[[ ${BASH_REMATCH[3]} != '#' ]] || die_non_empty_option_part "$1" '<release>'
bd_remote_github_release=${BASH_REMATCH[3]:1}
fi
shift
else die_option "$1"; fi
;;
--bd-remote-asar)
if [[ ${2:+x} ]]; then bd_remote_asar=$2; shift
else die_non_empty_option "$1"; fi
;;
-i|--d-install)
if [[ ${2:+x} ]]; then case "$2" in
traditional|flatpak|snap) d_install=$2 ;;
*) die_with_help "ERROR: Unknown top-level $1 value: $2" ;;
esac; shift; else die_non_empty_option "$1"; fi
;;
--flatpak-bin)
if [[ ${2:+x} ]]; then flatpak_bin=$2; shift
else die_non_empty_option "$1"; fi
;;
--snap-bin)
if [[ ${2:+x} ]]; then snap_bin=$2; shift
else die_non_empty_option "$1"; fi
;;
--self-upgrade-url)
if [[ ${2:+x} ]]; then self_upgrade_url=$2; shift
else die_non_empty_option "$1"; fi
;;
# footer
-*=*) die "ERROR: Keyed options must not be separated by equals: $1" ;;
--) shift; break ;;
-?|--*) die_with_help "ERROR: Unknown top-level option: $1" ;;
-??*) die "ERROR: Switches must not be ran together: $1" ;;
*) break
esac
shift
done
# arg parsing: top-level: arguments
while :; do
if [[ -z ${1+x} ]]; then break; fi
case "$1" in
status|install|reinstall|uninstall|self-upgrade)
cmd=$1
shift
break
;;
*) die_with_help "ERROR: Unknown top-level argument: $1"
esac
shift
done
# arg parsing: top-level: validation
case "$bd_remote" in
github)
[[ $bd_remote_github_owner ]] || die_non_empty_option_part '--bd-remote-github' '<owner>'
[[ $bd_remote_github_repo ]] || die_non_empty_option_part '--bd-remote-github' '<repo>'
[[ $bd_remote_github_release ]] || die_non_empty_option_part '--bd-remote-github' '<release>'
;;
url)
[[ $bd_remote_url ]] || die_non_empty_option '--bd-remote-url'
;;
dir)
[[ $bd_remote_dir ]] || die_non_empty_option '--bd-remote-dir'
;;
esac
# arg parsing: top-level: command dispatch
case "$cmd" in
status|install|reinstall|uninstall|self-upgrade)
# arg parsing: (status|install|reinstall|uninstall|self-upgrade): options
while :; do
if [[ -z ${1+x} ]]; then break; fi
case "$1" in
# footer
-*=*) die "ERROR: Keyed options must not be separated by equals: $1" ;;
--) shift; break ;;
-?|--*) die_with_help "ERROR: Unknown |$cmd| option: $1" ;;
-??*) die "ERROR: Switches must not be ran together: $1" ;;
esac
shift
done
# arg parsing: (status|install|reinstall|uninstall|self-upgrade): arguments
if [[ -n ${1+x} ]]; then
die_with_help "ERROR: Unknown |$cmd| argument: $1"
fi
;;
'')
die_with_help "ERROR: Specify a non-empty command."
;;
*) die "ERROR: [arg parsing: top-level: command dispatch] Unknown command: $cmd" ;;
esac
# currently unused
# mkdir -p "$bdc_data"
# Commands
bdc_status() {
declare asar_install bd_remote_status index_mod
asar_install=no
index_mod=no
verbose 2 "VV: BetterDiscord asar installation: $bd_asar"
if [[ -h $bd_asar && ! -f $bd_asar ]]; then
asar_install='(broken link) no'
elif [[ -f $bd_asar ]]; then
asar_install='(symbolic link) yes'
elif [[ -d $bd_config ]]; then
asar_install='(missing) no'
fi
if grep -Fq "$bd_asar_escaped" "$d_core/index.js"; then
index_mod=yes
elif grep -Fq "$bd_asar_name" "$d_core/index.js"; then
index_mod=noncompliant
elif grep -Fq 'betterdiscord.asar' "$d_core/index.js"; then
index_mod=noncompliant
fi
bd_remote_status="$bd_remote"
case "$bd_remote" in
github)
bd_remote_status+="
BetterDiscord remote GitHub: ~$bd_remote_github_owner/$bd_remote_github_repo#$bd_remote_github_release"
;;
url)
bd_remote_status+="
BetterDiscord remote URL: $bd_remote_url"
;;
dir)
bd_remote_status+="
BetterDiscord remote directory: $bd_remote_dir"
;;
esac
printf 'Discord install: %s
Discord flavor: %s
Discord modules: %s
BetterDiscord directory: %s
BetterDiscord asar installed: %s
Discord "index.js" injected: %s
BetterDiscord remote: %s
' "$d_install" "$d_flavor" "$d_modules" "$bd_config" "$asar_install" \
"$index_mod" "$bd_remote_status"
}
bdc_install() {
grep -Fq "$bd_asar_escaped" "$d_core/index.js" && die 'ERROR: Already installed.'
bdc_clean_legacy
bd_remote_install
bd_install
>&2 printf 'Installed. (Restart Discord if necessary.)\n'
}
bdc_reinstall() {
grep -Fq "$bd_asar_name" "$d_core/index.js" || die 'ERROR: Not installed.'
bdc_clean_legacy
bdc_kill
bd_remote_install
bd_install
>&2 printf 'Reinstalled.\n'
}
bdc_uninstall() {
grep -Fq "$bd_asar_name" "$d_core/index.js" || die 'ERROR: Not installed.'
bdc_clean_legacy
bdc_kill
bd_uninstall
>&2 printf 'Uninstalled.\n'
}
bdc_self_upgrade() {
if [[ $DISABLE_SELF_UPGRADE ]]; then
die 'ERROR: Self-upgrading has been disabled.' \
'If you installed this from a package, its maintainer should keep it up to date.'
fi
declare self_upgrade_version semver_diff
self_upgrade_version=$(curl -NLSs "$self_upgrade_url" | sed -n 's/^VERSION=//p')
if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
die "ERROR: The remote script URL couldn't be reached to check the version."
fi
verbose 2 "VV: Local script location: $SOURCE"
verbose 2 "VV: Remote script URL: $self_upgrade_url"
verbose 1 "V: Local version: $VERSION"
verbose 1 "V: Remote version: $self_upgrade_version"
semver_diff=$(Semver::compare "$self_upgrade_version" "$VERSION")
if [[ $semver_diff -eq 1 ]]; then
>&2 printf 'Downloading betterdiscordctl...\n'
if curl -LSso "$SOURCE" "$self_upgrade_url"; then
>&2 printf 'Successfully self-upgraded betterdiscordctl.\n'
else
die 'ERROR: Failed to self-upgrade betterdiscordctl.' \
"You may want to rerun this command with \`sudo\`."
fi
else
if [[ $semver_diff -eq 0 ]]; then
>&2 printf 'betterdiscordctl is already the latest version (%s).\n' \
"$VERSION"
else
>&2 printf 'Local version (%s) is higher than remote version (%s).\n' \
"$VERSION" "$self_upgrade_version"
fi
fi
}
# Implementation functions
bdc_main() {
xdg_discover_config
bdc_discover
d_core=$d_modules/discord_desktop_core
[[ -d $d_core ]] || die "ERROR: Directory 'discord_desktop_core' not found in: $d_modules"
bd_remote_init
bd_asar=$bd_config/data/$bd_asar_name
bd_asar_escaped=${bd_asar/\\/\\\\}
}
xdg_discover_config() {
case "$d_install" in
traditional)
xdg_config=${XDG_CONFIG_HOME:-$HOME/.config}
;;
snap)
# shellcheck disable=SC2016
# Expansion should happen inside snap's shell.
xdg_config=$("$snap_bin" run --shell discord \
<<< $'printf -- \'%s/.config\n\' "$SNAP_USER_DATA" 1>&3' 3>&1)
;;
flatpak)
# shellcheck disable=SC2016
# Expansion should happen inside flatpak's shell.
xdg_config=$("$flatpak_bin" run --command=sh com.discordapp.Discord \
-c $'printf -- \'%s\n\' "$XDG_CONFIG_HOME"')
xdg_config=${xdg_config:-$HOME/.var/app/com.discordapp.Discord/config}
;;
*) die "ERROR: [xdg_discover_config] Unknown Discord install variant: $d_install" ;;
esac
[[ $xdg_config ]] || >&2 printf "WARN: XDG user config directory (\$XDG_CONFIG_HOME) not found.\n"
}
bdc_discover() {
d_discover_config
bd_discover_config
bdc_find_modules
}
bdc_find_modules() {
if [[ $d_modules ]]; then
[[ -d $d_modules ]] || die "ERROR: Discord modules directory not found: $d_modules"
d_flavor=${d_modules%/*/modules}
d_flavor=${d_flavor##*/discord}
else
[[ -d $d_config ]] || die "ERROR: Discord $d_flavor config directory not found: $d_config"
declare -a all_d_modules
all_d_modules=("$d_config/"+([0-9]).+([0-9]).+([0-9])/modules)
((${#all_d_modules[@]})) || die 'ERROR: Discord modules directory not found.' \
'Try specifying it with --d-modules.'
d_modules=${all_d_modules[-1]}
verbose 1 "V: Found modules in $d_modules"
fi
}
bdc_kill() {
>&2 printf 'Killing Discord %s processes...\n' "$d_flavor"
pkill -exi -KILL "discord${d_flavor:0:8}" || >&2 printf 'No active processes found.\n'
}
d_discover_config() {
[[ $xdg_config ]] || die "ERROR: XDG user config directory (\$XDG_CONFIG_HOME) not found."
case "$d_install" in
traditional)
for d_flavor in "${d_flavors[@]}"; do
verbose 2 "VV: Trying flavor '$d_flavor'"
d_config=$xdg_config/discord${d_flavor,,}
if [[ -d $d_config ]]; then
break
fi
>&2 printf 'WARN: Discord %s config directory not found (%s).\n' \
"$d_flavor" "$d_config"
done
;;
snap|flatpak)
d_config=$xdg_config/discord
if [[ ! -d $d_config ]]; then
>&2 printf 'WARN: Discord %s config directory not found (%s).\n' \
"$d_install" "$d_config"
fi
;;
*) die "ERROR: [d_discover_config] Unknown Discord install variant: $d_install" ;;
esac
}
bd_discover_config() {
[[ $xdg_config ]] || die "ERROR: XDG user config directory (\$XDG_CONFIG_HOME) not found."
case "$d_install" in
traditional|snap|flatpak)
bd_config=$xdg_config/BetterDiscord
;;
*) die "ERROR: [bd_discover_config] Unknown Discord install variant: $d_install" ;;
esac
}
# TODO: Integrate $bd_remote into main & install
bd_remote_init() {
case "$bd_remote" in
github) bd_remote_init_github ;;
url) bd_remote_init_url ;;
dir) bd_remote_init_dir ;;
*) die "ERROR: [bd remote init] Unknown remote type: $bd_remote" ;;
esac
verbose 2 "VV: BetterDiscord remote asar path: $bd_remote_asar"
bd_asar_name=${bd_remote_asar##*/}
}
bd_remote_init_github() {
bd_remote_url=https://github.com/$bd_remote_github_owner/$bd_remote_github_repo/releases/$bd_remote_github_release/download
verbose 2 "VV: BetterDiscord remote GitHub repository owner: $bd_remote_github_owner"
verbose 2 "VV: BetterDiscord remote GitHub repository name: $bd_remote_github_repo"
verbose 2 "VV: BetterDiscord remote GitHub repository release: $bd_remote_github_release"
bd_remote_init_url
}
bd_remote_init_url() {
bd_remote_dir=$bd_config/data
verbose 2 "VV: BetterDiscord remote URL: $bd_remote_url"
bd_remote_init_dir
}
bd_remote_init_dir() {
verbose 2 "VV: BetterDiscord remote directory: $bd_remote_dir"
}
bd_remote_install() {
case "$bd_remote" in
github) bd_remote_install_github ;;
url) bd_remote_install_url ;;
dir) bd_remote_install_dir ;;
*) die "ERROR: [bd remote install] Unknown remote type: $bd_remote" ;;
esac
}
bd_remote_install_github() {
verbose 2 "VV: Installing remote BetterDiscord (GitHub)..."
bd_remote_install_url
}
bd_remote_install_url() {
verbose 2 "VV: Installing remote BetterDiscord (URL)..."
verbose 1 "V: Downloading BetterDiscord asar..."
curl -LSso "$bd_remote_dir/$bd_remote_asar" --create-dirs \
"$bd_remote_url/$bd_remote_asar"
bd_remote_install_dir
}
bd_remote_install_dir() {
verbose 2 "VV: Installing remote BetterDiscord (directory)..."
if [[ "$bd_remote_dir/$bd_remote_asar" != "$bd_asar" ]]; then
verbose 1 "V: Copying BetterDiscord asar..."
install -Dm 644 "$bd_remote_dir/$bd_remote_asar" "$bd_asar"
fi
}
bdc_clean_legacy() {
if [[ -d $d_core/core ]]; then
>&2 printf 'Removing legacy core directory...\n'
rm -rf "$d_core/core"
fi
if [[ -d $d_core/injector ]]; then
>&2 printf 'Removing legacy injector directory...\n'
rm -rf "$d_core/injector"
fi
if [[ -d $bdc_data ]]; then
if [[ -f "$bdc_data/bd_map" || -d "$bdc_data/bd" ]]; then
>&2 printf 'Removing legacy machine-specific data...\n'
rm -rf "$bdc_data/bd_map" "$bdc_data/bd"
fi
fi
}
bd_install() {
verbose 1 'V: Injecting into index.js...'
printf $'require("%s");
module.exports = require(\'./core.asar\');
' "$bd_asar_escaped" > "$d_core/index.js"
}
bd_uninstall() {
verbose 1 'V: Removing BetterDiscord injection...'
printf $'module.exports = require(\'./core.asar\');
' > "$d_core/index.js"
}
# Included from https://github.com/bb010g/Semver.sh , under the MIT License.
Semver::validate() {
[[ $1 =~ ^([^+-.]*)\.?([^+-.]*)\.?([^+-]*)(-?)([^+]*)(\+?)(.*)$ ]]
declare -a ver; ver=("${BASH_REMATCH[@]:1}")
if [[ ${ver[0]} != +([0-9]) ]]; then printf '%s\n' "Semver::validate: invalid major: ${ver[0]}" >&2; return 1; fi
if [[ ${ver[1]} != +([0-9]) ]]; then printf '%s\n' "Semver::validate: invalid minor: ${ver[1]}" >&2; return 1; fi
if [[ ${ver[2]} != +([0-9]) ]]; then printf '%s\n' "Semver::validate: invalid patch: ${ver[2]}" >&2; return 1; fi
if [[ ${ver[3]} == '-' && ${ver[4]} != +([0-9A-Za-z-])*(.+([0-9A-Za-z-])) ]]; then
printf '%s\n' "Semver::validate: invalid pre-release: ${ver[4]}" >&2; return 1
fi
if [[ ${ver[5]} == '+' && ${ver[6]} != +([0-9A-Za-z-])*(.+([0-9A-Za-z-])) ]]; then
printf '%s\n' "Semver::validate: invalid build metadata: ${ver[6]}" >&2; return 1
fi
if [[ -n $2 ]]; then
printf '%s\n' "$2=(${ver[0]@Q} ${ver[1]@Q} ${ver[2]@Q} ${ver[4]@Q} ${ver[6]@Q})"
else
printf '%s\n' "$1"
fi
}
Semver::compare() {
declare -a xs ys
eval "$(Semver::validate "$1" xs)"
eval "$(Semver::validate "$2" ys)"
declare i x y
for i in 0 1 2; do
x=${xs[i]}; y=${ys[i]}
if [[ $x -eq $y ]]; then continue; fi
if [[ $x -gt $y ]]; then echo 1; return; fi
if [[ $x -lt $y ]]; then echo -1; return; fi
done
x=${xs[3]}; y=${ys[3]}
if [[ -z $x && -n $y ]]; then echo 1; return; fi
if [[ -n $x && -z $y ]]; then echo -1; return; fi
declare -a x_pre; declare x_len
declare -a y_pre; declare y_len
IFS=. read -ra x_pre <<< "$x."; x_len=${#x_pre[@]}
IFS=. read -ra y_pre <<< "$y."; y_len=${#y_pre[@]}
if (( x_len > y_len )); then echo 1; return; fi
if (( x_len < y_len )); then echo -1; return; fi
for (( i=0; i < x_len; i++ )); do
x=${x_pre[i]}; y=${y_pre[i]}
if [[ $x == "$y" ]]; then continue; fi
if [[ $x == +([0-9]) ]]; then
if [[ $y == +([0-9]) ]]; then
if [[ $x -gt $y ]]; then echo 1; return; fi
if [[ $x -lt $y ]]; then echo -1; return; fi
else echo -1; return; fi
elif [[ $y == +([0-9]) ]]; then echo 1; return
else
if [[ $x > $y ]]; then echo 1; return; fi
if [[ $x < $y ]]; then echo -1; return; fi
fi
done
echo 0
}
# Run command
case "$cmd" in
status)
bdc_main
bdc_status
;;
install)
bdc_main
bdc_install
;;
reinstall)
bdc_main
bdc_reinstall
;;
uninstall)
bdc_main
bdc_uninstall
;;
self-upgrade)
bdc_self_upgrade
;;
*) die "ERROR: Unknown command (in command dispatch): $cmd" ;;
esac