Decorate i3status with custom scripts
Freedom, that’s what you get when running Linux. You get the potential for almost unlimited customizability.
In this post, we’ll see how to add custom information to the i3status bar using our custom scripts. In my case, I wanted to display the count of visitors on my blog on any given day. I’ve used the googleapiclient lib for that, as you can see bellow.
I’m honestly sorry for forcing you to bulge your eyes over this tiny image on the screen, I’m really bad at image editing, but That! The blue globe, that’s what we’ll be working on - 48 daily views, not bad for a newbie, ham!? The same process can be used for virtually anything that you want to display on i3status.
But how does one config i3status exactly?
i3 + i3status configuration
First of all, make sure to add the i3bar output format to your i3status configuration.
# ~/.i3status.conf
general {
(...)
output_format = "i3bar"
(...)
}
Update your i3 status_command, pointing to the wrapper script.
# ~/.config/i3/config
bar {
status_command i3status | ~/scripts/i3status-wrapper.py
(...)
}
Adapted from here. This piece of code listens to the JSON like output of i3status that is piped through, in the invocation above, and adds our custom data.
#!/usr/bin/env python3
# i3status-wrapper.py
import sys
import json
from analytics import get_report, initialize_analyticsreporting
SCOPES = ['https://www.googleapis.com/auth/analytics.readonly']
KEY_FILE_LOCATION = ''
VIEW_ID = ''
def print_line(message):
""" Non-buffered printing to stdout. """
sys.stdout.write(message + '\n')
sys.stdout.flush()
def read_line():
""" Interrupted respecting reader for stdin. """
# try reading a line, removing any extra whitespace
try:
line = sys.stdin.readline().strip()
# i3status sends EOF, or an empty line
if not line:
sys.exit(3)
return line
# exit on ctrl-c
except KeyboardInterrupt:
sys.exit()
if __name__ == '__main__':
# Skip the first line which contains the version header.
print_line(read_line())
# The second line contains the start of the infinite array.
print_line(read_line())
analytics = initialize_analyticsreporting(KEY_FILE_LOCATION, SCOPES)
while True:
line, prefix = read_line(), ''
# ignore comma at start of lines
if line.startswith(','):
line, prefix = line[1:], ','
j = json.loads(line)
report = get_report(analytics, VIEW_ID)
# abominable data parsing, but this isn't a data-science course, so who cares
views = "🌐 " + \
report['reports'][0]['data']['rows'][0]['metrics'][0]['values'][0] + " views"
# this is where the magic happens
j.insert(0, {
'full_text': '%s' % views,
'name': 'views',
'separator_block_width': 25})
print_line(prefix+json.dumps(j))
Adapted from here.
# analytics.py
def initialize_analyticsreporting(key_file_location, scopes):
"""Initializes an Analytics Reporting API V4 service object.
Returns:
An authorized Analytics Reporting API V4 service object.
"""
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
credentials = ServiceAccountCredentials.from_json_keyfile_name(
key_file_location, scopes)
# Build the service object.
analytics = build('analyticsreporting', 'v4', credentials=credentials)
return analytics
def get_report(analytics, view_id):
"""Queries the Analytics Reporting API V4.
Args:
analytics: An authorized Analytics Reporting API V4 service object.
Returns:
The Analytics Reporting API V4 response.
"""
return analytics.reports().batchGet(
body={
'reportRequests': [
{
'viewId': view_id,
'dateRanges': [{'startDate': 'today', 'endDate': 'today'}],
'metrics': [{'expression': 'ga:users'}],
}]
}
).execute()
That’s it, just copy and paste the wrapper script, tweak it, and you are now able to add custom info to your i3status bar.