trying to set up a bash script and applet for expressvpn [SOLVED]

Quick to answer questions about finding your way around Linux Mint as a new user.
Forum rules
There are no such things as "stupid" questions. However if you think your question is a bit stupid, then this is the right place for you to post it. Stick to easy to-the-point questions that you feel people can answer fast. For long and complicated questions use the other forums in the support section.
Before you post read how to get help. Topics in this forum are automatically closed 6 months after creation.
Locked
dondondon

trying to set up a bash script and applet for expressvpn [SOLVED]

Post by dondondon »

I'm following these instructions from https://joshua14.homelinux.org/blog/?p=2318

The title reads "How I Automated My ExpressVPN Connection Under Ubuntu" and it was published in October 2016, so I can guess right here might be part of my problem, but I'm a total newb, so :shrug:

The end result I'm looking for is an applet that lets me know I'm connected to the vpn, and tells me when I'm not.

OK, here are the instructions:
When you list the countries that you can connect to, there is a “Y” next to some of the items. This means these countries/locations are “recommended” for best speed. They differ from the “smart” connection option in that the smart connection will always be the country you reside in, although a different IP address.
I thought it would be good so that when I login to my Ubuntu machine, it connects to a randomly selected VPN country which has the “recommended” “Y” next to it. Since I don’t use Unity under Ubuntu but Cinnamon (much better, IMHO) I’d also like to display the country I’m connected to as a Desklet in my top desktop panel.

Here is the bash script which does this on boot.

Code: Select all

#!/bin/bash
expressvpn refresh
expressvpn list | tail -n+3 | column -ts $'t' | sed 's/   */:/g' > data.tmp
cat data.tmp | while read LINE
do
        if [ `echo $LINE | tail -c 2` == 'Y' ]; then
                TEMP=`echo $LINE | grep : | awk -F: '{print $1}'`
                echo "$TEMP" >> array.tmp
        fi
done
ARRAY_SIZE=`wc -l array.tmp | awk {'print $1'}`
RND_VPN=`shuf -i 1-$ARRAY_SIZE -n 1`
VPN=`sed "${RND_VPN}q;d" array.tmp`
rm -f data.tmp
rm -f array.tmp
expressvpn connect $VPN
The last bit is showing this information in Cinnamon as an applet. I don’t know much about writing JavaScript applets apart from they’re written in JavaScript as the Cinnamon documentation for this is super-weak, but I found a simple network status applet which is basically a refreshing label and that will do. All this does is put the output from the “expressvpn status” command into a label and displays it. Simple applets are composed from two files, the JavaScript JS file and a JSON descriptor file. Here are my horrible hacked together versions.
applet.js

Code: Select all

const Applet = imports.ui.applet;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const GLib = imports.gi.GLib;
const UUID = "expressvpn@jon";
const REFRESH_INTERVAL = 10

function log(message) {
    global.log(UUID + '#' + log.caller.name + ': ' + message);
}

function logError(error) {
    global.logError(UUID + '#' + logError.caller.name + ': ' + error);
}

function MyApplet(orientation) {
    this._init(orientation);
}

MyApplet.prototype = {
    __proto__: Applet.TextApplet.prototype,
    _init: function (orientation) {
        Applet.TextIconApplet.prototype._init.call(this, orientation);
        try {
            this.set_applet_icon_name("emblem-web");
            this.set_applet_tooltip(_("ExpressVPN Node location."));
            this.set_applet_label("...");
        }
        catch (error) {
            logError(error);
        }
        this.refreshLocation();
},

    refreshLocation: function refreshLocation() {
        let [res, out] = GLib.spawn_command_line_sync(" expressvpn status ")
        let out = String(out).replace("n", "");
        let out = String(out).trim();
        //let out = String(out).replace(/ /g, "-");
        //let out = String(out).replace(/   /g, " ");
        this.set_applet_label('VPN: ' + out + '');
        Mainloop.timeout_add_seconds(REFRESH_INTERVAL, Lang.bind(this, function refreshTimeout() {
            this.refreshLocation();
        }));
    }
};

function main(metadata, orientation) {
    let myapplet = new MyApplet(orientation);
    return myapplet;
}
metadata.json

Code: Select all

{
    "dangerous": true,
    "description": "Shows ExpressVPN Location",
    "name": "ExpressVPNStatus",
    "uuid": "expressvpn@jon"
}
Both these files go in the directory “$HOME/.local/share/cinnamon/applets/expressvpn@jon” as the directory is “applet_name@author” format. You can then add the applet as normal in Cinnamon to a panel.
so, I made the script executable, created a scripts directory in my home folder, added it to the PATH variable, moved the script to that folder. not sure if that part worked, but the script works...

the problem is the applet, which I get an error when trying to add to my taskbar

errors from glass.log:

<----------------
Extension.prototype._init@/usr/share/cinnamon/js/ui/extension.js:155:13
Extension@/usr/share/cinnamon/js/ui/extension.js:116:5
loadExtension@/usr/share/cinnamon/js/ui/extension.js:449:25
onEnabledAppletsChanged@/usr/share/cinnamon/js/ui/appletManager.js:236:13
---------------->
error t=2018-01-16T20:31:09.042Z [Applet "expressvpn@jon"]: Error importing applet.js from expressvpn@jon
error t=2018-01-16T20:31:09.042Z Could not load applet expressvpn@jon

not sure which errors come from this in .xsession-errors so I dropped them in pastebin

https://pastebin.com/xN36WyX0


Hopefully I submitted all of the relevant information and someone can help me. I'm a newish linux user. Much more user friendly than 15 years ago when I first tried it out. I love mint, but it's all quite confusing to me. I'm not horrible at following instructions, but the linux rabbithole is deep and wide. any assistance will be greatly appreciated, since expressvpn hasn't come up with this feature themselves, yet (for the applet, which is the part I really care about)

Thank you.
Last edited by LockBot on Wed Dec 28, 2022 7:16 am, edited 2 times in total.
Reason: Topic automatically closed 6 months after creation. New replies are no longer allowed.
blockhead47
Level 3
Level 3
Posts: 140
Joined: Wed Jun 15, 2016 4:50 pm

Re: trying to set up a bash script and applet for expressvpn

Post by blockhead47 »

I had to modify the applet.js for newer versions of Cinnamon. Try the one below"

Code: Select all

const Applet = imports.ui.applet;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const GLib = imports.gi.GLib;
const UUID = "expressvpn@jon";
const REFRESH_INTERVAL = 5

function log(message) {
    global.log(UUID + '#' + log.caller.name + ': ' + message);
}

function logError(error) {
    global.logError(UUID + '#' + logError.caller.name + ': ' + error);
}

function MyApplet(orientation) {
    this._init(orientation);
}

MyApplet.prototype = {
    __proto__: Applet.TextApplet.prototype,
    _init: function (orientation) {
        Applet.TextIconApplet.prototype._init.call(this, orientation);
        try {
            this.set_applet_icon_name("emblem-web");
            this.set_applet_tooltip(_("ExpressVPN Connection Status."));
            this.set_applet_label("...");
        }
        catch (error) {
            logError(error);
        }
        this.refreshLocation();
},

    refreshLocation: function refreshLocation() {
        let [res,out3] = GLib.spawn_command_line_sync(" expressvpn status ");
        let out2 = String(out3).replace("n", "");
        let out = String(out2).trim();
        this.set_applet_label('VPN: ' + out + '');
        Mainloop.timeout_add_seconds(REFRESH_INTERVAL, Lang.bind(this, function refreshTimeout() {
            this.refreshLocation();
        }));
    }
};

function main(metadata, orientation) {
    let myapplet = new MyApplet(orientation);
    return myapplet;
}
dondondon

Re: trying to set up a bash script and applet for expressvpn

Post by dondondon »

yay! thank you!. I works now :-D
BTCSMS
Level 2
Level 2
Posts: 64
Joined: Sun Feb 14, 2021 7:27 pm

Re: trying to set up a bash script and applet for expressvpn [SOLVED]

Post by BTCSMS »

dondondon wrote: Tue Jan 16, 2018 4:39 pm I'm following these instructions from https://joshua14.homelinux.org/blog/?p=2318

The title reads "How I Automated My ExpressVPN Connection Under Ubuntu" and it was published in October 2016, so I can guess right here might be part of my problem, but I'm a total newb, so :shrug:

The end result I'm looking for is an applet that lets me know I'm connected to the vpn, and tells me when I'm not.

OK, here are the instructions:
When you list the countries that you can connect to, there is a “Y” next to some of the items. This means these countries/locations are “recommended” for best speed. They differ from the “smart” connection option in that the smart connection will always be the country you reside in, although a different IP address.
I thought it would be good so that when I login to my Ubuntu machine, it connects to a randomly selected VPN country which has the “recommended” “Y” next to it. Since I don’t use Unity under Ubuntu but Cinnamon (much better, IMHO) I’d also like to display the country I’m connected to as a Desklet in my top desktop panel.

Here is the bash script which does this on boot.

Code: Select all

#!/bin/bash
expressvpn refresh
expressvpn list | tail -n+3 | column -ts $'t' | sed 's/   */:/g' > data.tmp
cat data.tmp | while read LINE
do
        if [ `echo $LINE | tail -c 2` == 'Y' ]; then
                TEMP=`echo $LINE | grep : | awk -F: '{print $1}'`
                echo "$TEMP" >> array.tmp
        fi
done
ARRAY_SIZE=`wc -l array.tmp | awk {'print $1'}`
RND_VPN=`shuf -i 1-$ARRAY_SIZE -n 1`
VPN=`sed "${RND_VPN}q;d" array.tmp`
rm -f data.tmp
rm -f array.tmp
expressvpn connect $VPN
The last bit is showing this information in Cinnamon as an applet. I don’t know much about writing JavaScript applets apart from they’re written in JavaScript as the Cinnamon documentation for this is super-weak, but I found a simple network status applet which is basically a refreshing label and that will do. All this does is put the output from the “expressvpn status” command into a label and displays it. Simple applets are composed from two files, the JavaScript JS file and a JSON descriptor file. Here are my horrible hacked together versions.
applet.js

Code: Select all

const Applet = imports.ui.applet;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const GLib = imports.gi.GLib;
const UUID = "expressvpn@jon";
const REFRESH_INTERVAL = 10

function log(message) {
    global.log(UUID + '#' + log.caller.name + ': ' + message);
}

function logError(error) {
    global.logError(UUID + '#' + logError.caller.name + ': ' + error);
}

function MyApplet(orientation) {
    this._init(orientation);
}

MyApplet.prototype = {
    __proto__: Applet.TextApplet.prototype,
    _init: function (orientation) {
        Applet.TextIconApplet.prototype._init.call(this, orientation);
        try {
            this.set_applet_icon_name("emblem-web");
            this.set_applet_tooltip(_("ExpressVPN Node location."));
            this.set_applet_label("...");
        }
        catch (error) {
            logError(error);
        }
        this.refreshLocation();
},

    refreshLocation: function refreshLocation() {
        let [res, out] = GLib.spawn_command_line_sync(" expressvpn status ")
        let out = String(out).replace("n", "");
        let out = String(out).trim();
        //let out = String(out).replace(/ /g, "-");
        //let out = String(out).replace(/   /g, " ");
        this.set_applet_label('VPN: ' + out + '');
        Mainloop.timeout_add_seconds(REFRESH_INTERVAL, Lang.bind(this, function refreshTimeout() {
            this.refreshLocation();
        }));
    }
};

function main(metadata, orientation) {
    let myapplet = new MyApplet(orientation);
    return myapplet;
}
metadata.json

Code: Select all

{
    "dangerous": true,
    "description": "Shows ExpressVPN Location",
    "name": "ExpressVPNStatus",
    "uuid": "expressvpn@jon"
}
Both these files go in the directory “$HOME/.local/share/cinnamon/applets/expressvpn@jon” as the directory is “applet_name@author” format. You can then add the applet as normal in Cinnamon to a panel.
so, I made the script executable, created a scripts directory in my home folder, added it to the PATH variable, moved the script to that folder. not sure if that part worked, but the script works...

the problem is the applet, which I get an error when trying to add to my taskbar

errors from glass.log:

<----------------
Extension.prototype._init@/usr/share/cinnamon/js/ui/extension.js:155:13
Extension@/usr/share/cinnamon/js/ui/extension.js:116:5
loadExtension@/usr/share/cinnamon/js/ui/extension.js:449:25
onEnabledAppletsChanged@/usr/share/cinnamon/js/ui/appletManager.js:236:13
---------------->
error t=2018-01-16T20:31:09.042Z [Applet "expressvpn@jon"]: Error importing applet.js from expressvpn@jon
error t=2018-01-16T20:31:09.042Z Could not load applet expressvpn@jon

not sure which errors come from this in .xsession-errors so I dropped them in pastebin

https://pastebin.com/xN36WyX0


Hopefully I submitted all of the relevant information and someone can help me. I'm a newish linux user. Much more user friendly than 15 years ago when I first tried it out. I love mint, but it's all quite confusing to me. I'm not horrible at following instructions, but the linux rabbithole is deep and wide. any assistance will be greatly appreciated, since expressvpn hasn't come up with this feature themselves, yet (for the applet, which is the part I really care about)

Thank you.

This didn't work for me at all.
The first block of script fails after
"fi
done"

Next line of script ARRAY_SIZE=`wc -l array.tmp | awk {'print $1'}` returns:
wc: array.tmp: No such file or directory

Next line of script RND_VPN=`shuf -i 1-$ARRAY_SIZE -n 1` returns:
shuf: invalid input range: ‘’

Next line of script VPN=`sed "${RND_VPN}q;d" array.tmp` returns:
sed: can't read array.tmp: No such file or directory

Next line of script rm -f data.tmp does nothing
Next line of script rm -f array.tmp does nothing
Next line of script expressvpn connect $VPN[/code] does nothing

Therefore, the entire script for me, does nothing.
Linux Mint 20.1 Ulyssa
Kernel: 5.4.0-66-generic x86_64
CPU: Intel Core i5-6500 quad-core
Memory: 1TB, 16G RAM
Graphics: Intel HD Graphics 530
Audio: Intel 100 Series/C230 HD
Network: Intel Ethernet I219-V and
Realtek RTL8812AE 802.11ac PCIe wifi
Locked

Return to “Beginner Questions”