Skip to content

Instantly share code, notes, and snippets.

@Stewie410
Last active June 18, 2024 09:15
Show Gist options
  • Select an option

  • Save Stewie410/a5da07849e57fd264592168679d2d6b9 to your computer and use it in GitHub Desktop.

Select an option

Save Stewie410/a5da07849e57fd264592168679d2d6b9 to your computer and use it in GitHub Desktop.
TheOuterLinux 'bashrc - basic.txt' Overhaul
#!/usr/bin/env bash
# bashtask
alias bashtask='bashtask.sh'
alias taskadd='bashtask --add'
alias taskin='bashtask --insert'
alias taskrm='bashtask --remove'
alias taskcl='bashtask --clear'
alias tasklist='bashtask --print'
# Find out what is taking so much space on your drives
alias diskspace='du --separate-dirs | sort --numeric-sort --reverse | less'
#Create password protected .7z compressed file and hide file-list
#Use as: 7zp "/path/to/output.7z" "/path/to/folder_or_file"
alias 7zp='7z a -bd -bb1 -y -p -mhe=on -mx=7'
# Quickly jump 1-4 directories up
alias ..="cd .."
alias ...="cd ../.."
alias ....="cd ../../.."
alias .....="cd ../../../.."
# Common variations of 'ls' command
alias ll='ls -l'
alias lo='ls -o'
alias lh='ll --human-readable'
alias la='ll --all'
alias sl='ls'
alias l='ls'
alias s='ls'
#Nano for writing and help with spell-checking
alias nano='nano --mouse --unix --constantshow --wordbounds --tabsize=4 --autoindent'
alias writer='nano --fill=85 --smooth'
#The following is for spellchecking SGML/XML-like documents of project
#files. 'Scribus' is a free and open-source desktop publishing program.
alias spellcheck='aspell -c'
alias spellcheckgsml='aspell --lang=en --encoding=utf-8 --mode=sgml --add-sgml-check=ch check'
alias spellcheckxml='spellchecksgml'
alias spellcheckscribus='spellchecksgml'
#Print the last line of all logs within the "/var/log" directory
alias logs='find "/var/log" -type f -exec grep --binary-files="without-match" --quiet "." {} \; -print | xargs tail --follow'
# Git related
alias gs='git status'
alias gc='git commit'
alias ga='git add'
alias gd='git diff'
alias gb='git branch'
alias gl='git log'
alias gsb='git show-branch'
alias gco='git checkout'
alias gg='git grep'
alias gk='gitk --all'
alias gr='git rebase'
alias gri='git rebase --interactive'
alias gcp='git cherry-pick'
alias grm='git rm'
#For when you've spent too much time in DOS
alias cls='clear'
alias dir='ls'
alias deltree='rm --recursive'
alias rmdir='deltree'
alias rd='deltree'
alias rename='mv'
alias cd..='cd ..'
alias chdir='pwd'
alias cmd='bash'
alias erase='rm'
alias del='rm'
alias delete='rm'
alias expand='extract'
alias tasklist='htop'
alias tracert='traceroute'
#Expand current directory structure in tree form
alias treed='tree -R'
#Uses 'nmap' to scan all of the connected devices on your router
#You may need to change the '192.168.0.*' part to better match how your
#router gives addresses. This will most likely not give you hostnames,
#only MAC addresses.
alias lanscan='sudo nmap -sn 192.168.0.*'
#Use one of the following for when the boss comes around to look busy...
#But remember, as mentioned before, the /dev/urandom may cause some
#serious slow-down issues on older/lighter hardware.
alias busy='hexdump -C "/dev/urandom" | grep "ca fe"'
#Print last value returned from previous command
alias lastvalue='printf "%s\n" "$?"'
#Create a randomized playlist for audio and video recursively
#
# Usage: playlist > playlist.m3u
#
alias playlist='find -D tree . | sort --random-sort --random-source="/dev/urandom"'
#Optimize mpv for playing just about anything without having to think
#too much; 720p is chosen because of older hardware
alias mpv='mpv --vo=opengl,x11,drm,tct,caca --ao=pulse,alsa,jack --user-agent="Mozilla" --ytdl-format="best[ext=mp4][height<=?720]"'
#Nerd humor; use 'zardoz' instead of 'sudo'
alias zardoz='sudo'
#Day-mode...Ooooh aaaAAAh! Enemy of the nightmode... Ooooh aaaAAAh!
#Use daymode/nightmode to toggle the a red screen tint on/off for doing
#things such as Astronomy.
alias daymode='xgamma -gamma 1'
alias nightmode='xgamma -rgamma 1 -ggamma 0.3 -bgamma 0.3'
#Quickly open a color picker using 'GPick' that copies clicked color to
#the clipboard. Though, you could argue that it isn't much of a shortcut
#based on text length...
alias cgrab='gpick --pick'
#Grab audio only from YouTube
# Usage: yta-mp3 https://youtube.com/watch?v=???????????
#
# You could also replace youtube-dl with 'yt-dlp' as they both more or
# less use the same arguments.
#
alias yta-aac='youtube-dl --extract-audio --audio-format aac'
alias yta-best='youtube-dl --extract-audio --audio-format best'
alias yta-flac='youtube-dl --extract-audio --audio-format flac'
alias yta-m4a='youtube-dl --extract-audio --audio-format m4a'
alias yta-mp3='youtube-dl --extract-audio --audio-format mp3'
alias yta-opus='youtube-dl --extract-audio --audio-format opus'
alias yta-vorbis='youtube-dl --extract-audio --audio-format vorbis'
alias yta-wav='youtube-dl --extract-audio --audio-format wav'
#Grab the highest quality of video+audio from YouTube
alias ytv-best='youtube-dl -f bestvideo+bestaudio'
#Because I got tired of typing 'w3m https://duckduckgo.com'...
alias ddg='w3m duckduckgo.com'
#Add some flags to some basic commands that probably should be default
#The aliases below with '--interactive' refer to asking for confirmation before
#doing things with files; rm needs to have three or more files or have
#the '--recursive' flag involved before asking for confirmation to delete.
alias cp='cp --interactive'
alias mv='mv --interactive'
alias rm='rm --interactive'
alias ln='ln --interactive'
alias df='df --human-readable'
alias free='free --mebi'
alias mkdir='mkdir --parents --verbose'
# Some 'ps' command aliases...
alias psa='ps auxf'
alias psgrep='pgrep --full --list-full'
alias psmem='ps auxf | sort --numeric-sort --reverse --key="4"'
alias pscpu='ps auxf | sort --numeric-sort --reverse --key="3"'
#Have the 'mocp' command-line music player use the nightly_theme
#Default themes are located within "/usr/share/moc/themes/"
alias mocp='mocp --theme "nightly_theme"'
#Converting audio and video files using ffmpeg and eyeD3
#(sudo pip install eyeD3). Album art is removed in the '2ogg' function
#because if you are using ogg, you probably either do not need it or
#want to save as much space as possible. The '2voc' is very useful when
#dealing with DOOM WADS or certain DOS software. If you need to cancel a
#conversion that uses FFmpeg, use CTRL+C as 'q' will still delete the
#original and then leave you with a partially converted file. If you
#hate the idea of deleting the original file, remove the '&& rm "$1"'
#parts at the end.
#
# Usage example: 2ogg '/path/to/file.ext'
#
alias ff-conv='media_convert.sh --delete'
alias 2ogg='ff-conv --remove-images --format ogg'
alias 2wav='ff-conv --format wav'
alias 2opus='ff-conv --format opus'
alias 2aif='ff-conv --format aif'
alias 2mp3='ff-conv --format mp3'
alias 2mov='ff-conv --format mov'
alias 2mp4='ff-conv --format mp4'
alias 2avi='ff-conv --format avi'
alias 2webm='ff-conv --format webm'
alias 2h265='ff-conv --format h265'
alias 2flv='ff-conv --format flv'
alias 2mpg='ff-conv --format mpg'
alias 2doswav8='ff-conv --format doswav --eight'
alias 2doswav11='ff-conv --format doswav'
alias 2doswav='2doswav11'
alias 2voc8='ff-conv --format voc --eight'
alias 2voc11='ff-conv --format voc'
alias 2voc='2voc11'
#The following are for converting a video to a DVD-ready MPEG format
#for faster use with DVD creation programs. Use the "sub" versions
#below to permanently overlay subtitles (*.srt) onto the video. The
#output is automatically handled for you by placing the file in the same
#directory with the same name but with "_NTSC" or "_PAL" appended to the
#end. The original is deleted when finished so make shure to use Ctrl+c
#if canceling the conversion to prevent deleting the original as
#previously mentioned in the above other "2[format]" video conversions.
#
# Normal usage example: 2mpgNTSC input.ext
# Usage for subtitle overlay example: 2mpgNTSCsub input.srt input.ext
#
alias 2mpgNTSC='ff-conv --format mpg --ntsc'
alias 2mpgNTSCsub='2mpgNTSC --subtitles'
alias 2mpgPAL='ff-conv --format mpg --pal'
alias 2mpgPALsub='2mpgPAL --subtitles'
#Converting documents and images using pandoc
#
# Usage example: 2pdf '/path/to/file.html'
# Usage example: 2pdf '/path/to/file.html' '/path/to/file.pdf'
#
alias p-conv='office_convert.sh --delete'
alias 2txt='p-conv --format txt'
alias 2pdf='p-conv --format pdf'
alias 2doc='p-conv --format doc'
alias 2odt='p-conv --format odt'
#Convert images using ImageMagick
#
# Usage example: 2jpg '/path/to/image.ext'
#
alias im-conv='image_convert.sh --delete'
alias 2pcx='im-conv --format pcx'
alias 2lbm='im-conv --format ilbm'
alias 2jpg='im-conv --format jpg'
alias 2jpeg='2jpg'
alias 2png='im-conv --format png'
alias 2png8='im-conv --format png8'
alias 2bmp='im-conv --format bmp'
alias 2dosbmp='im-conv --format dosbmp'
alias 2dosgif='im-conv --format dosgif'
alias 2tiff='im-conv --format tiff'
alias 2ico='im-conv --format ico'
#Quickly use QEMU, if installed, to boot a 64-bit, i686/i586, or i486
#operating system from an ISO
alias bootiso='qemu_boot.sh'
alias boot32='bootiso --i686'
alias boot486='bootiso --i486'
#Potentially lower an image's file size using ImageMagick by lowering
#the amount of colors, using dithering, increasing contrast, etc...
#
# Usage: optimg '/path/to/image.ext'
#
alias optimg='im-conv --optimize'
#Potentially lower a PDF's file size using Ghostscript
#
# Usage: optpdf '/path/to/file.pdf'
#
alias optpdf='ff-conv --optimize'
alias optpdf72='ff-conv --optimize --dpi 72'
alias optpdf96='ff-conv --optimize --dpi 96'
alias optpdf300='ff-conv --optimize --dpi 300'
#Convert a PDF to a different version; pdfto11 = 1.1; pdfto12 = 1.2; etc...
#
# Usage Example: pdfto13 input.pdf output.pdf
#
alias pdfto11='pdf_version.sh --version "1.1"'
alias pdfto12='pdf_version.sh --version "1.2"'
alias pdfto13='pdf_version.sh --version "1.3"'
alias pdfto14='pdf_version.sh --version "1.4"'
alias pdfto15='pdf_version.sh --version "1.5"'
alias pdfto16='pdf_version.sh --version "1.6"'
alias pdfto17='pdf_version.sh --version "1.7"'
alias pdfto20='pdf_version.sh --version "2.0"'
#Append line numbers to the beginning of each line
#
# Usage: addlinenumbers '/path/to/file.txt'
# Make permanent: addlinenumbers input.txt | tee output.txt
#
alias addlinenumbers='nl --number-format="ln"'
#Use webcam as a timelapse camera
alias timelapse='timelapse.sh'
# Internet speed test using speedtest-cli
alias int-speed='speedtest'
#Zip all files in current directory INDEpendently from each other; in
#other words, each file gets its own zip.
#
# Usage: cd /path/to/directory && indezip
#
alias indezip='independent_zip.sh'
#Zip all files in current directory independently from each other AND
#delete the originals when finished.
#
# Usage: cd /path/to/directory && indeziprm
#
alias indeziprm='indezip --delete'
#Get the mime information (file-type) of a file
#For example, a plain text file would have 'text/plain' as the mime
#
# Usage: mime /path/to/file.ext
#
alias mime='file --mime-type'
#Convert a bunch of PNG's or JPEG's to video.
#I have two separate functions for JPG and JPEGs, even
#though they are the same format. Someone out there may be taking
#advantage of this and have JPGs that "stand for" one thing and then use
#the JPEG extension for some other purpose.
#
# Usage example B: cd /path/to/PNG/directory && png2video [framerate] output.mp4
# Usage example C: cd /path/to/JPG/directory && jpg2video [framerate] output.mp4
# Usage example D: cd /path/to/JPEG/directory && jpeg2video [framerate] output.mp4
#
alias png2video='stitch_frames.sh --format "png"'
alias jpg2video='stitch_frames.sh --format "jpg"'
alias jpeg2video='stitch_frames.sh --format "jpeg"'
#Use wget to download everything listed within a plain-text file
#
# Usage: grablist /path/to/URL_List.txt
#
alias grablist='wget --continue --content-disposition --trust-server-names -i'
#Use this to grap all of the files with the "$2" extension recursively
#from a website, or at least the sensible ones that let you crawl around
#in directories.
#
# Example: dlext "*.mp3" https://exmaple.org
#
alias dlext='wget --recursive --no-parent --level="1" --accept'
#Use this to grab all of the ZIP files recursively from a website
alias dlzips='dlext "*.zip"'
#!/usr/bin/env bash
# Generate a psuedo-random password
# Though, I cannot stress this enough: use a dedicated tool, like:
# - pwgen
# - bw
# - keepassxc
genpasswd() {
if [[ "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help]"
return 0
fi
local pw
pw="$(LC_ALL="C" tr \
--delete \
--complement \
"A-Za-z0-9!\"#$%&'()*+,-./:;<>=?@[\]^_\`{|}~" < "/dev/urandom" | \
head --bytes="30" \
)"
printf '%s\n' "${pw}"
}
#Create a .7z compressed file; though, I am not saying '7z a...' is not
#easy enough to do but for some people, maybe not because of putting
#the output file before the input.
#Use as: 7zip "/path/to/folder_or_file" "/path/to/output.7z"
7zip() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [OPTIONS] SOURCE [DESTINATION]"
return 0
fi
7z a \
-t7z \
-m0=lzma \
-mx=9 \
-mfb=64 \
-md=32m \
-ms=on \
-mhe=on \
"${2:-${1##*/}.7z}" "${1}"
}
# Move 'up' so many directories instead of using several cd ../../, etc.
# Use as: up #
up() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] NUM"
return 0
fi
local path
path="$(printf '../%.0s' $(seq 1 "${1}"))"
cd "$(realpath "${path}")" && pwd
}
#List people in a Twitch channel chat
twitch_list() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] CHANNEL"
return 0
fi
curl \
--silent \
--fail \
--location \
"https://tmi.twitch.tv/group/user/${1}/chatters"
}
function spell() { echo "$1" | aspell -a; }
# Print a word from a certain column of the output when piping.
# Example: cat /path/to/file.txt | fawk 2
# This example prints every 2nd word on each line of file.txt
fawk() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] NUM"
return 0
fi
awk --assign "idx=${1}" '{print $idx}'
}
# 'cd' to the most recently modified directory in $PWD
cl() {
if [[ "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help]"
return 0
fi
local last_dir
last_dir="$(find "${PWD}" -mindepth 1 -maxdepth 1 -type d -printf '%T@ %p\n' 2>/dev/null | \
sort --numeric-sort --reverse | \
cut --fields="2-" --delimiter=" " | \
sed 1q \
)"
cd "${last_dir}" || return 1
}
# Directory bookmarking (one at a time)
remember_directory() {
local opts action bufhome buf
opts="$(getopt \
--options hlg \
--longoptions help,list,goto \
--name "${FUNCNAME[0]}" \
-- "${@}" \
)"
action="save"
bufhome="${XDG_STATE_HOME:-${HOME}/.cache}/${FUNCNAME[0]}"
eval set -- "${opts}"
while true; do
case "${1}" in
-h | --help )
cat << EOF
Save current directory to numbered "buffers", or move to a previously saved directory
USAGE: ${FUNCNAME[0]} [OPTIONS] NUM
-h, --help Show this help message
-l, --list List all directories stored in current buffers
-g, --goto Move to directory saved in buffer NUM
EOF
return 0
;;
-l | --list ) action="list";;
-g | --goto ) action="goto";;
-- ) shift; break;;
* ) break;;
esac
shift
done
if [[ "${action}" != "list" && -z "${1}" ]]; then
printf '%s\n' "No buffer specified" >&2
return 1
fi
mkdir --parents "${bufhome}"
case "${action}" in
list )
while read -r buf; do
printf '%s: %s\n' "${buf##*/}" "$(< "${buf}")"
done < <(find "${bufhome}" -type f | sort --numeric-sort)
;;
goto )
cd "$(< "${bufhome}/${1}")" || return 1
;;
* )
printf '%s\n' "${PWD}" > "${bufhome}/${1}"
;;
esac
return 0
}
rd() {
remember_directory "${@}"
}
crd() {
remember_directory --goto "${@}"
}
# 'cd' into a directory and then list contents
cdls() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] PATH"
return 0
fi
cd "${1}" && ls "${1}"
}
#For when you've spent too much time in DOS
edit() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] FILE"
return 0
fi
nano \
--mouse \
--unix \
--constantshow \
--breaklonglines \
--linenumbers \
--tabsize="4" \
--file="72" \
--atblanks \
--autoindent \
"${1}" || return
sed -i'' 's/\n/\r\n/g' "${1}"
}
diskcopy() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] SOURCE DESTINATION"
return 0
fi
if [[ -z "${2}" ]]; then
printf '%s\n' "No destination specified" >&2
return 1
fi
if ! [[ -b "${1}" ]]; then
printf '%s\n' "Source is not a block device: '${1}'" >&2
return 1
fi
if ! [[ -b "${2}" ]]; then
printf '%s\n' "Destination is not a block device: '${2}'" >&2
return 1
fi
dd if="${1}" of="${2}"
}
#List directories by in order of size in current directory
sbs() {
if [[ -n "${1}" ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help]"
return 0
fi
du --human-readable --max-depth "1" 2>/dev/null | \
sort --reverse --human-numeric-sort --key="1"
}
#Kill any lingering SSH processes
sshkill() {
if [[ -n "${1}" ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help]"
return 0
fi
killall --quiet "ssh"
}
#Rough function to display the number of unread emails in your gmail;
#HOWEVER, I am Google-free these days, so I have no idea if this still
#works...
#
# Usage: gmail [user name]
#
gmail() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} EMAIL"
return 0
fi
curl --user "${1}" --silent 'https://mail.google.com/mail/feed/atom' | \
sed 's|</fullcount.*|\n|;s|.*fullcount>||'
}
#Use one of the following for when the boss comes around to look busy...
#But remember, as mentioned before, the /dev/urandom may cause some
#serious slow-down issues on older/lighter hardware.
busytext() {
if [[ -n "${1}" ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help]"
return 0
fi
while true; do
head "/dev/urandom" | \
tr --delete --complement 'A-Za-z0-9'
sleep '0.15'
done
}
#If input is a video, convert use '2gif' to created an animated
#(89a) GIF; otherwise, use ImageMagick to create a still (87a) GIF.
#
# Usage example: 2gif '/path/to/image/or/video.ext'
#
2gif() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) || ! -s "${1}" ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] INPUT [OUTPUT]"
return 0
fi
if file --mime "${1}" | grep --quiet "image"; then
image_convert --delete --format "gif" "${@}" || return 1
else
media_convert --delete --format "gif" "${@}" || return 1
fi
return 0
}
#Tonvid is a YouTube frontend and this helps for when copy/paste text
#isn't possible as you only need to type the video ID.
#
# Usage: tonvid [video ID]
#
tonvid() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] TONVID_ID"
return 0
fi
if ! command -v "mpv" &>/dev/null; then
printf '%s\n' "Missing required application: 'mpv'" >&2
return 1
fi
mpv \
--vo='opengl,x11,drm,tct,caca' \
--ao='pulse,alsa' \
--ytdl-format='[ext=mp4][height<=?720]' \
"https://tonvid.com/info.php?video_id=${1}"
}
#Grab a pretty ascii forecast picture for anywhere; without arguments,
#uses ISP location to print your weather. Example: weather New York, NY
weather() {
if [[ "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] [QUERY]"
curl --silent "wttr.in/:help"
return 0
fi
curl --silent "wttr.in/${*}"
}
#Grab weather information from USAirNet and have a pretty Wttr.in ascii
#output. Example: weather 02118 boston
weatherus() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]] || (( $# < 2 )); then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] ZIPCODE CITYNAME"
return 0
fi
if ! command -v "w3m" &>/dev/null; then
printf '%s\n' "Missing required application: 'w3m'" >&2
return 1
fi
# *Surely* there's an RSS feed or something to provide better results
# without relying on w3m's plain-text dump...
w3m -M -dump "http://www.usairnet.com/weather/forecast/local/?pands=${1}" | \
grep --after-context="10" --color="never" "${2^^}"
printf "\n"
weather "${2}"
}
#Convert hex data file to a binary
function hex2bin() {
if [[ "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] [HEXFILE]"
return 0
fi
if ! command -v 'xxd' &>/dev/null; then
printf '%s\n' "Missing required application: 'xxd'" >&2
return 1
fi
xxd --revert --plain "${1:-/dev/stdin}"
}
#Or, if you have a live stream's full URL (use with Twitch, YouTube,
#etc.)... Usage: stream https://examplestreamservice.tv/user
stream() {
local i
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] URL"
return 0
fi
for i in 'mpv' 'yt-dlp'; do
command -v "${i}" &>/dev/null && continue
printf '%s\n' "Missing required application: '${i}'" >&2
return 1
done
mpv "${1}"
}
#Play Twitch streams with MPV in GUI or TTY
#
# Usage: twitch username
# You may have to add "1080p" to the function if for whatever
# reason the stream does not have a 720p or lower option; keeping
# it low helps on older/lighter hardware.
# Use 'sudo pip install streamlink' to install 'streamlink'.
#
twitch() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] CHANNEL"
return 0
fi
stream "https://twitch.tv/${1}"
}
#Play just about anything web related that youtube-dl supports
#You can also replace 'youtube-dl' with 'yt-dlp'
webplay() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] URL"
return 0
fi
if ! command -v "mpv" &>/dev/null; then
printf '%s\n' "Missing required application: 'mpv'" >&2
return 1
fi
mpv "${1}"
}
webplayer() {
webplay "${@}"
}
# Get last viewed/attempted video from Kodi logfile
get_last_kodi() {
awk '
/mp4/ {
video = gensub(/^([^\|]+?).*$/, "\\1", 1, $0)
}
END {
print video
}
' "${HOME}/.kodi/temp/kodi.log"
}
#Play last viewed, or attempted to view video from Kodi using mpv; may
#not work due to CDNs (Content Delivery Networks).
mpvkodi() {
if [[ -n "${1}" ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help]"
return 0
fi
if ! command -v 'mpv' &>/dev/null; then
printf '%s\n' "Missing required application: 'mpv'" >&2
return 1
fi
mpv "$(get_last_kodi)"
}
#If playback on Kodi is slow, download last viewed, or attempted to view
#video using axel; may not work do to CDNs (Content Delivery Networks).
axelkodi() {
if [[ -n "${1}" ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help]"
return 0
fi
if ! command -v 'kodi' &>/dev/null; then
printf '%s\n' "Missing required application: 'kodi'" >&2
return 1
fi
axel --num-connections="10" "$(get_last_kodi)"
}
#Do a fuzzy search using 'fzy' for an installed program in the
#"/usr/share/applications/" and "$HOME/.local/share/applications"
#directories and run it; you can replace the 'fzy' with 'fzf' if it is
#installed. Also, you may have to replace 'xdg-open' with 'exo-open'.
#If nothing is selected and 'CTRL+C' is used to exit, 'xdg-open' and
#'exo-open' will print the --help; it is what it is.
appsearch() {
local i
if [[ -n "${1}" ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help]"
return 0
fi
for i in 'fzy' 'xdg-open'; do
command -v "${i}" &>/dev/null && continue
printf '%s\n' "Missing required application: '${i}'" >&2
return 1
done
find "/usr/share/applications" "${XDG_DATA_HOME:-${HOME}/.local/share}/applications" -type f 2>/dev/null | \
fzy | \
xargs -I {} xdg-open "{}"
}
run() {
appsearch "${@}"
}
#Use curl and "https://cht.sh/" to quickly search how to do things
#Examples: 'howin html do I view an image'
# 'howin python do I add numbers'
howin() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} LANG QUERY"
return 0
fi
local lang
lang="${1}"
shift
curl "https://cheat.sh/${lang}/${*}"
}
#Create comma-separated, single-quoted, lists from multi-line output
# Usage example: cat '/path/to/multi-lineList.txt' | commalist
function commalist() {
if [[ "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] [FILE [...]]"
return 0
fi
sed "s/^/'/;s/$/'/" "${@:-/dev/stdin}" | \
paste --serial --delimiter="," | \
sed 's/,/, /g'
}
#Use the following functions to create an encrypted PDF from all of the
#the images in the current directory. Start with 'img2pdfenc' and if
#you get an "Invalid" error, use the 'img2pdfcheck' function to go
#through each image and print the file-names associated with the error
#as 'img2pdf' annoying does not do this for you; echo "$i" helps; the
#'img2pdfcheck' function will take a long time if you have a lot of
#images; it uses a FOR-LOOP, so it does not check recursively. If you
#already have a PDF you want to encrypt, run the 'pdf2enc' function.
#
# Usage Example: img2pdfenc output.pdf
# Usage Example: pdf2enc input.pdf output.pdf
# Usage Example: pdf2decrypt input.pdf output.pdf
#
img2pdfenc() {
local stage
local -a images
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [PDF]"
return 0
fi
if ! command -v 'convert' &>/dev/null; then
printf '%s\n' "Missing required application: 'convert'" >&2
return 1
fi
mapfile -t images < <(find "${PWD}" -type f -iname "*.jpg" -printf '%p\n' 2>/dev/null)
if (( ${#images} == 0 )); then
printf '%s\n' "No jpegs in current path" >&2
return 1
fi
stage="$(mktemp --tmpdir="/tmp" "tmp.XXXXXXXXXXXX.pdf")"
if ! convert "${images[@]}" "${stage}"; then
printf '%s\n' "Failed to merge images into PDF: './*.jpg' !> '${stage}'" >&2
rm --force "${stage}"
return 1
fi
if ! pdf2enc "${stage}" "${1:-${PWD}/${PWD##*/}.enc.pdf}"; then
printf '%s\n' "Failed to created encrypted PDF: '${_}'" >&2
rm --force "${stage}"
return 1
fi
rm --force "${stage}"
return 0
}
pdf2enc() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} INPUT OUTPUT"
return 0
fi
if ! command -v 'pdftk' &>/dev/null; then
printf '%s\n' "Missing required application: 'pdftk'" >&2
return 1
fi
pdftk "${1}" output "${2}" user_pw PROMPT
}
pdf2decrypt() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} INPUT OUTPUT"
return 0
fi
if ! command -v 'pdftk' &>/dev/null; then
printf '%s\n' "Missing required application: 'pdftk'" >&2
return 1
fi
pdftk "${1}" input_pw PROMPT output "${2}"
}
#Potentially lower an animated GIF's (89a) file size using gifsicle
#
# Usage: optgif input.gif output.gif
#
function optgif() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] INPUT [OUTPUT]"
return 0
fi
if ! command -v 'gifsicle' &>/dev/null; then
printf '%s\n' "Missing required application: 'gifsicle'" >&2
return 1
fi
gifsicle \
--interlace "${1}" \
--optimize="3" \
--output "${2:-${1%.*}.optimized.gif}"
}
#Displaying a #hex or rgb(#,#,#) color using ImageMagick; this is so you
#do not have to do an Internet search or open a heavy program just to
#find out what the color looks like. Do not forget the quotes.
#
# Usage HEX: dispcolor '#hex'
# Usage RGB: dispcolor 'rgb(#,#,#)'
#
displaycolor() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf "USAGE: ${FUNCNAME[0]} [-h|--help] %s\n" '#RRGGBB' 'rgb(R,G,B)'
return 0
fi
if ! command -v 'display' &>/dev/null; then
printf '%s\n' "Missing required application: 'display'" >&2
return 1
fi
display -size '300x300' "xc:${1}"
}
dispcolor() {
displaycolor "${@}"
}
#If you are encrypting/decrypting files using OpenSSL...
#
# Usage encrypt: encrypt normalFile.ext encryptedFile.enc public.key
# Usage decrypt: decrypt encryptedFile.enc private.key
#
encrypt() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] INFILE OUTFILE PUBKEY"
return 0
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "Input file is empty or does not exist: '${1}'" >&2
return 1
fi
if ! command -v 'openssl' &>/dev/null; then
printf '%s\n' "Missing required application: 'openssl'" >&2
return 1
fi
openssl smime \
-encrypt \
-binary \
-aes-256-cbc \
-in "${1}" \
-out "${2}" \
-outform "DEM" \
"${3}"
}
decrypt() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] FILE PRIVKEY"
return 0
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "Input file is empty or does not exist: '${1}'" >&2
return 1
fi
if ! command -v 'openssl' &>/dev/null; then
printf '%s\n' "Missing required application: 'openssl'" >&2
return 1
fi
openssl smime \
-decrypt \
-in "${1}" \
-binary \
-inform "DEM" \
-inkey "${2}"
}
#Sorts out unique lines
#
# Usage: unique '/path/to/file.txt'
#
unique() {
awk '!seen[$0]++'
}
#Grab a copy of an entire website or starting from whichever URL you use
#in place of "$1". It doesn't always work 100% of the time and do not
#get made at me if a server bands you for using it.
#
# Usage: grabindex https://example.org
#
grabindex() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} URL [OUTDIR]"
return 0
fi
if ! command -v 'wget' &>/dev/null; then
printf '%s\n' "missing required application: 'wget'" >&2
return 1
fi
[[ -n "${2}" ]] && mkdir --parents "${2}"
wget \
--mirror \
--convert-links \
--no-verbose \
--no-host-directories \
--no-clobber \
--page-requisites \
--html-extension \
--no-parent \
--reject-regex '\?' \
--restrict-file-names="windows" \
--execute "robots=off" \
--directory-prefix="${2:-${PWD}}"
"${@}"
}
#Use 'axel' download accelorator with youtube-dl to grab YouTube videos
#
# Usage: axelyt https://youtube.com/watch?v=???????????
#
#HOWEVER, instead, you may want to consider using 'yt-dlp'
#
axelyt() {
local i
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] VIDEOID"
return 0
fi
for i in 'yt-dlp' 'axel'; do
command -v "${i}" &>/dev/null && continue
printf '%s\n' "Missing required application: '${i}'" >&2
return 1
done
yt-dlp \
--continue \
--ignore-errors \
--user-agent "Mozilla" \
--downloader "axel" \
--downloader-args "axel:--num-connections 10" \
"${1}"
}
#Lists URLs that start with 'http' or 'https' on a webpage using lynx
#
# Usage: listurls https://example.org
#
listurls() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] URL"
return 0
fi
if ! command -v 'lynx' &>/dev/null; then
printf '%s\n' "Missing required application: 'lynx'" >&2
return 1
fi
lynx -dump -listonly -image_links -nonumbers "${@}" | \
sed --quiet '/http/p'
}
#Download "nicely embedded" images from a site page; this function does
#not work if lynx gives JS errors. Or, you can use 'gallery-dl' via
#'sudo pip install gallery-dl' for more complex sites.
#
# Usage: grabimg https://example.org
#
grabimg() {
local i
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] URL"
return 0
fi
for i in 'lynx' 'wget'; do
command -v "${i}" &>/dev/null && continue
printf '%s\n' "Missing required application: '${i}'" >&2
return 1
done
# based on: https://stackoverflow.com/a/71550235
lisurls "${@}" | \
awk --assign "ORS=\000" '/\.(jpg|png)$/'
xargs -0 wget --no-verbose
}
#Use this as a way to get nano to create a text file that is a bit more
#DOS-friendly. Make sure your file name has no spaces and is only 8
#characters long and does not have more than 3 characters for the file-
#extension.
#
# Usage doswrite /path/to/new/file.txt
#
doswrite() {
local fname ext
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] FILE"
return 0
fi
if ! command -v 'nano' &>/dev/null; then
printf '%s\n' "Missing required application: 'nano'" >&2
return 1
fi
fname="$(basename "${1%%.*}")"
ext="${1##*.}"
if (( ${#fname} > 8 )); then
printf '%s\n' "Filename must be 8 characters or less: '${1##*/}'" >&2
return 1
fi
if (( ${#ext} > 3 )); then
printf '%s\n' "Extension must be 3 characters or less: '${1##*/}'" >&2
return 1
fi
nano \
--mouse \
--unix \
--constantshow \
--breaklonglines \
--linenumbers \
--tabsize="4" \
--fill="72" \
--atblanks \
--autoindent \
"${1}" || return
sed -i'' 's/\n/\r\n/' "${1}"
}
#Mount a raw image (IMG) file containing an installation of FreeDOS
#
# Usage: fdsomount '/path/to/fdos.img' '/path/to/mount/point'
#
dosmount() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] IMG MOUNT"
return 0
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "Image file is empty or does not exist: '${1}'" >&2
return 1
fi
if [[ -z "${2}" ]]; then
printf '%s\n' "No mount point specified" >&2
return 1
fi
sudo mkdir --parents "${2}"
sudo mount --options "loop,offset=32256" "${@}"
}
#Look for files within current directory and all sub directories that
#were modified between two dates
#
# Usage: cd /path/to/directory && findbetween yesterday
# Usage: cd /path/to/directory && findbetween "2 weeks ago" "1 week ago"
#
findbetween() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] DATE1 [DATE2]"
return 0
fi
find "${PWD}" \
-type f \
-newermt "$(date --date="${1}" --iso-8601)" \
! -newermt "$(date --date="${2:-today}" --iso-8601)"
}
#Convert an image to a 10 second MP4 video
#
# Usage: img2vid 'input.jpg' 640 480 'output.mp4'
#
#The numbers above are for WxH in pixels
img2vid() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] IMG X Y [MP4]"
return 0
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "Image file is empty or does not exist: '${1}'" >&2
return 1
elif ! file --mime "${1}" | grep --quiet "image"; then
printf '%s\n' "File is not an image: '${1}'" >&2
return 1
fi
if [[ -z "${2}" ]]; then
printf '%s\n' "Must include a X value for scaling" >&2
return 1
elif [[ "${2}" =~ [^0-9.\-] ]]; then
printf '%s\n' "X value contains invalid characters: '${2}'" >&2
return 1
fi
if [[ -z "${3}" ]]; then
printf '%s\n' "Must include a Y value for scaling" >&2
return 1
elif [[ "${3}" =~ [^0-9.\-] ]]; then
printf '%s\n' "Y value contains invalid characters: '${3}'" >&2
return 1
fi
if ! command -v 'ffmpeg' &>/dev/null; then
printf '%s\n' "Missing required application: 'ffmpeg'" >&2
return 1
fi
ffmpeg \
-hide_banner \
-threads "0" \
-loop "1" \
-i "${1}" \
-c:v 'libx264' \
-t 10 \
-pix_fmt 'yuv420p' \
-vf "scale=${2}:${3}" \
"${4:-${1%.*}.mp4}"
}
#Merge video and audio together; replaces current audio if it exists
#
# Usage: avmerge 'video.ext' 'audio.ext' [output.ext]
#
function avmerge() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} VIDEO AUDIO [OUTFILE]"
return 0
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "Video file is empty or does not exist: '${1}'" >&2
return 1
fi
if [[ -z "${2}" ]]; then
printf '%s\n' "No audio file specified" >&2
return 1
elif ! [[ -s "${2}" ]]; then
printf '%s\n' "Audio file is empty or does not exist: '${2}'" >&2
return 1
fi
if ! command -v 'ffmpeg' &>/dev/null; then
printf '%s\n' "Missing required application: 'ffmpeg'" >&2
return 1
fi
ffmpeg \
-hide_banner \
-threads "0" \
-i "${1}" \
-i "${2}" \
-map "0:v" \
-map "1:a" \
-c:v "copy" \
-shortest \
"${3:-${1%/*}/$(date '+%F-%H-%M-%S').mp4}"
}
#Add an image (album cover) to an MP3 using ffmpeg
#
# Usage: addimage '/path/to/image.jpg' '/path/to/audio.mp3'
#
addimage() {
local stage
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} IMAGE MP3"
return 0
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "Image file is empty or does not exist: '${1}'" >&2
return 1
elif ! file --mime "${1}" | grep --quiet "image"; then
printf '%s\n' "Image file is not an image: '${1}'" >&2
return 1
fi
if [[ -z "${2}" ]]; then
printf '%s\n' "No MP3 file specified" >&2
return 1
elif ! file --mime "${2}" | grep --quiet 'audio/mpeg'; then
printf '%s\n' "Audio file is not an MP3: '${2}'" >&2
return 1
fi
if ! command -v 'ffmpeg' &>/dev/null; then
printf '%s\n' "Missing required application: 'ffmpeg'" >&2
return 1
fi
stage="$(mktempt --tmpdir="/tmp" "tmp.XXXXXXXXXXX.mp3")"
ffmpeg \
-i "${2}" \
-i "${1}" \
-map "0:0" \
-map "1:0" \
-c "copy" \
-id3v2_version "3" \
-metadata:s:v "title=Album cover" \
-metadata:s:v "comment=Cover (front)" \
"${stage}" && mv --force "${stage}" "${2}" && return 0
rm --force "${stage}"
return 1
}
#Copy the contents of a CD-ROM to an ISO if /dev/sr0 is your device,
#to which is usually the case for external disc drives.
#
# Usage: cpcd output.iso
#
cpcd() {
local dev bs i
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] ISO"
return 0
fi
dev="$(blkid | sed --quiet '/iso9660' | sed '1q')"
if [[ -z "${dev}" ]]; then
printf '%s\n' "Cannot locate CD-ROM" >&2
return 1
fi
dev="${dev%%:*}"
for i in "isoinfo" "isosize"; do
command -v "${i}" &>/dev/null && continue
printf '%s\n' "Missing required application: '${i}'" >&2
return 1
done
isinfo -di "${dev}" || return
bs="2048"
dd \
if="${dev}" \
of="${1}" \
bs="${bs}" \
count="$(isosize -d "${bs}" "${dev}" 2>/dev/null)" \
status="progress"
}
#Move up by a number of specified directories
function up(){
local i path
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] NUM"
return 0
elif [[ "${1}" =~ [^0-9] ]]; then
printf '%s\n' "Invalid number format: '${1}'" >&2
return 1
fi
for (( i = 0; i < ${1}; i++ )); do
path+="../"
done
cd "$(realpath "${path:-${PWD}}")" || return
}
#Create an empty audio file for n amount of seconds.
#This is useful for DVD authoring software (DevedeNG, DVD Styler, etc.)
#in which you need an audio layer for menus, even if it is an empty one;
#some older DVD players and game consoles notice when this is missing
#and may create a short (or long) "chirp" noise during certain menus,
#especially those with background video or animated chapter selection.
#Sometimes these menus are loopable but only loop based on whether the
#video layer or audio layer, if separate, have the smallest amount of
#time. Hopefully this makes sense.
#
#Usage: emptyaudio seconds output.mp3
#
emptyaudio() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] LENGTH MP3"
return 0
elif [[ "${1}" =~ [^0-9\.] ]]; then
printf '%s\n' "Invalid length: '${1}'" >&2
return 1
elif [[ -z "${2}" ]]; then
printf '%s\n' "No MP3 file specified" >&2
return 1
fi
if ! command -v 'ffmpeg' &>/dev/null; then
printf '%s\n' "Missing required application: 'ffmpeg'" >&2
return 1
fi
ffmpeg \
-hide_banner \
-threads "0" \
-ar "48000" \
-t "${1}" \
-f "s16le" \
-i "/dev/zero" \
"${2}"
}
#This function lists the most used commands and how many times in a simplistic way
top-history() {
tr '|' "\n" < "${HOME}/.bash_history" | \
awk '
{
seen[$1]++
}
END {
for (i in seen)
print seen[i] " " i
}
' | \
sort --numeric-sort --reverse | \
head -10 | \
column -t
}
#Convert a video to a bunch of JPEG's
#
# Usage example: video2jpg /path/to/video.mp4 [framerate]
#
video2jpg() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} [-h|--help] MP4 FPS [OUTDIR]"
return 0
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "Input file is empty or does not exist: '${1}'" >&2
return 1
elif ! file --mime "${1}" | grep --quiet 'video/mp4'; then
printf '%s\n' "Input file is not an MP4: '${1}'" >&2
return 1
elif [[ -z "${2}" ]]; then
printf '%s\n' "No framerate specified" >&2
return 1
elif [[ "${2}" =~ [^0-9.] ]]; then
printf '%s\n' "Invalid FPS Amount: '${2}'" >&2
return 1
fi
if ! command -v 'ffmpeg' &>/dev/null; then
printf '%s\n' "Missing required application: 'ffmpeg'" >&2
return 1
fi
ffmpeg \
-hide_banner \
-threads "0" \
-i "${1}" \
-r "${2}" \
"${3:-${1%/*}}/$(basename "${1%.*}")_%05d.jpg"
}
#Use this to send random numbers to the clipboard every five seconds; it
#is very useful if selectively saving a bunch of long-named files from a
#website but could care less about the name of the files. Just use
#CTRL+v like usual in the SAVE-AS area of the file-saving dialog to
#paste the number. I guess it could also help with those paranoid about
#certain software having clipboard access, though I have no idea why
#anyone would voluntarily run that sort of thing.
randomclip() {
local -a clip
clip=('xsel' '--clipboard')
if uname --kernel-release | grep --quiet "microsoft.*WSL"; then
clip=('clip.exe')
elif [[ "${XDG_SESSION_TYPE,,}" != "x11" ]]; then
clip=('wl-copy')
fi
if ! command -v "${clip[0]}" &>/dev/null; then
printf '%s\n' "Cannot locate clipboard command: '${clip[0]}'" >&2
return 1
fi
while true; do
"${clip[@]}" <<< "${RANDOM}"
sleep 5
done
}
#Need a simple espeak timer? Values can be things like 10s, 30m, 1h.
#However, because of how simplistic this is, you cannot combine times so
#if you need something like "1h 30m," then you need to use "90m"
#instead, without the quotes. The second argument will need quotes.
#
# Example: espeaktimer 30m "Go check your oven!"
#
espeaktimer() {
local i
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf '%s\n' "USAGE: ${FUNCNAME[0]} TIME TEXT"
return 0
fi
for i in 'at' 'espeak'; do
command -v "${i}" &>/dev/null && continue
printf '%s\n' "Missing required application: '${i}'" >&2
return 1
done
at "${1}" <<< "espeak '${2}'"
}
#I did not like how the 'ebook-convert' program from 'Calibre' converts
#comic books to whatever with automatic grayscale, especially when the
#CBR or CBZ file in question is not a typical comic and is full-color.
#
# Usage: ebook-convert-cbz input.cb[r,z] output.ext
#
ebook_convert_cbz() {
if [[ -z "${1}" || "${1}" =~ -(h|-help) ]]; then
printf "USAGE: ${FUNCNAME[0]} %s OUTFILE\n" "CBR" "CBZ"
return 0
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "Input file is empty or does not exist: '${1}'" >&2
return 1
elif [[ -z "${2}" ]]; then
printf '%s\n' "No output file specified" >&2
return 1
fi
if ! command -v 'ebook-convert' &>/dev/null; then
printf '%s\n' "Missing required application: 'ebook-convert'" >&2
return 1
fi
ebook-convert \
"${1}" \
"${2}" \
--dont-grayscale \
--dont-normalize \
--no-process
}
#!/usr/bin/env bash
export PATH="${PATH}:${HOME}/scripts"
# Add color in manpages for less
export LESS_TERMCAP_mb=$'\E[01;31m'
export LESS_TERMCAP_md=$'\E[01;31m'
export LESS_TERMCAP_me=$'\E[0m'
export LESS_TERMCAP_se=$'\E[0m'
export LESS_TERMCAP_so=$'\E[01;44;33m'
export LESS_TERMCAP_ue=$'\E[0m'
export LESS_TERMCAP_us=$'\E[01;32m'
# Colors for all grep commands such as grep, egrep and zgrep
export GREP_OPTIONS='--color=auto'
# Tasklist prompt, sorta
bashtask.sh --init &>/dev/null
bashtask.sh --print
[[ -s "${HOME}/.bash_functions" ]] && source "${HOME}/.bash_functions"
[[ -s "${HOME}/.bash_aliases" ]] && source "${HOME}/.bash_aliases"
#!/usr/bin/env bash
#
# Simple todo-list
show_help() {
cat << EOF
Simple todo-list
USAGE: ${0##*/} [OPTIONS] TASK
OPTIONS:
-h, --help Show this help message
-a, --add Add TASK to end of the list (default)
-i, --insert POS Insert TASK at line POS
-r, --remove POS Remove TASK at line POS
-x, --clear Remove all tasks in list
-p, --print Show all tasks
--init Initialize tasklist and exit
ENVIRONMENT:
The BASHTASK_FILE variable can be set to specify a custom location of the
tasklist. By default '\$XDG_CONFIG_HOME/bashtask/list'
EOF
}
_header() {
local red blue nc
red="$(tput setaf 1)"
blue="$(tput setaf 4)"
nc="$(tput sgr0)"
if [[ -s "${tasklist}" ]]; then
printf '%s\n\n' "${red}Task List${nc} as of ${blue}$(date --referece="${tasklist}")${nc}"
print_list
else
printf '%s\n' "Yay! No tasks :)"
fi
printf '%80s\n' " " | tr ' ' "-"
}
print_list() {
sed 's/^/- /' "${tasklist}"
}
main() {
local opts tasklist action position
opts="$(getopt \
--options haxpi:r: \
--longoptions "help,add,clear,print,insert:,remove:,init" \
--name "${0##*/}" \
-- "${@}" \
)"
action="add"
tasklist="${XDG_CONFIG_HOME:-${HOME}/.config}/bashtask/list"
tasklist="${BASHTASK_FILE:-${tasklist}}"
eval set -- "${opts}"
while true; do
case "${1}" in
-h | --help ) show_help; return 0;;
-a | --add ) action="add";;
-i | --insert ) action="ins"; position="${2}"; shift;;
-r | --remove ) action="del"; position="${2}"; shift;;
-x | --clear ) action="cls";;
-p | --print ) action="cat";;
--init ) action="init";;
-- ) shift; break;;
* ) break;;
esac
shift
done
mkdir --parents "${tasklist%/*}"
touch -a "${tasklist}"
[[ "${action}" == "init" ]] && return 0
if [[ "${action}" =~ (add|ins) && -z "${1}" ]]; then
printf '%s\n' "Task not specified" >&2
return 1
fi
case "${action}" in
add )
printf '%s\n' "${1}" >> "${tasklist}"
;;
ins )
if ! sed -i'' "${position}i${1}" "${tasklist}"; then
printf '%s\n' "Failed to insert task" >&2
return 1
fi
;;
del )
if ! sed -i'' "${position}d" "${tasklist}"; then
printf '%s\n' "Failed to delete task" >&2
return 1
fi
;;
cls )
touch "${tasklist}"
;;
cat )
print_list
;;
esac
return 0
}
main "${@}"
#!/usr/bin/env bash
#
# Easy way to extract archives
show_help() {
cat << EOF
Easy way to extract archives
USAGE: ${0##*/} [OPTIONS] FILE1 ...
OPTIONS:
-h, --help Show this help message
EOF
}
main() {
local opts err
opts="$(getopt \
--options h \
--longoptions help \
--name "${0##*/}" \
-- "${@}" \
)"
eval set -- "${opts}"
while true; do
case "${1}" in
-h | --help ) show_help; return 0;;
-- ) shift; break;;
* ) break;;
esac
shift
done
while [[ -n "${1}" ]]; do
if ! [[ -s "${1}" ]]; then
printf '%s\n' "File does not exist or is empty: '${1}'" >&2
err="1"
shift
continue
fi
case "${1,,}" in
*.tar* )
case "${1#*tar.}" in
bz2 ) tar --extract --verbose --bzip2 --file="${1}";;
tgz ) tar --extract --verbose --gzip --file="${1}";;
Z ) tar --extract --verbose --compress --file="${1}";;
zst ) tar --extract --verbose --zstd --file="${1}";;
* ) tar --extract --verbose --file="${1}";;
esac
;;
*.bz2 )
bunzip2 "${1}"
;;
*.rar )
unrar x "${1}"
;;
*.gz )
gunzip "${1}"
;;
*.zip )
unzip "${1}"
;;
*.Z )
uncompress "${1}"
;;
*.zst )
zstd --uncompress "${1}"
;;
*.7z )
7z x "${1}"
;;
* )
printf '%s\n' "Unknown archive type: '${1}'" >&2
err="1"
;;
esac
shift
done
return "${err:-0}"
}
main "${@}"
#!/usr/bin/env bash
#
# Convert images using ImageMagick
show_help() {
cat << EOF
Convert images using ImageMagick
USAGE: ${0##*/} [OPTIONS] INPUT [OUTPUT]
OPTIONS:
-h, --help Show this help message
-x, --delete Remove the source file after conversion
-f, --format FMT Convert INPUT to FMT
-o, --optimize Optmize INPUT's filesize
FORMAT:
pcx ZSoft IBM PC Paintbrush
ppm Portable pixmap
ilbm Amiga Interchange File Format (requires 'ppmtoilbm')
jpg JPEG
png PNG
png8 8-bit PNG
bmp Microsoft Windows Bitmap v4
bmp2 Microsoft Windows Bitmap v2
bmp3 Microsoft Windows Bitmap v3
dosbmp DOS-compliant Bitmap
dosgif DOS-compliant GIF
tif Tagged Image File
ico Microsoft Icon
gif Graphics Interchange Format
EOF
}
require() {
command -v "${1}" &>/dev/null && return
printf '%s\n' "Missing required application: '${1}'" >&2
return 1
}
mktemp_img() {
mktemp --tempdir="/tmp" "tmp.XXXXXXXXXXXX.${1}"
}
get_extension() {
local fmt
case "${format,,}" in
ilbm ) fmt="lbm";;
png8 ) fmt="png";;
dosbmp ) fmt="dos.bmp";;
dosgif ) fmt="dos.gif";;
* ) fmt="${format,,}";;
esac
printf '%s\n' "${fmt}"
}
im_conv() {
local -a argv
local stage
case "${format,,}" in
dosbmp )
argv+=("${1}" '-colors' '16' '-depth' '4' '-dither' 'none')
argv+=('resize' '640x480' "BMP3:${2}")
;;
dosgif )
argv+=("${1}" '-colors' '256' '-dither' 'none' '-resize' '320x200!')
argv+=("GIF87:${2}")
;;
gif )
argv+=("${1}" "GIF87:${2}")
;;
ico )
argv+=('-background' 'transparent' "${1}")
argv+=('-define' 'icon:auto-resize=16,32,48,64,128' "${2}")
;;
ilbm )
require 'ppm2toilbm' || return 1
stage="$(mktemp_imp 'ppm')"
convert -colors 4 -depth 2 -resize '320x200' "${1}" "${stage}" || return
# Unsure what options are needed to replicate 'pictview' conversion
ppm2ilbm "${stage}" > "${2}"
return
;;
pcx )
argv=("${1}" '-colors' '256' "${2}")
;;
png8 )
stage="$(mktemp_img 'png8')"
convert "${1}" "${stage}" || return
mv --force "${stage}" "${2}"
return
;;
* )
argv+=("${1}" "${2}")
;;
esac
convert "${argv[@]}"
}
optimize() {
[[ "${1#*.}" =~ i?lbm ]] && return 1
convert "${1}" \
-dither "FloydSteinberg" \
-colors "256" \
-morphology "Thicken:0.5" "3x1+0+0:1,0,0" \
-remap "netscape:" \
-ordered-dither "o8x8,6" +contrast \
"${1%%.*}_optimize_${1#*.}"
}
main() {
local opts del format optimize
opts="$(getopt \
--options hxf:o \
--longoptions help,delete,format:,optimize \
--name "${0##*/}" \
-- "${@}" \
)"
eval set -- "${opts}"
while true; do
case "${1}" in
-h | --help ) show_help; return 0;;
-x | --delete ) del="1";;
-f | --format ) format="${2}"; shift;;
-o | --optimize ) optimize="1";;
-- ) shift; break;;
* ) break;;
esac
shift
done
if [[ -z "${1}" ]]; then
printf '%s\n' "No input file specified" >&2
return 1
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "Input file is empty or does not exist: '${1}'" >&2
return 1
fi
require "convert" || return
( [[ "${format,,}" == "ilbm" ]] && require "ppmtoilbm" ) || return
if [[ -n "${format}" ]]; then
im_conv "${1}" "${2:-${1%.*}.$(get_extension)}" || return
[[ -n "${optimize}" ]] && optimize "${_}" || return
elif [[ -n "${optimize}" ]]; then
optimize "${1}" || return
else
printf '%s\n' "Format/Optimize action not specified" >&2
return 1
fi
[[ -n "${del}" ]] && rm --force "${1}"
return 0
}
main "${@}"
#!/usr/bin/env bash
#
# Independently zip each file in a given directory
show_help() {
cat << EOF
Independently zip each file in a given directory
USAGE: ${0##*/} [OPTIONS] [DIR]
OPTIONS:
-h, --help Show this help message
-x, --delete Remove original file after successful zipping
EOF
}
require() {
command -v "${1}" &>/dev/null && return
printf '%s\n' "Missing required application: '${1}'" >&2
return 1
}
find_files() {
find "${1}" \
-maxdepth 1 \
-type f \
! -iname '*.zip' \
-printf '%p\n'
}
main() {
local opts del f
opts="$(getopt \
--options hx \
--longoptions help,delete \
--name "${0##*/}" \
-- "${@}" \
)"
eval set -- "${opts}"
while true; do
case "${1}" in
-h | --help ) show_help; return 0;;
-x | --delete ) del="1";;
-- ) shift; break;;
* ) break;;
esac
shift
done
if ! [[ -d "${1:-${PWD}}" ]]; then
printf '%s\n' "Cannot locate directory: '${1}'" >&2
return 1
fi
require 'zip' || return 1
while read -r f; do
if ! zip "${f%.*}.zip" "${f}"; then
printf '%s\n' "Failed to zip file: '${f}'" >&2
continue
fi
[[ -n "${del}" ]] && rm --force "${f}"
done < <(find_files "${1:-${PWD}}")
return 0
}
main "${@}"
#!/usr/bin/env bash
#
# Convert media files using ffmpeg, eyed3 & sox
show_help() {
cat << EOF
Convert media files using ffmpeg & eyeD3
USAGE: ${0##*/} [OPTIONS] FILE [DESTINATION]
OPTIONS:
-h, --help Show this help message
-I, --remove-images Remove all images in file
-x, --delete Remove original file after conversion
-8, --eight Use 8K for sample rate on supported formats (see FORMAT)
-f, --format FMT Convert FILE to FMT (see FORMAT)
-n, --ntsc Convert to NTSC-DVD-ready format
-p, --pal Convert to PAL-DVD-ready format
-s, --subtitles SRT Include subtitles SRT file in output
FORMAT:
ogg Vorbis/ogg
wav Wave
doswav DOS-compatible Wave (11K, 8K with -8)
voc PlayVoc (11K, 8K with -8)
opus Opus/ogg
aif Audio Interchange Format
mp3 MP3
mov Apple Quicktime
mp4 MPEG-4
avi Audio Video Interleve
webm WebM
h265 H265 MPEG-4
flv Flash Video
mpg MPEG
gif Graphics Interchange Format
EOF
}
require() {
command -v "${1}" &>/dev/null && return 0
printf '%s\n' "Missing required application: '${1}'" >&2
return 1
}
is_valid_format() {
[[ "${1}" =~ (ogg|(dos)?wav|voc|opus|a(if|vi)|m(p[34g]|ov)|webm|h265|flv) ]]
}
get_extension() {
local fmt
case "${format}" in
doswav ) fmt="dos.wav";;
h265 ) fmt="h265.mp4";;
mpg )
fmt="${format}"
[[ -n "${dvd}" ]] && fmt="${dvd%-*}.${fmt}"
;;
esac
printf '%s\n' "${fmt:-${format}}"
}
remove_images() {
eyeD3 --remove-all-images "${1}"
}
ff_conv() {
local -a argv
argv=('-hide_banner' '-threads' '0' '-i' "${1}")
case "${format}" in
ogg )
argv+=('-c:a' 'libvorbis' '-b:a' "${samplereate}")
;;
doswav | voc )
argv+=('-c:a' 'pcm_u8' '-b:a' "${samplerate}" '-ac' '1')
;;
opus )
argv+=('-c:a' 'libopus' '-b:a' '2K' '-vbr' 'off' '-ac' '1')
;;
webm )
argv+=('-c:v' 'libvpx')
;;
h265 )
argv+=('-c:v' 'libx265')
;;
mpg )
if [[ -n "${dvd}" ]]; then
argv+=('-i' "${1}" '-map' '1:0' '-map' '0:1' '-y')
if [[ -n "${subtitles}" ]]; then
argv+=('-vf' "subtitles=${subtitles// /\\ }")
fi
argv+=('-target' "${dvd}" '-sn' '-g' '12' '-bf' '2')
argv+=('-strict' '1' '-ac' '2' '-aspect' '4/3' '-trellis' '0')
argv+=('-mbd' '0' '-b:a' '224K' '-b:v' '9000K')
argv+=('-passlogfile' "${2}" '-pass' '1')
fi
;;
gif )
argv+=('-vf' 'fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse')
argv+=('-loop' '0')
;;
esac
ffmpeg "${argv[@]}" "${2}"
}
main() {
local opts format rmimg samplerate del dvd subtitles
opts="$(getopt \
--options hIx8f:nps: \
--longoptions help,remove-images,delete,eight,format:,ntsc,pal,subtitles: \
--name "${0##*/}" \
-- "${@}" \
)"
samplerate="11K"
eval set -- "${opts}"
while true; do
case "${1}" in
-h | --help ) show_help; return 0;;
-I | --remove-images ) rmimg="1";;
-x | --delete ) del="1";;
-8 | --eight ) samplerate="8K";;
-f | --format ) format="${2}"; shift;;
-n | --ntsc ) dvd="ntsc-dvd";;
-p | --pal ) dvd="pal";;
-s | --subtitles ) subtitles="${2}";;
-- ) shift; break;;
* ) break;;
esac
shift
done
require 'ffmpeg' || return 1
if [[ -z "${1}" ]]; then
printf '%s\n' "No input file specified" >&2
return 1
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "Input file does not exist or is empty: '${1}'" >&2
return 1
fi
if [[ -z "${format}" ]]; then
printf '%s\n' "No format specified" >&2
return 1
elif ! is_valid_format "${format}"; then
printf '%s\n' "Invalid format: '${format}'" >&2
return 1
fi
if [[ -n "${subtitles}" ]]; then
if ! [[ "${subtitles,,}" =~ \.srt$ ]]; then
printf '%s\n' "Invalid subtitles format: '${subtitles}'" >&2
return 1
elif ! [[ -s "${subtitles}" ]]; then
printf '%s\n' "Subtitles file does not exist or is empty" >&2
return 1
fi
fi
if [[ -n "${rmimg}" ]]; then
require 'eyeD3' || return 1
printf '%s\n' "Removing album art..."
remove_images "${1}"
fi
ff_conv "${1}" "${2:-${1%.*}.$(get_extension)}"|| return
[[ -n "${del}" ]] && rm --force "${1}"
}
main "${@}"
#!/usr/bin/env bash
#
# Convert office documents with pandoc
show_help() {
cat << EOF
Convert office documents with pandoc
USAGE: ${0##*/} [OPTIONS] INPUT [OUTPUT]
OPTIONS:
-h, --help Show this help message
-x, --delete Remove original file after successful operation
-f, --format FMT Convert INPUT to FMT format
-o, --optimize Optimize file size (PDF only)
-p, --dpi DPI Set PDF's resolution to DPI (default: 96)
EOF
}
require() {
command -v "${1}" &>/dev/null && return
printf '%s\n' "Missing required application: '${1}'" >&2
return 1
}
optimize() {
pandoc \
--standalone \
--dpi="${dpi}" \
"${1}" \
--output="${2}"
}
main() {
local opts format optimize dpi outfile del
opts="$(getopt \
--options hxf:op: \
--longoptions help,delete,format:,optimize,dpi: \
--name "${0##*/}" \
-- "${@}" \
)"
dpi="96"
eval set -- "${opts}"
while true; do
case "${1}" in
-h | --help ) show_help; return 0;;
-x | --delete ) del="1";;
-f | --format ) format="${2}"; shift;;
-o | --optimize ) optimize="1";;
-p | --dpi ) dpi="${2}";;
-- ) shift; break;;
* ) break;;
esac
shift
done
require 'pandoc' || return 1
if [[ -z "${1}" ]]; then
printf '%s\n' "No input file specified: '${1}'" >&2
return 1
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "Input file is empty or does not exist: '${1}'" >&2
return 1
fi
outfile="${2:-${1%.*}.${format,,}}"
if [[ -n "${format}" ]]; then
pandoc --standalone "${1}" --output="${outfile}" || return 1
if [[ -n "${optimize}" && "${format,,}" == "pdf" ]]; then
optimize "${outfile}" || return 1
fi
elif [[ -n "${optimize}" && "${1%.*}" == "pdf" ]]; then
optimize "${outfile%.*}.${dpi}.pdf" || return 1
else
printf '%s\n' "No Conversion/Optimization action aspecified" >&2
return 1
fi
[[ -n "${del}" ]] && rm --force "${1}"
return 0
}
main "${@}"
#!/usr/bin/env bash
#
# Set the PDF Compatability Version
show_help() {
cat << EOF
Set the PDF Compatability Version
USAGE: ${0##*/} [OPTIONS] INPUT [OUTPUT]
OPTIONS:
-h, --help Show this help message
-x, --delete Remove the original file after successful conversion
-v, --version VERSION Set the PDF compatabiliy to VERSION (default: 2.0)
EOF
}
main() {
local opts ver
opts="$(getopt \
--options hxv: \
--longoptions help,delete,version: \
--name "${0##*/}" \
-- "${@}" \
)"
ver="2.0"
eval set -- "${opts}"
while true; do
case "${1}" in
-h | --help ) show_help; return 0;;
-x | --delete ) del="1";;
-v | --version ) ver="${2}"; shift;;
-- ) shift; break;;
* ) break;;
esac
shift
done
if [[ -z "${1}" ]]; then
printf '%s\n' "No input file specified" >&2
return 1
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "Input file is empty or does not exist: '${1}'" >&2
return 1
fi
if ! command -v 'gs' &>/dev/null; then
printf '%s\n' "Missing required application: 'gs'" >&2
return 1
fi
if ! [[ "${ver}" == *.* ]]; then
printf '%s\n' "Invalid PDF Version: '${ver}'" >&2
return 1
fi
gs \
-dNOPAUSE \
-dBATCH \
-sDEVICE="pdfwrite" \
-dCompatibilityLevel="${ver}" \
-sOutputFile="${2:-${1%.*}.${ver//\./_}.pdf}" \
"${1}" || return
[[ -n "${del}" ]] && rm --force "${1}"
return 0
}
main "${@}"
#!/usr/bin/env bash
#
# Quckly boot an ISO with QEMU
show_help() {
cat << EOF
Quckly boot an ISO with QEMU
USAGE: ${0##*/} [OPTIONS] ISO
OPTIONS:
-h, --help Show this help message
-f, --file PATH Add disk-image from PATH
-m, --memory MEM Specify maxmimum memory in human-readable SI units (default: 2M)
-6, --i686 Boot an i586/i686 ISO
-4, --i486 Boot an i486 ISO
EOF
}
qemu_boot() {
local -a argv
argv=('-cdrom' "${1}" '-boot' 'd' '-m' "${mem}")
[[ -n "${hda}" ]] && argv+=('-hda' "${hda}")
case "${type}" in
64 ) qemu-system-x86_64 "${argv[@]}";;
686 ) qemu-system-i386 "${argv[@]}";;
486 ) qemu-system-i386 -cpu '486' "${argv[@]}";;
esac
}
main() {
local opts mem hda type i
opts="$(getopt \
--options h64f:m: \
--longoptions help,i686,i486,file:,memory: \
--name "${0##*/}" \
-- "${@}" \
)"
type="64"
mem="2M"
eval set -- "${opts}"
while true; do
case "${1}" in
-h | --help ) show_help; return 0;;
-f | --file ) hda="${2}"; shift;;
-m | --memory ) mem="${2}"; shift;;
-6 | --i686 ) type="686";;
-4 | --i486 ) type="486";;
-- ) shift; break;;
* ) break;;
esac
shift
done
for i in "x86_64" "i386"; do
command -v "qemu-system-${i}" &>/dev/null && continue
printf '%s\n' "Missing required application: '${_}'" >&2
return 1
done
if [[ -z "${1}" ]]; then
printf '%s\n' "No ISO specified" >&2
return 1
elif ! [[ -s "${1}" ]]; then
printf '%s\n' "ISO file is empty or does not exist: '${1}'" >&2
return 1
fi
qemu_boot "${1}"
}
main "${@}"
#!/usr/bin/env bash
#
# Combine all of an image type in a directory into a MP4 video
show_help() {
cat << EOF
Combine all of an image type in a directory into a MP4 video
USAGE: ${0##*/} [OPTIONS] FPS [MP4]
OPTIONS:
-h, --help Show this help message
-x, --delete Remove images after successful stitching
-f, --format FMT Search for images matching FMT (default: png)
-p, --path PATH Search for images in PATH (default: PWD)
EOF
}
require() {
command -v "${1}" &>/dev/null && return
printf '%s\n' "Missing required application: '${1}'" >&2
return 1
}
stitch() {
ffmpeg \
-hide_banner \
-threads "0" \
-framerate "${1}" \
-pattern_type "glob" \
-i "${path}/*.${format}" \
-r "${1}" \
"${2}"
}
main() {
local opts format
opts="$(getopt \
--options hxf:p: \
--longoptions help,delete,format:,path: \
--name "${0##*/}" \
-- "${@}" \
)"
format="png"
path="${PWD}"
eval set -- "${opts}"
while true; do
case "${1}" in
-h | --help ) show_help; return 0;;
-f | --format ) format="${2}";;
-p | --path ) path="${2}";;
-x | --delete ) del="1";;
-- ) shift; break;;
* ) break;;
esac
shift
done
if [[ -z "${1}" ]]; then
printf '%s\n' "No framerate specified" >&2
return 1
elif [[ "${1}" =~ [^0-9.] ]]; then
printf '%s\n' "Invalid FPS format: '${1}'" >&2
return 1
fi
if ! [[ -d "${path}" ]]; then
printf '%s\n' "Cannot locate directory: '${path}'" >&2
return 1
fi
require 'ffmpeg' || return
stitch "${1}" "${2:-${PWD}/stitch.mp4}" || return
[[ -n "${del}" ]] && find "${path}" -type f -name "*.${format}" -delete
return 0
}
main "${@}"
#!/usr/bin/env bash
#
# Use webcam as a timelapse camera
show_help() {
cat << EOF
Use webcam as a timelapse camera
USAGE: ${0##*/} [OPTIONS]
OPTIONS:
-h, --help Show this help message
-c, --camera DEV Use DEV as camera (default: '${settings['device']}')
-d, --delay NUM Wait NUM seconds before capturing another frame (default: '${defaults['delay']}')
-f, --font FILE Use font FILE for text rendering (default: '${defaults['font']}')
-o, --outdir DIR Save frames to DIR (default: '${defaults['outdir']}')
OUTDIR:
The output directory can also be set with the TIMELAPSE_DIR environment
variable. Additionally, -o will override the current TIMELAPSE_DIR value
for that run.
EOF
}
require() {
command -v "${1}" &>/dev/null && return
printf '%s\n' "Missing required application: '${1}'" >&2
return 1
}
capture() {
ffmpeg \
-y \
-hide_banner \
-err_detect 'ignore_err' \
-threads '0' \
-f 'video4linux2' \
-s '640x480' \
-i "${settings['device']}" \
-vf "drawtext=fontfile=${settings['font']}:text=%{localtime\:%T}:x=20:y=20:fontcolor=white" \
-vframes "1" \
"${settings['outdir']}/$(date '+%F-%H-%M').jpg"
}
main() {
local -A defaults settings
local opts i
opts="$(getopt \
--options hc:d:f:o: \
--longoptions help,camera:,delay:,font:,outdir: \
--name "${0##*/}" \
-- "${@}" \
)"
defaults['device']="/dev/video0"
defaults['delay']="30"
defaults['font']="/usr/share/fonts/truetype/dejavu/DeJaVuSansMono"
defaults['outdir']="${TIMELAPSE_DIR:-${HOME}/.timelapse/$(date '+%F')}"
for i in "${!defaults[@]}"; do settings["${i}"]="${defaults[$i]}"; done
eval set -- "${opts}"
while true; do
case "${1}" in
-h | --help ) show_help; return 0;;
-c | --camera ) settings['device']="${2}"; shift;;
-d | --delay ) settings['delay']="${2}"; shift;;
-f | --font ) settings['font']="${2}"; shift;;
-o | --outdir ) settings['outdir']="${2}"; shift;;
-- ) shift; break;;
* ) break;;
esac
shift
done
if ! [[ -e "${settings['device']}" ]]; then
printf '%s\n' "Cannot locate camera: '${settings['device']}'" >&2
return 1
fi
if ! [[ -s "${settings['font']}" ]]; then
printf '%s\n' "Font file does not exist or is empty: '${settings['font']}'" >&2
return 1
fi
if (( settings['delay'] <= 0 )); then
printf '%s\n' "Delay must be greater than 0 seconds" >&2
return 1
fi
require 'ffmpeg' || return 1
mkdir --parents "${settings['outdir']}"
capture
while true; do
sleep "${settings['delay']}"
capture
done
}
main "${@}"
#!/usr/bin/env bash
#
# Translate text with translate.google.com
show_help() {
cat << EOF
Translate text with translate.google.com
USAGE: ${0##*/} [OPTIONS] LANG TEXT [...]
OPTIONS:
-h, --help Show this help message
-l, --list Show a list of valid ISO 639-1 language codes
EOF
}
urlencode() {
xxd -plain <<< "${1}" | sed 's/\(..\)/%\1/g'
}
get_codes() {
curl \
--silent \
--fail \
'https://pkgstore.datahub.io/core/language-codes/language-codes_csv/data/b65af208b52970a4683fa8fde9af8e9f/language-codes_csv.csv'
}
get_uri() {
local lang
lang="${1}"
shift
printf 'http://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=%s&dt=t&q=%s\n' \
"${lang}" \
"$(urlencode "${*}")"
}
main() {
local opts codes
opts="$(getopt \
--options hl \
--longoptions help,list \
--name "${0##*/}" \
-- "${@}" \
)"
codes="${XDG_DATA_HOME:-${HOME}/.local/share}/translate/codes.csv"
eval set -- "${opts}"
while true; do
case "${1}" in
-h | --help ) show_help; return 0;;
-l | --list ) list="1";;
-- ) shift; break;;
* ) break;;
esac
shift
done
if [[ -n "${list}" ]]; then
if ! [[ -s "${codes}" ]]; then
mkdir --parents "${codes%/*}"
get_codes > "${codes}"
fi
sed '1d;s/,/\t/;s/"//g' "${codes}" | column
return
fi
if [[ -z "${1}" ]]; then
printf '%s\n' "No language/text specified" >&2
return 1
elif [[ "${1}" != "${1:0:2}" ]]; then
printf '%s\n' "Invalid language code: '${1}'" >&2
return 1
fi
get_uri "${@}" | \
xargs -I {} curl --silent --fail "{}" 2>/dev/null | \
jq --monochrome-output '.[0][0][0]' | \
sed 's/^"\|"$//g'
}
main "${@}"
@Stewie410
Copy link
Author

This was a first-pass rewrite of TheOuterLinux's bashrc file, which was posted to reddit 3 days ago.

The goal here was to both see if I could learn anything (which I did, thankfully); and to maybe provide an idea to TOL of what my previous feedback would look like...

Its still far from ideal in many ways; but I think it can still be helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment