diff --git a/action.php b/action.php
index 1b5406d..edb8599 100644
--- a/action.php
+++ b/action.php
@@ -23,6 +23,10 @@ class action_plugin_botmon extends DokuWiki_Action_Plugin {
$controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'insertHeader');
}
+ /* session information */
+ private $sessionId = 'unset';
+ private $sessionType = '';
+
/**
* Inserts tracking code to the page header
*
@@ -33,12 +37,15 @@ class action_plugin_botmon extends DokuWiki_Action_Plugin {
global $INFO;
+ // populate the session id and type:
+ $this->getSessionInfo();
+
// is there a user logged in?
$username = ( !empty($INFO['userinfo']) && !empty($INFO['userinfo']['name'])
? $INFO['userinfo']['name'] : '');
// build the tracker code:
- $code = NL . DOKU_TAB . "document._botmon = {'t0': Date.now()};" . NL;
+ $code = NL . DOKU_TAB . "document._botmon = {'t0': Date.now(), 'session': '" . json_encode($this->sessionId) . "'};" . NL;
if ($username) {
$code .= DOKU_TAB . 'document._botmon.user = "' . $username . '";'. NL;
}
@@ -68,22 +75,11 @@ class action_plugin_botmon extends DokuWiki_Action_Plugin {
global $conf;
global $INFO;
- // what is the session identifier?
- $sessionId = $_COOKIE['DokuWiki'] ?? '';
- $sessionType = 'dw';
- if ($sessionId == '') {
- $sessionId = $_SERVER['REMOTE_ADDR'] ?? '';
- if ($sessionId == '127.0.0.1' || $sessionId == '::1') {
- $sessionId = 'localhost';
- }
- $sessionType = 'ip';
- }
-
// clean the page ID
$pageId = preg_replace('/[\x00-\x1F]/', "\u{FFFD}", $INFO['id'] ?? '');
// collect GeoIP information (if available):
- $geoIp = 'XX'; /* User-defined code for unknown country */
+ $geoIp = ( $this->sessionId == 'localhost' ? 'local' : 'ZZ' ); /* User-defined code for unknown country */
try {
if (extension_loaded('geoip') && geoip_db_avail(GEOIP_COUNTRY_EDITION)) {
$geoIp = geoip_country_code_by_name($_SERVER['REMOTE_ADDR']);
@@ -98,8 +94,8 @@ class action_plugin_botmon extends DokuWiki_Action_Plugin {
$logArr = Array(
$_SERVER['REMOTE_ADDR'] ?? '', /* remote IP */
$pageId, /* page ID */
- $sessionId, /* Session ID */
- $sessionType, /* session ID type */
+ $this->sessionId, /* Session ID */
+ $this->sessionType, /* session ID type */
$username,
$_SERVER['HTTP_USER_AGENT'] ?? '', /* User agent */
$_SERVER['HTTP_REFERER'] ?? '', /* HTTP Referrer */
@@ -126,4 +122,31 @@ class action_plugin_botmon extends DokuWiki_Action_Plugin {
/* Done */
fclose($logfile);
}
+
+ private function getSessionInfo() {
+
+ // what is the session identifier?
+ if (isset($_SESSION)) {
+ $sesKeys = array_keys($_SESSION); /* DokuWiki Session ID preferred */
+ foreach ($sesKeys as $key) {
+ if (substr($key, 0, 2) == 'DW') {
+ $this->sessionId = $key;
+ $this->sessionType = 'dw';
+ return;
+ }
+ }
+ }
+ if ($this->sessionId == '') { /* no DokuWiki Session ID, try PHP session ID */
+ $this->sessionId = session_id();
+ $this->sessionType = 'php';
+ }
+ if ($this->sessionId == '') { /* no PHP session ID, try IP address */
+ $this->sessionId = $_SERVER['REMOTE_ADDR'] ?? '';
+ $this->sessionType = 'ip';
+ }
+ if ($this->sessionId == '') { /* if everything else fails, just us a random ID */
+ $this->sessionId = rand(1000000, 9999999);
+ $this->sessionType = 'rand';
+ }
+ }
}
\ No newline at end of file
diff --git a/admin.php b/admin.php
index 5bc1797..aae7228 100644
--- a/admin.php
+++ b/admin.php
@@ -32,6 +32,9 @@ class admin_plugin_botmon extends AdminPlugin {
global $conf;
+ // spinner animation as SVG image:
+ $svg = '';
+
$pluginPath = $conf['basedir'] . 'lib/plugins/' . $this->getPluginName();
/* Plugin Headline */
@@ -44,7 +47,7 @@ class admin_plugin_botmon extends AdminPlugin {
';
if ($this->hasOldLogFiles()) {
- echo '
Note: There are old log files that can be deleted.
Click here to run a delete script, or use
cron to automatically delete them.
';
+ echo 'Note: There are old log files that can be deleted.
Click here to run a delete script, or use
cron to automatically delete them.
';
}
echo '
@@ -75,7 +78,7 @@ class admin_plugin_botmon extends AdminPlugin {
diff --git a/client.js b/client.js
index 8402037..91b7c7b 100644
--- a/client.js
+++ b/client.js
@@ -24,8 +24,9 @@ botmon_client = {
const visit = {
'pg': JSINFO.id,
'u': document._botmon.user || null,
- 'lg': navigator.language,
+ 'lg': navigator.language.substring(0,2),
'lt': ( document._botmon ? Date.now() - document._botmon.t0 : null),
+ 'id': (document._botmon.session || 'null').replaceAll('\"', ''),
'r': document.referrer /*,
'tz': new Date().getTimezoneOffset(),
'url': window.location.href,
@@ -55,10 +56,15 @@ botmon_client = {
//console.info('botmon_client._onHeartbeat', url);
let uid = document._botmon.user || null;
+ let sessionId = (document._botmon.session || 'null').replaceAll('\"', '')
try {
- const response = await fetch(url + '?p=' + encodeURIComponent(JSINFO.id) + '&t=' + Date.now() + ( uid ? '&u=' + encodeURIComponent(uid) : ''), {
- method: 'HEAD'
+ const req = '?p=' + encodeURIComponent(JSINFO.id)
+ + '&t=' + encodeURIComponent(Date.now())
+ + ( sessionId ? '&id=' + encodeURIComponent(sessionId) : '')
+ + ( uid ? '&u=' + encodeURIComponent(uid) : '');
+ const response = await fetch(url + req, {
+ /*method: 'HEAD'*/
});
if (!response.ok) {
throw new Error(response.status + ' ' + response.statusText + ' - ' + url);
diff --git a/config/botmon-config.json b/conf/botmon-config.json
similarity index 96%
rename from config/botmon-config.json
rename to conf/botmon-config.json
index 06b704a..c17bd77 100644
--- a/config/botmon-config.json
+++ b/conf/botmon-config.json
@@ -65,8 +65,8 @@
"id": "isFrom", "desc": "Location is in a known bot-spamming country.",
"bot": 50
},
- {"func": "notFromCountry", "params": ["DE", "AT", "CH", "LI", "LU", "BE"],
- "id": "notFromHere", "desc": "Location is not among the site’s main target countries.",
+ {"func": "matchesCountry", "params": ["ZZ"],
+ "id": "zzCtry", "desc": "Location could not be determined",
"bot": 20
}
],
diff --git a/config/known-bots.json b/conf/known-bots.json
similarity index 90%
rename from config/known-bots.json
rename to conf/known-bots.json
index b59c634..40ab292 100644
--- a/config/known-bots.json
+++ b/conf/known-bots.json
@@ -1,17 +1,17 @@
[ {"id": "bingbot",
- "n": "Bing Bot",
+ "n": "BingBot",
"r": ["bingbot"],
"rx": ["\\sbingbot\\/(\\d+\\.\\d+);"],
"url": "http://www.bing.com/bingbot.htm"
},
{"id": "googlebot",
- "n": "Google Bot",
+ "n": "GoogleBot",
"r": ["Googlebot"],
"rx": ["Googlebot\\/(\\d+\\.\\d+)", "Googlebot-Image\\/(\\d+\\.\\d+)"],
"url": "http://www.google.com/bot.html"
},
{"id": "googleads",
- "n": "Google Ads Bot",
+ "n": "Google Ads",
"r": ["AdsBot-Google", "AdsBot-Google-Mobile", "Mediapartners-Google"],
"rx": ["AdsBot-Google;","AdsBot-Google-Mobile;", "Mediapartners-Google\\/(\\d+\\.\\d+);"],
"url": "https://developers.google.com/search/docs/crawling-indexing/google-special-case-crawlers"
@@ -35,31 +35,31 @@
"url": "http://help.yahoo.com/help/us/ysearch/slurp"
},
{"id": "ddg",
- "n": "DuckDuckGo Bots",
+ "n": "DuckDuckGo",
"r": ["DuckDuckBot","DuckAssistBot","DuckDuckGo-Favicons-Bot"],
"rx": ["DuckDuckBot\\/(\\d+\\.\\d+);", "DuckAssistBot\\/(\\d+\\.\\d+);", "DuckDuckGo-Favicons-Bot\\/(\\d+\\.\\d+);"],
"url": "https://duckduckgo.com/duckduckbot.html"
},
{"id": "openai",
- "n": "OpenAI/ChatGPT Bots",
+ "n": "OpenAI/ChatGPT",
"r": ["OAI-SearchBot", "ChatGPT-User", "GPTBot"],
"rx": ["OAI-SearchBot\\/(\\d+\\.\\d+);", "ChatGPT-User\\/(\\d+\\.\\d+);", "GPTBot\\/(\\d+\\.\\d+);"],
"url": "https://platform.openai.com/docs/bots/"
},
{"id": "claude",
- "n": "Anthropic Claude Bots",
+ "n": "Anthropic Claude",
"r": ["ClaudeBot", "Claude-User", "Claude-SearchBot"],
"rx": ["ClaudeBot\\/(\\d+\\.\\d+);"],
"url": "https://darkvisitors.com/agents/claudebot"
},
{"id": "perplexity",
- "n": "Perplexity Crawlers",
+ "n": "Perplexity",
"r": ["PerplexityBot", "Perplexity‑User"],
"rx": ["PerplexityBot\\/(\\d+\\.\\d+);", "Perplexity‑User\\/(\\d+\\.\\d+);"],
"url": "https://perplexity.ai/perplexitybot"
},
{"id": "metabots",
- "n": "Meta/Facebook Bots",
+ "n": "Meta/Facebook",
"r": ["facebookexternalhit", "facebookcatalog","meta-webindexer","meta-externalads","meta-externalagent","meta-externalfetcher"],
"rx": ["facebook\\w+\\/(\\d+\\.\\d+)", "meta-\\w+\\/(\\d+\\.\\d+)"],
"url": "https://developers.facebook.com/docs/sharing/webmasters/crawler"
@@ -71,43 +71,43 @@
"url": "https://help.qwant.com/bot/"
},
{"id": "yandex",
- "n": "Yandex Bots",
+ "n": "Yandex", "geo": "CN",
"r": ["YandexBot", "YandexAdNet", "YandexBlogs", "YandexImages", "YandexImageResizer", "YandexMarket", "YandexMedia", "YandexOntoDB", "YandexSitelinks","YandexSpravBot", "YandexVertis", "YandexVerticals", "YandexVideo", "YandexWebmaster", "YandexComBot"],
"rx": ["Yandex\\w+\\/(\\d+\\.\\d+);"],
"url": "http://yandex.com/bots"
},
{"id": "seznambot",
- "n": "SeznamBot (CZ)",
+ "n": "SeznamBot", "geo": "CZ",
"r": ["SeznamBot"],
"rx": ["SeznamBot\\/(\\d+\\.\\d+);"],
"url": "https://o-seznam.cz/napoveda/vyhledavani/en/seznambot-crawler/"
},
{"id": "ahrefs",
- "n": "Ahrefs Bots (SEO/marketing)",
+ "n": "Ahrefs",
"r": ["AhrefsBot", "AhrefsSiteAudit"],
"rx": ["AhrefsBot\\/(\\d+\\.\\d+);", "AhrefsSiteAudit\\/(\\d+\\.\\d+);"],
"url": "https://ahrefs.com/robot/"
},
{"id": "ccbot",
- "n": "Common Crawl Bot (AI-Scraper)",
+ "n": "CommonCrawl Bot",
"r": ["CCBot"],
"rx": ["CCBot\\/(\\d+\\.\\d+)[\\s\\.;]*"],
"url": "https://commoncrawl.org/bot.html"
},
{"id": "mjbot",
- "n": "Majestic Crawler (UK)",
+ "n": "Majestic Crawler (UK)", "geo": "GB",
"r": ["MJ12bot"],
"rx": ["MJ12bot\\/v?(\\d+\\.\\d+)[\\s\\.;]"],
"url": "http://www.majestic12.co.uk/bot.php"
},
{"id": "petal",
- "n": "PetalSearch Bot (CN)",
+ "n": "PetalSearch Bot (CN)", "geo": "CN",
"r": ["PetalBot", "AspiegelBot"],
"rx": ["[\\s;]PetalBot[\\s\\/;]", "AspiegelBot[\\)$]"],
"url": "https://webmaster.petalsearch.com/site/petalbot"
},
{"id": "barkrowler",
- "n": "Barkrowler (Babbar Bot)",
+ "n": "Barkrowler (Babbar)",
"r": ["Barkrowler"],
"rx": ["[\\s;^]Barkrowler\\/(\\d+\\.\\d+)?"],
"url": "https://babbar.tech/crawler"
@@ -119,7 +119,7 @@
"url": "http://www.semrush.com/bot.html"
},
{"id": "bytespider",
- "n": "Bytespider (ByteDance, TikTok)",
+ "n": "Bytespider (ByteDance, TikTok)", "geo": "CN",
"r": ["Bytespider"],
"rx": ["Bytespider[;$]"],
"url": "https://darkvisitors.com/agents/bytespider"
@@ -143,7 +143,7 @@
"url": "https://serpstatbot.com/"
},
{"id": "netestate",
- "n": "netEstate NE Crawler (DE)",
+ "n": "netEstate NE Crawler", "geo": "DE",
"r": ["netEstate NE Crawler"],
"rx": ["netEstate NE Crawler\\s"],
"url": "http://www.website-datenbank.de/"
@@ -167,7 +167,7 @@
"url": "https://darkvisitors.com/agents/mauibot"
},
{"id": "plagaware",
- "n": "PlagAwareBot (DE)",
+ "n": "PlagAwareBot (DE)", "geo": "DE",
"r": ["PlagAwareBot"],
"rx": ["PlagAwareBot\\/(\\d\\.\\d)"],
"url": "https://www.plagaware.com/bot"
@@ -213,5 +213,11 @@
"r": ["TerraCotta"],
"rx": ["TerraCotta"],
"url": "https://github.com/CeramicTeam/CeramicTerracotta"
+ },
+ {"id": "tiktok",
+ "n": "TikTok Spider", "geo": "CN",
+ "r": ["TikTokSpider"],
+ "rx": ["TikTokSpider"],
+ "url": "https://darkvisitors.com/agents/tiktokspider"
}
]
\ No newline at end of file
diff --git a/config/known-clients.json b/conf/known-clients.json
similarity index 100%
rename from config/known-clients.json
rename to conf/known-clients.json
diff --git a/config/known-platforms.json b/conf/known-platforms.json
similarity index 100%
rename from config/known-platforms.json
rename to conf/known-platforms.json
diff --git a/img/addr.png b/img/addr.png
new file mode 100644
index 0000000..a99f874
Binary files /dev/null and b/img/addr.png differ
diff --git a/img/ahrefs.png b/img/ahrefs.png
deleted file mode 100644
index 1802d9f..0000000
Binary files a/img/ahrefs.png and /dev/null differ
diff --git a/img/android.svg b/img/android.svg
deleted file mode 100644
index 4e58649..0000000
--- a/img/android.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/anthropic.png b/img/anthropic.png
deleted file mode 100644
index 18ea8a0..0000000
Binary files a/img/anthropic.png and /dev/null differ
diff --git a/img/aol.png b/img/aol.png
deleted file mode 100644
index 16a15fe..0000000
Binary files a/img/aol.png and /dev/null differ
diff --git a/img/apple.svg b/img/apple.svg
deleted file mode 100644
index 04dc1c8..0000000
--- a/img/apple.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/babbar.png b/img/babbar.png
deleted file mode 100644
index ffede22..0000000
Binary files a/img/babbar.png and /dev/null differ
diff --git a/img/bing.svg b/img/bing.svg
deleted file mode 100644
index f50b683..0000000
--- a/img/bing.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/bots.png b/img/bots.png
new file mode 100644
index 0000000..bcb69b5
Binary files /dev/null and b/img/bots.png differ
diff --git a/img/brave.svg b/img/brave.svg
deleted file mode 100644
index 8206e81..0000000
--- a/img/brave.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/bytedance.svg b/img/bytedance.svg
deleted file mode 100644
index 7b7cef5..0000000
--- a/img/bytedance.svg
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
diff --git a/img/ccbot.svg b/img/ccbot.svg
deleted file mode 100644
index b2f4567..0000000
--- a/img/ccbot.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/chrome.svg b/img/chrome.svg
deleted file mode 100644
index f8987d7..0000000
--- a/img/chrome.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/chromeold.svg b/img/chromeold.svg
deleted file mode 100644
index 8160631..0000000
--- a/img/chromeold.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/chromium.svg b/img/chromium.svg
deleted file mode 100644
index 9d3bcf0..0000000
--- a/img/chromium.svg
+++ /dev/null
@@ -1,144 +0,0 @@
-
-
diff --git a/img/clients.png b/img/clients.png
new file mode 100644
index 0000000..fc6a01d
Binary files /dev/null and b/img/clients.png differ
diff --git a/img/dataforseo.png b/img/dataforseo.png
deleted file mode 100644
index c4da2c3..0000000
Binary files a/img/dataforseo.png and /dev/null differ
diff --git a/img/ddg.svg b/img/ddg.svg
deleted file mode 100644
index 5721e8c..0000000
--- a/img/ddg.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/ecosia.svg b/img/ecosia.svg
deleted file mode 100644
index fc60eed..0000000
--- a/img/ecosia.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/fileview.svg b/img/fileview.svg
deleted file mode 100644
index abac089..0000000
--- a/img/fileview.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/firefox.png b/img/firefox.png
deleted file mode 100644
index d1f0292..0000000
Binary files a/img/firefox.png and /dev/null differ
diff --git a/img/freebsd.png b/img/freebsd.png
deleted file mode 100644
index 6305f58..0000000
Binary files a/img/freebsd.png and /dev/null differ
diff --git a/img/google.svg b/img/google.svg
deleted file mode 100644
index 9004205..0000000
--- a/img/google.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/hive.svg b/img/hive.svg
deleted file mode 100644
index 98c9c18..0000000
--- a/img/hive.svg
+++ /dev/null
@@ -1,105 +0,0 @@
-
-
diff --git a/img/hmos.svg b/img/hmos.svg
deleted file mode 100644
index 2a553c7..0000000
--- a/img/hmos.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/huawei.png b/img/huawei.png
deleted file mode 100644
index 89f3e5a..0000000
Binary files a/img/huawei.png and /dev/null differ
diff --git a/img/hunter.png b/img/hunter.png
deleted file mode 100644
index 4180226..0000000
Binary files a/img/hunter.png and /dev/null differ
diff --git a/img/idtyp.png b/img/idtyp.png
new file mode 100644
index 0000000..dbd4a39
Binary files /dev/null and b/img/idtyp.png differ
diff --git a/img/ios.svg b/img/ios.svg
deleted file mode 100644
index 5c302f1..0000000
--- a/img/ios.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/ip4.svg b/img/ip4.svg
deleted file mode 100644
index cd42250..0000000
--- a/img/ip4.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/ip6.svg b/img/ip6.svg
deleted file mode 100644
index 36f09d1..0000000
--- a/img/ip6.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/linux.svg b/img/linux.svg
deleted file mode 100644
index ad51cb7..0000000
--- a/img/linux.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/localhost.svg b/img/localhost.svg
deleted file mode 100644
index 3fed84c..0000000
--- a/img/localhost.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/macos.svg b/img/macos.svg
deleted file mode 100644
index ba53ad8..0000000
--- a/img/macos.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/majestic.png b/img/majestic.png
deleted file mode 100644
index 4a1498d..0000000
Binary files a/img/majestic.png and /dev/null differ
diff --git a/img/meta.svg b/img/meta.svg
deleted file mode 100644
index 4fc6a72..0000000
--- a/img/meta.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/msedge.svg b/img/msedge.svg
deleted file mode 100644
index f56c0f7..0000000
--- a/img/msedge.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/msie.svg b/img/msie.svg
deleted file mode 100644
index 9c71290..0000000
--- a/img/msie.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/img/netestate.png b/img/netestate.png
deleted file mode 100644
index 8bcabaa..0000000
Binary files a/img/netestate.png and /dev/null differ
diff --git a/img/openai.svg b/img/openai.svg
deleted file mode 100644
index 89150e2..0000000
--- a/img/openai.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/opera.svg b/img/opera.svg
deleted file mode 100644
index c038666..0000000
--- a/img/opera.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/perplexity.svg b/img/perplexity.svg
deleted file mode 100644
index 4bf985e..0000000
--- a/img/perplexity.svg
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
diff --git a/img/petal.svg b/img/petal.svg
deleted file mode 100644
index 41e7619..0000000
--- a/img/petal.svg
+++ /dev/null
@@ -1,110 +0,0 @@
-
-
-
-
diff --git a/img/placeholder.svg b/img/placeholder.svg
deleted file mode 100644
index 5c162e9..0000000
--- a/img/placeholder.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/plagaware.png b/img/plagaware.png
deleted file mode 100644
index 55f4ce7..0000000
Binary files a/img/plagaware.png and /dev/null differ
diff --git a/img/platforms.png b/img/platforms.png
new file mode 100644
index 0000000..46a33b7
Binary files /dev/null and b/img/platforms.png differ
diff --git a/img/qwant.svg b/img/qwant.svg
deleted file mode 100644
index 2c4b9b6..0000000
--- a/img/qwant.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/robot.svg b/img/robot.svg
deleted file mode 100644
index 6070578..0000000
--- a/img/robot.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/safari.png b/img/safari.png
deleted file mode 100644
index fbe7f7f..0000000
Binary files a/img/safari.png and /dev/null differ
diff --git a/img/samsung.svg b/img/samsung.svg
deleted file mode 100644
index d3314de..0000000
--- a/img/samsung.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/scriptrun.svg b/img/scriptrun.svg
deleted file mode 100644
index 7a87cbb..0000000
--- a/img/scriptrun.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/semrush.png b/img/semrush.png
deleted file mode 100644
index 5e15d0d..0000000
Binary files a/img/semrush.png and /dev/null differ
diff --git a/img/serpstat.svg b/img/serpstat.svg
deleted file mode 100644
index 90d4891..0000000
--- a/img/serpstat.svg
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
diff --git a/img/seznam.svg b/img/seznam.svg
deleted file mode 100644
index a95f053..0000000
--- a/img/seznam.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/spinner.svg b/img/spinner.svg
deleted file mode 100644
index 75c5a25..0000000
--- a/img/spinner.svg
+++ /dev/null
@@ -1,168 +0,0 @@
-
\ No newline at end of file
diff --git a/img/tizen.png b/img/tizen.png
deleted file mode 100644
index 236e128..0000000
Binary files a/img/tizen.png and /dev/null differ
diff --git a/img/uc.svg b/img/uc.svg
deleted file mode 100644
index 5eba2f2..0000000
--- a/img/uc.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
diff --git a/img/vivaldi.svg b/img/vivaldi.svg
deleted file mode 100644
index c3c211e..0000000
--- a/img/vivaldi.svg
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
diff --git a/img/win11.svg b/img/win11.svg
deleted file mode 100644
index aaf6a7a..0000000
--- a/img/win11.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/winold.png b/img/winold.png
deleted file mode 100644
index bac4773..0000000
Binary files a/img/winold.png and /dev/null differ
diff --git a/img/yahoo.svg b/img/yahoo.svg
deleted file mode 100644
index 488505e..0000000
--- a/img/yahoo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/yandex.svg b/img/yandex.svg
deleted file mode 100644
index a39c923..0000000
--- a/img/yandex.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/plugin.info.txt b/plugin.info.txt
index 3292553..f1e2eae 100644
--- a/plugin.info.txt
+++ b/plugin.info.txt
@@ -1,7 +1,7 @@
base botmon
author Sascha Leib
email ad@hominem.com
-date 2025-09-11
+date 2025-09-12
name Bot Monitoring
desc Live monitoring of bot traffic on your DokuWiki instance (under development)
url https://www.dokuwiki.org/plugin:botmon
diff --git a/pview.php b/pview.php
index 2c5d48a..dbc4128 100644
--- a/pview.php
+++ b/pview.php
@@ -7,27 +7,16 @@ if (!$json) {
die("Invalid JSON Data.");
}
-// select the session identifier?
-$sessionId = $_COOKIE['DokuWiki'] ?? '';
-$sessionType = 'dw';
-if ($sessionId == '') {
- $sessionId = $_SERVER['REMOTE_ADDR'] ?? '';
- if ($sessionId == '127.0.0.1' || $sessionId == '::1') {
- $sessionId = 'localhost';
- }
- $sessionType = 'ip';
-}
-
-// check if valid session id string:
-if (strlen($sessionId) < 46 && !preg_match('/^[\w\d\.:]+$/', $sessionId)) {
- $sessionId = 'invalid-session-id';
-}
+// what is the session identifier?
+$sessionId = preg_replace('/[\x00-\x1F{};\"\']/', "\u{FFFD}", $json['id']) /* clean json parameter */
+ ?? session_id()
+ ?? $_SERVER['REMOTE_ADDR'];
// clean the page ID
-$pageId = preg_replace('/[\x00-\x1F{};]/', "\u{FFFD}", $json['pg'] ?? '');
+$pageId = preg_replace('/[\x00-\x1F{};\"\']/', "\u{FFFD}", $json['pg'] ?? '');
// clean the user-name
-$userName = preg_replace('/[\x00-\x1F]/', "\u{FFFD}", $json['u'] ?? '');
+$userName = preg_replace('/[\x00-\x1F\"]/', "\u{FFFD}", $json['u'] ?? '');
// check load time
$loadTime = $json['lt'] ?? '';
diff --git a/script.js b/script.js
index 57bf98b..2f51c7d 100644
--- a/script.js
+++ b/script.js
@@ -1,6 +1,6 @@
"use strict";
/* DokuWiki BotMon Plugin Script file */
-/* 06.09.2025 - 0.2.0 - beta */
+/* 12.09.2025 - 0.3.0 - beta */
/* Author: Sascha Leib */
// enumeration of user types:
@@ -21,6 +21,7 @@ const BotMon = {
// find the plugin basedir:
this._baseDir = document.currentScript.src.substring(0, document.currentScript.src.indexOf('/exe/'))
+ '/plugins/botmon/';
+ this._DWBaseDir = document.currentScript.src.substring(0, document.currentScript.src.indexOf('/lib/')) + '/';
// read the page language from the DOM:
this._lang = document.getRootNode().documentElement.lang || this._lang;
@@ -33,6 +34,7 @@ const BotMon = {
},
_baseDir: null,
+ _DWBaseDir: null,
_lang: 'en',
_today: (new Date()).toISOString().slice(0, 10),
_timeDiff: '',
@@ -242,20 +244,20 @@ BotMon.live = {
// shortcut to make code more readable:
const model = BotMon.live.data.model;
- const timeout = 60 * 60 * 1000; /* session timeout: One hour */
+ const timeout = 60 * 60 * 1000; // session timeout: One hour
// loop over all visitors already registered:
for (let i=0; i 1 ? rxr[1] : -1)
};
@@ -958,7 +961,7 @@ BotMon.live = {
// Load the list of known bots:
BotMon.live.gui.status.showBusy("Loading known clients");
- const url = BotMon._baseDir + 'config/known-clients.json';
+ const url = BotMon._baseDir + 'conf/known-clients.json';
try {
const response = await fetch(url);
if (!response.ok) {
@@ -1024,7 +1027,7 @@ BotMon.live = {
// Load the list of known bots:
BotMon.live.gui.status.showBusy("Loading known platforms");
- const url = BotMon._baseDir + 'config/known-platforms.json';
+ const url = BotMon._baseDir + 'conf/known-platforms.json';
try {
const response = await fetch(url);
if (!response.ok) {
@@ -1090,7 +1093,26 @@ BotMon.live = {
// Load the list of known bots:
BotMon.live.gui.status.showBusy("Loading list of rules …");
- const url = BotMon._baseDir + 'config/botmon-config.json';
+
+ // relative file path to the rules file:
+ const filePath = 'conf/botmon-config.json';
+
+ // check if the user has a configuration file in their DokuWiki installation,
+ // then load the appropriate file:
+ this._checkForUserConfig( filePath, (hasUserConfig) => {
+ this._loadrulesFile(( hasUserConfig ? BotMon._DWBaseDir : BotMon._baseDir ) + filePath);
+ });
+ },
+
+ /**
+ * Loads the list of rules and settings from a JSON file.
+ * @param {String} url - the URL from which to load the rules file.
+ */
+
+ _loadrulesFile: async function(url) {
+ //console.info('BotMon.live.data.rules._loadrulesFile(',url,')');}
+
+ const me = BotMon.live.data.rules;
try {
const response = await fetch(url);
if (!response.ok) {
@@ -1100,12 +1122,11 @@ BotMon.live = {
const json = await response.json();
if (json.rules) {
- this._rulesList = json.rules;
+ me._rulesList = json.rules;
}
- if (json.threshold) {
- this._threshold = json.threshold;
- }
+ // override the threshold?
+ if (json.threshold) me._threshold = json.threshold;
if (json.ipRanges) {
// clean up the IPs first:
@@ -1119,10 +1140,10 @@ BotMon.live = {
list.push(item);
});
- this._botIPs = list;
+ me._botIPs = list;
}
- this._ready = true;
+ me._ready = true;
} catch (error) {
BotMon.live.gui.status.setError("Error while loading the ‘rules’ file: " + error.message);
@@ -1132,6 +1153,28 @@ BotMon.live = {
}
},
+ /**
+ * Checks if the user has a configuration file in their DokuWiki installation.
+ * @param {function} whenDone - an optional callback function to call when the check is finished.
+ */
+ _checkForUserConfig: async function(filePath, whenDone = undefined) {
+ //console.info('BotMon.live.data.rules._checkForUserConfig()');
+
+ let hasUserConfig = false;
+ try {
+ const response = await fetch(BotMon._DWBaseDir + '/' + filePath, {
+ method: 'HEAD'
+ });
+ hasUserConfig = response.ok;
+ } catch (err) {
+ console.info("An error occured while trying to check for a user configuration file:", err);
+ } finally {
+ if (whenDone) {
+ whenDone(hasUserConfig);
+ }
+ }
+ },
+
_rulesList: [], // list of rules to find out if a visitor is a bot
_threshold: 100, // above this, it is considered a bot.
@@ -1306,7 +1349,7 @@ BotMon.live = {
matchesCountry: function(visitor, ...countries) {
// ingore if geoloc is not set or unknown:
- if (visitor.geo && visitor.geo !== 'ZZ') {
+ if (visitor.geo) {
return (countries.indexOf(visitor.geo) >= 0);
}
return false;
@@ -1349,11 +1392,11 @@ BotMon.live = {
},
- /**
- * Loads a log file (server, page load, or ticker) and parses it.
- * @param {String} type - the type of the log file to load (srv, log, or tck)
- * @param {Function} [onLoaded] - an optional callback function to call after loading is finished.
- */
+ /**
+ * Loads a log file (server, page load, or ticker) and parses it.
+ * @param {String} type - the type of the log file to load (srv, log, or tck)
+ * @param {Function} [onLoaded] - an optional callback function to call after loading is finished.
+ */
loadLogFile: async function(type, onLoaded = undefined) {
//console.info('BotMon.live.data.loadLogFile(',type,')');
@@ -1389,50 +1432,56 @@ BotMon.live = {
try {
const response = await fetch(url);
if (!response.ok) {
+
throw new Error(`${response.status} ${response.statusText}`);
- }
- const logtxt = await response.text();
-
- logtxt.split('\n').forEach((line) => {
- if (line.trim() === '') return; // skip empty lines
- const cols = line.split('\t');
-
- // assign the columns to an object:
- const data = {};
- cols.forEach( (colVal,i) => {
- colName = columns[i] || `col${i}`;
- const colValue = (colName == 'ts' ? new Date(colVal) : colVal.trim());
- data[colName] = colValue;
- });
-
- // register the visit in the model:
- switch(type) {
- case 'srv':
- BotMon.live.data.model.registerVisit(data, type);
- break;
- case 'log':
- data.typ = 'js';
- BotMon.live.data.model.updateVisit(data);
- break;
- case 'tck':
- data.typ = 'js';
- BotMon.live.data.model.updateTicks(data);
- break;
- default:
- console.warn(`Unknown log type ${type}.`);
- return;
+ } else {
+
+ // parse the data:
+ const logtxt = await response.text();
+ if (logtxt.length <= 0) {
+ throw new Error(`Empty log file ${url}.`);
}
- });
- if (onLoaded) {
- onLoaded(); // callback after loading is finished.
+ logtxt.split('\n').forEach((line) => {
+ if (line.trim() === '') return; // skip empty lines
+ const cols = line.split('\t');
+
+ // assign the columns to an object:
+ const data = {};
+ cols.forEach( (colVal,i) => {
+ colName = columns[i] || `col${i}`;
+ const colValue = (colName == 'ts' ? new Date(colVal) : colVal.trim());
+ data[colName] = colValue;
+ });
+
+ // register the visit in the model:
+ switch(type) {
+ case 'srv':
+ BotMon.live.data.model.registerVisit(data, type);
+ break;
+ case 'log':
+ data.typ = 'js';
+ BotMon.live.data.model.updateVisit(data);
+ break;
+ case 'tck':
+ data.typ = 'js';
+ BotMon.live.data.model.updateTicks(data);
+ break;
+ default:
+ console.warn(`Unknown log type ${type}.`);
+ return;
+ }
+ });
}
} catch (error) {
BotMon.live.gui.status.setError(`Error while loading the ${typeName} log file: ${error.message}.`);
} finally {
BotMon.live.gui.status.hideBusy("Status: Done.");
+ if (onLoaded) {
+ onLoaded(); // callback after loading is finished.
+ }
}
}
},
@@ -1443,7 +1492,14 @@ BotMon.live = {
this.lists.init();
},
+ /* The Overview / web metrics section of the live tab */
overview: {
+ /**
+ * Populates the overview part of the today tab with the analytics data.
+ *
+ * @method make
+ * @memberof BotMon.live.gui.overview
+ */
make: function() {
const data = BotMon.live.data.analytics.data;
@@ -1486,29 +1542,29 @@ BotMon.live = {
}
// update known bots list:
- const botlist = document.getElementById('botmon__botslist');
- botlist.innerHTML = "Known bots (top 4)";
+ const botlist = document.getElementById('botmon__botslist'); /* Known bots */
+ botlist.innerHTML = "Known bots (top 5)";
let bots = BotMon.live.data.analytics.groups.knownBots.toSorted( (a, b) => {
return b._pageViews.length - a._pageViews.length;
});
- for (let i=0; i < Math.min(bots.length, 4); i++) {
+ for (let i=0; i < Math.min(bots.length, 5); i++) {
const dd = makeElement('dd');
- dd.appendChild(makeElement('span', {'class': 'bot bot_' + bots[i]._bot.id }, bots[i]._bot.n));
- dd.appendChild(makeElement('strong', undefined, bots[i]._pageViews.length));
+ dd.appendChild(makeElement('span', {'class': 'has_icon bot bot_' + bots[i]._bot.id }, bots[i]._bot.n));
+ dd.appendChild(makeElement('span', undefined, bots[i]._pageViews.length));
botlist.appendChild(dd);
}
// update the suspected bot IP ranges list:
const botIps = document.getElementById('botmon__today__botips');
if (botIps) {
- botIps.appendChild(makeElement('dt', {}, "Bot IP ranges (top 4)"));
+ botIps.appendChild(makeElement('dt', {}, "Bot IP ranges (top 5)"));
- const ipList = BotMon.live.data.analytics.getTopBotIPRanges(4);
+ const ipList = BotMon.live.data.analytics.getTopBotIPRanges(5);
ipList.forEach( (ipInfo) => {
const li = makeElement('dd');
- li.appendChild(makeElement('span', {'class': 'ip ip' + ipInfo.typ }, ipInfo.ip));
+ li.appendChild(makeElement('span', {'class': 'has_icon ipaddr ip' + ipInfo.typ }, ipInfo.ip));
li.appendChild(makeElement('span', {'class': 'count' }, ipInfo.num));
botIps.append(li)
});
@@ -1517,11 +1573,11 @@ BotMon.live = {
// update the top bot countries list:
const botCountries = document.getElementById('botmon__today__countries');
if (botCountries) {
- botCountries.appendChild(makeElement('dt', {}, "Bot Countries (top 4)"));
- const countryList = BotMon.live.data.analytics.getCountryList('likely_bot', 4);
+ botCountries.appendChild(makeElement('dt', {}, "Bot Countries (top 5)"));
+ const countryList = BotMon.live.data.analytics.getCountryList('likely_bot', 5);
countryList.forEach( (cInfo) => {
const cLi = makeElement('dd');
- cLi.appendChild(makeElement('span', {'class': 'country ctry_' + cInfo.iso }, cInfo.name));
+ cLi.appendChild(makeElement('span', {'class': 'has_icon country ctry_' + cInfo.iso.toLowerCase() }, cInfo.name));
cLi.appendChild(makeElement('span', {'class': 'count' }, cInfo.count));
botCountries.appendChild(cLi);
});
@@ -1569,7 +1625,7 @@ BotMon.live = {
if (clientList) {
clientList.forEach( (cInfo) => {
const cDd = makeElement('dd');
- cDd.appendChild(makeElement('span', {'class': 'has_icon client_' + cInfo.id }, ( cInfo.name ? cInfo.name : cInfo.id)));
+ cDd.appendChild(makeElement('span', {'class': 'has_icon client cl_' + cInfo.id }, ( cInfo.name ? cInfo.name : cInfo.id)));
cDd.appendChild(makeElement('span', {
'class': 'count',
'title': cInfo.count + " page views"
@@ -1589,7 +1645,7 @@ BotMon.live = {
if (pfList) {
pfList.forEach( (pInfo) => {
const pDd = makeElement('dd');
- pDd.appendChild(makeElement('span', {'class': 'has_icon client_' + pInfo.id }, ( pInfo.name ? pInfo.name : pInfo.id)));
+ pDd.appendChild(makeElement('span', {'class': 'has_icon platform pf_' + pInfo.id }, ( pInfo.name ? pInfo.name : pInfo.id)));
pDd.appendChild(makeElement('span', {
'class': 'count',
'title': pInfo.count + " page views"
@@ -1622,7 +1678,7 @@ BotMon.live = {
BotMon.live.gui.status._errorCount += 1;
const el = document.getElementById('botmon__today__status');
if (el) {
- el.innerText = "An error occured. See the browser log for details!";
+ el.innerText = "An error occurred. Data may be incomplete! See browser console for details";
el.classList.add('error');
}
},
@@ -1688,8 +1744,8 @@ BotMon.live = {
'data-loaded': false
});
const title = details.appendChild(makeElement('summary'));
- title.appendChild(makeElement('span', {'class':'title'}, listTitle));
- title.appendChild(makeElement('span', {'class':'counter'}, '–'));
+ title.appendChild(makeElement('span', {'class': 'title'}, listTitle));
+ title.appendChild(makeElement('span', {'class': 'counter'}));
details.addEventListener("toggle", this._onDetailsToggle);
parent.appendChild(details);
@@ -1731,6 +1787,8 @@ BotMon.live = {
const make = BotMon.t._makeElement;
let ipType = ( data.ip.indexOf(':') >= 0 ? '6' : '4' );
+ if (data.ip == '127.0.0.1' || data.ip == '::1' ) ipType = '0';
+
const platformName = (data._platform ? data._platform.n : 'Unknown');
const clientName = (data._client ? data._client.n: 'Unknown');
@@ -1742,12 +1800,22 @@ BotMon.live = {
const span1 = make('span'); /* left-hand group */
// country flag:
- if (data.geo && data.geo !=='') {
- span1.appendChild(make('span', {
- 'class': 'icon country ctry_' + data.geo.toLowerCase(),
- 'data-ctry': data.geo,
- 'title': "Country: " + data._country
- }, data._country));
+ span1.appendChild(make('span', {
+ 'class': 'icon_only country ctry_' + data.geo.toLowerCase(),
+ 'data-ctry': (data.geo | 'ZZ'),
+ 'title': "Country: " + ( data._country || "Unknown")
+ }, ( data._country || "Unknown") ));
+
+ if (data._type !== BM_USERTYPE.KNOWN_BOT) { /* No platform/client for bots */
+ span1.appendChild(make('span', { /* Platform */
+ 'class': 'icon_only platform pf_' + (data._platform ? data._platform.id : 'unknown'),
+ 'title': "Platform: " + platformName
+ }, platformName));
+
+ span1.appendChild(make('span', { /* Client */
+ 'class': 'icon_only client client cl_' + (data._client ? data._client.id : 'unknown'),
+ 'title': "Client: " + clientName
+ }, clientName));
}
// identifier:
@@ -1755,36 +1823,29 @@ BotMon.live = {
const botName = ( data._bot && data._bot.n ? data._bot.n : "Unknown");
span1.appendChild(make('span', { /* Bot */
- 'class': 'bot bot_' + (data._bot ? data._bot.id : 'unknown'),
+ 'class': 'has_icon bot bot_' + (data._bot ? data._bot.id : 'unknown'),
'title': "Bot: " + botName
}, botName));
} else if (data._type == BM_USERTYPE.KNOWN_USER) { /* User only */
span1.appendChild(make('span', { /* User */
- 'class': 'user_known',
+ 'class': 'has_icon user_known',
'title': "User: " + data.usr
}, data.usr));
} else { /* others */
- if (data.ip == '127.0.0.1' || data.ip == '::1' ) ipType = '0';
- span1.appendChild(make('span', { /* IP-Address */
- 'class': 'ipaddr ip' + ipType,
+
+ /*span1.appendChild(make('span', { // IP-Address
+ 'class': 'has_icon ipaddr ip' + ipType,
'title': "IP-Address: " + data.ip
- }, data.ip));
- }
+ }, data.ip));*/
- if (data._type !== BM_USERTYPE.KNOWN_BOT) { /* Not for bots */
- span1.appendChild(make('span', { /* Platform */
- 'class': 'icon platform platform_' + (data._platform ? data._platform.id : 'unknown'),
- 'title': "Platform: " + platformName
- }, platformName));
-
- span1.appendChild(make('span', { /* Client */
- 'class': 'icon client client_' + (data._client ? data._client.id : 'unknown'),
- 'title': "Client: " + clientName
- }, clientName));
+ span1.appendChild(make('span', { /* Internal ID */
+ 'class': 'has_icon session typ_' + data.typ,
+ 'title': "ID: " + data.id
+ }, data.id));
}
summary.appendChild(span1);
@@ -1818,7 +1879,7 @@ BotMon.live = {
if (data._type == BM_USERTYPE.KNOWN_BOT) {
dl.appendChild(make('dt', {}, "Bot name:")); /* bot info */
- dl.appendChild(make('dd', {'class': 'has_icon bot bot_' + (data._bot ? data._bot.id : 'unknown')},
+ dl.appendChild(make('dd', {'class': 'icon_only bot bot_' + (data._bot ? data._bot.id : 'unknown')},
(data._bot ? data._bot.n : 'Unknown')));
if (data._bot && data._bot.url) {
@@ -1834,15 +1895,15 @@ BotMon.live = {
} else { /* not for bots */
dl.appendChild(make('dt', {}, "Client:")); /* client */
- dl.appendChild(make('dd', {'class': 'has_icon client_' + (data._client ? data._client.id : 'unknown')},
+ dl.appendChild(make('dd', {'class': 'has_icon client cl_' + (data._client ? data._client.id : 'unknown')},
clientName + ( data._client.v > 0 ? ' (' + data._client.v + ')' : '' ) ));
dl.appendChild(make('dt', {}, "Platform:")); /* platform */
- dl.appendChild(make('dd', {'class': 'has_icon platform_' + (data._platform ? data._platform.id : 'unknown')},
+ dl.appendChild(make('dd', {'class': 'has_icon platform pf_' + (data._platform ? data._platform.id : 'unknown')},
platformName + ( data._platform.v > 0 ? ' (' + data._platform.v + ')' : '' ) ));
dl.appendChild(make('dt', {}, "IP-Address:"));
- dl.appendChild(make('dd', {'class': 'has_icon ip' + ipType}, data.ip));
+ dl.appendChild(make('dd', {'class': 'has_icon ipaddr ip' + ipType}, data.ip));
/*dl.appendChild(make('dt', {}, "ID:"));
dl.appendChild(make('dd', {'class': 'has_icon ip' + data.typ}, data.id));*/
@@ -1867,7 +1928,7 @@ BotMon.live = {
if (data.geo && data.geo !=='') {
dl.appendChild(make('dt', {}, "Location:"));
dl.appendChild(make('dd', {
- 'class': 'country ctry_' + data.geo.toLowerCase(),
+ 'class': 'has_icon country ctry_' + data.geo.toLowerCase(),
'data-ctry': data.geo,
'title': "Country: " + data._country
}, data._country + ' (' + data.geo + ')'));
@@ -1876,6 +1937,9 @@ BotMon.live = {
/*dl.appendChild(make('dt', {}, "Visitor Type:"));
dl.appendChild(make('dd', undefined, data._type ));*/
+ dl.appendChild(make('dt', {}, "Session ID:"));
+ dl.appendChild(make('dd', {'class': 'has_icon session typ_' + data.typ}, data.id));
+
dl.appendChild(make('dt', {}, "Seen by:"));
dl.appendChild(make('dd', undefined, data._seenBy.join(', ') ));
diff --git a/style.less b/style.less
index 89dd7cd..8090bb7 100644
--- a/style.less
+++ b/style.less
@@ -4,11 +4,346 @@
margin: .25rem 0;
}
+ /* icon items */
+ .has_icon {
+ display: inline-flex;
+ }
+ .icon_only {
+ display: inline-grid;
+ grid-template-columns: 20px max-content;
+ overflow: hidden;
+ width: 20px;
+ }
+
+ .has_icon, .icon_only {
+ & {
+ align-items: center;
+ column-gap: .25em;
+ }
+
+ &::before {
+ content: '';
+ display: inline-block;
+ width: 20px; height: 20px;
+ background: transparent none center no-repeat;
+ background-position: 0 0;
+ background-size: 20px;
+ }
+
+ /* user info Icon */
+ &.user_known::before { background-image: url('img/user.svg') }
+
+ /* IP Address types */
+ &.ipaddr::before { background-image: url('img/addr.png') }
+ &.ip4::before { background-position-y: -20px }
+ &.ip6::before { background-position-y: -40px }
+
+ /* Bot icons */
+ &.bot::before { background-image: url('img/bots.png') }
+ &.bot_googlebot::before, &.bot_googleads::before, &.bot_googleapi::before { background-position-y: -20px }
+ &.bot_bingbot::before { background-position-y: -40px }
+ &.bot_applebot::before { background-position-y: -60px }
+ &.bot_openai::before { background-position-y: -80px }
+ &.bot_metabots::before { background-position-y: -100px }
+ &.bot_ahrefs::before { background-position-y: -120px }
+ &.bot_seznambot::before { background-position-y: -140px }
+
+ /* platform icons */
+
+ &.platform::before { background-image: url('img/platforms.png') }
+ &.pf_win10::before { background-position-y: -20px }
+ &.pf_winold::before, dd.platform_winold::before,
+ &.pf_winsrvr:before { background-position-y: -40px }
+ &.pf_macos::before { background-position-y: -60px }
+ &.pf_macosold::before { background-position-y: -80px }
+ &.pf_ios::before { background-position-y: -100px }
+ &.pf_android::before { background-position-y: -120px }
+ &.pf_linux::before { background-position-y: -160px }
+ &.pf_bsd::before { background-position-y: -180px }
+ &.pf_chromium::before { background-position-y: -200px }
+ &.pf_hmos::before { background-position-y: -220px }
+ &.pf_tizen::before { background-position-y: -240px }
+
+ /* browser icons */
+ &.client::before { background-image: url('img/clients.png') }
+ &.cl_firefox::before { background-position-y: -20px }
+ &.cl_safari::before { background-position-y: -40px }
+ &.cl_chrome::before { background-position-y: -60px }
+ &.cl_chromeold::before { background-position-y: -60px; opacity: 75%; filter: ~"saturate(25%)"; }
+ &.cl_msedge::before { background-position-y: -80px }
+ &.cl_msie::before { background-position-y: -100px }
+ &.cl_opera::before { background-position-y: -120px }
+ &.cl_brave::before { background-position-y: -140px }
+ &.cl_ddg::before { background-position-y: -160px }
+ &.cl_samsung::before { background-position-y: -180px }
+ &.cl_huawei::before { background-position-y: -200px }
+ &.cl_vivaldi::before { background-position-y: -220px }
+ &.cl_aol::before { background-position-y: -240px }
+ &.cl_ya::before { background-position-y: -260px }
+
+ /* Country flags */
+ /* Note: flag images and CSS adapted from: https://github.com/lafeber/world-flags-sprite/ */
+ &.country::before {
+ content: '';
+ height: 20px; width: 20px;
+ background:url(img/flags.png) no-repeat 0 0;
+ background-size: 20px auto;
+ }
+ &.ctry_ad::before { background-position-y: -441px }
+ &.ctry_ae::before { background-position-y: -461px }
+ &.ctry_af::before { background-position-y: -481px }
+ &.ctry_ag::before { background-position-y: -501px }
+ &.ctry_ai::before { background-position-y: -521px }
+ &.ctry_al::before { background-position-y: -541px }
+ &.ctry_am::before { background-position-y: -561px }
+ &.ctry_ao::before { background-position-y: -581px }
+ &.ctry_aq::before { background-position-y: -601px }
+ &.ctry_ar::before { background-position-y: -621px }
+ &.ctry_as::before { background-position-y: -641px }
+ &.ctry_at::before { background-position-y: -661px }
+ &.ctry_au::before { background-position-y: -681px }
+ &.ctry_aw::before { background-position-y: -701px }
+ &.ctry_ax::before { background-position-y: -721px }
+ &.ctry_az::before { background-position-y: -741px }
+ &.ctry_ba::before { background-position-y: -761px }
+ &.ctry_bb::before { background-position-y: -781px }
+ &.ctry_bd::before { background-position-y: -801px }
+ &.ctry_be::before { background-position-y: -821px }
+ &.ctry_bf::before { background-position-y: -841px }
+ &.ctry_bg::before { background-position-y: -861px }
+ &.ctry_bh::before { background-position-y: -881px }
+ &.ctry_bi::before { background-position-y: -901px }
+ &.ctry_bj::before { background-position-y: -921px }
+ &.ctry_bm::before { background-position-y: -941px }
+ &.ctry_bn::before { background-position-y: -961px }
+ &.ctry_bo::before { background-position-y: -981px }
+ &.ctry_br::before { background-position-y: -1001px }
+ &.ctry_bs::before { background-position-y: -1021px }
+ &.ctry_bt::before { background-position-y: -1041px }
+ &.ctry_bw::before { background-position-y: -1061px }
+ &.ctry_by::before { background-position-y: -1081px }
+ &.ctry_bz::before { background-position-y: -1101px }
+ &.ctry_ca::before { background-position-y: -1121px }
+ &.ctry_cd::before { background-position-y: -1141px }
+ &.ctry_cf::before { background-position-y: -1161px }
+ &.ctry_cg::before { background-position-y: -1181px }
+ &.ctry_ch::before { background-position-y: -1201px }
+ &.ctry_ci::before { background-position-y: -1221px }
+ &.ctry_ck::before { background-position-y: -1241px }
+ &.ctry_cl::before { background-position-y: -1261px }
+ &.ctry_cm::before { background-position-y: -1281px }
+ &.ctry_cn::before { background-position-y: -1301px }
+ &.ctry_co::before { background-position-y: -1321px }
+ &.ctry_cr::before { background-position-y: -1341px }
+ &.ctry_cu::before { background-position-y: -1361px }
+ &.ctry_cv::before { background-position-y: -1381px }
+ &.ctry_cy::before { background-position-y: -1401px }
+ &.ctry_cz::before { background-position-y: -1421px }
+ &.ctry_de::before { background-position-y: -1441px }
+ &.ctry_dj::before { background-position-y: -1461px }
+ &.ctry_dk::before { background-position-y: -1481px }
+ &.ctry_dm::before { background-position-y: -1501px }
+ &.ctry_do::before { background-position-y: -1521px }
+ &.ctry_dz::before { background-position-y: -1541px }
+ &.ctry_ec::before { background-position-y: -1561px }
+ &.ctry_ee::before { background-position-y: -1581px }
+ &.ctry_eg::before { background-position-y: -1601px }
+ &.ctry_eh::before { background-position-y: -1621px }
+ &.ctry_er::before { background-position-y: -1641px }
+ &.ctry_es::before { background-position-y: -1661px }
+ &.ctry_et::before { background-position-y: -1681px }
+ &.ctry_fi::before { background-position-y: -1701px }
+ &.ctry_fj::before { background-position-y: -1721px }
+ &.ctry_fm::before { background-position-y: -1741px }
+ &.ctry_fo::before { background-position-y: -1761px }
+ &.ctry_fr::before, &.ctry_bl::before, &.ctry_cp::before, &.ctry_mf::before,
+ &.ctry_yt::before { background-position-y: -1781px }
+ &.ctry_ga::before { background-position-y: -1801px }
+ &.ctry_bg::before, &.ctry_uk::before,
+ &.ctry_sh::before { background-position-y: -1821px }
+ &.ctry_gd::before { background-position-y: -1841px }
+ &.ctry_ge::before { background-position-y: -1861px }
+ &.ctry_gg::before { background-position-y: -1881px }
+ &.ctry_gh::before { background-position-y: -1901px }
+ &.ctry_gi::before { background-position-y: -1921px }
+ &.ctry_gl::before { background-position-y: -1941px }
+ &.ctry_gm::before { background-position-y: -1961px }
+ &.ctry_gn::before { background-position-y: -1981px }
+ &.ctry_gp::before { background-position-y: -2001px }
+ &.ctry_gq::before { background-position-y: -2021px }
+ &.ctry_gr::before { background-position-y: -2041px }
+ &.ctry_gt::before { background-position-y: -2061px }
+ &.ctry_gu::before { background-position-y: -2081px }
+ &.ctry_gw::before { background-position-y: -2101px }
+ &.ctry_gy::before { background-position-y: -2121px }
+ &.ctry_hk::before { background-position-y: -2141px }
+ &.ctry_hn::before { background-position-y: -2161px }
+ &.ctry_hr::before { background-position-y: -2181px }
+ &.ctry_ht::before { background-position-y: -2201px }
+ &.ctry_hu::before { background-position-y: -2221px }
+ &.ctry_mc::before { background-position-y: -2241px }
+ &.ctry_ie::before { background-position-y: -2261px }
+ &.ctry_il::before { background-position-y: -2281px }
+ &.ctry_im::before { background-position-y: -2301px }
+ &.ctry_in::before { background-position-y: -2321px }
+ &.ctry_iq::before { background-position-y: -2341px }
+ &.ctry_ir::before { background-position-y: -2361px }
+ &.ctry_is::before { background-position-y: -2381px }
+ &.ctry_it::before { background-position-y: -2401px }
+ &.ctry_je::before { background-position-y: -2421px }
+ &.ctry_jm::before { background-position-y: -2441px }
+ &.ctry_jo::before { background-position-y: -2461px }
+ &.ctry_jp::before { background-position-y: -2481px }
+ &.ctry_ke::before { background-position-y: -2501px }
+ &.ctry_kg::before { background-position-y: -2521px }
+ &.ctry_kh::before { background-position-y: -2541px }
+ &.ctry_ki::before { background-position-y: -2561px }
+ &.ctry_km::before { background-position-y: -2581px }
+ &.ctry_kn::before { background-position-y: -2601px }
+ &.ctry_kp::before { background-position-y: -2621px }
+ &.ctry_kr::before { background-position-y: -2641px }
+ &.ctry_kw::before { background-position-y: -2661px }
+ &.ctry_ky::before { background-position-y: -2681px }
+ &.ctry_kz::before { background-position-y: -2701px }
+ &.ctry_la::before { background-position-y: -2721px }
+ &.ctry_lb::before { background-position-y: -2741px }
+ &.ctry_lc::before { background-position-y: -2761px }
+ &.ctry_li::before { background-position-y: -2781px }
+ &.ctry_lk::before { background-position-y: -2801px }
+ &.ctry_lr::before { background-position-y: -2821px }
+ &.ctry_ls::before { background-position-y: -2841px }
+ &.ctry_lt::before { background-position-y: -2861px }
+ &.ctry_lu::before { background-position-y: -2881px }
+ &.ctry_lv::before { background-position-y: -2901px }
+ &.ctry_ly::before { background-position-y: -2921px }
+ &.ctry_ma::before { background-position-y: -2941px }
+ &.ctry_md::before { background-position-y: -2961px }
+ &.ctry_me::before { background-position-y: -2981px }
+ &.ctry_mg::before { background-position-y: -3001px }
+ &.ctry_mh::before { background-position-y: -3021px }
+ &.ctry_mk::before { background-position-y: -3041px }
+ &.ctry_ml::before { background-position-y: -3061px }
+ &.ctry_mm::before { background-position-y: -3081px }
+ &.ctry_mn::before { background-position-y: -3101px }
+ &.ctry_mo::before { background-position-y: -3121px }
+ &.ctry_mq::before { background-position-y: -3141px }
+ &.ctry_mr::before { background-position-y: -3161px }
+ &.ctry_ms::before { background-position-y: -3181px }
+ &.ctry_mt::before { background-position-y: -3201px }
+ &.ctry_mu::before { background-position-y: -3221px }
+ &.ctry_mv::before { background-position-y: -3241px }
+ &.ctry_mw::before { background-position-y: -3261px }
+ &.ctry_mx::before { background-position-y: -3281px }
+ &.ctry_my::before { background-position-y: -3301px }
+ &.ctry_mz::before { background-position-y: -3321px }
+ &.ctry_na::before { background-position-y: -3341px }
+ &.ctry_nc::before { background-position-y: -3361px }
+ &.ctry_ne::before { background-position-y: -3381px }
+ &.ctry_ng::before { background-position-y: -3401px }
+ &.ctry_ni::before { background-position-y: -3421px }
+ &.ctry_nl::before,
+ &.ctry_bq::before { background-position-y: -3441px }
+ &.ctry_no::before, &.ctry_bv::before , &.ctry_nq::before,
+ &.ctry_sj::before { background-position-y: -3461px }
+ &.ctry_np::before { background-position-y: -3481px }
+ &.ctry_nr::before { background-position-y: -3501px }
+ &.ctry_nz::before { background-position-y: -3521px }
+ &.ctry_om::before { background-position-y: -3541px }
+ &.ctry_pa::before { background-position-y: -3561px }
+ &.ctry_pe::before { background-position-y: -3581px }
+ &.ctry_pf::before { background-position-y: -3601px }
+ &.ctry_pg::before { background-position-y: -3621px }
+ &.ctry_ph::before { background-position-y: -3641px }
+ &.ctry_pk::before { background-position-y: -3661px }
+ &.ctry_pl::before { background-position-y: -3681px }
+ &.ctry_pr::before { background-position-y: -3701px }
+ &.ctry_ps::before { background-position-y: -3721px }
+ &.ctry_pt::before { background-position-y: -3741px }
+ &.ctry_pw::before { background-position-y: -3761px }
+ &.ctry_py::before { background-position-y: -3781px }
+ &.ctry_qa::before { background-position-y: -3801px }
+ &.ctry_re::before { background-position-y: -3821px }
+ &.ctry_ro::before { background-position-y: -3841px }
+ &.ctry_rs::before { background-position-y: -3861px }
+ &.ctry_ru::before { background-position-y: -3881px }
+ &.ctry_rw::before { background-position-y: -3901px }
+ &.ctry_sa::before { background-position-y: -3921px }
+ &.ctry_sb::before { background-position-y: -3941px }
+ &.ctry_sc::before { background-position-y: -3961px }
+ &.ctry_sd::before { background-position-y: -3981px }
+ &.ctry_se::before { background-position-y: -4001px }
+ &.ctry_sg::before { background-position-y: -4021px }
+ &.ctry_si::before { background-position-y: -4041px }
+ &.ctry_sk::before { background-position-y: -4061px }
+ &.ctry_sl::before { background-position-y: -4081px }
+ &.ctry_sm::before { background-position-y: -4101px }
+ &.ctry_sn::before { background-position-y: -4121px }
+ &.ctry_so::before { background-position-y: -4141px }
+ &.ctry_sr::before { background-position-y: -4161px }
+ &.ctry_st::before { background-position-y: -4181px }
+ &.ctry_sv::before { background-position-y: -4201px }
+ &.ctry_sy::before { background-position-y: -4221px }
+ &.ctry_sz::before { background-position-y: -4241px }
+ &.ctry_tc::before { background-position-y: -4261px }
+ &.ctry_td::before { background-position-y: -4281px }
+ &.ctry_tg::before { background-position-y: -4301px }
+ &.ctry_th::before { background-position-y: -4321px }
+ &.ctry_tj::before { background-position-y: -4341px }
+ &.ctry_tl::before { background-position-y: -4361px }
+ &.ctry_tm::before { background-position-y: -4381px }
+ &.ctry_tn::before { background-position-y: -4401px }
+ &.ctry_to::before { background-position-y: -4421px }
+ &.ctry_tr::before { background-position-y: -4441px }
+ &.ctry_tt::before { background-position-y: -4461px }
+ &.ctry_tv::before { background-position-y: -4481px }
+ &.ctry_tw::before { background-position-y: -4501px }
+ &.ctry_tz::before { background-position-y: -4521px }
+ &.ctry_ua::before { background-position-y: -4541px }
+ &.ctry_ug::before { background-position-y: -4561px }
+ &.ctry_us::before { background-position-y: -4581px }
+ &.ctry_uy::before { background-position-y: -4601px }
+ &.ctry_uz::before { background-position-y: -4621px }
+ &.ctry_va::before { background-position-y: -4641px }
+ &.ctry_vc::before { background-position-y: -4661px }
+ &.ctry_ve::before { background-position-y: -4681px }
+ &.ctry_vg::before { background-position-y: -4701px }
+ &.ctry_vi::before { background-position-y: -4721px }
+ &.ctry_vn::before { background-position-y: -4741px }
+ &.ctry_vu::before { background-position-y: -4761px }
+ &.ctry_ws::before { background-position-y: -4781px }
+ &.ctry_ye::before { background-position-y: -4801px }
+ &.ctry_za::before { background-position-y: -4821px }
+ &.ctry_zm::before { background-position-y: -4841px }
+ &.ctry_zw::before { background-position-y: -4861px }
+ &.ctry_sx::before { background-position-y: -4881px }
+ &.ctry_cw::before { background-position-y: -4901px }
+ &.ctry_ss::before { background-position-y: -4921px }
+ &.ctry_nu::before { background-position-y: -4941px }
+
+ &.ctry_local::before { background-image: url('img/addr.png') } /* localhost */
+
+ /* Session icons */
+ &.session::before { background-image: url('img/idtyp.png') }
+ &.typ_dw::before { background-position-y: -20px }
+ &.typ_php::before { background-position-y: -40px }
+ &.typ_ip::before { background-position-y: -60px }
+ &.typ_usr::before { background-position-y: -80px }
+ }
+
/* grid layout for the overview: */
.botmon_overview_grid {
- display: grid;
- grid-template-columns: 1fr 1fr 1fr 1fr;
- grid-gap: 0 .33em;
+ & {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr;
+ grid-gap: 0 .33em;
+ }
+ dl {
+ dd {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ }
+ }
}
/* the "today" tab: */
@@ -43,9 +378,11 @@
margin-bottom: .2em;
}
dd {
+ padding: 0; margin: 0;
+ }
+ dd.spaced {
display: flex;
justify-content: space-between;
- padding: 0; margin: 0;
}
dd:nth-child(even) {
background-color: #EEE;
@@ -151,26 +488,6 @@
details ul > li > details > summary > span:first-child {
flex-grow: 1;
}
- details ul > li > details > summary > span > span {
- display: flex;
- align-items: center;
- column-gap: .25em;
- height: 1.5em;
- overflow: hidden;
- margin-right: .2rem;
- }
- details ul > li > details > summary > span > span::before {
- content: '';
- display: inline-block;
- min-width: 1.25em; height: 1em;
- text-align: center;
- background: transparent url('img/placeholder.svg') center no-repeat;
- background-size: 1em;
- }
- details ul > li > details > summary > span > span.icon {
- width: 1.25em;
- overflow: hidden;
- }
details ul > li > details > summary > span > span[title] {
cursor: help;
}
@@ -186,14 +503,8 @@
white-space: nowrap;
}
dd {
- & {
- grid-column: 2;
- display: inline-block;
- background-color: transparent;
- }
- /*&.bot-rating {
- text-align: right;
- }*/
+ grid-column: 2;
+ background-color: transparent;
}
dd.pages {
& {
@@ -225,13 +536,6 @@
}
}
}
- dd.has_icon::before {
- content: '';
- display: inline-block;
- width: 1.25em; height: 1.25em;
- background: transparent url('img/placeholder.svg') center no-repeat;
- background-size: 1em;
- }
ul.eval {
li {
@@ -248,316 +552,10 @@
}
}
- /* bot icons */
- span.bot::before, dd.bot::before { background-image: url('img/robot.svg') }
- span.bot_bingbot::before, dd.bot_bingbot::before { background-image: url('img/bing.svg') }
- span.bot_googlebot::before, dd.bot_googlebot::before,
- span.bot_googleads::before, dd.bot_googleads::before,
- span.bot_googleapi::before, dd.bot_googleapi::before { background-image: url('img/google.svg') }
- span.bot_applebot::before, dd.bot_applebot::before { background-image: url('img/apple.svg') }
- span.bot_slurp::before, dd.bot_slurp::before { background-image: url('img/yahoo.svg') }
- span.bot_ddg::before, dd.bot_ddg::before { background-image: url('img/ddg.svg') }
- span.bot_openai::before, dd.bot_openai::before { background-image: url('img/openai.svg') }
- span.bot_claude::before, dd.bot_claude::before { background-image: url('img/anthropic.png') }
- span.bot_perplexity::before, dd.bot_perplexity::before { background-image: url('img/perplexity.svg') }
- span.bot_metabots::before, dd.bot_metabots::before { background-image: url('img/meta.svg') }
- span.bot_qwant::before, dd.bot_qwant::before { background-image: url('img/qwant.svg') }
- span.bot_yandex::before, dd.bot_yandex::before { background-image: url('img/yandex.svg') }
- span.bot_seznambot::before, dd.bot_seznambot::before { background-image: url('img/seznam.svg') }
- span.bot_ahrefs::before, dd.bot_ahrefs::before { background-image: url('img/ahrefs.png') }
- span.bot_ccbot::before, dd.bot_ccbot::before { background-image: url('img/ccbot.png') }
- span.bot_mjbot::before, dd.bot_mjbot::before { background-image: url('img/majestic.png') }
- span.bot_petal::before, dd.bot_petal::before { background-image: url('img/petal.svg') }
- span.bot_barkrowler::before, dd.bot_barkrowler::before { background-image: url('img/babbar.png') }
- span.bot_semrush::before, dd.bot_semrush::before { background-image: url('img/semrush.png') }
- span.bot_bytespider::before, dd.bot_bytespider::before { background-image: url('img/bytedance.svg') }
- span.bot_dfseo::before, dd.bot_dfseo::before { background-image: url('img/dataforseo.png') }
- span.bot_hunter::before, dd.bot_hunter::before { background-image: url('img/hunter.png') }
- span.bot_serpstat::before, dd.bot_serpstat::before { background-image: url('img/serpstat.svg') }
- span.bot_netestate::before, dd.bot_netestate::before { background-image: url('img/netestate.png') }
- span.bot_imagesift::before, dd.bot_imagesift::before { background-image: url('img/hive.svg') }
- /*span.bot_mozcom::before, dd.bot_mozcom::before { background-image: url('img/moz.svg') }*/
- /*span.bot_maui::before, dd.bot_maui::before { background-image: url('img/maui.svg') }*/
- span.bot_plagaware::before, dd.bot_plagaware::before { background-image: url('img/plagaware.png') }
-
- /* user info */
- span.user_known::before { background-image: url('img/user.svg') }
-
- /* platform icons */
- span.platform_win10::before, dd.platform_win10::before { background-image: url('img/win11.svg') }
- span.platform_macos::before, dd.platform_macos::before { background-image: url('img/apple.svg') }
- span.platform_linux::before, dd.platform_linux::before { background-image: url('img/linux.svg') }
- span.platform_ios::before, dd.platform_ios::before { background-image: url('img/ios.svg') }
- span.platform_android::before, dd.platform_android::before { background-image: url('img/android.svg') }
- span.platform_winold::before, dd.platform_winold::before,
- span.platform_winsrvr:before, dd.platform_winsrvr::before { background-image: url('img/winold.png') }
- span.platform_macosold::before, dd.platform_macosold::before { background-image: url('img/macos.svg') }
- span.platform_tizen::before, dd.platform_tizen::before { background-image: url('img/tizen.png') }
- span.platform_hmos::before, dd.platform_hmos::before { background-image: url('img/hmos.svg') }
- span.platform_chromium::before, dd.platform_chromium::before { background-image: url('img/chromium.svg') }
- span.platform_bsd::before, dd.platform_bsd::before { background-image: url('img/freebsd.png') }
-
- /* browser icons */
- span.client_opera::before, dd.client_opera::before { background-image: url('img/opera.svg') }
- span.client_msie::before, dd.client_msie::before { background-image: url('img/msie.svg') }
- span.client_brave::before, dd.client_brave::before { background-image: url('img/brave.svg') }
- span.client_msedge::before, dd.client_msedge::before { background-image: url('img/msedge.svg') }
- span.client_chrome::before, dd.client_chrome::before { background-image: url('img/chrome.svg') }
- span.client_chromeold::before, dd.client_chromeold::before { background-image: url('img/chromeold.svg') }
- span.client_safari::before, dd.client_safari::before { background-image: url('img/safari.png') }
- span.client_ddg::before, dd.client_ddg::before { background-image: url('img/ddg.svg') }
- span.client_firefox::before, dd.client_firefox::before { background-image: url('img/firefox.png') }
- span.client_samsung::before, dd.client_samsung::before { background-image: url('img/samsung.svg') }
- span.client_uc::before, dd.client_uc::before { background-image: url('img/uc.svg') }
- span.client_huawei::before, dd.client_huawei::before { background-image: url('img/huawei.png') }
- span.client_vivaldi::before, dd.client_vivaldi::before { background-image: url('img/vivaldi.svg') }
- span.client_aol::before, dd.client_aol::before { background-image: url('img/aol.png') }
- span.client_ya::before, dd.client_ya::before { background-image: url('img/yandex.svg') }
-
- /* ip address type */
- span.ip6::before, dd.ip6::before { background-image: url('img/ip6.svg') }
- span.ip4::before, dd.ip4::before { background-image: url('img/ip4.svg') }
- span.ip0::before, dd.ip0::before { background-image: url('img/localhost.svg') }
-
- /* Country flags */
- /* Note: flag images and CSS adapted from: https://github.com/lafeber/world-flags-sprite/ */
- span.country::before, dd.country::before {
- content: '';
- display: inline-block;
- height: 16px; width: 16px;
- background:url(img/flags.png) no-repeat center;
- background-position: 0 0;
- }
- span.ctry_ad::before, dd.ctry_ad::before { background-position-y: -353px }
- span.ctry_ae::before, dd.ctry_ae::before { background-position-y: -369px }
- span.ctry_af::before, dd.ctry_af::before { background-position-y: -385px }
- span.ctry_ag::before, dd.ctry_ag::before { background-position-y: -401px }
- span.ctry_ai::before, dd.ctry_ai::before { background-position-y: -417px }
- span.ctry_al::before, dd.ctry_al::before { background-position-y: -433px }
- span.ctry_am::before, dd.ctry_am::before { background-position-y: -449px }
- span.ctry_ao::before, dd.ctry_ao::before { background-position-y: -465px }
- span.ctry_aq::before, dd.ctry_aq::before { background-position-y: -481px }
- span.ctry_ar::before, dd.ctry_ar::before { background-position-y: -497px }
- span.ctry_as::before, dd.ctry_as::before { background-position-y: -513px }
- span.ctry_at::before, dd.ctry_at::before { background-position-y: -529px }
- span.ctry_au::before, dd.ctry_au::before { background-position-y: -545px }
- span.ctry_aw::before, dd.ctry_aw::before { background-position-y: -561px }
- span.ctry_ax::before, dd.ctry_ax::before { background-position-y: -577px }
- span.ctry_az::before, dd.ctry_az::before { background-position-y: -593px }
- span.ctry_ba::before, dd.ctry_ba::before { background-position-y: -609px }
- span.ctry_bb::before, dd.ctry_bb::before { background-position-y: -625px }
- span.ctry_bd::before, dd.ctry_bd::before { background-position-y: -641px }
- span.ctry_be::before, dd.ctry_be::before { background-position-y: -657px }
- span.ctry_bf::before, dd.ctry_bf::before { background-position-y: -673px }
- span.ctry_bg::before, dd.ctry_bg::before { background-position-y: -689px }
- span.ctry_bh::before, dd.ctry_bh::before { background-position-y: -705px }
- span.ctry_bi::before, dd.ctry_bi::before { background-position-y: -721px }
- span.ctry_bj::before, dd.ctry_bj::before { background-position-y: -737px }
- span.ctry_bm::before, dd.ctry_bm::before { background-position-y: -753px }
- span.ctry_bn::before, dd.ctry_bn::before { background-position-y: -769px }
- span.ctry_bo::before, dd.ctry_bo::before { background-position-y: -785px }
- span.ctry_br::before, dd.ctry_br::before { background-position-y: -801px }
- span.ctry_bs::before, dd.ctry_bs::before { background-position-y: -817px }
- span.ctry_bt::before, dd.ctry_bt::before { background-position-y: -833px }
- span.ctry_bw::before, dd.ctry_bw::before { background-position-y: -849px }
- span.ctry_by::before, dd.ctry_by::before { background-position-y: -865px }
- span.ctry_bz::before, dd.ctry_bz::before { background-position-y: -881px }
- span.ctry_ca::before, dd.ctry_ca::before { background-position-y: -897px }
- span.ctry_cd::before, dd.ctry_cd::before { background-position-y: -913px }
- span.ctry_cf::before, dd.ctry_cf::before { background-position-y: -929px }
- span.ctry_cg::before, dd.ctry_cg::before { background-position-y: -945px }
- span.ctry_ch::before, dd.ctry_ch::before { background-position-y: -961px }
- span.ctry_ci::before, dd.ctry_ci::before { background-position-y: -977px }
- span.ctry_ck::before, dd.ctry_ck::before { background-position-y: -993px }
- span.ctry_cl::before, dd.ctry_cl::before { background-position-y: -1009px }
- span.ctry_cm::before, dd.ctry_cm::before { background-position-y: -1025px }
- span.ctry_cn::before, dd.ctry_cn::before { background-position-y: -1041px }
- span.ctry_co::before, dd.ctry_co::before { background-position-y: -1057px }
- span.ctry_cr::before, dd.ctry_cr::before { background-position-y: -1073px }
- span.ctry_cu::before, dd.ctry_cu::before { background-position-y: -1089px }
- span.ctry_cv::before, dd.ctry_cv::before { background-position-y: -1105px }
- span.ctry_cy::before, dd.ctry_cy::before { background-position-y: -1121px }
- span.ctry_cz::before, dd.ctry_cz::before { background-position-y: -1137px }
- span.ctry_de::before, dd.ctry_de::before { background-position-y: -1153px }
- span.ctry_dj::before, dd.ctry_dj::before { background-position-y: -1169px }
- span.ctry_dk::before, dd.ctry_dk::before { background-position-y: -1185px }
- span.ctry_dm::before, dd.ctry_dm::before { background-position-y: -1201px }
- span.ctry_do::before, dd.ctry_do::before { background-position-y: -1217px }
- span.ctry_dz::before, dd.ctry_dz::before { background-position-y: -1233px }
- span.ctry_ec::before, dd.ctry_ec::before { background-position-y: -1249px }
- span.ctry_ee::before, dd.ctry_ee::before { background-position-y: -1265px }
- span.ctry_eg::before, dd.ctry_eg::before { background-position-y: -1281px }
- span.ctry_eh::before, dd.ctry_eh::before { background-position-y: -1297px }
- span.ctry_er::before, dd.ctry_er::before { background-position-y: -1313px }
- span.ctry_es::before, dd.ctry_es::before { background-position-y: -1329px }
- span.ctry_et::before, dd.ctry_et::before { background-position-y: -1345px }
- span.ctry_fi::before, dd.ctry_fi::before { background-position-y: -1361px }
- span.ctry_fj::before, dd.ctry_fj::before { background-position-y: -1377px }
- span.ctry_fm::before, dd.ctry_fm::before { background-position-y: -1393px }
- span.ctry_fo::before, dd.ctry_fo::before { background-position-y: -1409px }
- span.ctry_yt::before, dd.ctry_yt::before { background-position-y: -1425px }
- span.ctry_ga::before, dd.ctry_ga::before { background-position-y: -1441px }
- span.ctry_sh::before, dd.ctry_sh::before { background-position-y: -1457px }
- span.ctry_gd::before, dd.ctry_gd::before { background-position-y: -1473px }
- span.ctry_ge::before, dd.ctry_ge::before { background-position-y: -1489px }
- span.ctry_gg::before, dd.ctry_gg::before { background-position-y: -1505px }
- span.ctry_gh::before, dd.ctry_gh::before { background-position-y: -1521px }
- span.ctry_gi::before, dd.ctry_gi::before { background-position-y: -1537px }
- span.ctry_gl::before, dd.ctry_gl::before { background-position-y: -1553px }
- span.ctry_gm::before, dd.ctry_gm::before { background-position-y: -1569px }
- span.ctry_gn::before, dd.ctry_gn::before { background-position-y: -1585px }
- span.ctry_gp::before, dd.ctry_gp::before { background-position-y: -1601px }
- span.ctry_gq::before, dd.ctry_gq::before { background-position-y: -1617px }
- span.ctry_gr::before, dd.ctry_gr::before { background-position-y: -1633px }
- span.ctry_gt::before, dd.ctry_gt::before { background-position-y: -1649px }
- span.ctry_gu::before, dd.ctry_gu::before { background-position-y: -1665px }
- span.ctry_gw::before, dd.ctry_gw::before { background-position-y: -1681px }
- span.ctry_gy::before, dd.ctry_gy::before { background-position-y: -1697px }
- span.ctry_hk::before, dd.ctry_hk::before { background-position-y: -1713px }
- span.ctry_hn::before, dd.ctry_hn::before { background-position-y: -1729px }
- span.ctry_hr::before, dd.ctry_hr::before { background-position-y: -1745px }
- span.ctry_ht::before, dd.ctry_ht::before { background-position-y: -1761px }
- span.ctry_hu::before, dd.ctry_hu::before { background-position-y: -1777px }
- span.ctry_mc::before, dd.ctry_mc::before { background-position-y: -1793px }
- span.ctry_ie::before, dd.ctry_ie::before { background-position-y: -1809px }
- span.ctry_il::before, dd.ctry_il::before { background-position-y: -1825px }
- span.ctry_im::before, dd.ctry_im::before { background-position-y: -1841px }
- span.ctry_in::before, dd.ctry_in::before { background-position-y: -1857px }
- span.ctry_iq::before, dd.ctry_iq::before { background-position-y: -1873px }
- span.ctry_ir::before, dd.ctry_ir::before { background-position-y: -1889px }
- span.ctry_is::before, dd.ctry_is::before { background-position-y: -1905px }
- span.ctry_it::before, dd.ctry_it::before { background-position-y: -1921px }
- span.ctry_je::before, dd.ctry_je::before { background-position-y: -1937px }
- span.ctry_jm::before, dd.ctry_jm::before { background-position-y: -1953px }
- span.ctry_jo::before, dd.ctry_jo::before { background-position-y: -1969px }
- span.ctry_jp::before, dd.ctry_jp::before { background-position-y: -1985px }
- span.ctry_ke::before, dd.ctry_ke::before { background-position-y: -2001px }
- span.ctry_kg::before, dd.ctry_kg::before { background-position-y: -2017px }
- span.ctry_kh::before, dd.ctry_kh::before { background-position-y: -2033px }
- span.ctry_ki::before, dd.ctry_ki::before { background-position-y: -2049px }
- span.ctry_km::before, dd.ctry_km::before { background-position-y: -2065px }
- span.ctry_kn::before, dd.ctry_kn::before { background-position-y: -2081px }
- span.ctry_kp::before, dd.ctry_kp::before { background-position-y: -2097px }
- span.ctry_kr::before, dd.ctry_kr::before { background-position-y: -2113px }
- span.ctry_kw::before, dd.ctry_kw::before { background-position-y: -2129px }
- span.ctry_ky::before, dd.ctry_ky::before { background-position-y: -2145px }
- span.ctry_kz::before, dd.ctry_kz::before { background-position-y: -2161px }
- span.ctry_la::before, dd.ctry_la::before { background-position-y: -2177px }
- span.ctry_lb::before, dd.ctry_lb::before { background-position-y: -2193px }
- span.ctry_lc::before, dd.ctry_lc::before { background-position-y: -2209px }
- span.ctry_li::before, dd.ctry_li::before { background-position-y: -2225px }
- span.ctry_lk::before, dd.ctry_lk::before { background-position-y: -2241px }
- span.ctry_lr::before, dd.ctry_lr::before { background-position-y: -2257px }
- span.ctry_ls::before, dd.ctry_ls::before { background-position-y: -2273px }
- span.ctry_lt::before, dd.ctry_lt::before { background-position-y: -2289px }
- span.ctry_lu::before, dd.ctry_lu::before { background-position-y: -2305px }
- span.ctry_lv::before, dd.ctry_lv::before { background-position-y: -2321px }
- span.ctry_ly::before, dd.ctry_ly::before { background-position-y: -2337px }
- span.ctry_ma::before, dd.ctry_ma::before { background-position-y: -2353px }
- span.ctry_md::before, dd.ctry_md::before { background-position-y: -2369px }
- span.ctry_me::before, dd.ctry_me::before { background-position-y: -2385px }
- span.ctry_mg::before, dd.ctry_mg::before { background-position-y: -2401px }
- span.ctry_mh::before, dd.ctry_mh::before { background-position-y: -2417px }
- span.ctry_mk::before, dd.ctry_mk::before { background-position-y: -2433px }
- span.ctry_ml::before, dd.ctry_ml::before { background-position-y: -2449px }
- span.ctry_mm::before, dd.ctry_mm::before { background-position-y: -2465px }
- span.ctry_mn::before, dd.ctry_mn::before { background-position-y: -2481px }
- span.ctry_mo::before, dd.ctry_mo::before { background-position-y: -2497px }
- span.ctry_mq::before, dd.ctry_mq::before { background-position-y: -2513px }
- span.ctry_mr::before, dd.ctry_mr::before { background-position-y: -2529px }
- span.ctry_ms::before, dd.ctry_ms::before { background-position-y: -2545px }
- span.ctry_mt::before, dd.ctry_mt::before { background-position-y: -2561px }
- span.ctry_mu::before, dd.ctry_mu::before { background-position-y: -2577px }
- span.ctry_mv::before, dd.ctry_mv::before { background-position-y: -2593px }
- span.ctry_mw::before, dd.ctry_mw::before { background-position-y: -2609px }
- span.ctry_mx::before, dd.ctry_mx::before { background-position-y: -2625px }
- span.ctry_my::before, dd.ctry_my::before { background-position-y: -2641px }
- span.ctry_mz::before, dd.ctry_mz::before { background-position-y: -2657px }
- span.ctry_na::before, dd.ctry_na::before { background-position-y: -2673px }
- span.ctry_nc::before, dd.ctry_nc::before { background-position-y: -2689px }
- span.ctry_ne::before, dd.ctry_ne::before { background-position-y: -2705px }
- span.ctry_ng::before, dd.ctry_ng::before { background-position-y: -2721px }
- span.ctry_ni::before, dd.ctry_ni::before { background-position-y: -2737px }
- span.ctry_bq::before, dd.ctry_bq::before { background-position-y: -2753px }
- span.ctry_bv::before, dd.ctry_bv::before { background-position-y: -2769px }
- span.ctry_np::before, dd.ctry_np::before { background-position-y: -2785px }
- span.ctry_nr::before, dd.ctry_nr::before { background-position-y: -2801px }
- span.ctry_nz::before, dd.ctry_nz::before { background-position-y: -2817px }
- span.ctry_om::before, dd.ctry_om::before { background-position-y: -2833px }
- span.ctry_pa::before, dd.ctry_pa::before { background-position-y: -2849px }
- span.ctry_pe::before, dd.ctry_pe::before { background-position-y: -2865px }
- span.ctry_pf::before, dd.ctry_pf::before { background-position-y: -2881px }
- span.ctry_pg::before, dd.ctry_pg::before { background-position-y: -2897px }
- span.ctry_ph::before, dd.ctry_ph::before { background-position-y: -2913px }
- span.ctry_pk::before, dd.ctry_pk::before { background-position-y: -2929px }
- span.ctry_pl::before, dd.ctry_pl::before { background-position-y: -2945px }
- span.ctry_pr::before, dd.ctry_pr::before { background-position-y: -2961px }
- span.ctry_ps::before, dd.ctry_ps::before { background-position-y: -2977px }
- span.ctry_pt::before, dd.ctry_pt::before { background-position-y: -2993px }
- span.ctry_pw::before, dd.ctry_pw::before { background-position-y: -3009px }
- span.ctry_py::before, dd.ctry_py::before { background-position-y: -3025px }
- span.ctry_qa::before, dd.ctry_qa::before { background-position-y: -3041px }
- span.ctry_re::before, dd.ctry_re::before { background-position-y: -3057px }
- span.ctry_ro::before, dd.ctry_ro::before { background-position-y: -3073px }
- span.ctry_rs::before, dd.ctry_rs::before { background-position-y: -3089px }
- span.ctry_ru::before, dd.ctry_ru::before { background-position-y: -3105px }
- span.ctry_rw::before, dd.ctry_rw::before { background-position-y: -3121px }
- span.ctry_sa::before, dd.ctry_sa::before { background-position-y: -3137px }
- span.ctry_sb::before, dd.ctry_sb::before { background-position-y: -3153px }
- span.ctry_sc::before, dd.ctry_sc::before { background-position-y: -3169px }
- span.ctry_sd::before, dd.ctry_sd::before { background-position-y: -3185px }
- span.ctry_se::before, dd.ctry_se::before { background-position-y: -3201px }
- span.ctry_sg::before, dd.ctry_sg::before { background-position-y: -3217px }
- span.ctry_si::before, dd.ctry_si::before { background-position-y: -3233px }
- span.ctry_sk::before, dd.ctry_sk::before { background-position-y: -3249px }
- span.ctry_sl::before, dd.ctry_sl::before { background-position-y: -3265px }
- span.ctry_sm::before, dd.ctry_sm::before { background-position-y: -3281px }
- span.ctry_sn::before, dd.ctry_sn::before { background-position-y: -3297px }
- span.ctry_so::before, dd.ctry_so::before { background-position-y: -3313px }
- span.ctry_sr::before, dd.ctry_sr::before { background-position-y: -3329px }
- span.ctry_st::before, dd.ctry_st::before { background-position-y: -3345px }
- span.ctry_sv::before, dd.ctry_sv::before { background-position-y: -3361px }
- span.ctry_sy::before, dd.ctry_sy::before { background-position-y: -3377px }
- span.ctry_sz::before, dd.ctry_sz::before { background-position-y: -3393px }
- span.ctry_tc::before, dd.ctry_tc::before { background-position-y: -3409px }
- span.ctry_td::before, dd.ctry_td::before { background-position-y: -3425px }
- span.ctry_tg::before, dd.ctry_tg::before { background-position-y: -3441px }
- span.ctry_th::before, dd.ctry_th::before { background-position-y: -3457px }
- span.ctry_tj::before, dd.ctry_tj::before { background-position-y: -3473px }
- span.ctry_tl::before, dd.ctry_tl::before { background-position-y: -3489px }
- span.ctry_tm::before, dd.ctry_tm::before { background-position-y: -3505px }
- span.ctry_tn::before, dd.ctry_tn::before { background-position-y: -3521px }
- span.ctry_to::before, dd.ctry_to::before { background-position-y: -3537px }
- span.ctry_tr::before, dd.ctry_tr::before { background-position-y: -3553px }
- span.ctry_tt::before, dd.ctry_tt::before { background-position-y: -3569px }
- span.ctry_tv::before, dd.ctry_tv::before { background-position-y: -3585px }
- span.ctry_tw::before, dd.ctry_tw::before { background-position-y: -3601px }
- span.ctry_tz::before, dd.ctry_tz::before { background-position-y: -3617px }
- span.ctry_ua::before, dd.ctry_ua::before { background-position-y: -3633px }
- span.ctry_ug::before, dd.ctry_ug::before { background-position-y: -3649px }
- span.ctry_us::before, dd.ctry_us::before { background-position-y: -3665px }
- span.ctry_uy::before, dd.ctry_uy::before { background-position-y: -3681px }
- span.ctry_uz::before, dd.ctry_uz::before { background-position-y: -3697px }
- span.ctry_va::before, dd.ctry_va::before { background-position-y: -3713px }
- span.ctry_vc::before, dd.ctry_vc::before { background-position-y: -3729px }
- span.ctry_ve::before, dd.ctry_ve::before { background-position-y: -3745px }
- span.ctry_vg::before, dd.ctry_vg::before { background-position-y: -3761px }
- span.ctry_vi::before, dd.ctry_vi::before { background-position-y: -3777px }
- span.ctry_vn::before, dd.ctry_vn::before { background-position-y: -3793px }
- span.ctry_vu::before, dd.ctry_vu::before { background-position-y: -3809px }
- span.ctry_ws::before, dd.ctry_ws::before { background-position-y: -3825px }
- span.ctry_ye::before, dd.ctry_ye::before { background-position-y: -3841px }
- span.ctry_za::before, dd.ctry_za::before { background-position-y: -3857px }
- span.ctry_zm::before, dd.ctry_zm::before { background-position-y: -3873px }
- span.ctry_zw::before, dd.ctry_zw::before { background-position-y: -3889px }
- span.ctry_sx::before, dd.ctry_sx::before { background-position-y: -3905px }
- span.ctry_cw::before, dd.ctry_cw::before { background-position-y: -3921px }
- span.ctry_ss::before, dd.ctry_ss::before { background-position-y: -3937px }
- span.ctry_nu::before, dd.ctry_nu::before { background-position-y: -3953px }
-
-
/* user agent */
- span.agent::before { background-image: url('img/info.svg') }
+ span.agent::before {
+ background-image: url('img/info.svg')
+ }
/* pageviews */
span.pageviews {
@@ -566,7 +564,13 @@
font-size: smaller;
border-radius: .25em;
}
- span.pageviews::before { background-image: url('img/page.svg') }
+ span.pageviews::before {
+ content : '';
+ display: inline-block;
+ width: 1.25em; height: 1.25em;
+ background: transparent url('img/page.svg') center no-repeat;
+ background-size: 1.25em;
+ }
}
diff --git a/tick.php b/tick.php
index b5393e7..1d46b1e 100644
--- a/tick.php
+++ b/tick.php
@@ -1,22 +1,12 @@