fedarovich / qbittorrent-cli

Command line interface for QBittorrent
MIT License
312 stars 17 forks source link

How I prefer to view the output of 'gbt torrent list' #94

Open PriamX opened 11 months ago

PriamX commented 11 months ago
#!/bin/bash
#
# A humble script to format qbitorrent-cli's "qbt torrent list"
# the way I like to view it.
#
# PriamX@github 10/5/23

#
# Handle optional debug flag (-d) or exit on bad flag
#
[ $@ ] && getopts :hdns FLAG
case "${FLAG}" in
        h)
                echo "Usage: $0 [-h] [-d] [-n] [-s]"
                echo "  -h: this help"
                echo "  -d: print debug output"
                echo "  -n: no header"
                echo "  -s: summary only"
                exit 0
                ;;
        d)
                DEBUG=1
                echo "Printing DEBUG output..."
                ;;
        n)
                HEADER=1
                ;;
        s)
                SUMMARY=1
                ;;
        \?)
                echo "ERROR: Invalid option -$OPTARG"
                exit 1
                ;;
        *)
                ;;
esac

#
# Text colors
# Most are unused but I include them if you'd like
# to add more colors or make changes
#
BLK='\033[0;30m'     # Black
RED='\033[0;31m'     # Red
GRN='\033[0;32m'     # Green
BLU='\033[0;34m'     # Blue
CYA='\033[0;36m'     # Cyan
WHI='\033[0;37m'     # White
YEL='\033[0;33m'     # Yellow
PUR='\033[0;35m'     # Purple
PLX='\033[38;5;220m' # Plex Yellow
NOC='\033[0m'        # No Color

#
# Normal, Bold and Underline text
#
NO="\e[0m"
BD="\e[1m"
UL="\e[4m"

#
# Get the terminal dimensions, we'll use the width later to maximize the
# torrent name column.
#
read ROWS COLS <<< $(stty size < `tty`)

#
# Run the "qbt torrent list" command and grab the csv output for fields we want
#
TLIST=`qbt torrent list -F csv | cut -d',' -f1,2,4,5,6,7,8,9,10,11,12,13,14,15,18`

#
# A rounding function based on 'bc'
#
round()
{
        echo $(printf %.$2f $(echo "scale=$2;(((10^$2)*$1)+0.5)/(10^$2)" | bc))
};

#
# A function to Scale the speed to be more human readable
#
fmt_speed()
{
        local -n speed=$1

        if ((speed == 0))
        then
                speed=""
        elif ((speed >= 1073741824))
        then
                speed=$(echo "scale=2; $speed / 1024 / 1024 / 1024" | bc)
                speed="$speed Gb"
        elif ((speed >= 1048576))
        then
                speed=$(echo "scale=2; $speed / 1024 / 1024" | bc)
                speed="$speed Mb"
        elif ((speed >= 1024))
        then
                speed=$(echo "scale=2; $speed / 1024" | bc)
                speed="$speed Kb"
        else
                speed="$speed b"
        fi
};

#
# A fuction to scale down the file size to be more human-readable
#
fmt_size()
{
        local -n lsize=$1

        if ((lsize >= 1099511627776))
        then
                lsize=$(echo "scale=2; $lsize / 1024 / 1024 / 1024 / 1024" | bc)
                lsize="$lsize TB"
        elif ((lsize >= 1073741824))
        then
                lsize=$(echo "scale=2; $lsize / 1024 / 1024 / 1024" | bc)
                lsize="$lsize GB"
        elif ((lsize >= 1048576))
        then
                lsize=$(echo "scale=2; $lsize / 1024 / 1024" | bc)
                lsize="$lsize MB"
        elif ((lsize >= 1024))
        then
                lsize=$(echo "scale=2; $lsize / 1024" | bc)
                lsize="$lsize KB"
        else
                lsize="$lsize B "
        fi
};

#
# Variables we collect for the summary output
#
tottorrent=0
totsize=0
totpercent=0
totupspeed=0
totdlspeed=0
totratio=0
fauxratio=0

#
# Loop through each line of the output
#
while read TOR
do
        #
        # Assign the output to variables
        #
        IFS=$','
        read hash name size progress dlspeed upspeed priority num_seeds num_complete num_leechs num_incomplete ratio eta state category <<<$TOR
        unset IFS

        #
        # Skip the row with column titles
        #
        if [ "$hash" == "Hash" ]
        then
                continue
        fi

        #
        # Just use the first six characters of the hash (this is what qbittorrent-cli uses)
        #
        hash="${hash:0:6}"

        #
        # Rough hack, replace some characters with '?' that were messing with layout
        # (I'm sure there's a better way to do this, but don't care right now)
        #
        name=$(echo $name | sed 's/[长白山天池水怪]/?/g')

        #
        # Augment the cumulative download speed variable
        #
        ((totsize += size))

        #
        # Scale down the file size to be more human-readable
        #
        fmt_size size

        #
        # Augment the total percent
        #
        totpercent=$(echo "scale=8; $totpercent + $progress" | bc)

        #
        # Change progress to a percent
        #
        progress=$(round "$progress * 100" 0)

        #
        # We'll color progress
        #
        if ((progress == 100))
        then
                progcol=$GRN
        elif ((progress == 0))
        then
                progcol=$RED
        else
                progcol=$NOC
        fi

        #
        # Add the percent sign
        #
        progress="${progress}%"

        #
        # Augment the cumulative download speed variable
        #
        ((totdlspeed += dlspeed))

        #
        # Scale the download speed to be more human readable
        #
        fmt_speed dlspeed

        #
        # Augment the cumulative upload speed variable
        #
        ((totupspeed += upspeed))

        #
        # Scale the upload speed to be more human readable
        #
        fmt_speed upspeed

        #
        # Format the seeds and peers variables to be qbitorrentish
        #
        seeds="${num_seeds}/${num_complete}"
        peers="${num_leechs}/${num_incomplete}"

        #
        # Augment the cumulative ratio (dropping 0.00)
        #
        if (( $(echo "$ratio != 0" | bc -l) ))
        then
                totratio=$(echo "scale=8; $totratio + $ratio" | bc)
        else
                ((fauxratio++))
        fi

        #
        # Round the ratio to two decimal places
        #
        ratio=$(round "$ratio" 2)

        #
        # Pre-formatted ETA (for debugging)
        #
        origeta=$eta

        #
        # Convert the ETA to a friendlier format
        #
        if [[ $eta == "100.00:00:00" ]]
        then
                # "Infinity" character
                #eta="\u221E" This messed up formatting, so commented it out
                eta="-"
        else
                #
                # If it has a 'days' component, separate that
                #
                if [[ $eta =~ '.' ]]
                then
                        days=$(echo "$eta" | cut -s -d'.' -f1)
                        time=$(echo "$eta" | cut -s -d'.' -f2)
                else
                        days=0
                        time=$eta
                fi

                #
                # Split up the time string
                #
                hours=$(echo "$time" | cut -d':' -f1)
                mins=$(echo "$time" | cut -d':' -f2)
                secs=$(echo "$time" | cut -d':' -f2)

                #
                # Get rid of leading zeros
                #
                hours=$(echo $hours | sed 's/^0//')
                mins=$(echo $mins | sed 's/^0//')
                secs=$(echo $secs | sed 's/^0//')

                #
                # Format the ETA string to look nice
                #
                if ((days >= 365))
                then
                        years=$(echo "scale=1; $days / 365" | bc)
                        eta="${years}y"
                elif ((days >= 1))
                then
                        eta="${days}d ${hours}h"
                elif ((hours >= 1))
                then
                        eta="${hours}h ${mins}m"
                elif ((mins >= 1))
                then
                        eta="${mins}m ${secs}s"
                else
                        eta="${secs}s"
                fi
        fi

        #
        # Convert the status to an abbreviated string.
        # This is the same conversion qbittorrent-cli does.
        #
        case "$state" in
                "State")
                        state="ST"
                        ;;
                "Error")
                        state="E"
                        ;;
                "PausedUpload")
                        state="PU"
                        ;;
                "PausedDownload")
                        state="PD"
                        ;;
                "QueuedUpload")
                        state="QU"
                        ;;
                "QueuedDownload")
                        state="QD"
                        ;;
                "Uploading")
                        state="U"
                        ;;
                "StalledUpload")
                        state="SU"
                        ;;
                "CheckingUpload")
                        state="CU"
                        ;;
                "CheckingDownload")
                        state="CD"
                        ;;
                "Downloading")
                        state="D"
                        ;;
                "StalledDownload")
                        state="SD"
                        ;;
                "FetchingMetadata")
                        state="MD"
                        ;;
                "ForcedUpload")
                        state="FU"
                        ;;
                "ForcedDownload")
                        state="FD"
                        ;;
                "MissingFiles")
                        state="MF"
                        ;;
                "Allocating")
                        state="A"
                        ;;
                "QueuedForChecking")
                        state="QC"
                        ;;
                "CheckingResumeData")
                        state="CR"
                        ;;
                "Moving")
                        state="MV"
                        ;;
                "Unknown")
                        state="?"
                        ;;
                *)
                        state="??"
                        ;;
        esac

        #
        # If there's no category assigned...
        #
        if [ -z "$category" ]
        then
                category="(none)"
        fi

        #
        # Calculate the size of the field for the torrent name
        #
        namesize=12 # Minimum size

        leeway=$(echo "$COLS - 101" | bc) # 101 is the size of our printf format string + 3 spaces at the end

        if [ "$leeway" -gt "0" ]
        then
                namesize=$(echo "$namesize + $leeway" | bc)
        fi

        #
        # We'll print the header once, it'll be the first line, nothing if '-n' option is used
        #
        if [ ! $HEADER ] && [ ! $SUMMARY ] && [ ! $DEBUG ]
        then
                printf "${PLX}${UL}%-6.6s${NO} ${PLX}${UL}%-${namesize}.${namesize}b${NO} ${PLX}${UL}%-2.2s${NO} ${PLX}${UL}%4.4s${NO} ${PLX}${UL}%9.9s${NO} ${PLX}${UL}%7.7s${NO} ${PLX}${UL}%7.7s${NO} ${PLX}${UL}%9.9s${NO} ${PLX}${UL}%9.9s${NO} ${PLX}${UL}%-7.7s${NO} ${PLX}${UL}%5.5s${NO} ${PLX}${UL}%-8.8s${NO} ${PLX}${UL}%1.1s${NO}${NOC}\n" "Hash" "Name" "ST" "Prog" "Size" "Seeds" "Peers" "DL Speed" "UL Speed" "ETA" "Ratio" "Cat" "#"
                HEADER=1
        fi

        #
        # Print the pretty format unless the '-d' option is used
        #
        if [ $DEBUG ]
        then
                echo "hash: $hash"
                echo "name: $name"
                echo "size: $size"
                echo "progress: $progress"
                echo "dlspeed: $dlspeed"
                echo "upspeed: $upspeed"
                echo "priority: $priority"
                echo "num_seeds: $num_seeds"
                echo "num_complete: $num_complete"
                echo "seeds: $seeds"
                echo "num_leechs: $num_leechs"
                echo "num_incomplete: $num_incomplete"
                echo "peers: $peers"
                echo "ratio: $ratio"
                echo "eta1: $origeta"
                echo -e "eta2: $eta"
                echo "state: $state"
                echo "category: $category"
                echo ""
        elif [ ! $SUMMARY ]
        then
                #name=$(printf '%.12b' "$name")
                #echo -e "$hash $name $state $progress $size $seeds $peers $dlspeed $upspeed $eta $ratio $category $priority"
                printf "%6.6s ${CYA}%-${namesize}.${namesize}b${NOC} %-2.2s ${progcol}%4.4s${NOC} %9.9s %7.7s %7.7s %9.9s %9.9s %-7.7b %5.2f %-8.8s %1.1s\n" "$hash" "$name" "$state" "$progress" "$size" "$seeds" "$peers" "$dlspeed" "$upspeed" "$eta" "$ratio" "$category" "$priority"
        fi

        ((tottorrent++))

done <<< ${TLIST}

#
# Summary
#
if [ $SUMMARY ]
then
        #
        # Total count of torrents
        #
        echo "total torrents: ${tottorrent}"

        #
        # Total size of all torrents
        #
        fmt_size totsize
        echo "total size: ${totsize}"

        #
        # Average percent
        #
        totprogress=$(echo "scale=8; $totpercent / $tottorrent" | bc)
        echo "overall progress: $(round "$totprogress * 100" 0)%"

        #
        # Total download speed
        #
        fmt_speed totdlspeed
        echo "download speed: ${totdlspeed}"

        #
        # Total upload speed
        #
        fmt_speed totupspeed
        echo "upload speed: ${totupspeed}"

        #
        # Average ratio (excluding 0.00)
        #
        avgratio=$(echo "scale=8; $totratio / ($tottorrent - $fauxratio)" | bc)
        echo "average ratio: $(round $avgratio 2)"
fi

#
# Debug things
#
if [ $DEBUG ]
then
        echo "rows:    ${ROWS}"
        echo "columns: ${COLS}"
fi

#
# Exit nicely
#
exit 0