Skip to content

Commit

Permalink
⚡ update visitor count
Browse files Browse the repository at this point in the history
  • Loading branch information
snowykami committed Sep 3, 2024
1 parent a7ce527 commit 90d805f
Show file tree
Hide file tree
Showing 4 changed files with 314 additions and 13 deletions.
36 changes: 25 additions & 11 deletions public/data_source.json
Original file line number Diff line number Diff line change
@@ -1,51 +1,55 @@
[
{
"collectionName": "轻雪相关内容",
"collectionName": "轻雪相关内容 Liteyuki official sites",
"contents": [
{
"text": "Liteyuki Gitea",
"text": "Github",
"link": "https://github.com/LiteyukiStudio"
},
{
"text": "Gitea Workspace",
"link": "https://git.liteyuki.icu"
},
{
"text": "Liteyuki Server 轻雪MC服务器",
"text": "Minecraft Server",
"link": "https://mc.liteyuki.icu"
},
{
"text": "LiteyukiBot",
"text": "Bot 机器人",
"link": "https://bot.liteyuki.icu"
},
{
"text": "Liteyuki Lab 轻雪社区",
"text": "Lab 社区",
"link": "https://lab.liteyuki.icu"
},
{
"text": "Liteyuki Meme",
"text": "Meme 梗图归档",
"link": "https://meme.liteyuki.icu"
},
{
"text": "Liteyuki Netdisk 网盘",
"text": "Netdisk 网盘",
"link": "https://nd.liteyuki.icu"
},
{
"text": "Liteyuki biography 人物传记",
"text": "Biography 传记",
"link": "https://bio.liteyuki.icu"
},
{
"text": "Liteyuki status 轻雪状态",
"text": "Status 状态页",
"link": "https://status.liteyuki.icu"
},
{
"text": "LMTR 轻雪铁路",
"link": "https://mtr.lite.ac.cn"
},
{
"text": "LiteyukiBot StarMap 轻雪星图",
"text": "Bot StarMap 星图",
"link": "https://starmap.liteyuki.icu/"
}
]
},
{
"collectionName": "友情链接",
"collectionName": "友链 Partner links",
"contents": [
{
"text": "SnowyKami个人主页",
Expand Down Expand Up @@ -91,6 +95,16 @@
"text": "EDream的小破站",
"link": "https://blog.edmc.cn/",
"owner": "EDream"
},
{
"text": "可爱就对了",
"link": "https://dream.day/",
"owner": "Executor-Cheng"
},
{
"text": "Viki 写东西的地方",
"link": "https://blog.viki.moe/",
"owner": "vikiboss"
}
]
}
Expand Down
17 changes: 15 additions & 2 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<script setup lang="ts">
import CollectionComp from "./components/CollectionComp.vue";
import {ref} from "vue";
import {onMounted, ref} from "vue";
import {statsApi, uploadVisitRecord} from "./components/scripts/statsApi.ts";
let collections = ref([])
let totalVisit = ref(0)
let currentVisit = ref(0)
fetch("data_source.json")
.then(response => response.json())
Expand All @@ -11,11 +14,21 @@ fetch("data_source.json")
console.log(data)
})
onMounted(async () => {
await uploadVisitRecord();
totalVisit.value = await statsApi.getVisitCount();
currentVisit.value = await statsApi.getCurrentVisitCount();
});
</script>

<template>
<div class="title">Liteyuki Index</div>
<div class="title">Liteyuki Index 索引站</div>
<CollectionComp v-for="c in collections" :collection="c"></CollectionComp>
<footer>
<p>Liteyuki Studio | 总计到访者: {{ totalVisit }} | 你是第 {{ currentVisit }} 位</p>
</footer>
</template>

<style scoped>
Expand Down
74 changes: 74 additions & 0 deletions src/components/scripts/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {ref} from "vue";

import {useData} from "vitepress";

const i18nData = {
en: {
stats: 'Stats',
online: 'Online',
offline: 'Offline',
total: 'Total',
fetching: 'Fetching',
stars: 'Stars',
forks: 'Forks',
issues: 'Issues',
prs: 'Pull Requests',
visitors: 'Visitor',
size: 'Size',
plugins: 'Plugins',
resources: 'Resources',
pluginStore: 'Plugin Store',
pluginStoreDesc: 'Content from the LightSnow Plugin Store, LightSnow supports NoneBot through the lpnonebot plugin, and references some NoneBot plugins',
liteyukiOnly: 'Liteyuki Only',
search: 'Search',
resourceStore: 'Resources Store',
},
zh: {
stats: '统计信息',
online: '在线',
offline: '离线',
total: '实例',
fetching: '获取中',
stars: '星标',
forks: '分叉',
issues: '开启议题',
prs: '合并请求',
visitors: '访客',
size: '大小',
plugins: '插件',
resources: '主题资源',
store: '商店',
pluginStore: '插件商店',
pluginStoreDesc: '内容来自轻雪插件商店,轻雪通过lpnonebot插件对NoneBot实现支持,引用了部分NoneBot插件',
liteyukiOnly: '仅轻雪',
search: '搜索',
resourceStore: '资源商店',
}
}

let refData = {}

function getText(lang: string, key: string): string {
lang = formatLang(lang);
return i18nData[lang][key];
}

function formatLang(lang: string): string {
if (lang.includes('-')) {
return lang.split('-')[0];
}
return lang;
}

export function updateRefData() {
const lang = formatLang(useData().site.value.lang);
for (let key in refData) {
refData[key].value = getText(lang, key);
}
}

export function getTextRef(key: string): any {
const lang = formatLang(useData().site.value.lang);
refData[key] = getText(lang, key);
return refData[key]
}
200 changes: 200 additions & 0 deletions src/components/scripts/statsApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// URL
export const OWNER = "LiteyukiStudio"
export const REPO = "LiteyukiBot"
const githubAPIUrl = "https://api.github.com"
const giteaAPIUrl = "https://git.liteyuki.icu/api/v1"
const onlineFetchUrl = "https://api.liteyuki.icu/online";
const totalFetchUrl = "https://api.liteyuki.icu/count";
const visitRecordUrl = "https://api.liteyuki.icu/visit";
const visitCountUrl = "https://api.liteyuki.icu/visit_count";
const visitCurrentCountUrl = "https://api.liteyuki.icu/visit_index";

export const RepoUrl = `https://github.com/${OWNER}/${REPO}`
export const StarMapUrl = "https://starmap.liteyuki.icu"

type GithubStats = {
stars: number;
forks: number;
watchers: number;
issues?: number;
prs?: number;
size?: number;
}

// 异步接口
interface StatsApi {
getTotal: () => Promise<number>;
getOnline: () => Promise<number>;
getGithubStats: () => Promise<GithubStats>;
getPluginNum: () => Promise<number>;
getResourceNum: () => Promise<number>;
getVisitCount: () => Promise<number>;
getCurrentVisitCount: () => Promise<number>;
}


export type {GithubStats};

async function getGiteaStats() {
try {
const url = `${giteaAPIUrl}/repos/${OWNER}/${REPO}`;
console.log(url);
const res = await fetch(url);
const data = await res.json();
return {
stars: data.stars_count,
forks: data.forks_count,
watchers: data.watchers_count,
issues: 0,
prs: 0,
size: data.size,
};
} catch (e) {
return {
stars: -1,
forks: -1,
watchers: -1,
issues: -1,
prs: -1,
size: -1,
};
}
}

async function getGithubStats() {
try {
const res = await fetch(`${githubAPIUrl}/repos/${OWNER}/${REPO}`);
const data = await res.json();
return {
stars: data.stargazers_count,
forks: data.forks_count,
watchers: data.watchers_count,
issues: data.open_issues_count,
prs: data.open_issues_count,
size: data.size,
};
} catch (e) {
return {
stars: -1,
forks: -1,
watchers: -1,
issues: -1,
prs: -1,
size: -1,
};
}
}

async function getRepoStats() {
// 两个接口各数据,加和返回
const githubStats = await getGithubStats();
const giteaStats = await getGiteaStats();
return {
stars: githubStats.stars + giteaStats.stars,
forks: githubStats.forks + giteaStats.forks,
watchers: githubStats.watchers + giteaStats.watchers,
issues: githubStats.issues + giteaStats.issues,
prs: githubStats.prs + giteaStats.prs,
size: githubStats.size + giteaStats.size,
};
}

// 实现接口
export const statsApi: StatsApi = {
getTotal: async () => {
try {
const res = await fetch(totalFetchUrl);
const data = await res.json();
return data.register;
} catch (e) {
return -1;
}
},
getOnline: async () => {
try {
const res = await fetch(onlineFetchUrl);
const data = await res.json();
return data.online;
} catch (e) {
return -1;
}
},
getGithubStats: getRepoStats,
getPluginNum: async () => {
try {
const res = await fetch('/plugins.json');
const data = await res.json();
return data.length;
} catch (e) {
return -1;
}
},
getResourceNum: async () => {
try {
const res = await fetch('/resources.json');
const data = await res.json();
return data.length;
} catch (e) {
return -1;
}
},
getVisitCount: async () => {
try {
const res = await fetch(visitCountUrl);
const data = await res.json();
return data.count;
} catch (e) {
return -1;
}
},
getCurrentVisitCount: async () => {
try {
// 带device_id post
const res = await fetch(visitCurrentCountUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({'device_id': getDeviceId()}).toString(),
});
const data = await res.json();
return data.index;
} catch (e) {
return -1;
}
},
};

function getDeviceId(): string {
// 用户每次访问时生成一个唯一的设备ID,储存在localStorage中,用于统计用户数量
const deviceIdKey = 'deviceId';
let deviceId = localStorage.getItem(deviceIdKey);

if (!deviceId) {
deviceId = generateUUID();
localStorage.setItem(deviceIdKey, deviceId);
}
return deviceId;
}

export async function uploadVisitRecord() {
const deviceId = getDeviceId();
try {
await fetch(visitRecordUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({'device_id': deviceId}).toString(),
});
} catch (e) {
console.error('Failed to upload visit record:', e);
}
}

function generateUUID(): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}

0 comments on commit 90d805f

Please sign in to comment.