mirror of
https://github.com/next-theme/hexo-theme-next.git
synced 2026-09-14 06:50:20 +00:00
refactor: use Firestore REST API
This commit is contained in:
parent
940b2263f6
commit
4352696dba
@ -807,13 +807,13 @@ plausible:
|
|||||||
script_url: # https://plausible.io/js/script.js
|
script_url: # https://plausible.io/js/script.js
|
||||||
site_domain: # www.example.com
|
site_domain: # www.example.com
|
||||||
|
|
||||||
# Another tool to show number of visitors to each article.
|
# Show the number of visitors to each article using the Firestore REST API.
|
||||||
# Visit https://console.firebase.google.com/u/0/ to get apiKey and projectId.
|
# Visit https://console.firebase.google.com/ to get projectId.
|
||||||
# Visit https://firebase.google.com/docs/firestore/ to get more information about firestore.
|
# Visit https://firebase.google.com/docs/firestore/use-rest-api for more information.
|
||||||
|
# Anonymous requests are authorized by your Firestore Security Rules.
|
||||||
firestore:
|
firestore:
|
||||||
enable: false
|
enable: false
|
||||||
collection: articles # Required, a string collection name to access firestore database
|
collection: articles # Required, a string collection name to access firestore database
|
||||||
apiKey: # Required
|
|
||||||
projectId: # Required
|
projectId: # Required
|
||||||
|
|
||||||
# Show Views / Visitors of the website / page with busuanzi.
|
# Show Views / Visitors of the website / page with busuanzi.
|
||||||
|
|||||||
10
_vendors.yml
10
_vendors.yml
@ -101,16 +101,6 @@ gitalk_css:
|
|||||||
version: 1.8.0
|
version: 1.8.0
|
||||||
file: dist/gitalk.css
|
file: dist/gitalk.css
|
||||||
integrity: sha256-AJnUHL7dBv6PGaeyPQJcgQPDjt/Hn/PvYZde1iqfp8U=
|
integrity: sha256-AJnUHL7dBv6PGaeyPQJcgQPDjt/Hn/PvYZde1iqfp8U=
|
||||||
firebase_app:
|
|
||||||
name: firebase
|
|
||||||
version: 12.2.1
|
|
||||||
file: firebase-app-compat.js
|
|
||||||
integrity: sha256-d21UgtIcA6c6qwr8nWk6lxs/KrpbWhknQN7qBjWA2Kk=
|
|
||||||
firebase_firestore:
|
|
||||||
name: firebase
|
|
||||||
version: 12.2.1
|
|
||||||
file: firebase-firestore-compat.js
|
|
||||||
integrity: sha256-leHatffkFuVGIg7ABaA5BDsqsEUtktL4tftb3OdQfg0=
|
|
||||||
algolia_search:
|
algolia_search:
|
||||||
name: algoliasearch
|
name: algoliasearch
|
||||||
version: 5.36.0
|
version: 5.36.0
|
||||||
|
|||||||
7
layout/_third-party/statistics/firestore.njk
vendored
7
layout/_third-party/statistics/firestore.njk
vendored
@ -1,6 +1,7 @@
|
|||||||
{%- if theme.firestore.enable %}
|
{%- if theme.firestore.enable %}
|
||||||
{{ next_vendors('firebase_app') }}
|
{{ next_data('firestore', {
|
||||||
{{ next_vendors('firebase_firestore') }}
|
collection: theme.firestore.collection,
|
||||||
{{ next_data('firestore', theme.firestore) }}
|
projectId: theme.firestore.projectId
|
||||||
|
}) }}
|
||||||
{{ next_js('third-party/statistics/firestore.js') }}
|
{{ next_js('third-party/statistics/firestore.js') }}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|||||||
100
source/js/third-party/statistics/firestore.js
vendored
100
source/js/third-party/statistics/firestore.js
vendored
@ -1,37 +1,76 @@
|
|||||||
/* global CONFIG, firebase */
|
/* global CONFIG */
|
||||||
|
|
||||||
firebase.initializeApp({
|
|
||||||
apiKey : CONFIG.firestore.apiKey,
|
|
||||||
projectId: CONFIG.firestore.projectId
|
|
||||||
});
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
const getCount = async (doc, increaseCount) => {
|
const database = `projects/${CONFIG.firestore.projectId}/databases/(default)`;
|
||||||
// IncreaseCount will be false when not in article page
|
const documents = `${database}/documents`;
|
||||||
const d = await doc.get();
|
const api = `https://firestore.googleapis.com/v1/${documents}`;
|
||||||
// Has no data, initialize count
|
|
||||||
let count = d.exists ? d.data().count : 0;
|
const fetchFirestore = async (path, options) => {
|
||||||
// If first view this article
|
const response = await fetch(`${api}${path}`, options);
|
||||||
if (increaseCount) {
|
if (response.status === 404) return null;
|
||||||
// Increase count
|
if (!response.ok) throw new Error(`Firestore request failed with status ${response.status}`);
|
||||||
count++;
|
return response.json();
|
||||||
doc.set({
|
|
||||||
count
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const db = firebase.firestore();
|
const documentName = title => `${documents}/${CONFIG.firestore.collection}/${title}`;
|
||||||
const articles = db.collection(CONFIG.firestore.collection);
|
const getValue = value => Number(value?.integerValue ?? value?.doubleValue ?? 0);
|
||||||
|
|
||||||
|
const getCount = async (title, increaseCount) => {
|
||||||
|
if (increaseCount) {
|
||||||
|
const data = await fetchFirestore(':commit', {
|
||||||
|
method : 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
writes: [{
|
||||||
|
transform: {
|
||||||
|
document : documentName(title),
|
||||||
|
fieldTransforms: [{
|
||||||
|
fieldPath: 'count',
|
||||||
|
increment: {
|
||||||
|
integerValue: '1'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
});
|
||||||
|
return getValue(data.writeResults[0].transformResults[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const collection = encodeURIComponent(CONFIG.firestore.collection);
|
||||||
|
const document = await fetchFirestore(`/${collection}/${encodeURIComponent(title)}`);
|
||||||
|
return getValue(document?.fields?.count);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCounts = async titles => {
|
||||||
|
if (titles.length === 0) return [];
|
||||||
|
const data = await fetchFirestore(':batchGet', {
|
||||||
|
method : 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
documents: titles.map(documentName),
|
||||||
|
mask : {
|
||||||
|
fieldPaths: ['count']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const counts = new Map(data.map(result => {
|
||||||
|
const document = result.found;
|
||||||
|
return [document?.name ?? result.missing, getValue(document?.fields?.count)];
|
||||||
|
}));
|
||||||
|
return titles.map(title => counts.get(documentName(title)) ?? 0);
|
||||||
|
};
|
||||||
|
|
||||||
document.addEventListener('page:loaded', async () => {
|
document.addEventListener('page:loaded', async () => {
|
||||||
|
try {
|
||||||
if (CONFIG.page.isPost) {
|
if (CONFIG.page.isPost) {
|
||||||
// Fix issue #118
|
// Fix issue #118
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent
|
// https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent
|
||||||
const title = document.querySelector('.post-title').textContent.trim();
|
const title = document.querySelector('.post-title').textContent.trim();
|
||||||
const doc = articles.doc(title);
|
|
||||||
let increaseCount = CONFIG.hostname === location.hostname;
|
let increaseCount = CONFIG.hostname === location.hostname;
|
||||||
if (localStorage.getItem(title)) {
|
if (localStorage.getItem(title)) {
|
||||||
increaseCount = false;
|
increaseCount = false;
|
||||||
@ -39,19 +78,18 @@ firebase.initializeApp({
|
|||||||
// Mark as visited
|
// Mark as visited
|
||||||
localStorage.setItem(title, true);
|
localStorage.setItem(title, true);
|
||||||
}
|
}
|
||||||
const count = await getCount(doc, increaseCount);
|
const count = await getCount(title, increaseCount);
|
||||||
document.querySelector('.firestore-visitors-count').innerText = count;
|
document.querySelector('.firestore-visitors-count').innerText = count;
|
||||||
} else if (CONFIG.page.isHome) {
|
} else if (CONFIG.page.isHome) {
|
||||||
const promises = [...document.querySelectorAll('.post-title')].map(element => {
|
const titles = [...document.querySelectorAll('.post-title')].map(element => element.textContent.trim());
|
||||||
const title = element.textContent.trim();
|
const counts = await getCounts(titles);
|
||||||
const doc = articles.doc(title);
|
|
||||||
return getCount(doc);
|
|
||||||
});
|
|
||||||
const counts = await Promise.all(promises);
|
|
||||||
const metas = document.querySelectorAll('.firestore-visitors-count');
|
const metas = document.querySelectorAll('.firestore-visitors-count');
|
||||||
counts.forEach((val, idx) => {
|
counts.forEach((val, idx) => {
|
||||||
metas[idx].innerText = val;
|
metas[idx].innerText = val;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Failed to load Firestore visitor count:', error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user