Following a rather radical pruning of my Twitter followings (people who I am following) my timeline has got both better and less exciting. So I wanted to follow some new people but not just random accounts.

I have a list of ununfollowables: the followings I like best. Those people are probably good judges of the people I should follow – or in any case better at it than random followings.

This script looks who they are following and follows those account. The result is that periodically I automatically follow some of my friends’ friends. It keeps a list of those I’ve followed automatically. If it doesn’t work out I unfollow them again. Of course nothing is keeping me from re-following them manually.

The script relies heavily on @sferik’s Twitter client for Ruby called ‘t’. It’s easy to install but it helps if you read the help file and get to know it a bit should you need to troubleshoot or adjust the script.

It is designed to be run from cron and written on a Debian 8 system but it should run on any Linux flavour. Be sure to add t’s path to your cron file.

The script is called freshmeat.sh on my system.

#!/bin/bash

#######################################################################
# Purpose of this script:                                             #
# Follow random followings from followings from the ununfollowables   #
# list, hopefully generating a bit more diversity in your timeline.   #
#                                                                     #
# The ununfollowables list is just a list of people you like.         #
# A 'following' is someone you are following. It is the reverse of    #
# a follower.                                                         #
#                                                                     #
# Requires:                                                           #
#  - Working and authenticated installation of Ruby gem t:            #
#    https://github.com/sferik/t                                      #
#  - Twitter list called 'Ununfollowables' (change as needed)         #
#    containing friends whose followings you might like to follow     #
#  - Twitter list called 'freshmeat' for the new followings           #
#                                                                     # 
# Feel free to use, change and redistribute this script as long as    #
# you include a link to https://vorkbaard.nl and this text. Enjoy :)  #
#                                                                     # 
#  @Vorkbaard, 2017                                                   #
#######################################################################


#######################################################################
#  Settings                                                           #
#######################################################################

# Ununfollowables list
UNUNFOLLOWABLES_LIST=de-onontvolgbaren

# Freshmeat list
FRESHMEAT_LIST=freshmeat
 
# Number to days to wait before unfollowing if they're not interested
WAITDAYS=13

# Number of new random followings to add - must be more than 0.
# Note that this script uses up your api access allowance:
# https://dev.twitter.com/rest/public/rate-limiting 
# Also note that a list cannot contain over 5000 members.
NEWADDINGS=5

# Do not follow people with the following words in their bio.
NOTFOLLOW="entrepreneur|founder|coach"


## MAIL - Make sure your server can send out mail first.
## I'm using xmail but you may want to change it.

# Send mail here:
MY_EMAIL=your@email.here

# The mail's from address
FROMADDR=your@servers_email.here


#######################################################################
#  End of settings                                                    #
#######################################################################

# Change to directory this script is in so we can use relative file locations when running from cron
cd "$(dirname "$0")";

# Retrieve Twitter handle
ME=@$(t whoami | head -4 | tail -1 | cut -d'@' -f2)
if [ "$?" != "0" ] ; then
	echo "Unable to retrieve Twitter handle, please make sure t is installed and working correctly."
	echo "Either that or we've ran out of api calls."
	exit
fi

echo "---------------------- $(date) --------------------" >> freshmeat.log
echo "Twitter handle: $ME" >> freshmeat.log

if [ -e mailtext ] ; then rm mailtext; fi

# Ok, here's the gist.

# Unfollow those not interested
# 1. Get list of randomfollowings followed over two weeks ago.
# 2. If they're not interested then unfollow them.
# 3. Remove them from the freshmeat list and the inprocess file.

# Get new users
# 4. Select random user from ununfollowables list.
# 5. Select random following from selected user.
# 6. Check if we're not already following the random following. If we do, select another one.
# 7. Follow the random following.
# 8. Put following on the freshmeat list.

# Create list of leaders so we only need to retrieve it once.
# Leaders are people who you are following but who don't follow you.
echo "Creating list of leaders. Please hold." >> freshmeat.log
t leaders > leaderslist
if [ "$?" != "0" ] ; then 
	echo "Error: probably not enough api calls left. Try again later." >> freshmeat.log
	echo "We ran out of api calls. Better luck next time!" | mailx -a "From: Freshmeat provider <$FROMADDR>" -s "Fresh meat!" $MY_EMAIL
	exit
fi

if [ -e freshmeat.inprocess ] ; then
	let WAITSECONDS=$WAITDAYS*60*60*24
	echo "WAITSECONDS: $WAITSECONDS" >> freshmeat.log
	echo "Getting list of randomfollowings followed over two weeks ago" >> freshmeat.log
	NOW=`date +%s`
	while read RANDOMFOLLOWING; do
		SINCE=$(echo $RANDOMFOLLOWING | cut -d' ' -f2)
		RAFO=$(echo $RANDOMFOLLOWING | cut -d' ' -f1)
		echo "Rafo: $RAFO" >> freshmeat.log
		echo "Since: $SINCE" >> freshmeat.log
		echo "NOW..: $NOW" >> freshmeat.log
		let DIFF=$NOW-$SINCE
		let HDIFF=$DIFF/3600
		echo "Time difference: $DIFF ($HDIFF hours)" >> freshmeat.log
		if [ "$DIFF" -lt "$WAITSECONDS" ] ; then
			echo "Time difference is less than $WAITDAYS days." >> freshmeat.log
			# Not doing anything with them now, just add them to the list for next time
			echo $RANDOMFOLLOWING >> freshmeat.inprocess_new.log
		else
			echo "Time difference is greater than $WAITDAYS days." >> freshmeat.log
			# Check if they're following back
			
			grep -iq "^$RAFO$" leaderslist
			if [ "$?" == "1" ] ; then
				# They're following back
				echo "$RAFO is following back!" >> freshmeat.log
				echo "$RAFO" >> newfollowers.log
				echo "New connection made: $RAFO - https://twitter.com/$RAFO" >> mailtext				
			else
				# They're not following back
				echo "$RAFO is not interested so unfollowing them." >> freshmeat.log
				t unfollow $RAFO >/dev/null 2>&1
				echo "Unfollowed $RAFO." >> mailtext			
			fi
			
			echo "Removing $RAFO from freshmeat list." >> freshmeat.log
			t list remove $FRESHMEAT_LIST $RAFO >/dev/null 2>&1
			if [ "$?" == "0" ] ; then
				echo "Removing $RAFO from random follower log file." >> freshmeat.log
			else
				echo "Error unfollowing $RAFO. Perhaps we've ran out of api calls." >> freshmeat.log
			fi
		fi
		echo "----" >> freshmeat.log
	done <freshmeat.inprocess
	# Recreate freshmeat.inprocess file with only remaining (current) followings
	mv freshmeat.inprocess_new.log freshmeat.inprocess 
else
	# if not exist freshmeat.inprocess
	echo "freshmeat.inprocess doesn't exist; nothing to compare so skipping the unfollow part." >> freshmeat.log
fi

# Create list of ununfollowables so we only need to retrieve it once
echo "Creating list of ununfollowables. This may take a while." >> freshmeat.log
t list members $ME/$UNUNFOLLOWABLES_LIST > ununfollowableslist
if [ "$?" != "0" ] ; then
	echo "Error: probably not enough api calls left. Try again later." >> freshmeat.log
	echo "We ran out of api calls. Better luck next time!" | mailx -a "From: Freshmeat provider <$FROMADDR>" -s "Fresh meat!" $MY_EMAIL
	exit
fi

# Create list of followings so we only need to retrieve it once.
echo "Creating list of followings. Please hold." >> freshmeat.log
t followings > followingslist
if [ "$?" != "0" ] ; then 
	echo "Error: probably not enough api calls left. Try again later." >> freshmeat.log
	echo "We ran out of api calls. Better luck next time!" | mailx -a "From: Freshmeat provider <$FROMADDR>" -s "Fresh meat!" $MY_EMAIL
	exit
fi

# Initialize the number of succesfull new followings
ADDINGS=0

printf "\n\n" >> mailtext
echo "New followings" >> mailtext
echo "------------------------------" >> mailtext
while [ $ADDINGS -lt $NEWADDINGS ] ; do
	echo "Succesfull addings: $ADDINGS" >> freshmeat.log

	# Get random ununfollowable
	UNUNFOLLOWABLES=$(cat ununfollowableslist | shuf -n 1)
	echo "Following from ununfollowableslist: $UNUNFOLLOWABLES" >> freshmeat.log

	for UNUNFOLLOWABLE in $UNUNFOLLOWABLES; do
		echo "Getting random following from $UNUNFOLLOWABLES_LIST." >> freshmeat.log
		RANDOMFOLLOWING=$(t followings $UNUNFOLLOWABLE | shuf -n 1)
		echo "Randomfollowing: $RANDOMFOLLOWING" >> freshmeat.log
		if [ -n "$RANDOMFOLLOWING" ] ; then
			
			# Check if we're not already following this particular random following
			grep -iq "^$RANDOMFOLLOWING$" followingslist
			if [ "$?" == "1" ] ; then
				echo "Not already following, but is this a protected account?" >> freshmeat.log

				# Protected accounts don't have the 'Last update' bit set in their public profile.
				# Also, get to know them a bit by reading their bio. 
				t whois $RANDOMFOLLOWING > tmpwhois

				# Check if the account is protected
				grep -q "Last update" tmpwhois
				if [ "$?" == "0" ] ; then

					# Check if they're not unwanted
					BIO=$(grep "Bio" tmpwhois)
					if echo $BIO | egrep -iqv $NOTFOLLOW; then

						echo "Not already following $RANDOMFOLLOWING AND not a protectect account AND they're not unwanted so following them now." >> freshmeat.log
						t follow $RANDOMFOLLOWING >/dev/null 2>&1
						if [ "$?" == "0" ] ; then
							echo "Follow succesful so adding them to $FRESHMEAT_LIST." >> freshmeat.log
							t list add $FRESHMEAT_LIST $RANDOMFOLLOWING >/dev/null 2>&1
							NOW=`date +%s`
							echo "$RANDOMFOLLOWING $NOW" >> freshmeat.inprocess
							# Increase addings number
							ADDINGS=$(( $ADDINGS + 1 ))
							SHOWBIO="$(echo $BIO|cut -c5-)"
							echo "Via $UNUNFOLLOWABLES: $RANDOMFOLLOWING - $SHOWBIO [https://twitter.com/$RANDOMFOLLOWING]" >> mailtext
						fi 
					else
						echo "Not going to follow $NOTFOLLOW." >> freshmeat.log   
					fi
				else
					echo "Not going to follow protected account." >> freshmeat.log
				fi
			else
				echo "Already following $RANDOMFOLLOWING." >> freshmeat.log
			fi
			echo "---- done ----"  >> freshmeat.log
		else
			echo "We've probably ran out of api calls so let's call it a day." >> freshmeat.log
			ADDINGS=$(( $NEWADDINGS + 1 ))

		# if -n $RANDOMFOLLOWING
		fi

	# for UNUNFOLLOWABLE
	done

# Addings
done

# Mail logfile
	# Get number of connections generated
	if [ -e newfollowers.log ] ; then
		FreshFollNr=$(wc -l newfollowers.log | cut -d' ' -f1)
		echo "Freshmeat has generated $FreshFollNr connections." >> mailtext
	else
		echo "Freshmeat has not generated any connections yet." >> mailtext
	fi	

	# Get number of people in Freshmeat list
	FreshmeatMembersNr=$(t list information $FRESHMEAT_LIST | head -5 | tail -1 | cut -d ' ' -f7)
	echo "There are now $FreshmeatMembersNr people on the $FRESHMEAT_LIST list." >> mailtext

	# Send mail
	cat mailtext | mailx -a "From: Freshmeat provider <$FROMADDR>" -s "Fresh meat!" $MY_EMAIL
	rm mailtext

# Clean up
	if [ -e tmpwhois ] ; then rm tmpwhois; fi
	if [ -e followingslist ] ; then rm followingslist; fi
	if [ -e ununfollowableslist ] ; then rm ununfollowableslist; fi
	if [ -e leaderslist ] ; then rm leaderslist; fi