├── scrot.png ├── resources ├── gmail │ ├── configFile │ └── genToken.sh └── example.conf ├── internet ├── loadavg ├── volume ├── disk ├── LICENSE ├── music ├── gmail └── README.md /scrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UtkarshVerma/i3blocklets/HEAD/scrot.png -------------------------------------------------------------------------------- /resources/gmail/configFile: -------------------------------------------------------------------------------- 1 | # API variables 2 | clientId=""; 3 | clientSecret=""; 4 | tokenFile=""; 5 | -------------------------------------------------------------------------------- /internet: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #---------------------------------------------------------------------------------------------------- 3 | #Check internet connectivity through ping exit code 4 | if ping -c 1 8.8.8.8 > /dev/null 2>&1; then 5 | echo "Link Up"; 6 | else 7 | echo "Link Down"; 8 | fi 9 | -------------------------------------------------------------------------------- /loadavg: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #---------------------------------------------------------------------------------------------------- 3 | threshold=${BLOCK_INSTANCE:-5}; 4 | load=$(cut -d ' ' -f1 /proc/loadavg); 5 | 6 | #Display as red if load exceeds threshold 7 | if (( $(echo "$load $threshold" | awk '{print ($1 > $2)}') )); then 8 | echo "$load"; 9 | else echo $load; 10 | fi 11 | -------------------------------------------------------------------------------- /volume: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #---------------------------------------------------------------------------------------------------- 3 | #Mouse actions for the block 4 | case $BLOCK_BUTTON in 5 | 1) pamixer -t ;; 6 | 4) pamixer -i 3 ;; 7 | 5) pamixer -d 3 ;; 8 | esac 9 | 10 | #Toggle mute 11 | [[ $(pamixer --get-mute) = "true" ]] && echo -n 🔇 && exit 12 | #Display volume 13 | echo 🔊 $(pamixer --get-volume)%; 14 | -------------------------------------------------------------------------------- /resources/example.conf: -------------------------------------------------------------------------------- 1 | command=/$BLOCK_NAME 2 | separator_block_width=15 3 | 4 | [music] 5 | label= 🎧 6 | interval=1 7 | signal=3 8 | 9 | [gmail] 10 | label=📧 11 | interval=1800 12 | instance=.gmail 13 | signal=2 14 | 15 | [loadavg] 16 | label= 17 | interval=10 18 | markup=pango 19 | 20 | [disk] 21 | label=🗄 22 | interval=3600 23 | 24 | [volume] 25 | interval=once 26 | signal=1 27 | 28 | [date] 29 | label=📅 30 | interval=5 31 | command=echo $(date '+%d %b %Y') 32 | 33 | [time] 34 | label=🕓 35 | interval=5 36 | command=echo $(date '+%H:%M:%S') 37 | -------------------------------------------------------------------------------- /disk: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #---------------------------------------------------------------------------------------------------- 3 | #Directory whose available space is to be displayed 4 | dir="${BLOCK_INSTANCE:-$HOME}"; 5 | 6 | #Color text red when less than 10% space is available 7 | lowAlert=10; 8 | 9 | #Fetch directory space info 10 | total=$(df -h -P -l "$dir" | tail -1 | awk '{print $2}' | tr -dc '0-9'); 11 | avail=$(df -h -P -l "$dir" | tail -1 | awk '{print $4}' | tr -dc '0-9'); 12 | 13 | #Display output 14 | if (( $(( $avail*100/$total )) < $lowAlert )); then 15 | echo "${avail}G"; 16 | else 17 | echo "${avail}G"; 18 | fi 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Utkarsh Verma 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /music: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #---------------------------------------------------------------------------------------------------- 3 | # Requires playerctl - https://github.com/acrisci/playerctl 4 | #---------------------------------------------------------------------------------------------------- 5 | #Exit the script if no music players running 6 | [[ "$(playerctl status 2>&1)" = "No players found" ]] && exit 33; 7 | 8 | # Define cursor icons 9 | playIcon=""; 10 | pauseIcon=" ⏸️"; 11 | stopIcon=" ⏹️"; 12 | 13 | #User provided args for playerctl 14 | ARGUMENTS="$INSTANCE"; 15 | 16 | #Mouse actions for the block 17 | case $BLOCK_BUTTON in 18 | 1) playerctl $ARGUMENTS previous ;; 19 | 2) playerctl $ARGUMENTS play-pause ;; 20 | 3) playerctl $ARGUMENTS next ;; 21 | 4) playerctl $ARGUMENTS position 5+ ;; 22 | 5) playerctl $ARGUMENTS position 5- ;; 23 | esac 24 | 25 | #Define song info variables 26 | playerStatus=$(playerctl $ARGUMENTS status); 27 | songArtist="$(playerctl $ARGUMENTS metadata artist)"; 28 | songArtist="${songArtist:-(Unknown Artist)}"; 29 | songTitle=$(playerctl $ARGUMENTS metadata title); 30 | songInfo="$songArtist - $songTitle"; 31 | songDuration=""; 32 | elapsedTime=$(playerctl metadata --format "{{ duration(position) }}"); 33 | songLength=$(playerctl metadata --format "{{ duration(mpris:length) }}"); 34 | 35 | #`playerctl position` doesn't work for "Spotify" 36 | if [[ $(playerctl -l) != "spotify" ]]; then 37 | songDuration=" ($elapsedTime/$songLength)"; 38 | fi 39 | 40 | #Display output 41 | if [[ "${playerStatus^}" = "Paused" ]]; then 42 | echo "$songInfo$songDuration$pauseIcon"; 43 | elif [[ "${playerStatus^}" = "Playing" ]]; then 44 | echo "$songInfo$songDuration$playIcon"; 45 | elif [[ "${playerStatus^}" = "Stopped" ]]; then 46 | echo "Stopped$stopIcon"; 47 | fi 48 | -------------------------------------------------------------------------------- /gmail: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #---------------------------------------------------------------------------------------------------- 3 | # Scipt for fetching the unread mail count of Gmail. 4 | # Uses OAuth2 for authentication. 5 | # Requires jq - https://stedolan.github.io/jq 6 | #---------------------------------------------------------------------------------------------------- 7 | # Exit the script if there's no internet. 8 | ping -c 1 8.8.8.8 > /dev/null 2>&1 || exit 33 9 | 10 | # Path to config file. 11 | configFile="$HOME/$BLOCK_INSTANCE" 12 | 13 | # Exit script if no config file found. 14 | if [[ ! -f "$configFile" ]]; then 15 | echo "$configFile: No such file or directory"; 16 | exit 33; 17 | fi 18 | 19 | # Mouse actions for the block. 20 | case $BLOCK_BUTTON in 21 | 1) xdg-open https://mail.google.com > /dev/null 2>&1 ;; 22 | esac 23 | 24 | # Source variables from config file. 25 | source $configFile 26 | eval tokenFile=$tokenFile 27 | 28 | # Google API variables. 29 | refreshToken=$(jq '.refresh_token' "$tokenFile" | tr -d \") 30 | 31 | # Generates JSON to be POSTed. 32 | generateJSON() { 33 | cat << EOF 34 | { 35 | "client_id":"$clientID", 36 | "client_secret":"$clientSecret", 37 | "refresh_token":"$refreshToken", 38 | "grant_type":"refresh_token" 39 | } 40 | EOF 41 | } 42 | 43 | # Fetch the new access token. 44 | accessToken=$(curl -s https://www.googleapis.com/oauth2/v4/token \ 45 | -H "Content-Type: application/json" \ 46 | -d "$(generateJSON)" | jq '.access_token' | tr -d \") 47 | 48 | # Update access_token in tokenFile. 49 | tmp=$(mktemp) 50 | jq ".access_token = \"$accessToken\"" "$tokenFile" > "$tmp" && mv "$tmp" "$tokenFile" 51 | 52 | # Fetch unread mails count. 53 | count=$(curl -s -H "Authorization: Bearer $accessToken" \ 54 | 'https://www.googleapis.com/gmail/v1/users/me/labels/INBOX' \ 55 | | jq '.messagesUnread') 56 | 57 | # Display the count, if non-zero. 58 | [[ $count = "0" ]] || echo $count 59 | -------------------------------------------------------------------------------- /resources/gmail/genToken.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #---------------------------------------------------------------------------------------------------- 3 | # Script to generate access token for Gmail blocklet. 4 | # Requires jq - https://stedolan.github.io/jq 5 | #---------------------------------------------------------------------------------------------------- 6 | # Default config path. 7 | configFile="~/.gmail" 8 | 9 | # Read CLI arguments. 10 | while getopts ":c:" opt; do 11 | case $opt in 12 | c) configFile="$OPTARG";; 13 | \?) echo "Invalid option -$OPTARG" >&2;; 14 | esac 15 | done 16 | 17 | eval configFile=$configFile; 18 | source $configFile || exit 1 19 | eval tokenFile=$tokenFile 20 | 21 | scope="https://www.googleapis.com/auth/gmail.labels" 22 | redirectURL="http://localhost:" 23 | 24 | # Find a random unused local port. 25 | while : 26 | do 27 | if [[ "$(netstat -lntu | grep -c ":$port")" -gt "0" ]] 28 | then 29 | port=$(( $RANDOM % 4000 )) 30 | else 31 | redirectURL+="$port" 32 | break 33 | fi 34 | done 35 | 36 | # Generates JSON which has to be POSTed. 37 | generateJSON() { 38 | cat << EOF 39 | { 40 | "code":"$oauthCode", 41 | "client_id":"$clientID", 42 | "client_secret":"$clientSecret", 43 | "grant_type":"authorization_code", 44 | "redirect_uri":"$redirectURL", 45 | } 46 | EOF 47 | } 48 | 49 | # Open user consent window. 50 | echo "Opening user-consent in web browser..." 51 | sleep 2 52 | authURL="\ 53 | https://accounts.google.com/o/oauth2/v2/auth?\ 54 | client_id=$clientID&\ 55 | redirect_uri=$redirectURL&\ 56 | response_type=code&\ 57 | scope=$scope&\ 58 | access_type=offline" 59 | xdg-open $authURL 60 | 61 | if [[ $? != 0 ]] 62 | then 63 | echo -e "Could not open web browser. Open this link manually:\n$authURL" 64 | sleep 10 65 | fi 66 | 67 | # Fetch the authorization code. 68 | oauthCode=`nc -lW 1 $port | head -1 | sed -nr "s/.*code=(.*)&.*/\1/p"` 69 | if [[ $? != 0 ]] 70 | then 71 | echo "Authorization code fetched successfully." 72 | else 73 | echo "Failed to get authorization code." 74 | exit 33 75 | fi 76 | 77 | # Fetch and save access, refresh tokens as JSON. 78 | mkdir -p $(dirname $tokenFile); 79 | touch $tokenFile; 80 | curl -s https://www.googleapis.com/oauth2/v4/token \ 81 | -H "Content-Type: application/json" \ 82 | -d "$(generateJSON)" > $tokenFile; 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # i3blocklets 2 | ![Demo](/scrot.png) 3 | 4 | This repository contains the bash scripts which I use with [i3blocks](https://github.com/vivien/i3blocks). 5 | 6 | ## Dependencies 7 | To use these scripts, the following dependencies need to be satisfied: 8 | 9 | * **Volume Block:** 10 | - pamixer - [cdemoulins/pamixer](https://github.com/cdemoulins/pamixer) 11 | 12 | * **Music Block:** 13 | - playerctl - [acrisci/playerctl](https://github.com/acrisci/playerctl) 14 | - ~~formatTime - [UtkarshVerma/scripts/formatTime](https://github.com/UtkarshVerma/scripts/blob/master/formatTime)~~ 15 | 16 | * **Gmail Block:** 17 | - jq - [stedolan/js](https://github.com/stedolan/jq) 18 | 19 | * **[FontAwesome](https://fontawesome.com/)** fonts(tested with v4.7.0) are required to render the unicode emojis, therefore specify it in i3bar config as shown: 20 | ``` 21 | bar { 22 | # .... other stuff 23 | font pango:DejaVu Sans Mono, FontAwesome 9 24 | } 25 | ``` 26 | 27 | ## Installation 28 | * Place [`example.conf`](/resources/example.conf) as `i3blocks.conf` in your i3 config directory. 29 | * Replace `PATH_TO_BLOCKLETS` in the `i3blocks.conf` file with the directory's path which contains your blocklets. 30 | 31 | ## Usage 32 | ### Music Block 33 | ``` 34 | [music] 35 | label= 🎧 36 | interval=1 37 | instance="" 38 | signal=3 39 | ``` 40 | You can also pass arguments to `playerctl` through the `instance` config variable. For example, `instance="-p audacious"` will be interpreted as `playerctl -p audacious `. 41 | 42 | #### The following actions can be performed via the mouse 43 | * Left click - Switch to the previous song; 44 | * Right click - Switch to the next song; 45 | * Middle click - Pause/play the current song. 46 | * Scroll up - Seek song forward by 5 seconds; 47 | * Scroll down - Seek song backward by 5 seconds. 48 | 49 | ~~This seeking capability is only available for `audacious` currently.~~ 50 | 51 | The seeking capability has now been extended to all music players. 52 | 53 | This script focuses only on MPRIS media players. Therefore this script won't work for `cmus`< v2.8.0. You may either update `cmus` or just add a bit of code as a workaround as done in this [older commit](https://github.com/UtkarshVerma/i3blocklets/blob/77ec353d01a12539edb3a3b211dd06f275807d2d/music). 54 | 55 | --- 56 | 57 | ### Gmail Block 58 | ``` 59 | [gmail] 60 | label=📧 61 | interval=1800 62 | instance=.gmail 63 | ``` 64 | This block will check your gmail account for mails every 1800 seconds, that is the `interval` time. 65 | This blocket uses [OAuth2](https://oauth.net/2/) for authorizing itself. To use this blocklet: 66 | * Create a project on [Google API Console](https://console.developers.google.com/), [enable Gmail API](https://developers.google.com/identity/protocols/OAuth2InstalledApp#enable-apis) for your project, and [create authorization credentials](https://developers.google.com/identity/protocols/OAuth2InstalledApp#creatingcred) for this blocklet. Choose **Other** as *Application Type* while creating the OAuth client ID. Make sure to provide your application `read-only` access. 67 | * Once created, take note of the **Client ID** and **Client Secret**. These will be used later on. 68 | * Edit the [`configFile`](/resources/gmail/configFile) for this blocklet according to your needs and place it in the `$HOME` directory. You may rename it if you like. I personally prefer `.gmail`. 69 | > The `tokenFile` variable must contain the path to the file which you want to create for storing access tokens for the API. 70 | * Now, generate your access token using [genToken.sh](/resources/gmail/genToken.sh) by running `./genToken.sh -c ` in the terminal. For example: 71 | 72 | ```bash 73 | # Specify config file using -c flag 74 | ./genToken.sh -c 75 | # Or simply use ~/.gmail as config file 76 | ./genToken.sh 77 | ``` 78 | Google's user consent webpage will open up in your default browser. Allow this application there. This will generate a JSON file at the path specified in `tokenFile` variable in `configFile`. 79 | 80 | Everything's done now. Just add the `gmail` block to your `i3blocks` config as shown above. 81 | > Note that the `instance` variable holds the path of the config file relative to the home directory, therefore *.gmail* is implicitly expanded to *~/.gmail*. 82 | 83 | #### The following actions can be performed via the mouse 84 | * Left click - Open GMail in the default browser; 85 | * Right click - Update mail count. 86 | 87 | --- 88 | 89 | ### Average Load Block 90 | ``` 91 | [loadavg] 92 | label= 93 | interval=10 94 | markup=pango 95 | instance=3 96 | ``` 97 | Shows the average load of the processor. The output is colored **red** if the *average load* exceeds the *threshold value*. The threshold value can be provided through `instance` variable, which defaults to `5`. 98 | 99 | #### The following actions can be performed via the mouse: 100 | * Left click- Refresh average load value. 101 | 102 | --- 103 | 104 | ### Storage Block 105 | ``` 106 | [disk] 107 | label=🗄 108 | interval=3600 109 | markup=pango 110 | instance="" 111 | ``` 112 | This block shows the remaining space on your disk. By default, the free space of `$HOME` partition will be shown, however, you may specify other partitions as well using the `instance` config variable. For exampe, `instance="/dev/sda2"`. 113 | 114 | --- 115 | 116 | ### Volume Block 117 | ``` 118 | [volume] 119 | interval=once 120 | signal=1 121 | ``` 122 | This block shows the volume level in percent. To reduce load, this script is loaded only once and then triggered on the press of **media keys** and block clicks. Therefore, it is **highly important** to bind the following command to your *volume keys* on the keyboard, otherwise the changes won't appear on the i3bar. 123 | ``` 124 | pkill -RTMIN+1 i3blocks 125 | ``` 126 | #### The following actions can be performed via the mouse 127 | * Left click - Mute; 128 | * Scroll up - Increase volume by 5%; 129 | * Scroll down - Decrease volume by 5%. 130 | 131 | --- 132 | 133 | ### Internet Block 134 | ``` 135 | [internet] 136 | interval=1800 137 | markup=pango 138 | ``` 139 | This block shows whether your PC is connected to the internet or not. It relies on the `ping` command. 140 | 141 | #### The following actions can be performed via the mouse 142 | * Left click - Refresh internet status. 143 | 144 | --- 145 | 146 | For additional insight, you may also look into my i3blocks config file: [i3blocks.conf](https://github.com/UtkarshVerma/dotfiles/blob/master/i3/i3blocks.conf). 147 | --------------------------------------------------------------------------------