├── LICENSE ├── README.md ├── air-raid-monitor@sirens.in.ua ├── extension.js ├── metadata.json └── ua.svg └── docs └── screenshot.jpg /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Dmytro Panin 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Air raid widget for Linux 2 | 3 | ![widget](docs/screenshot.jpg) 4 | 5 | This widget shows the current status of air raid sirens in Ukraine. The data is pulled every 20 seconds 6 | from https://sirens.in.ua/ 7 | 8 | #### Version of this widget for other platforms: 9 | 10 | * [Windows](https://github.com/dr-mod/air-raid-widget-windows) 11 | * [macOS](https://github.com/dr-mod/air-raid-widget-macos) 12 | * [RaspberryPi](https://github.com/dr-mod/air-raid-monitor) 13 | 14 | ## Installation 15 | 16 | ### Gnome 17 | 18 | 1. Install Gnome extensions 19 | ``` 20 | sudo apt install gnome-shell-extensions 21 | ``` 22 | 2. Download the widget 23 | ``` 24 | git clone https://github.com/dr-mod/air-raid-widget-linux.git 25 | ``` 26 | 3. Copy the widget to your Gnome shell extensions folder 27 | ``` 28 | cp -r air-raid-widget-linux/air-raid-monitor@sirens.in.ua ~/.local/share/gnome-shell/extensions/ 29 | ``` 30 | 4. Widgets can be enabled through console, therefore in our case 31 | ``` 32 | gnome-extensions enable air-raid-monitor@sirens.in.ua 33 | ``` 34 | and if you wish to disable it 35 | ``` 36 | gnome-extensions disable air-raid-monitor@sirens.in.ua 37 | ``` 38 | widgets can also be configured though other GUI management tools available in your distro, e.g. Tweaks, _Tweaks -> Extensions_. 39 | 40 | -------------------------------------------------------------------------------- /air-raid-monitor@sirens.in.ua/extension.js: -------------------------------------------------------------------------------- 1 | imports.gi.versions.Gtk = "3.0"; 2 | const Main = imports.ui.main; 3 | const Lang = imports.lang; 4 | const ExtensionUtils = imports.misc.extensionUtils; 5 | const Me = ExtensionUtils.getCurrentExtension(); 6 | const {St, Gio, Soup, GLib} = imports.gi; 7 | const ByteArray = imports.byteArray; 8 | 9 | // Parameters 10 | const api = 'http://sirens.in.ua/api/v1/'; 11 | const width = 240; 12 | const x = 80; 13 | const y = 40; 14 | const opacity = 210; 15 | 16 | const interval = 20 * 1000; 17 | const height = width * 0.67; 18 | 19 | let map; 20 | let extension = null; 21 | let icon; 22 | let box; 23 | let timer; 24 | 25 | const AirRaidWidget = new Lang.Class({ 26 | Name: 'AirRaidWidget', 27 | 28 | createBox: function () { 29 | const gicon = this.svg2Gicon(this.noDataMap(map)); 30 | icon = new St.Icon({ 31 | gicon: gicon, 32 | icon_size: width 33 | }); 34 | icon.width = width; 35 | icon.height = height; 36 | let propBox = new St.BoxLayout(); 37 | propBox.opacity = opacity; 38 | propBox.set_position(x, y); 39 | propBox.add_actor(icon); 40 | return propBox; 41 | }, 42 | 43 | svg2Gicon: function (svg) { 44 | return Gio.BytesIcon.new(ByteArray.toGBytes(ByteArray.fromString(svg))); 45 | }, 46 | 47 | changeColor: function (xml, region, color) { 48 | const regionName = this.escapeRegExp(region.trim()) 49 | var replace = `(name="${regionName}" fill=".*?")|(name="${regionName}")`; 50 | var re = new RegExp(replace, "g"); 51 | return xml.replace(re, `name="${regionName}" fill="${color}"`); 52 | }, 53 | 54 | escapeRegExp: function (string) { 55 | return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 56 | }, 57 | 58 | updateRegions: function (map, pieces) { 59 | let current_state_map = map; 60 | Object.entries(pieces).forEach(([key, value]) => { 61 | if (value == "full") { 62 | current_state_map = this.changeColor(current_state_map, key, '#EF476F') 63 | } else if (value == "partial") { 64 | current_state_map = this.changeColor(current_state_map, key, '#FFD166') 65 | } else if (value == "no_data") { 66 | current_state_map = this.changeColor(current_state_map, key, '#118AB2') 67 | } else { 68 | current_state_map = this.changeColor(current_state_map, key, '#06D6A0') 69 | } 70 | }); 71 | return current_state_map; 72 | }, 73 | 74 | noDataMap: function (map) { 75 | var replace = `(?:name="(.*?)" fill=".*?")|(?:name="(.*?)")`; 76 | var re = new RegExp(replace, "g"); 77 | return map.replace(re, `name="$1$2" fill="#118AB2"`); 78 | }, 79 | 80 | updateWidget: function () { 81 | try { 82 | const session = new Soup.SessionAsync({timeout: 10}); 83 | let message = Soup.form_request_new_from_hash('GET', api, {}); 84 | session.queue_message(message, () => { 85 | try { 86 | const obj = JSON.parse(message.response_body.data); 87 | icon.set_gicon(this.svg2Gicon(this.updateRegions(map, obj))); 88 | } catch (e) { 89 | icon.set_gicon(this.svg2Gicon(this.noDataMap(map))); 90 | } 91 | }); 92 | } catch (e) { 93 | icon.set_gicon(this.svg2Gicon(this.noDataMap(map))); 94 | } 95 | }, 96 | 97 | enable: function () { 98 | box = this.createBox(); 99 | Main.layoutManager._backgroundGroup.add_actor(box); 100 | this.updateWidget(); 101 | timer = GLib.timeout_add(GLib.PRIORITY_DEFAULT, interval, () => { 102 | this.updateWidget(); 103 | return GLib.SOURCE_CONTINUE; 104 | }); 105 | }, 106 | 107 | disable: function () { 108 | GLib.source_remove(timer); 109 | Main.layoutManager._backgroundGroup.remove_actor(box); 110 | }, 111 | }); 112 | 113 | function init() { 114 | const file = Gio.File.new_for_path(Me.path + "/ua.svg"); 115 | const [, contents, etag] = file.load_contents(null); 116 | map = ByteArray.toString(contents); 117 | } 118 | 119 | function enable() { 120 | extension = new AirRaidWidget(); 121 | extension.enable(); 122 | } 123 | 124 | function disable() { 125 | extension.disable(); 126 | extension = null; 127 | } -------------------------------------------------------------------------------- /air-raid-monitor@sirens.in.ua/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "uuid": "air-raid-monitor@sirens.in.ua", 3 | "name": "Air raid monitor", 4 | "description": "Shows active air raid sirens in Ukraine.", 5 | "version": 1, 6 | "shell-version": [ 7 | "3.34", 8 | "3.36", 9 | "3.38", 10 | "40", 11 | "42" 12 | ], 13 | "url": "https://github.com/dr-mod/air-raid-widget-linux" 14 | } -------------------------------------------------------------------------------- /air-raid-monitor@sirens.in.ua/ua.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /docs/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mod/air-raid-widget-linux/c8219a68e3666fda0441703d2e37311b5d5c3b0b/docs/screenshot.jpg --------------------------------------------------------------------------------