From fa4319d69f24d063537b74418234ac7d548f2be8 Mon Sep 17 00:00:00 2001 From: mobeicanyue <81098819+mobeicanyue@users.noreply.github.com> Date: Sat, 24 Feb 2024 22:38:51 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20umami=20=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=8C=82=E8=BD=BD=E7=BB=9F=E8=AE=A1=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _config.yml | 51 ++++++++----- layout/_partials/footer/statistics.ejs | 22 +++++- layout/_partials/plugins/analytics.ejs | 17 +++-- layout/_partials/post/meta-top.ejs | 8 +++ source/js/umami-view.js | 99 ++++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 27 deletions(-) create mode 100644 source/js/umami-view.js diff --git a/_config.yml b/_config.yml index c392d668..5f253913 100644 --- a/_config.yml +++ b/_config.yml @@ -260,21 +260,6 @@ web_analytics: google: measurement_id: - # Umami Analytics,src 和 data-website-id 是必填项,其他可选 - # Umami Analytics, src and data-website-id are required, others are optional - umami: - # umami js 文件地址,需要在 umami 后台创建站点后获取 - # umami js file url, get after create website in umami - src: - # umami 的 website id,需要在 umami 后台创建站点后获取 - # umami website id, get after create website in umami - data_website_id: - # 如果你只想跟踪器跟踪特定的域名,你可以将它们添加到你的跟踪器脚本中。这是一个逗号分隔的域名列表。 - # 如果你在一个分阶段、开发的环境中工作,这会很有帮助。避免统计 localhost。 - # If you want the tracker to only run on specific domains, you can add them to your tracker script. This is a comma delimited list of domain names. - # Helps if you are working in a staging/development environment. Avoids tracking localhost. - data_domains: - # 腾讯统计的 H5 App ID,开启高级功能才有cid # Tencent analytics, set APP ID # See: https://mta.qq.com/h5/manage/ctr_app_manage @@ -307,6 +292,34 @@ web_analytics: # If true, ignore localhost & 127.0.0.1 ignore_local: false + # Umami Analytics,仅支持自部署。如果要展示 PV UV 需要填写所有配置项,否则只填写 `src` 和 `website_id` 即可 + # Umami Analytics, only Self-host support. If you want to display PV UV need to set all config items, otherwise only set 'src' and 'website_id' + # See: https://umami.is/docs/authentication + umami: + # umami js 文件地址,需要在 umami 后台创建站点后获取 + # umami js file url, get after create website in umami + src: + + # umami 的 website id,需要在 umami 后台创建站点后获取 + # umami website id, get after create website in umami + website_id: + + # 如果你只想统计特定的域名可以填入此字段,多个域名通过逗号分隔,这可以避免统计 localhost。 + # If you only want to tracker to specific domains you can fill in this field, multiple domain names are separated by commas, which can avoid tracker localhost + domains: + + # 用于统计 PV UV 的开始时间,格式为 "YYYY-MM-DD" + # statistics on the start time, the format is "YYYY-MM-DD" + start_time: 2024-01-01 + + # 新建一个 umami viewOnly 用户,然后通过 login api 获取该用户 token + # create an umami viewOnly user, and then get user token through the login api + token: + + # 填写 umami 部署的服务器地址,如 "https://umami.example.com" + # server url of umami deployment, such as "https://umami.example.com" + api_server: + # Canonical 用于向 Google 搜索指定规范网址,开启前确保 hexo _config.yml 中配置 `url: http://yourdomain.com` # Canonical, to specify a canonical URL for Google Search, need to set up `url: http://yourdomain.com` in hexo _config.yml # See: https://support.google.com/webmasters/answer/139066 @@ -453,9 +466,9 @@ footer: statistics: enable: false - # 统计数据来源,使用 leancloud 需要设置 `web_analytics: leancloud` 中的参数;使用 busuanzi 不需要额外设置,但是有时不稳定,另外本地运行时 busuanzi 显示统计数据很大属于正常现象,部署后会正常 - # Data source. If use leancloud, you need to set the parameter in `web_analytics: leancloud` - # Options: busuanzi | leancloud + # 统计数据来源,使用 leancloud, umami 需要设置 `web_analytics` 中对应的参数;使用 busuanzi 不需要额外设置,但是有时不稳定,另外本地运行时 busuanzi 显示统计数据很大属于正常现象,部署后会正常 + # Data source. If use leancloud, umami, you need to set the parameter in `web_analytics` + # Options: busuanzi | leancloud | umami source: "busuanzi" # 国内大陆服务器的备案信息 @@ -598,7 +611,7 @@ post: enable: false # 统计数据来源 # Data Source - # Options: busuanzi | leancloud + # Options: busuanzi | leancloud | umami source: "busuanzi" # 在文章开头显示文章更新时间,该时间默认是 md 文件更新时间,可通过 front-matter 中 `updated` 手动指定(和 date 一样格式) diff --git a/layout/_partials/footer/statistics.ejs b/layout/_partials/footer/statistics.ejs index 84f061b1..9f05e2dc 100644 --- a/layout/_partials/footer/statistics.ejs +++ b/layout/_partials/footer/statistics.ejs @@ -1,6 +1,6 @@
- <% var pv_texts = (theme.footer.statistics.pv_format || __('footer.pv')).split('{}') %> - <% var uv_texts = (theme.footer.statistics.uv_format || __('footer.uv')).split('{}') %> + <% let pv_texts = (theme.footer.statistics.pv_format || __('footer.pv')).split('{}') %> + <% let uv_texts = (theme.footer.statistics.uv_format || __('footer.uv')).split('{}') %> <% if (theme.footer.statistics.source === 'leancloud') { %> <% if (pv_texts.length >= 2) { %> @@ -35,5 +35,23 @@ <% } %> <% import_js(theme.static_prefix.busuanzi, 'busuanzi.pure.mini.js', 'defer') %> + + <% } else if (theme.footer.statistics.source === 'umami') { %> + <% if (pv_texts.length >= 2) { %> + + <% } %> + <% if (uv_texts.length >= 2) { %> + + <% } %> + <% import_js(theme.static_prefix.internal_js, 'umami-view.js', 'defer') %> <% } %> +
diff --git a/layout/_partials/plugins/analytics.ejs b/layout/_partials/plugins/analytics.ejs index b8392070..dd5c1a6b 100644 --- a/layout/_partials/plugins/analytics.ejs +++ b/layout/_partials/plugins/analytics.ejs @@ -31,12 +31,17 @@ <% } %> - <% if(theme.web_analytics.umami && theme.web_analytics.umami.src && theme.web_analytics.umami.data_website_id) { %> - - + <% if(theme.web_analytics.umami && theme.web_analytics.umami.src && theme.web_analytics.umami.website_id) { %> + <% } %> <% if(theme.web_analytics.tencent && theme.web_analytics.tencent.sid && theme.web_analytics.tencent.cid) { %> diff --git a/layout/_partials/post/meta-top.ejs b/layout/_partials/post/meta-top.ejs index b94e15c9..3e2e5452 100644 --- a/layout/_partials/post/meta-top.ejs +++ b/layout/_partials/post/meta-top.ejs @@ -51,12 +51,20 @@ <%- views_texts[0] %><%- views_texts[1] %> <% import_js(theme.static_prefix.internal_js, 'leancloud.js', 'defer') %> + <% } else if (theme.post.meta.views.source === 'busuanzi') { %> <% import_js(theme.static_prefix.busuanzi, 'busuanzi.pure.mini.js', 'defer') %> + + <% } else if (theme.post.meta.views.source === 'umami') { %> + + <% import_js(theme.static_prefix.internal_js, 'umami-view.js', 'defer') %> <% } %> <% } %> diff --git a/source/js/umami-view.js b/source/js/umami-view.js new file mode 100644 index 00000000..6ee3f6a8 --- /dev/null +++ b/source/js/umami-view.js @@ -0,0 +1,99 @@ +// 从配置文件中获取 umami 的配置 +const website_id = CONFIG.web_analytics.umami.website_id; +// 拼接请求地址 +const request_url = `${CONFIG.web_analytics.umami.api_server}/websites/${website_id}/stats`; + +const start_time = new Date(CONFIG.web_analytics.umami.start_time).getTime(); +const end_time = new Date().getTime(); +const token = CONFIG.web_analytics.umami.token; + +// 检查配置是否为空 +if (!website_id) { + throw new Error("Umami website_id is empty"); +} +if (!request_url) { + throw new Error("Umami request_url is empty"); +} +if (!start_time) { + throw new Error("Umami start_time is empty"); +} +if (!token) { + throw new Error("Umami token is empty"); +} + +// 构造请求参数 +const params = new URLSearchParams({ + startAt: start_time, + endAt: end_time, +}); +// 构造请求头 +const request_header = { + method: "GET", + headers: { + "Content-Type": "application/json", + "x-umami-api-key": "oZKCH3msvqt10VlXKwoJvHclmaS4bVx0", + }, +}; + +// 获取站点统计数据 +async function siteStats() { + try { + const response = await fetch(`${request_url}?${params}`, request_header); + const data = await response.json(); + const uniqueVisitors = data.uniques.value; // 获取独立访客数 + const pageViews = data.pageviews.value; // 获取页面浏览量 + + let pvCtn = document.querySelector("#umami-site-pv-container"); + if (pvCtn) { + let ele = document.querySelector("#umami-site-pv"); + if (ele) { + ele.textContent = pageViews; // 设置页面浏览量 + pvCtn.style.display = "inline"; // 将元素显示出来 + } + } + + let uvCtn = document.querySelector("#umami-site-uv-container"); + if (uvCtn) { + let ele = document.querySelector("#umami-site-uv"); + if (ele) { + ele.textContent = uniqueVisitors; + uvCtn.style.display = "inline"; + } + } + } catch (error) { + console.error(error); + return "-1"; + } +} + +// 获取页面浏览量 +async function pageStats(path) { + try { + const response = await fetch(`${request_url}?${params}&url=${path}`, request_header); + const data = await response.json(); + const pageViews = data.pageviews.value; + + let viewCtn = document.querySelector("#umami-page-views-container"); + if (viewCtn) { + let ele = document.querySelector("#umami-page-views"); + if (ele) { + ele.textContent = pageViews; + viewCtn.style.display = "inline"; + } + } + } catch (error) { + console.error(error); + return "-1"; + } +} + +siteStats(); + +// 获取页面容器 +let viewCtn = document.querySelector("#umami-page-views-container"); +// 如果页面容器存在,则获取页面浏览量 +if (viewCtn) { + let path = window.location.pathname; + let target = decodeURI(path.replace(/\/*(index.html)?$/, "/")); + pageStats(target); +}