Skip to content

Instantly share code, notes, and snippets.

@ncfavier
Last active August 18, 2020 22:59
Show Gist options
  • Save ncfavier/55c20a77a3fd72e00407f8889fc6e852 to your computer and use it in GitHub Desktop.
Save ncfavier/55c20a77a3fd72e00407f8889fc6e852 to your computer and use it in GitHub Desktop.
Syncplay<->IRC bridge
#!/usr/bin/env bash
# dependencies: bash 4+, jq
. ./config.sh
: "${verbose:=0}"
: "${syncplay_host:=syncplay.pl}"
: "${syncplay_port:=8999}"
: "${syncplay_nick:=syncplaybridge}"
: "${syncplay_room:?"can't be empty"}"
: "${irc_host:=chat.freenode.net}"
: "${irc_port:=6667}"
: "${irc_nick:=syncplaybridge}"
: "${irc_channel:?"can't be empty"}"
irc_send() {
local args=("$@")
args[0]=${args[0]^^}
if (( ${#args[@]} > 1 )); then
args[${#args[@]}-1]=:${args[${#args[@]}-1]}
fi
printf '%s\r\n' "${args[*]}" >&"$irc_fd"
(( verbose )) && printf 'IRC %s==>%s %s\n' "$(tput setaf 1)" "$(tput sgr0)" "${args[*]}" >&2
}
irc_say() {
irc_send privmsg "$irc_channel" "$*"
}
irc_ctcp() {
local args=("$@")
args[0]=${args[0]^^}
irc_send notice "$sender_nick" $'\1'"${args[*]}"$'\1'
}
syncplay_send() {
local msg=$(jq -nc "$@")
printf '%s\r\n' "$msg" >&"$syncplay_fd"
(( verbose )) && printf 'syncplay %s==>%s %s\n' "$(tput setaf 1)" "$(tput sgr0)" "$msg" >&2
}
syncplay_say() {
syncplay_send --arg message "$*" '{Chat: $message}'
}
on_exit() {
irc_send quit
kill $(jobs -p)
}
exec {irc_fd}<> /dev/tcp/"$irc_host"/"$irc_port" || exit
exec {syncplay_fd}<> /dev/tcp/"$syncplay_host"/"$syncplay_port" || exit
trap on_exit exit
irc_send nick "$irc_nick"
irc_send user "$irc_nick" 0 '*' 'Syncplay<->IRC'
syncplay_send --arg username "$syncplay_nick" --arg room "$syncplay_room" \
'{Hello: {$username, room: {name: $room}, realversion: "1.6.5"}}'
while read -ru "$irc_fd" line; do
line=${line%$'\r'}
(( verbose )) && printf 'IRC %s<==%s %s\n' "$(tput setaf 2)" "$(tput sgr0)" "$line" >&2
sender= sender_nick=
args=()
if [[ $line == :* ]]; then
sender=${line%% *}
sender=${sender#:}
sender_nick=${sender%%!*}
line=${line#* }
fi
while [[ $line == *' '* && $line != :* ]]; do
args+=("${line%% *}")
line=${line#* }
done
args+=("${line#:}")
cmd=${args[0]}
set -- "${args[@]:1}"
case ${cmd,,} in
001) irc_send join "$irc_channel";;
ping) irc_send pong "$1";;
privmsg)
target=$1
message=$2
if [[ $target == "$irc_nick" ]] && [[ $message =~ ^$'\1'(.*)$'\1'$ ]]; then
message=${BASH_REMATCH[1]}
read -r ctcp_cmd _ <<< "$message"
case ${ctcp_cmd,,} in
version) irc_ctcp version "syncplaybridge";;
esac
elif [[ $target == "$irc_channel" ]]; then
if [[ $message =~ ^$'\1ACTION '(.*)$'\1'$ ]]; then
syncplay_say "* $sender_nick ${BASH_REMATCH[1]}"
else
syncplay_say "<$sender_nick> $2"
fi
fi
esac
done &
while read -ru "$syncplay_fd" line; do
line=${line%$'\r'}
(( verbose )) && printf 'syncplay %s<==%s %s\n' "$(tput setaf 2)" "$(tput sgr0)" "$line" >&2
. <(jq <<< "$line" -r --arg self "$syncplay_nick" '
def irc($msg): @sh "irc_say \($msg)";
(.State // empty
| @sh "syncplay_send \"{State: {}}\""),
(.Chat // empty
| select(.username != $self)
| irc("<\(.username)> \(.message)")),
(.Set // empty
| .user // empty
| keys[0] as $nick
| .[$nick]
| (
(.event // empty
| irc("\($nick) \(if .joined then "joined" else "left" end)")),
(.file // empty
| irc("\($nick) is now playing \(.name)"))
)
)
')
done &
wait
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment