First mainly working with not embedded auth string
This commit is contained in:
commit
808581a92f
8 changed files with 521 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
tmp
|
4
export-zip
Executable file
4
export-zip
Executable 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
|
346
pi-hole@fnxweb.com/extension.js
Normal file
346
pi-hole@fnxweb.com/extension.js
Normal 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;
|
||||
}
|
54
pi-hole@fnxweb.com/icons/pi-hole-disabled-symbolic.svg
Normal file
54
pi-hole@fnxweb.com/icons/pi-hole-disabled-symbolic.svg
Normal 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 |
1
pi-hole@fnxweb.com/icons/pi-hole-symbolic.svg
Normal file
1
pi-hole@fnxweb.com/icons/pi-hole-symbolic.svg
Normal 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 |
98
pi-hole@fnxweb.com/icons/pi-hole-unknown-symbolic.svg
Normal file
98
pi-hole@fnxweb.com/icons/pi-hole-unknown-symbolic.svg
Normal 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 |
8
pi-hole@fnxweb.com/metadata.json
Normal file
8
pi-hole@fnxweb.com/metadata.json
Normal 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
|
||||
}
|
9
pi-hole@fnxweb.com/stylesheet.css
Normal file
9
pi-hole@fnxweb.com/stylesheet.css
Normal file
|
@ -0,0 +1,9 @@
|
|||
StLabel
|
||||
{
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.pihole-label
|
||||
{
|
||||
color: #999999;
|
||||
}
|
Loading…
Reference in a new issue