Mint Serena 64 bit using the Mate desktop environment. Most of the following scripts will run on this machine, although some have only been tested with the Gnome desktop. Extra software requirements can be met by the Ubuntu and safe PPA repositories. Scripts may be re-written or added to from time to time, the date serves as the version number. Syntax highlighting on these pages is provided by GVim's "Convert to HTML" option.

Timer Mk3


#!/bin/bash
# Filename: progbar-timer.sh
# Version.: 19042017
# Author..: robz
# What another one!
# Improved from the "Egg Timer" script, a countdown timer with progress bar.
# This one has an indication of time remaining provided by Zenity's progress
# bar function. You'll need to choose a sound file below and maybe fiddle with
# the vector_tl function x&y coordinates.

vector_tl ()                                              # Dialog to top left.
{
x="541"; y="315"
until [ "$x" -lt "0" ]; do
    wmctrl -r "Egg Timer Mk3" -e 0,"$x","$y",210,129
    ((x-=30)); ((y-=18))
done
}

count=$(zenity --title "Egg Timer Mk3" --text "Decimals allowed Min/Hrs"\
    --entry-text "eg. 10s or 5m or 2h" --entry)           # Input dialogue.
if [ $? = 1 ]; then exit $?; fi

# Determine number of seconds to count down from depending on input suffix.
case "${count: -1}" in
    "S" | "s" ) count=$(echo ${count%?}/1 | bc) ;;
    "M" | "m" ) count=$(echo ${count%?}*60/1 | bc) ;;
    "H" | "h" ) count=$(echo ${count%?}*3600/1 | bc) ;;
    *         ) zenity --error --text "<span color=\"red\"><b>\
    \nUse the form of 10s or 5m or 2h\nDecimals allowed Min/Hrs.</b></span>"
    sh -c "$0"                                            # On error restart.
    exit ;;
esac

(sleep 1 && vector_tl) &

start=$count                                              # Set a start point.

until [ "$count" -eq "0" ]; do                            # countdown loop.
    ((count-=1))                                          # Decrement seconds.
    percent=$((100*count/start))                          # Calc percentage.
    echo "#Time remaining:$(echo "obase=60;$count" | bc)" # Convert to H:M:S.
    echo $percent                                         # Outut for progbar.
    sleep 1
done | zenity --title "Egg Timer Mk3" --progress --percentage=0 --text=""\
    --auto-close                                          # Progbar/time left.

if [ $? = 1 ]; then exit $?; fi
zenity --info --title "Egg Timer Mk3" --text "## TIMES UP ##" &
play $HOME/Scripts/glass_ping.wav                         # Ping sound finish!
vector_tl
exit


Cooler CPU


#!/bin/bash
# Filename: cpulimit-ghb.sh
# Version.: 09032017
# Author..: robz
# I know, I'm cheap, I should buy a better than stock cooling fan, but....
# Dynamically use the cpulimit utility to keep cpu within a sane temperature
# range when using Handbrake or another resource hammering program.
# sudo apt install cpulimit lmsensors - use PPA for the latest Handbrake.
# Dependant on the output of "sensors" you may need to tweak line ##.

if [ "$UID" != "0" ]; then                          # Get root privilege.
    sudo -k; exec gksudo --message "$(echo\
    'Enter your password please, you need root';\
    echo 'privileges to run cpulimit effectively.')"\
    "$0"
fi

max='67'                                            # Maximum temperature°C.
cores='2'                                           # Number of cpu cores.
prog='/usr/bin/ghb'                                 # Program you're limiting.
limit=$((100*cores))                                # Total 100% limit range.
base="$limit"

while [[ "$(pidof "$prog")" ]]; do
    temp=$(sensors | grep 'CPU:' | cut -c18-19)     ## Get cpu temperature.
    if [[ "$temp" -gt "$max" && "$limit" -gt '25' ]]; then
        killall /usr/bin/cpulimit                   # Kill old process.
        ((limit-=25))                               # Increment limit down.
        cpulimit -qb -P "$prog" -l "$limit"         # Start new process.
    elif [[ "$temp" -lt "$max" && "$limit" -lt "$base" ]]; then
        killall /usr/bin/cpulimit
        ((limit+=25))                               # Increment limit up.
        cpulimit -qb -P "$prog" -l "$limit"
    fi
    sleep 5
done

killall /usr/bin/cpulimit
exit


Report


#!/bin/bash
# Filename: report.sh
# Version: 170816
# Author: robz
# Report for newPVR.sh activity, HTML page served by nginx.
# Root crontab
# Update index.html page.
# @reboot /home/pi/Downloads/scripts/report.sh > /dev/null 2>&1
# Kill server.
# 00 18 * * * sudo /etc/init.d/nginx stop

boot="$(date -d "@"$(awk '/btime/{print $2}' /proc/stat) +"%H:%M:%S")"
stor="$(df -h / | awk 'NR==2 {print $5}')"
lst1="$(cat "/home/pi/Downloads/log/motd.txt")"
lst2="/home/pi/Downloads/scripts/followed-shows.txt"
lst2="$(grep -v '^$\|^\s*\#' "$lst2" | nl -w3 -s ')  ')"

cat > /usr/share/nginx/www/index.html << EOF
<!DOCTYPE html>
<html>
<head>
  <title>robz Report</title>
  <style>
    html {
      background: url(pi.jpg) no-repeat center center fixed;
      background-size: cover;
      -webkit-background-size: cover;
      -o-background-size: cover;
    }
    h1 {
      color: #BD1143; text-shadow: 2px 2px 1px #FFFFFF;
      font-size: 40px; font-style: italic;
    }
    h3 {
      font-style: italic; font-weight: 600;
      margin: 0;
    }
    body {
      color: #FFFFFF;
      font-family: sans-serif; font-size: 12px; font-weight: 500;
      margin-left: 25px;
    }
    .footer {
      color: #BD1143;
      font-size: 8px; font-style: italic; font-weight: 700;
      position: fixed;
      bottom: 5px; right: 5px;
    }
  </style>
</head>
<body>
<h1>The <img src="pi5.png" align="top" width="34" height="42"> Pi Torrent Box...
</h1>
<pre>
<h3> Download report for $(date +%A" "%d" "%B)</h3>
 Machine last rebooted at $boot - SD card usage is currently at $stor
<br>$lst1
<br> Tracked shows.:
<br>$lst2
</pre>
<span class="footer">Raspberry powered page by robz</span>
</body>
</html>
EOF



New PVR


#!/bin/bash
# Filename: new-pvr.sh
# Version: 290716
# Author: robz
# WARNING! this works on my system it may break yours, read, check, tweak ##
# A torrent box script for a headless Raspberry Pi model B, it auto downloads
# media files for show episodes followed, then renames and transfers to NAS.
# You may need to "apt-get install gvfs-bin" for the mount and move daemons,
# also tvnamer, xmllint, transmission-daemon and transmission-remote.
# Enable the "Watch" and "Incomplete" directories in transmission-daemon's
# settings.json, this can also be done using the web interface.
# http://<your-pi's-net-address-192.168.0.etc>:9091/transmission/web/#all
# No login required no gui, just power up pi whenever or leave on all the time.
# Downloads will occur at random times 01:00-05:00 ie. during off peak hours.
# List show names in the "followed-shows.txt" file one entry per line.
# Manually added links are copy/pasted to the "add-magnet.txt", one per line.
# Make script executable and run it first in /home/<user> i.e. ./new-pvr.sh

# Directory might not be standard in your pi, create it before running script.
cd "$HOME/Downloads" || exit                        # Go to working directory.

smb="smb://wdmycloud/media/Cloud TV"                # My samba path to NAS.
trk="$HOME/.config/transmission-daemon"             # The daemon's config file.
mag="scripts/add-magnet.txt"                        # Any extra magnet links.
don="scripts/done-shows.txt"                        # Done downloads list.
rss="scripts/rss.txt"                               # Feed file rss listing.
rlg="log/$(date +%a-%-d%b)-runlog.txt"              # This session, statistics.
rec="log/rec.txt"                                   # Recently downloaded list.
mod="log/motd.txt"                                  # Message for ssh login.
cdn="0"                                             # Count/countdown variable.
export trk                                          # Give access for subshell.

set -x                                              # Generate debug output.
exec > "log/$(date +%a-%-d%b)-debug.txt" 2>&1       # Route debug to debug log.
date > "$rlg"                                       # Start a new session log.
> "$mod"                                            # Blank motd.txt.
# Script started via cron schedule, expand that enviroment so gvfs will work.
[ -z "$DBUS_SESSION_BUS_ADDRESS" ] && eval \
"$(dbus-launch --sh-syntax --exit-with-session)"    # Make gvfs & cron buddies.
# If script fails kill daemon to avoid possible bandwidth overruns.
trap "killall -q transmission-daemon; sync; exit" SIGINT SIGTERM SIGHUP EXIT
# Timer will wait for "Incomplete" to empty or for a file to appear dependant
# on whether the $swh variable is set or not, or it'll just time out.
run_timer ()
{
while [ "$cdn" -gt "1" ]; do
    [[ ! "$swh" && "$(ls Incomplete)" ]] && break
    [[ "$swh" && ! "$(ls Incomplete)" ]] && break
    (( cdn-=5 )); sleep 5
done 2> /dev/null
}
# Strip unwanted characters from filenames, magnet links and xml input.
strip_title ()
{
sed -e 's/\(S[0-9]*E[0-9]*\).*\<.*/\1/;s/.*>//;s/[.+]/ /g;s/.*dn=//;s/New.*: //'
}
# This part of the script executes once to create the directory/file structure
# in ##> Downloads <##, it also installs the random time run-script crontab.
if [ ! -e scripts/"$(basename $0)" ]; then
    set -o noclobber
    mkdir -p {Complete,Incomplete,Watch,temp,scripts,log,ted}
    &> /dev/null > scripts/followed-shows.txt
    &> /dev/null > "$mag"
    &> /dev/null > "$don"
    &> /dev/null > "$rss"
    t0='# Randomly between 01:00 and 05:00 new-pvr.sh run it.'
    t1='00 00 * * * /bin/sleep $(((RANDOM\%10800)+3600)); '
    t2="/home/pi/Downloads/scripts/$(basename $0); sudo reboot"
    (crontab -u "$USER" -l; echo -e "\n$t0\n$t1$t2\n" ) | crontab -u "$USER" -
    cp "$0" scripts; mv "$0" "$0".backup
    echo "Now add some shows to the followed-shows.txt"
    exit
else
    echo "### File exists, no action taken ###"
fi
# Housekeeping, clean up old downloads and logs.    # NB. subshell used here.
echo "$(tail -30 "$rec")" > "$rec"
find log -mtime +14 -type f -delete
find Complete -mindepth 1 -mtime +4 -delete
find "$trk" -mtime +4 -name *.torrent -type f -delete -execdir bash -c\
    'del="{}"; del="${del##*/}"; rm -f "$trk/resume/${del%.*}.resume"' \;
# Check the "Watch" directory for extras or one off shows.
[ "$(ls Watch)" ] && \
for lnk in Watch/*; do
    basename "$lnk" | strip_title >> "$don"
done

transmission-daemon -g "$trk"
echo "$(date +%T) - Transmission-daemon started." >> "$rlg"
# Check "add.magnet" file for extras or one off shows.
[ -s "$mag" ] && \
sleep 5 && \
while read lnk; do
    transmission-remote --add "$lnk"
    strip_title <<< "$lnk" >> "$don"
done < "$mag"
> "$mag"
# Download rss feeds, pretty print to seperate lines allowing parsing.
# Two feeds? I've found that the feed listings are slightly different between
# the old and new sites, so yes, two feeds for now.
> "$rss"                                            # Empty old rss feed file.
wget -q -O - "http://showrss.info/feeds/all.rss" | xmllint --format - >> "$rss"
wget -q -O - "http://showrss.info/other/all.rss" | xmllint --format - >> "$rss"
# Check followed-shows list against new rss feed file, standard def. not HD. If
# you want HD versions you'll have to modify the "sed" statments, alternatively
# you could use the "add.magnets" file or the "Watch" directory for a one off.
## NB. GNU sed is being used in this script, BSD/POSIX versions won't do.##
## TODO Code chokes here if the show name format is not "Show Name S01E01" ##
if [ -s "$rss" ]; then
    while read shw; do
        if [[ "${shw:0:1}" != "#" && "$shw" != "" ]]; then
            epi=$(sed -n "/720\|1080/d;/description.*$shw/Ip" "$rss" | sed q)
            [ -z "$epi" ] && continue
            if ! grep -iq "$(strip_title <<< "$epi")" "$don"; then
                strip_title <<< "$epi" >> "$don"
                lnk="$(sed 's/.*href=\"//;s/\".*//' <<< "$epi")"
                transmission-remote --add "$lnk"
            fi
        fi
    done < scripts/followed-shows.txt
    grep "raw.*title" "$rss" | sed "/720\|1080/d" | strip_title | sort -u \
    > log/rss-today.txt
else
    echo ' ## ERROR no rss feed.' | tee -a "$rlg" "$mod"
fi

sort -u "$don" -o "$don"                            # Tidy up done-shows list.
# Wait for first link to start downloading, skipped if incomplete files exist.
[ -z "${lnk+x}" ] || \
(echo "$(date +%T) - Wait for links or resume incompletes." >> "$rlg";
cdn="420"; swh=""; run_timer)                       # Set to wait for link load.
# If torrents are downloading start session timer.
if [ "$(ls Incomplete)" ]; then
    cdn="3600"; swh="1"                             # Timer max & function.
    transmission-remote --torrent all --start
    echo "$(date +%T) - Proceeding with download $((cdn/60))m max." >> "$rlg"
    run_timer
    echo "$(date +%T) - Seed for another 10 minutes." >> "$rlg"
    sleep 600
    transmission-remote --torrent all --stop
    transmission-remote --session-stats | sed '3,6!d' >> "$rlg"
    (
    echo "$(date +%T) - End of $(date +%A)'s downloads."
    [ "$(ls Incomplete)" ] && echo 'Incomplete download(s):' && ls Incomplete
    ) >> "$rlg"
    echo " PVR session...: $(awk '/Downloaded/{print $1,$2$3}' "$rlg")" > "$mod"
    echo "Rename & tranfer to network storage." >> "$rlg"
fi

transmission-remote --exit
cdn=0
# Leaving original torrents to seed for a few runs, just the main video files
# are copied (ignoring previews and promos) to "temp" then renamed. Now create 
# directories if needed on network drive and transfer the media files there.
new="$(find Complete -size +50M -daystart -mtime -1)"
if [ "$new" ]; then                                 # Do we have episodes.
    gvfs-mount "$smb"; sleep 60                     # Mount network drive.
    while read -r vid; do
        cp "$vid" temp/
        tvnamer -b temp/
        ls temp/ | sed 's/^/  /;s/....$//' | tee -a "$rlg" "$mod" |\
        sed "s/^/$(date +%a-%d)/;s/$/  \:$(du -h temp/ | cut -f1)/"\
        >> "$rec"
        dir="$(basename "$(ls temp/)")"
        dir="${dir% - [*}"/"Season $(echo "${dir##*[}" |\
        cut -dx -f1 | sed 's/^0//')"                # Determine directory tree.
        gvfs-mkdir -p "$smb"/"$dir"                 # Create directory on NAS.
        gvfs-move temp/* "$smb"/"$dir"
        (( cdn+=1 ))                                # Increment LED indicator.
    done <<< "$new"
fi
# This works in conjunction with the "ted-talks.sh" script if it exists.
new="$(find ted -type f)"
if [ "$new" ]; then
    echo " TED session...: Downloaded "$(du -hs ted | cut -f1)"B" |\
    tee -a "$rlg" "$mod"
    while read -r vid; do
        [ -e "$vid" ] && mv "$vid"\
        ted/"$(grep "${vid##*/}" scripts/ted-donelist.txt | cut -d"|" -f1-2 |\
        tr -cd [:alnum:][:blank:]).mp4"             # Make a sane filename.
        (( cdn+=1 ))
    done <<< "$new"
    ls ted | sed 's/^/  /;s/.mp4//' | cut -c1-77 | tee -a "$rlg" "$mod"
    if ! gvfs-mount -l | grep $(dirname "$smb"); then
        gvfs-mount "$smb"; sleep 60                 # Mount if not mounted.
    fi
    gvfs-move ted/* "$smb"/TED-talks
fi
# Finish up.
echo "$cdn" > scripts/flash.txt                     # Flash LED $cdn times.
if [ "$cdn" -lt "1" ]; then
    echo " This session..: $(date +%A) nothing new." | tee -a "$rlg" "$mod"
else
    echo "$(date +%T) - File(s) transfer completed." >> "$rlg"
    echo " Script runtime: $(date -d@"$SECONDS" -u +%H:%M:%S)" |\
    tee -a "$rlg" "$mod"
    gvfs-mount -u "$smb"
fi

# exit - see trap.



LED flash


#!/bin/bash
# Filename: countLED.sh
# Version: 270716
# Author: robz
# Raspberry Pi script, flashes an LED number in "flash.txt" times. 
# GPIO pin 18 flash for new-pvr.sh, flashes number of shows downloaded.
# Requires an LED on pin 18 with a 470ohm resistor to a ground pin.
# An alternative is to use the green activity LED, comment code appropriately.
# Sudo crontab entries for this to work with new-pvr.sh:
# @reboot /home/pi/Downloads/scripts/countLED.sh > /dev/null 2>&1
# 00 18 * * * /usr/bin/pkill countLED.sh > /dev/null 2>&1

cdn="$(cat /home/pi/Downloads/scripts/flash.txt)"   # Current number of shows.
[ "$cdn" -lt "1" ] && exit

cleanup ()
{
echo "18" > /sys/class/gpio/unexport
# echo "mmc0" > /sys/class/leds/led0/trigger
}

trap 'cleanup > /dev/null 2>&1; exit' SIGTERM SIGHUP ERR EXIT

echo "18" > /sys/class/gpio/export                  # Activate GPIO pin 18.
echo "out" > /sys/class/gpio/gpio18/direction       # Designate as an output.

while true; do                                      # Continuous loop.
    for ((n=1; n<=cdn; n++)); do                    # Count shows loop.
        echo 1 > /sys/class/gpio/gpio18/value       # GPIO 18 high, LED on.
      # echo 1 > /sys/class/leds/led0/brightness    # Activity LED on.
        sleep .1
        echo 0 > /sys/class/gpio/gpio18/value       # GPIO 18 low, LED off.
      # echo 0 > /sys/class/leds/led0/brightness    # Activity LED off.
        sleep .2
    done
    sleep 4
done