diff --git a/.gitignore b/.gitignore
index 1f5d281..ff3b193 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,9 @@ Thumbs.db
.Spotlight-V100
.Trashes
+# Jetbrains
+/.idea
+
# Created by https://www.gitignore.io/api/node
### Node ###
diff --git a/index.html b/index.html
index 63cf425..b5ea846 100644
--- a/index.html
+++ b/index.html
@@ -935,6 +935,18 @@ Pixel-perfect Retina-ready Fast Consistent Hackable
 |
https://img.shields.io/swagger/valid/2.0/https/bitbucket.org/api/swagger.json.svg |
+ Uptime Robot status: |
+  |
+ https://img.shields.io/uptimerobot/status/m778918918-3e92c097147760ee39d02d36.svg |
+
+ Uptime Robot ratio: |
+  |
+ https://img.shields.io/uptimerobot/ratio/m778918918-3e92c097147760ee39d02d36.svg |
+
+ Uptime Robot ratio (7 days): |
+  |
+ https://img.shields.io/uptimerobot/ratio/7/m778918918-3e92c097147760ee39d02d36.svg |
+
Longer Miscellaneous
diff --git a/server.js b/server.js
index 3f1a140..94f5bf1 100644
--- a/server.js
+++ b/server.js
@@ -6089,6 +6089,138 @@ cache(function(data, match, sendBadge, request) {
});
}));
+// Uptime Robot status integration.
+// API documentation : https://uptimerobot.com/api
+camp.route(/^\/uptimerobot\/status\/(.*)\.(svg|png|gif|jpg|json)$/,
+cache(function(data, match, sendBadge, request) {
+ var monitorApiKey = match[1]; // eg, m778918918-3e92c097147760ee39d02d36
+ var format = match[2];
+ var badgeData = getBadgeData('status', data);
+ var options = {
+ method: 'POST',
+ json: true,
+ body: {
+ "api_key": monitorApiKey,
+ "format": "json"
+ },
+ uri: 'https://api.uptimerobot.com/v2/getMonitors'
+ };
+ // A monitor API key must start with "m"
+ if (monitorApiKey.substring(0, "m".length) !== "m") {
+ badgeData.text[1] = 'must use a monitor key';
+ sendBadge(format, badgeData);
+ return;
+ }
+ request(options, function(err, res, json) {
+ if (err !== null || res.statusCode >= 500 || typeof json !== 'object') {
+ badgeData.text[1] = 'inaccessible';
+ sendBadge(format, badgeData);
+ return;
+ }
+ try {
+ if (json.stat === 'fail') {
+ badgeData.text[1] = 'vendor error';
+ if (json.error && typeof json.error.message === 'string') {
+ badgeData.text[1] = json.error.message;
+ }
+ badgeData.colorscheme = 'lightgrey';
+ sendBadge(format, badgeData);
+ return;
+ }
+ var status = json.monitors[0].status;
+ if (status === 0) {
+ badgeData.text[1] = 'paused';
+ badgeData.colorscheme = 'yellow';
+ } else if (status === 1) {
+ badgeData.text[1] = 'not checked yet';
+ badgeData.colorscheme = 'yellowgreen';
+ } else if (status === 2) {
+ badgeData.text[1] = 'up';
+ badgeData.colorscheme = 'brightgreen';
+ } else if (status === 8) {
+ badgeData.text[1] = 'seems down';
+ badgeData.colorscheme = 'orange';
+ } else if (status === 9) {
+ badgeData.text[1] = 'down';
+ badgeData.colorscheme = 'red';
+ } else {
+ badgeData.text[1] = 'invalid';
+ badgeData.colorscheme = 'lightgrey';
+ }
+ sendBadge(format, badgeData);
+ } catch(e) {
+ badgeData.text[1] = 'invalid';
+ sendBadge(format, badgeData);
+ }
+ });
+}));
+
+// Uptime Robot ratio integration.
+// API documentation : https://uptimerobot.com/api
+camp.route(/^\/uptimerobot\/ratio(\/[^\/]+)?\/(.*)\.(svg|png|gif|jpg|json)$/,
+cache(function(data, match, sendBadge, request) {
+ var numberOfDays = match[1]; // eg, 7, null if querying 30
+ var monitorApiKey = match[2]; // eg, m778918918-3e92c097147760ee39d02d36
+ var format = match[3];
+ var badgeData = getBadgeData('uptime', data);
+ if (numberOfDays) {
+ numberOfDays = numberOfDays.slice(1);
+ } else {
+ numberOfDays = '30';
+ }
+ var options = {
+ method: 'POST',
+ json: true,
+ body: {
+ "api_key": monitorApiKey,
+ "custom_uptime_ratios": numberOfDays,
+ "format": "json"
+ },
+ uri: 'https://api.uptimerobot.com/v2/getMonitors'
+ };
+ // A monitor API key must start with "m"
+ if (monitorApiKey.substring(0, "m".length) !== "m") {
+ badgeData.text[1] = 'must use a monitor key';
+ sendBadge(format, badgeData);
+ return;
+ }
+ request(options, function(err, res, json) {
+ if (err !== null) {
+ badgeData.text[1] = 'inaccessible';
+ sendBadge(format, badgeData);
+ return;
+ }
+ try {
+ if (json.stat === 'fail') {
+ badgeData.text[1] = 'vendor error';
+ if (json.error && typeof json.error.message === 'string') {
+ badgeData.text[1] = json.error.message;
+ }
+ badgeData.colorscheme = 'lightgrey';
+ sendBadge(format, badgeData);
+ return;
+ }
+ var percent = parseFloat(json.monitors[0].custom_uptime_ratio);
+ badgeData.text[1] = percent + '%';
+ if (percent <= 10) {
+ badgeData.colorscheme = 'red';
+ } else if (percent <= 30) {
+ badgeData.colorscheme = 'yellow';
+ } else if (percent <= 50) {
+ badgeData.colorscheme = 'yellowgreen';
+ } else if (percent <= 70) {
+ badgeData.colorscheme = 'green';
+ } else {
+ badgeData.colorscheme = 'brightgreen';
+ }
+ sendBadge(format, badgeData);
+ } catch (e) {
+ badgeData.text[1] = 'invalid';
+ sendBadge(format, badgeData);
+ }
+ });
+}));
+
// Any badge.
camp.route(/^\/(:|badge\/)(([^-]|--)*?)-(([^-]|--)*)-(([^-]|--)+)\.(svg|png|gif|jpg)$/,
function(data, match, end, ask) {
diff --git a/try.html b/try.html
index ebcc052..9acb97c 100644
--- a/try.html
+++ b/try.html
@@ -946,6 +946,18 @@ Pixel-perfect Retina-ready Fast Consistent Hackable
 |
https://img.shields.io/swagger/valid/2.0/https/bitbucket.org/api/swagger.json.svg |
+ Uptime Robot status: |
+  |
+ https://img.shields.io/uptimerobot/status/m778918918-3e92c097147760ee39d02d36.svg |
+
+ Uptime Robot ratio: |
+  |
+ https://img.shields.io/uptimerobot/ratio/m778918918-3e92c097147760ee39d02d36.svg |
+
+ Uptime Robot ratio (7 days): |
+  |
+ https://img.shields.io/uptimerobot/ratio/7/m778918918-3e92c097147760ee39d02d36.svg |
+
Longer Miscellaneous