Ubuntu – File System Usage Indicator

disk-usageindicatorpartitioningtools

I am unable to find a suitable utility to just indicate the file system usage (% space free for partitions) on the panel.

And I am not looking forward to install any bad kinds of desktop management tool, but a simple indicator.

I appreciate all your suggestions.

Best Answer

EDIT:

1. NEW ANSWER

While the answer at the bottom of this one can be used (see [2.]), it lead to a ppa -version with additional options, to be set in a preferences window.

enter image description here

enter image description here

Options include:

  • Setting all aliases in one window
  • Setting theme colors for the panel icon:

    enter image description hereenter image description hereenter image description hereenter image description here

  • Setting threshold for warnings
  • Show info on newly mounted / connected volumes in a notification:

    enter image description here

  • Run on Startup

Furthermore, the indicator now includes a smaller (width) icon set for other distro's (like xfce), which will be automatically applied, depending on the window manager.

enter image description here

To install:

sudo add-apt-repository ppa:vlijm/spaceview
sudo apt-get update
sudo apt-get install spaceview



2. OLD ANSWER

The script below is an indicator that lists your devices and shows their usage. The information is updated (if necessary) once per ten seconds.

enter image description here

Furthermore

  • While the indicator is running, you can choose a device to be represented in the icon. The device will be remembered on the next time you run the indicator:

    enter image description here

    ![enter image description here

    enter image description here

  • For one or more (or all) devices, you can set an alternative name ("custom name"), to be set in the head of the script

    As an example, this:

    alias = [
        ["sdc1", "stick"],
        ["sdb1", "External"],
        ["sda2", "root"],
        ["sda4", "ntfs1"],
        ["sda5", "ntfs2"],
        ["//192.168.0.104/media", "netwerk media"],
        ["//192.168.0.104/werkmap_documenten", "netwerk docs"],
        ]
    

    Will show:

    enter image description here

  • You can set a threshhold; if the free space of either one of your devices is below that, you'll get a warning:

    enter image description here

  • Plugged/unplugged devices will be added/removed from the menulist within 10 seconds.

The script

#!/usr/bin/env python3
import subprocess
import os
import time
import signal
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')
from gi.repository import Gtk, AppIndicator3, GObject
from threading import Thread

#--- set alias names below in the format [[device1, alias1], [device2, alias2]]
#--- just set alias = [] to have no custom naming
alias = []
#--- set the threshold to show a warning below 
#--- set to 0 to have no warning
threshold = 17
#---
currpath = os.path.dirname(os.path.realpath(__file__))
prefsfile = os.path.join(currpath, "showpreferred")

class ShowDevs():
    def __init__(self):
        self.default_dev = self.get_showfromfile()
        self.app = 'show_dev'
        iconpath = currpath+"/0.png"
        self.indicator = AppIndicator3.Indicator.new(
            self.app, iconpath,
            AppIndicator3.IndicatorCategory.OTHER)
        self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)       
        self.indicator.set_menu(self.create_menu())
        self.indicator.set_label("Starting up...", self.app)
        self.update = Thread(target=self.check_changes)
        self.update.setDaemon(True)
        self.update.start()

    def check_changes(self):
        state1 = None
        while True:
            self.state2 = self.read_devices()
            if self.state2 != state1:
                self.update_interface(self.state2)
            state1 = self.state2
            time.sleep(10)

    def update_interface(self, state):
        warning = False; self.newmenu = []
        for dev in state:
            mention = self.create_mention(dev)
            name = mention[0]; deci = mention[2]; n = mention[1]
            if n <= threshold:
                warning = True
            try:
                if self.default_dev in name:
                    newlabel = mention[3]
                    newicon = currpath+"/"+str(10-deci)+".png"
            except TypeError:
                pass
            self.newmenu.append(name+" "+str(n)+"% free")
        if warning:
            newlabel = "Check your disks!"
            newicon = currpath+"/10.png"
        try:
            self.update_indicator(newlabel, newicon)
        except UnboundLocalError:
            labeldata = self.create_mention(state[0])
            newlabel = labeldata[3]
            newicon = currpath+"/"+str(10-labeldata[2])+".png"
            self.update_indicator(newlabel, newicon)
        GObject.idle_add(self.set_new, 
            priority=GObject.PRIORITY_DEFAULT)  

    def update_indicator(self, newlabel, newicon):
        GObject.idle_add(self.indicator.set_label,
            newlabel, self.app,
            priority=GObject.PRIORITY_DEFAULT)   
        GObject.idle_add(self.indicator.set_icon,
            newicon,
            priority=GObject.PRIORITY_DEFAULT)

    def set_new(self):
        for i in self.initmenu.get_children():
            self.initmenu.remove(i)
        for item in self.newmenu:
            add = Gtk.MenuItem(item)
            add.connect('activate', self.change_show)
            self.initmenu.append(add) 
        menu_sep = Gtk.SeparatorMenuItem()
        self.initmenu.append(menu_sep)
        self.item_quit = Gtk.MenuItem('Quit')
        self.item_quit.connect('activate', self.stop)
        self.initmenu.append(self.item_quit)
        self.initmenu.show_all()

    def change_show(self, *args):
        index = self.initmenu.get_children().index(self.initmenu.get_active())
        self.default_dev = self.newmenu[index].split()[0]
        open(prefsfile, "wt").write(self.default_dev)
        self.update_interface(self.read_devices())

    def create_mention(self, dev):
        name = dev[1] if dev[1] else dev[0]
        n = dev[2]; deci = round(dev[2]/10)
        newlabel = name+" "+str(n)+"% free"
        return (name, n, deci, newlabel)        

    def create_menu(self):
        # create initial basic menu
        self.initmenu = Gtk.Menu()
        self.item_quit = Gtk.MenuItem('Quit')
        self.item_quit.connect('activate', self.stop)
        self.initmenu.append(self.item_quit)
        self.initmenu.show_all()
        return self.initmenu

    def read_devices(self):
        # read the devices, look up their alias and the free sapace
        devdata = []
        data = subprocess.check_output(["df", "-h"]).decode("utf-8").splitlines()
        relevant = [l for l in data if all([
                    any([l.startswith("/dev/"), l.startswith("//")]),
                    not "/loop" in l])
                    ]
        for dev in relevant:
            data = dev.split(); name = data[0]; pseudo = None       
            free = 100-int([s.strip("%") for s in data if "%" in s][0])
            for al in alias:
                if al[0] in name:
                    pseudo = al[1]
                    break
            devdata.append((name, pseudo, free)) 
        return devdata

    def get_showfromfile(self):
        # read the preferred default device from file
        try:
            defdev = open(prefsfile).read().strip()
        except FileNotFoundError:
            defdev = None
        return defdev

    def stop(self, source):
        Gtk.main_quit()

ShowDevs()
GObject.threads_init()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()

The icons

enter image description here 0.png

enter image description here 1.png

enter image description here 2.png

enter image description here 3.png

enter image description here 4.png

enter image description here 5.png

enter image description here 6.png

enter image description here 7.png

enter image description here 8.png

enter image description here 9.png

enter image description here 10.png

Setting up

Setting up is simple:

  • Copy the script into an empty file, save it as showusage.py
  • Save the icons above, exactly named as in their label, into one and the very same directory as the script (right- click > Save as)
  • In the headsection of the script, set (possible) alternative names (aliasses). Below an example:

    alias = [
        ["sda2", "root"],
        ["sdb1", "External"]
        ]
    

    If you want to display the devices unchanged, use:

    alias = []
    

    ...and if you want, change the threshold to show a warning:

    #--- set the threshold to show a warning below (% free, in steps of 10%)
    #--- set to 0 to have no warning
    threshold = 10
    

    That's it

Running it

To use the indicator, run the command:

python3 /path/to/showusage.py

To add it to Startup Applications, use the command:

/bin/bash -c "sleep 10 && python3 /path/to/showusage.py"

Choose Applications: Dash > Startup Applications > Add, add the command above.

Related Question