First mainly working with not embedded auth string

This commit is contained in:
Neil Bird 2021-02-19 17:43:41 +00:00
commit 808581a92f
8 changed files with 521 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
tmp

4
export-zip Executable file
View file

@ -0,0 +1,4 @@
#!/bin/bash
[ -d pi-hole@fnxweb,.com ] && cd pi-hole@fnxweb.com
git archive --format=zip -o /tmp/pihole-extension.zip master
# .. from inside pi-hole@fnxweb.com

View file

@ -0,0 +1,346 @@
// Import
const Atk = imports.gi.Atk;
const ExtensionUtils = imports.misc.extensionUtils
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Main = imports.ui.main;
const Mainloop = imports.mainloop;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Soup = imports.gi.Soup;
const St = imports.gi.St;
const IndicatorName = 'pi-hole';
// Global storage
let PiHoleExt = {
// Extension metadata
Metadata : null,
// The button
Button : null
};
// Implement MythTV class
const PiHole = new Lang.Class(
{
Name : IndicatorName,
Extends : PanelMenu.Button,
// Debug
Debug: true,
// Timer period (seconds)
UpdateTime : 20,
// API key
ApiKey : '',
// Disable duration (seconds)
DisableTime : 20,
// Status URL
StatusUrl: 'http://pi.hole/admin',
// $StatusUrl/api.php?disable=$duration&auth=$auth
// Updates
StatusEvent: null,
// Current status
StatusField: null,
IconStatus: "",
Status: "unknown",
// Buttons
Icon: null,
PauseButton: null,
EnableDisableButton: null,
SettingsButton: null,
// ctor
_init : function()
{
this.parent(null, IndicatorName);
this.actor.accessible_role = Atk.Role.TOGGLE_BUTTON;
PiHoleExt.Metadata = ExtensionUtils.getCurrentExtension();
// TEMP read auth from file until settings done
let auth_file = PiHoleExt.Metadata.path + "/auth";
if (GLib.file_test(auth_file, GLib.FileTest.EXISTS))
{
this.dprint("Found auth file");
let auth = imports.gi.Shell.get_file_contents_utf8_sync(auth_file).split(/\n/);
this.ApiKey = auth[0];
}
else
{
this.dprint("NOT FOUND auth file");
}
this.dprint("Using auth '" + this.ApiKey + "'");
// Create a Soup session with which to do requests
this.SoupSession = new Soup.SessionAsync();
if (Soup.Session.prototype.add_feature != null)
Soup.Session.prototype.add_feature.call(this.SoupSession, new Soup.ProxyResolverDefault());
// Create button/icon
this.Icon = new St.Icon({ style_class: 'system-status-icon' });
this.add_child( this.Icon );
this.setIcon();
// Prep. menu
if (Main.panel._menus == undefined)
Main.panel.menuManager.addMenu(this.menu);
else
Main.panel._menus.addMenu(this.menu);
// Add status popup
// .. status
let box = new St.BoxLayout({style_class:'pihole-heading-row'});
let label = new St.Label({style_class:'pihole-label', text:"Pi-Hole Status: "});
box.add_actor(label);
this.StatusField = new St.Label({text:this.Status});
box.add_actor(this.StatusField);
this.addMenuItem(box);
// .. sep
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
// .. buttons
this.PauseButton = new PopupMenu.PopupMenuItem("Pause temporarily");
this.PauseButton.connect('activate', Lang.bind(this, function() {
this.onPauseButton();
return 0;
}));
this.menu.addMenuItem(this.PauseButton);
//
this.EnableDisableButton = new PopupMenu.PopupMenuItem("Disable");
this.EnableDisableButton.connect('activate', Lang.bind(this, function() {
this.onEnableDisableButton();
return 0;
}));
this.menu.addMenuItem(this.EnableDisableButton);
// .. sep
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
// .. settings
this.SettingsButton = new PopupMenu.PopupMenuItem("Settings");
this.SettingsButton.connect('activate', Lang.bind(this, function() {
this.onSettingsButton();
return 0;
}));
this.menu.addMenuItem(this.SettingsButton);
// Initial status (and starts timer for next)
this.getPiHoleStatus();
},
// Debug
dprint: function(msg)
{
if (this.Debug)
print("PiHole: " + msg);
},
// Error
eprint: function(msg)
{
global.log("PiHole: " + msg);
},
// Add an item to the “menu”
addMenuItem: function(item)
{
let menuitem = new PopupMenu.PopupBaseMenuItem({ reactive:false });
menuitem.actor.add_actor( item );
this.menu.addMenuItem( menuitem );
},
// Set correct icon
setIcon: function()
{
if (this.Status == this.IconStatus)
return;
this.IconStatus = this.Status;
if (this.IconStatus == "enabled")
this.Icon.set_gicon( this.getCustomIcon('pi-hole-symbolic') );
else if (this.IconStatus == "disabled")
this.Icon.set_gicon( this.getCustomIcon('pi-hole-disabled-symbolic') );
else
this.Icon.set_gicon( this.getCustomIcon('pi-hole-unknown-symbolic') );
},
// Get custom icon from theme or file
getCustomIcon: function(icon_name)
{
let icon_path = PiHoleExt.Metadata.dir.get_child('icons').get_child( icon_name + ".svg" ).get_path();
let theme = Gtk.IconTheme.get_default();
if (theme)
{
let theme_icon = theme.lookup_icon( icon_name, -1, 2 );
if (theme_icon)
icon_path = theme_icon.get_filename();
}
this.dprint("setting new icon from " + icon_path);
return Gio.FileIcon.new( Gio.File.new_for_path( icon_path ) );
},
// Request pi-hole status
getPiHoleStatus: function()
{
this.dprint("getting pi-hole status");
try
{
// Trigger request
let me = this;
let url = this.StatusUrl + "/api.php?status&auth=" + this.ApiKey;
let request = Soup.Message.new('GET', url);
this.SoupSession.queue_message(request, function(soup, message) {
if (message.status_code == 200)
me.processPiHoleStatus(request.response_body.data);
else
me.dprint("error retrieving status: " + message.status_code);
});
// Now do it again in a bit
this.StatusEvent = GLib.timeout_add_seconds(0, this.UpdateTime, Lang.bind(this, function() {
this.getPiHoleStatus();
return 0;
}));
}
catch (err)
{
this.eprint("exception requesting status: " + err);
}
},
// Pause pi-hole
onPauseButton: function()
{
// Do op
this.dprint("pausing pi-hole");
this.enableDisable( "disable=" + this.DisableTime.toString() );
// Now ask for status again a second after it should be re-enabled
Mainloop.source_remove(PiHoleExt.Button.StatusEvent);
this.StatusEvent = GLib.timeout_add_seconds(0, this.DisableTime + 1, Lang.bind(this, function() {
this.getPiHoleStatus();
return 0;
}));
},
// Enable or disable pi-hole
onEnableDisableButton: function()
{
// Do correct op
let op;
if (this.Status == "enabled")
{
this.dprint("disabling pi-hole (currently " + this.Status + ")");
op = "disable";
}
else
{
this.dprint("enabling pi-hole (currently " + this.Status + ")");
op = "enable";
}
this.enableDisable( op );
// Restart status request cycle since we just got an up-to-date status
Mainloop.source_remove(PiHoleExt.Button.StatusEvent);
this.StatusEvent = GLib.timeout_add_seconds(0, this.UpdateTime, Lang.bind(this, function() {
this.getPiHoleStatus();
return 0;
}));
},
// Enable or disable pi-hole given op
enableDisable: function( op )
{
this.dprint("requesting " + op);
try
{
// Trigger request
let me = this;
let url = this.StatusUrl + "/api.php?" + op + "&auth=" + this.ApiKey;
let request = Soup.Message.new('GET', url);
this.SoupSession.queue_message(request, function(soup, message) {
if (message.status_code == 200)
me.processPiHoleStatus(request.response_body.data);
else
me.dprint("error requesting disable: " + message.status_code);
});
}
catch (err)
{
this.eprint("exception requesting enable/disable: " + err);
}
},
// Read status
processPiHoleStatus: function(data)
{
this.dprint("processing status");
// Process JSON response status
this.Status = "unknown";
try
{
// Process results string
var obj = JSON.parse( data.toString() );
this.Status = obj.status;
}
catch (err)
{
this.eprint("exception processing status [" + data.toString() + "]: " + err);
}
// Update statuses
this.dprint("got status " + this.Status);
this.StatusField.set_text( this.Status );
this.setIcon();
if (this.Status == "enabled")
this.EnableDisableButton.label.set_text("Disable");
else
this.EnableDisableButton.label.set_text("Enable");
},
})
// Setup
function init()
{
}
// Turn on
function enable()
{
PiHoleExt.Button = new PiHole();
Main.panel.addToStatusArea( IndicatorName, PiHoleExt.Button );
}
// Turn off
function disable()
{
Mainloop.source_remove(PiHoleExt.Button.StatusEvent);
PiHoleExt.Button.
PiHoleExt.Button.destroy();
PiHoleExt.Button = null;
}

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="mdi-pi-hole"
width="24"
height="24"
viewBox="0 0 24 24"
sodipodi:docname="pi-hole-disabled-symbolic.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata1192">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1190" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1266"
inkscape:window-height="1053"
id="namedview1188"
showgrid="false"
inkscape:zoom="28.844358"
inkscape:cx="11.830741"
inkscape:cy="11.326561"
inkscape:window-x="794"
inkscape:window-y="156"
inkscape:window-maximized="0"
inkscape:current-layer="mdi-pi-hole" />
<path
id="rect1863"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
d="M 1.8144531 0.68554688 C 1.2374455 0.68554688 0.7734375 1.151508 0.7734375 1.7285156 L 0.7734375 22.130859 C 0.7734375 22.707867 1.2374455 23.171875 1.8144531 23.171875 L 22.216797 23.171875 C 22.793805 23.171875 23.259766 22.707867 23.259766 22.130859 L 23.259766 1.7285156 C 23.259766 1.151508 22.793805 0.68554688 22.216797 0.68554688 L 1.8144531 0.68554688 z M 5.6191406 2 C 9.4991406 2 11.569531 4.2896875 11.769531 7.9296875 C 12.499531 3.5696875 15.929688 4.0800781 15.929688 4.0800781 C 16.099688 6.5500781 14.069531 8.0499219 11.769531 8.1699219 C 11.119531 6.8099219 7.25 3.4707031 7.25 3.4707031 C 7.23 3.5007031 10.970078 6.7403906 10.830078 8.1503906 C 8.3300781 7.8803906 5.8191406 6 5.6191406 2 z M 12.042969 8.3730469 C 12.811719 8.3730469 13.580156 8.665 14.160156 9.25 L 18 13.109375 C 19.19 14.279375 19.19 16.179609 18 17.349609 L 14.160156 21.210938 C 13.000156 22.380938 11.089922 22.380937 9.9199219 21.210938 L 6.0605469 17.349609 C 4.8905469 16.179609 4.8905469 14.279375 6.0605469 13.109375 L 9.9199219 9.25 C 10.504922 8.665 11.274219 8.3730469 12.042969 8.3730469 z M 14.689453 11.339844 C 14.629453 12.329844 13.82 13.769531 12 13.769531 C 10.59 13.769531 9.5491406 12.630859 7.8691406 12.630859 C 8.5791406 12.670859 10.5 13.299609 10.5 15.349609 C 10.5 16.999609 9.390625 17.499844 9.390625 19.589844 C 9.390625 18.359844 10.149844 16.849609 12.089844 16.849609 C 13.399844 16.849609 14.870547 18.100938 16.310547 17.960938 C 14.870547 17.920938 13.589844 16.849453 13.589844 15.189453 C 13.589844 13.859453 14.689453 12.899844 14.689453 11.339844 z " />
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="mdi-pi-hole" width="24" height="24" viewBox="0 0 24 24"><path d="M5.62,2C9.5,2 11.57,4.29 11.77,7.93C12.5,3.57 15.93,4.08 15.93,4.08C16.1,6.55 14.07,8.05 11.77,8.17C11.12,6.81 7.25,3.47 7.25,3.47C7.23,3.5 10.97,6.74 10.83,8.15C8.33,7.88 5.82,6 5.62,2M6.06,13.11L9.92,9.25C11.09,8.08 13,8.08 14.16,9.25L18,13.11C19.19,14.28 19.19,16.18 18,17.35L14.16,21.21C13,22.38 11.09,22.38 9.92,21.21L6.06,17.35C4.89,16.18 4.89,14.28 6.06,13.11M9.39,19.59C9.39,18.36 10.15,16.85 12.09,16.85C13.4,16.85 14.87,18.1 16.31,17.96C14.87,17.92 13.59,16.85 13.59,15.19C13.59,13.86 14.69,12.9 14.69,11.34C14.63,12.33 13.82,13.77 12,13.77C10.59,13.77 9.55,12.63 7.87,12.63C8.58,12.67 10.5,13.3 10.5,15.35C10.5,17 9.39,17.5 9.39,19.59Z" /></svg>

After

Width:  |  Height:  |  Size: 958 B

View file

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="mdi-pi-hole"
width="24"
height="24"
viewBox="0 0 24 24"
sodipodi:docname="pi-hole-unknown-symbolic.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata9">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs7">
<marker
style="overflow:visible"
id="Arrow1Lstart"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lstart"
inkscape:isstock="true">
<path
transform="scale(0.8) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path836" />
</marker>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1510"
inkscape:window-height="1072"
id="namedview5"
showgrid="false"
inkscape:zoom="26.25"
inkscape:cx="12.506064"
inkscape:cy="13.164637"
inkscape:window-x="45"
inkscape:window-y="27"
inkscape:window-maximized="0"
inkscape:current-layer="mdi-pi-hole" />
<path
d="M5.62,2C9.5,2 11.57,4.29 11.77,7.93C12.5,3.57 15.93,4.08 15.93,4.08C16.1,6.55 14.07,8.05 11.77,8.17C11.12,6.81 7.25,3.47 7.25,3.47C7.23,3.5 10.97,6.74 10.83,8.15C8.33,7.88 5.82,6 5.62,2M6.06,13.11L9.92,9.25C11.09,8.08 13,8.08 14.16,9.25L18,13.11C19.19,14.28 19.19,16.18 18,17.35L14.16,21.21C13,22.38 11.09,22.38 9.92,21.21L6.06,17.35C4.89,16.18 4.89,14.28 6.06,13.11M9.39,19.59C9.39,18.36 10.15,16.85 12.09,16.85C13.4,16.85 14.87,18.1 16.31,17.96C14.87,17.92 13.59,16.85 13.59,15.19C13.59,13.86 14.69,12.9 14.69,11.34C14.63,12.33 13.82,13.77 12,13.77C10.59,13.77 9.55,12.63 7.87,12.63C8.58,12.67 10.5,13.3 10.5,15.35C10.5,17 9.39,17.5 9.39,19.59Z"
id="path2" />
<rect
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.392266;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;image-rendering:auto"
id="rect1106"
width="2.0748031"
height="6.1596851"
x="19.034275"
y="2.1843567"
ry="1.4848629"
rx="1.538754" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.398031;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path1122"
sodipodi:type="arc"
sodipodi:cx="20.071678"
sodipodi:cy="11.030456"
sodipodi:rx="1.0345261"
sodipodi:ry="0.96718389"
sodipodi:start="1.5707963"
sodipodi:end="1.5634302"
sodipodi:arc-type="slice"
d="m 20.071678,11.997639 a 1.0345261,0.96718389 0 0 1 -1.034524,-0.965402 1.0345261,0.96718389 0 0 1 1.030714,-0.968959 1.0345261,0.96718389 0 0 1 1.03832,0.961834 1.0345261,0.96718389 0 0 1 -1.026889,0.972501 l -0.0076,-0.967157 z" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1929"
width="23.190338"
height="23.210533"
x="0.40832201"
y="0.4021095"
rx="1.5387501"
ry="1.4848599" />
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -0,0 +1,8 @@
{
"shell-version": ["3.38"],
"uuid": "pi-hole@fnxweb.com",
"name": "pi-hole",
"url" : "https://github.com/fnxweb/gnome-shell-pi-hole",
"description": "Status and basic controls of local Pi-Hole",
"version": 0
}

View file

@ -0,0 +1,9 @@
StLabel
{
color: #ffffff;
}
.pihole-label
{
color: #999999;
}