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 @@ -View only \ 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 @@ -localhost \ 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 @@ - - - - - - - image/svg+xml - - - - - - - - - \ 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 @@ - - - - - Petal Search logo - - - - - - - - - - - - - Petal Search logo - 16 agt 2021 - - es - - - - - - - - - - - - - - - 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 @@ -placeholder \ 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 @@ -robot \ 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 @@ -script-text-play \ 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 @@