Add initial analytics for downloads (#43)

* Add initial analytics for downloads.

* Change analytics events and enable it.

* Change to a custom ID.

* Use custom analytics plugin.

* Bound gtag to window.

* Update id for `kodo.moe`.
This commit is contained in:
Alessandro Jean 2023-09-10 15:30:57 -03:00 committed by GitHub
parent c410fcbffe
commit 0af948cd8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 97 additions and 21 deletions

View File

@ -52,6 +52,7 @@
"@mdit/plugin-img-size": "^0.4.8", "@mdit/plugin-img-size": "^0.4.8",
"@mdit/plugin-include": "^0.4.8", "@mdit/plugin-include": "^0.4.8",
"@resvg/resvg-js": "^2.4.1", "@resvg/resvg-js": "^2.4.1",
"@types/gtag.js": "^0.0.13",
"@types/lodash.groupby": "^4.6.7", "@types/lodash.groupby": "^4.6.7",
"@types/markdown-it": "^13.0.1", "@types/markdown-it": "^13.0.1",
"@types/node": "^20.6.0", "@types/node": "^20.6.0",
@ -71,7 +72,6 @@
"unplugin-element-plus": "^0.8.0", "unplugin-element-plus": "^0.8.0",
"vite-plugin-eslint": "^1.8.1", "vite-plugin-eslint": "^1.8.1",
"vitepress": "1.0.0-rc.11", "vitepress": "1.0.0-rc.11",
"vitepress-plugin-google-analytics": "^1.0.2",
"vitepress-plugin-tabs": "^0.3.0", "vitepress-plugin-tabs": "^0.3.0",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-eslint-parser": "^9.3.1", "vue-eslint-parser": "^9.3.1",

22
website/pnpm-lock.yaml generated
View File

@ -1,9 +1,5 @@
lockfileVersion: '6.0' lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies: dependencies:
'@iconify-prerendered/vue-mdi': '@iconify-prerendered/vue-mdi':
specifier: ^0.23.1689058119 specifier: ^0.23.1689058119
@ -64,6 +60,9 @@ devDependencies:
'@resvg/resvg-js': '@resvg/resvg-js':
specifier: ^2.4.1 specifier: ^2.4.1
version: 2.4.1 version: 2.4.1
'@types/gtag.js':
specifier: ^0.0.13
version: 0.0.13
'@types/lodash.groupby': '@types/lodash.groupby':
specifier: ^4.6.7 specifier: ^4.6.7
version: 4.6.7 version: 4.6.7
@ -121,9 +120,6 @@ devDependencies:
vitepress: vitepress:
specifier: 1.0.0-rc.11 specifier: 1.0.0-rc.11
version: 1.0.0-rc.11(@algolia/client-search@4.19.1)(@types/node@20.6.0)(axios@1.5.0)(search-insights@2.8.2)(stylus@0.60.0) version: 1.0.0-rc.11(@algolia/client-search@4.19.1)(@types/node@20.6.0)(axios@1.5.0)(search-insights@2.8.2)(stylus@0.60.0)
vitepress-plugin-google-analytics:
specifier: ^1.0.2
version: 1.0.2
vitepress-plugin-tabs: vitepress-plugin-tabs:
specifier: ^0.3.0 specifier: ^0.3.0
version: 0.3.0(vitepress@1.0.0-rc.11)(vue@3.3.4) version: 0.3.0(vitepress@1.0.0-rc.11)(vue@3.3.4)
@ -1183,6 +1179,10 @@ packages:
resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==}
dev: true dev: true
/@types/gtag.js@0.0.13:
resolution: {integrity: sha512-yOXFkfnt1DQr1v9B4ERulJOGnbdVqnPHV8NG4nkQhnu4qbrJecQ06DlaKmSjI3nzIwBj5U9/X61LY4sTc2KbaQ==}
dev: true
/@types/json-schema@7.0.12: /@types/json-schema@7.0.12:
resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
dev: true dev: true
@ -5472,10 +5472,6 @@ packages:
fsevents: 2.3.3 fsevents: 2.3.3
dev: true dev: true
/vitepress-plugin-google-analytics@1.0.2:
resolution: {integrity: sha512-ri8bFUAmt3c/DtPrALauGBIUr2gIJ11c1qNRhwd3/+aiuYZBfQpOosSxcO1AswgwRxP9FwBS6Z7jgdDVyXb2hA==}
dev: true
/vitepress-plugin-tabs@0.3.0(vitepress@1.0.0-rc.11)(vue@3.3.4): /vitepress-plugin-tabs@0.3.0(vitepress@1.0.0-rc.11)(vue@3.3.4):
resolution: {integrity: sha512-3dKsBuP6PDzcFHgUtNCwwCs3bYoZduj7AcQkT9JfAKTRAKPCNmjiNInPT3IZ7AihL0SJNoQ3liz/e97z8oo+XA==} resolution: {integrity: sha512-3dKsBuP6PDzcFHgUtNCwwCs3bYoZduj7AcQkT9JfAKTRAKPCNmjiNInPT3IZ7AihL0SJNoQ3liz/e97z8oo+XA==}
peerDependencies: peerDependencies:
@ -5728,3 +5724,7 @@ packages:
/yoga-wasm-web@0.3.3: /yoga-wasm-web@0.3.3:
resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==} resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==}
dev: true dev: true
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false

View File

@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
/// <reference types="@types/gtag.js" />
import { computed, onMounted, ref } from "vue" import { computed, onMounted, ref } from "vue"
import { data as release } from "../data/release.data" import { data as release } from "../data/release.data"
@ -20,6 +22,16 @@ const isAndroid = ref(true)
onMounted(() => { onMounted(() => {
isAndroid.value = !!navigator.userAgent.match(/android/i) isAndroid.value = !!navigator.userAgent.match(/android/i)
}) })
function handleAnalytics(type: "preview" | "stable") {
window.gtag?.("event", "Download", {
event_category: "App",
event_label: type === "stable" ? "Stable" : "Preview",
version: type === "stable"
? release.stable.tag_name
: release.preview.tag_name,
})
}
</script> </script>
<template> <template>
@ -47,12 +59,22 @@ onMounted(() => {
</blockquote> </blockquote>
</div> </div>
<div class="download-buttons"> <div class="download-buttons">
<a class="download-button primary" :download="downloadInformation.stable.asset?.name" :href="downloadInformation.stable.asset?.browser_download_url"> <a
class="download-button primary"
:download="downloadInformation.stable.asset?.name"
:href="downloadInformation.stable.asset?.browser_download_url"
@click="handleAnalytics('stable')"
>
<IconDownload /> <IconDownload />
<span class="text">Stable</span> <span class="text">Stable</span>
<span class="version">{{ downloadInformation.stable.tagName }}</span> <span class="version">{{ downloadInformation.stable.tagName }}</span>
</a> </a>
<a class="download-button secondary" :download="downloadInformation.preview.asset?.name" :href="downloadInformation.preview.asset?.browser_download_url"> <a
class="download-button secondary"
:download="downloadInformation.preview.asset?.name"
:href="downloadInformation.preview.asset?.browser_download_url"
@click="handleAnalytics('preview')"
>
<IconBugReport /> <IconBugReport />
<span class="text">Preview</span> <span class="text">Preview</span>
<span class="version">{{ downloadInformation.preview.tagName }}</span> <span class="version">{{ downloadInformation.preview.tagName }}</span>

View File

@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
/// <reference types="@types/gtag.js" />
import { computed, toRefs } from "vue" import { computed, toRefs } from "vue"
import type { Extension } from "../../queries/useExtensionsRepositoryQuery" import type { Extension } from "../../queries/useExtensionsRepositoryQuery"
@ -19,6 +21,14 @@ const iconUrl = computed(() => {
const apkUrl = computed(() => { const apkUrl = computed(() => {
return `https://raw.githubusercontent.com/tachiyomiorg/tachiyomi-extensions/repo/apk/${item.value.apk}` return `https://raw.githubusercontent.com/tachiyomiorg/tachiyomi-extensions/repo/apk/${item.value.apk}`
}) })
function handleAnalytics() {
window.gtag?.("event", "Download", {
event_category: "Extension",
event_label: pkgName.value,
version: item.value.version,
})
}
</script> </script>
<template> <template>
@ -35,7 +45,15 @@ const apkUrl = computed(() => {
</div> </div>
<Badge v-if="pkgIsNsfw" type="danger" :text="item.version" title="This extension contains NSFW entries." /> <Badge v-if="pkgIsNsfw" type="danger" :text="item.version" title="This extension contains NSFW entries." />
<Badge v-else type="info" :text="item.version" title="This extension is free from NSFW entries." /> <Badge v-else type="info" :text="item.version" title="This extension is free from NSFW entries." />
<a :href="apkUrl" class="extension-download" title="Download APK" download></a> <a
:href="apkUrl"
class="extension-download"
title="Download APK"
:download="item.apk"
@click="handleAnalytics"
>
</a>
</div> </div>
</template> </template>

View File

@ -11,12 +11,11 @@ import { VueQueryPlugin } from "@tanstack/vue-query"
import { enhanceAppWithTabs } from "vitepress-plugin-tabs/client" import { enhanceAppWithTabs } from "vitepress-plugin-tabs/client"
// Import components // Import icon components
import { IconBugReport, IconDownload, IconNewspaperVariant } from "@iconify-prerendered/vue-mdi" import { IconBugReport, IconDownload, IconNewspaperVariant } from "@iconify-prerendered/vue-mdi"
import Layout from "./Layout.vue"
// Import Google Analytics plugin import analytics from "./plugin/analytics"
import googleAnalytics from "vitepress-plugin-google-analytics" import Layout from "./Layout.vue"
export default { export default {
extends: DefaultTheme, extends: DefaultTheme,
@ -26,7 +25,7 @@ export default {
app.component("IconDownload", IconDownload) app.component("IconDownload", IconDownload)
app.component("IconNewspaperVariant", IconNewspaperVariant) app.component("IconNewspaperVariant", IconNewspaperVariant)
app.component("IconBugReport", IconBugReport) app.component("IconBugReport", IconBugReport)
// googleAnalytics({ id: "G-2CBXXM1Y86" }) analytics({ id: "G-J1GE7WPJEX" })
}, },
Layout, Layout,
} }

View File

@ -0,0 +1,37 @@
// Code based on vitepress-plugin-google-analytics.
// Customized as the plugin did not consider the script loading time.
// https://github.com/ZhongxuYang/vitepress-plugin-google-analytics
function mountGoogleAnalytics(id: string) {
if (("dataLayer" in window && window.gtag) || window.location.hostname === "localhost") {
return
}
const analyticsScript = document.createElement("script")
analyticsScript.addEventListener("load", () => {
// @ts-expect-error Missing types
window.dataLayer = window.dataLayer || []
function gtag(..._args: any[]) {
// @ts-expect-error Missing types
// eslint-disable-next-line prefer-rest-params
window.dataLayer.push(arguments)
}
gtag("js", new Date())
gtag("config", id)
window.gtag = gtag
})
analyticsScript.src = `https://www.googletagmanager.com/gtag/js?id=${id}`
document.body.appendChild(analyticsScript)
}
export default function ({ id }: { id: string }) {
// eslint-disable-next-line n/prefer-global/process
if (process.env.NODE_ENV === "production" && id && typeof window !== "undefined") {
mountGoogleAnalytics(id)
}
}

View File

@ -12,7 +12,7 @@
"esModuleInterop": true, "esModuleInterop": true,
"lib": ["esnext", "dom"], "lib": ["esnext", "dom"],
"skipLibCheck": true, "skipLibCheck": true,
"types": ["vite/client"], "types": ["vite/client", "@types/gtag.js"],
"paths": { "paths": {
"@/*": ["./docs/.vitepress/*"] "@/*": ["./docs/.vitepress/*"]
} }