#!/bin/bash
# pdt: post to FSF social media via command line
# Copyright (C) 2021 Ian Kelling
# SPDX-License-Identifier: AGPL-3.0-or-later
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
# This is meant to be sourced.
PATH="$HOME/.local/bin:$PATH"
# usage: rbow [-PROFILE_NAME] [COMMAND]
#
# Wrapper for rainbowstream to use multiple logins and tweet directly
# from the command line. PROFILE_NAME can be anything you want.
rbow() {
local oath f
oath=$HOME/.rainbow_oauth
if [[ $1 == -* ]]; then
rm -f $oath
ln -s $oath$1 $oath
shift
fi
source ~/src/rainbowstream/venv/bin/activate
if (($#)); then
f=$(mktemp)
cat >$f <<'EOF'
# adds a short delay after each send for more reliable operation
set force_conservative 1
spawn "rainbowstream"
# wait for prompt
expect -nocase timeout {exit 1} "@*]: "
set cmd [lindex $argv 0];
send "$cmd\r\r"
expect -nocase timeout {exit 1} "@*]: "
# this may not be needed. didnt test
sleep 2
send "q\r"
interact
EOF
expect $f "$*" || { echo error: expect failed; deactivate; rm -f $f; return 1; }
rm -f $f
else
rainbowstream
fi
deactivate
}
diaspora() {
source ~/src/diaspy/venv/bin/activate
python3 ~/src/jan-pona-mute/jan-pona-mute.py "$@" || { deactivate; return 1; }
deactivate
}
# usage: toot [-PROFILE_NAME] [TOOT_ARGS]
toot() {
local account
source ~/src/toot/venv/bin/activate
if [[ $1 == -* ]]; then
account=${1#-}
shift
command toot activate --quiet $account || { deactivate; return 1; }
fi
command toot "$@" || { deactivate; return 1; }
deactivate
}
# post to mastodon + twitter + gnu social post + diaspora
#
# Diaspora is skipped if posting to dbd accounts.
#
# If posting video, it only goes to twitter. Other accounts can be
# posted to manually with free software.
#
# usage: pdt [--dbd] [-m MEDIA_FILE] [-v VIDEO_PATH] [POST]
pdt() {
local video media rbow_account gs_account mastodon_account dbd video rbow_arg toot_arg dia_arg gs_arg
if [[ $pdttest ]]; then
rbow_account=iank
gs_account=fsfes
mastodon_account=iank@hostux.social
else
rbow_account=fsf
gs_account=fsf
mastodon_account=fsf@hostux.social
fi
dbd=false
video=false
while [[ $1 == -* ]]; do
case $1 in
-m)
media="$2"
shift 2
rbow_arg=" --i $media"
toot_arg="--media $media"
dia_arg="-p $media "
gs_arg="-F media=@$media"
;;
--dbd)
dbd=true
rbow_account=dbd
gs_account=dbd
mastodon_account=endDRM@hostux.social
shift
;;
-v)
video=true
media="$2"
shift 2
;;
esac
done
if [[ $media ]]; then
if [[ ! -e $media ]]; then
echo "error: file not found $media"
return 1
fi
if [[ $media == *\ * ]]; then
echo "error: file path contains a space. move it to non-space path"
return 1
fi
fi
# if we have no argument
if (( ! $# )); then
read -r -p "input PDT text: " input
set -- "$input"
fi
if [[ $- == *i* ]]; then
echo "About to PDT the following line. Press enter to confirm or ctrl-c to quit:"
echo "$input"
read
fi
if $video; then
local oath
oath=$HOME/.rainbow_oauth
account=fsf
if $dbd; then
account=dbd
fi
rm -f $oath
ln -s ${oath}-$account $oath
python3 ~/src/video-tweet/async-upload.py "$media" "$*"
return
fi
fails=()
if ! rbow -$rbow_account t "$*" $rbow_arg; then
fails+=(tweet)
fi
if ! toot -$mastodon_account post "$*" $toot_arg; then
fails+=(toot)
fi
if ! $dbd; then
if ! printf "post %s\n" "${dia_arg}$*" | diaspora; then
fails+=(diaspora)
fi
fi
# https://gnusocial.net/doc/twitterapi
if ! curl -o /dev/null -sS -u "$gs_account:$(cat ~/.gnusocial_login-$gs_account)" \
$gs_arg -F "status=$*" https://status.fsf.org/api/statuses/update.xml; then
fails+=(gnu-social)
fi
if (( ${#fails[@]} )); then
printf "$(tput setaf 5)█$(tput sgr0)%.0s" $(eval echo "{1..${COLUMNS:-60}}"); echo
echo "FSF ERROR: ${fails[*]} might not have posted" >&2
fi
}
# Usage: pdt-setup
pdt-setup() {
if [[ $pdttest ]]; then
mastodon_accounts=(iank)
else
mastodon_accounts=(fsf endDRM)
fi
mkdir -p ~/src
cd ~/src
for repo in errhandle rainbowstream diaspy jan-pona-mute video-tweet; do
if [[ -e $repo ]]; then
cd $repo
git fetch
git reset --hard origin/master
git clean -xfffd
cd ..
else
git clone https://vcs.fsf.org/git/$repo.git
fi
done
source ~/src/errhandle/err
cp ~/src/rainbowstream/rainbowstream/colorset/config ~/.rainbow_config.json
if [[ ! -e ~/.local/bin/pip ]]; then
tmp=$(mktemp)
wget -O$tmp https://bootstrap.pypa.io/get-pip.py
python3 $tmp --user
hash -r
fi
if [[ ! -e ~/.local/bin/virtualenv ]]; then
python3 -m pip install --user virtualenv
fi
cd ~/src/rainbowstream
python3 -m virtualenv -p python3 venv
source venv/bin/activate
python3 -m pip install -r requirements.txt
python3 -m pip install -e .
deactivate
# This repo's upstream is https://alexschroeder.ch/cgit/diaspy which is
# recommended in the install instructions here:
# https://alexschroeder.ch/cgit/jan-pona-mute/about/
cd ~/src/diaspy
python3 -m virtualenv -p python3 venv
source venv/bin/activate
python3 -m pip install -r requirements.txt
python3 -m pip install -e .
deactivate
rm -rf ~/src/toot
mkdir -p ~/src/toot
cd ~/src/toot
python3 -m virtualenv -p python3 venv
source venv/bin/activate
# pip freeze after a pip install.
cat >requirements.txt <<'EOF'
beautifulsoup4==4.8.2
certifi==2019.11.28
chardet==3.0.4
idna==2.8
requests==2.22.0
soupsieve==1.9.5
toot==0.25.2
urllib3==1.25.8
urwid==2.1.0
wcwidth==0.1.8
EOF
python3 -m pip install -r requirements.txt
deactivate
if [[ ! -s ~/.config/jan-pona-mute/login ]]; then
mkdir ~/.config/jan-pona-mute
account=fsf@framasphere.org
read -r -p "enter the password for $account > " pass
# background: format for this found using the save command
cat >~/.config/jan-pona-mute/login < " pass
touch ~/.gnusocial_login-$account
chmod 600 ~/.gnusocial_login-$account
printf "%s\n" "$pass" > ~/.gnusocial_login-$account
fi
done
for account in ${mastodon_accounts[@]}; do
if ! toot activate $account@hostux.social &>/dev/null; then
printf "$(tput setaf 5)█$(tput sgr0)%.0s" $(eval echo "{1..${COLUMNS:-60}}");
echo "Please login to $account on https://hostux.social in your main browser then press enter."
read -r
toot login -i hostux.social
fi
done
err-allow
}