From 52f9adceb8345fccfedea7393ef1aa2cc4dfd2cc Mon Sep 17 00:00:00 2001
From: Olivier Savignac <1275666+sircharlo@users.noreply.github.com>
Date: Mon, 14 Oct 2024 16:49:45 -0400
Subject: [PATCH] feat: manual refresh button on song list; added yeartext
sanity checks
---
package.json | 2 +
.../dialog/DialogCongregationLookup.vue | 2 +-
src/components/media/SongPicker.vue | 13 ++-
src/pages/MediaPlayerPage.vue | 20 ++--
src/stores/jw.ts | 56 ++++++----
yarn.lock | 100 +++++++++++++++++-
6 files changed, 157 insertions(+), 36 deletions(-)
diff --git a/package.json b/package.json
index c25de6b1..b006cfef 100644
--- a/package.json
+++ b/package.json
@@ -41,6 +41,7 @@
"pretty-bytes": "^6.1.1",
"quasar": "^2.17.0",
"sanitize-filename": "^1.6.3",
+ "sanitize-html": "^2.13.1",
"upath": "^2.0.1",
"vue": "^3.5.12",
"vue-i18n": "^10.0.4",
@@ -62,6 +63,7 @@
"@types/klaw-sync": "^6.0.5",
"@types/node": "^20.16.11",
"@types/pretty-bytes": "^5.2.0",
+ "@types/sanitize-html": "^2",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"autoprefixer": "^10.4.20",
diff --git a/src/components/dialog/DialogCongregationLookup.vue b/src/components/dialog/DialogCongregationLookup.vue
index 669b39de..b62be0be 100644
--- a/src/components/dialog/DialogCongregationLookup.vue
+++ b/src/components/dialog/DialogCongregationLookup.vue
@@ -116,7 +116,7 @@ import { useLocale } from 'src/composables/useLocale';
import { errorCatcher } from 'src/helpers/error-catcher';
import { useCurrentStateStore } from 'src/stores/current-state';
import { useJwStore } from 'src/stores/jw';
-import { type Ref, ref, watch } from 'vue';
+import { ref, watch } from 'vue';
const jwStore = useJwStore();
const { jwLanguages } = storeToRefs(jwStore);
diff --git a/src/components/media/SongPicker.vue b/src/components/media/SongPicker.vue
index 53855bd1..222ed5be 100644
--- a/src/components/media/SongPicker.vue
+++ b/src/components/media/SongPicker.vue
@@ -46,7 +46,18 @@
-
+
+ (loading = false));
+ "
+ />
{{
diff --git a/src/pages/MediaPlayerPage.vue b/src/pages/MediaPlayerPage.vue
index 62f8f20c..db742a1f 100644
--- a/src/pages/MediaPlayerPage.vue
+++ b/src/pages/MediaPlayerPage.vue
@@ -1,4 +1,3 @@
-
-
+
+
{
+ const currentYear = new Date().getFullYear();
+ const yearText = yeartexts.value[currentYear]?.[currentSettings.value?.lang];
+ return yearText ?? '';
+});
+
const panzoom = ref
();
const initiatePanzoom = () => {
diff --git a/src/stores/jw.ts b/src/stores/jw.ts
index 57d25738..7b88173d 100644
--- a/src/stores/jw.ts
+++ b/src/stores/jw.ts
@@ -9,10 +9,12 @@ import type {
import { getLanguages, getYeartext } from 'boot/axios';
import { defineStore, storeToRefs } from 'pinia';
import { date, LocalStorage } from 'quasar';
+import sanitizeHtml from 'sanitize-html';
import { isCoWeek, isMwMeetingDay } from 'src/helpers/date';
import { errorCatcher } from 'src/helpers/error-catcher';
import { findBestResolution, getPubMediaLinks } from 'src/helpers/jw-media';
import { useCurrentStateStore } from 'src/stores/current-state';
+
export const MAX_SONGS = 500;
export function uniqueById(array: T[]): T[] {
@@ -128,7 +130,7 @@ export const useJwStore = defineStore('jw-store', {
errorCatcher(e);
}
},
- async updateJwSongs() {
+ async updateJwSongs(force = false) {
try {
const currentState = useCurrentStateStore();
if (
@@ -141,27 +143,30 @@ export const useJwStore = defineStore('jw-store', {
for (const fileformat of ['MP4', 'MP3']) {
try {
const langwritten = currentState.currentSettings.lang as string;
- const songbook = {
- fileformat,
- langwritten,
- pub: currentState.currentSongbook.pub,
- } as PublicationFetcher;
- const pubMediaLinks = await getPubMediaLinks(songbook);
- if (!pubMediaLinks || !pubMediaLinks.files) {
- continue;
- }
- const now = new Date();
this.jwSongs[langwritten] ??= { list: [], updated: oldDate };
+
+ // Check if the song list has been updated in the last month
+ const now = new Date();
const monthsSinceUpdated = date.getDateDiff(
now,
this.jwSongs[langwritten].updated,
'months',
);
- if (monthsSinceUpdated > 1) {
+
+ // Fetch media links only if the song list hasn't been updated in over a month or if force is true
+ if (monthsSinceUpdated > 1 || force) {
+ const songbook = {
+ fileformat,
+ langwritten,
+ pub: currentState.currentSongbook.pub,
+ } as PublicationFetcher;
+ const pubMediaLinks = await getPubMediaLinks(songbook);
+ if (!pubMediaLinks || !pubMediaLinks.files) {
+ continue;
+ }
+
const mediaItemLinks = (
- pubMediaLinks.files[songbook.langwritten][
- fileformat
- ] as MediaLink[]
+ pubMediaLinks.files[langwritten][fileformat] as MediaLink[]
).filter((mediaLink: MediaLink) => mediaLink.track < MAX_SONGS);
const filteredMediaItemLinks = mediaItemLinks.reduce(
(acc: MediaLink[], mediaLink: MediaLink) => {
@@ -197,13 +202,22 @@ export const useJwStore = defineStore('jw-store', {
(currentState.currentSettings.lang as string) || (lang as string);
if (!currentLang) return;
const currentYear = new Date().getFullYear();
- if (!this.yeartexts[currentYear]) {
- this.yeartexts[currentYear] = {};
- }
- if (currentLang && !this.yeartexts[currentYear][currentLang]) {
- const yeartextRequest = await getYeartext(currentLang, currentYear);
+ this.yeartexts[currentYear] ??= {};
+ if (!this.yeartexts[currentYear][currentLang]) {
+ const yeartextRequest = await getYeartext(
+ currentLang,
+ currentYear + 1,
+ );
if (yeartextRequest?.content) {
- this.yeartexts[currentYear][currentLang] = yeartextRequest.content;
+ this.yeartexts[currentYear][currentLang] = sanitizeHtml(
+ yeartextRequest.content,
+ {
+ allowedAttributes: {
+ p: ['class'],
+ },
+ allowedTags: ['b', 'i', 'em', 'strong', 'p'],
+ },
+ );
}
}
} catch (error) {
diff --git a/yarn.lock b/yarn.lock
index 7101c92c..5ea97dd7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1746,6 +1746,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/sanitize-html@npm:^2":
+ version: 2.13.0
+ resolution: "@types/sanitize-html@npm:2.13.0"
+ dependencies:
+ htmlparser2: "npm:^8.0.0"
+ checksum: 10c0/c6614b38f67dd6fb3a94c9163a55fa43b9aa81a845fe9584d9ffbd5da0e00e0ac8162ede9f4bde095840b2ef9db12265f5fcc40b707f48a420405c6aa7c3ff51
+ languageName: node
+ linkType: hard
+
"@types/send@npm:*":
version: 0.17.4
resolution: "@types/send@npm:0.17.4"
@@ -3866,6 +3875,13 @@ __metadata:
languageName: node
linkType: hard
+"deepmerge@npm:^4.2.2":
+ version: 4.3.1
+ resolution: "deepmerge@npm:4.3.1"
+ checksum: 10c0/e53481aaf1aa2c4082b5342be6b6d8ad9dfe387bc92ce197a66dea08bd4265904a087e75e464f14d1347cf2ac8afe1e4c16b266e0561cc5df29382d3c5f80044
+ languageName: node
+ linkType: hard
+
"default-browser-id@npm:^3.0.0":
version: 3.0.0
resolution: "default-browser-id@npm:3.0.0"
@@ -4111,6 +4127,33 @@ __metadata:
languageName: node
linkType: hard
+"dom-serializer@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "dom-serializer@npm:2.0.0"
+ dependencies:
+ domelementtype: "npm:^2.3.0"
+ domhandler: "npm:^5.0.2"
+ entities: "npm:^4.2.0"
+ checksum: 10c0/d5ae2b7110ca3746b3643d3ef60ef823f5f078667baf530cec096433f1627ec4b6fa8c072f09d079d7cda915fd2c7bc1b7b935681e9b09e591e1e15f4040b8e2
+ languageName: node
+ linkType: hard
+
+"domelementtype@npm:^2.3.0":
+ version: 2.3.0
+ resolution: "domelementtype@npm:2.3.0"
+ checksum: 10c0/686f5a9ef0fff078c1412c05db73a0dce096190036f33e400a07e2a4518e9f56b1e324f5c576a0a747ef0e75b5d985c040b0d51945ce780c0dd3c625a18cd8c9
+ languageName: node
+ linkType: hard
+
+"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3":
+ version: 5.0.3
+ resolution: "domhandler@npm:5.0.3"
+ dependencies:
+ domelementtype: "npm:^2.3.0"
+ checksum: 10c0/bba1e5932b3e196ad6862286d76adc89a0dbf0c773e5ced1eb01f9af930c50093a084eff14b8de5ea60b895c56a04d5de8bbc4930c5543d029091916770b2d2a
+ languageName: node
+ linkType: hard
+
"dompurify@npm:^3.1.7":
version: 3.1.7
resolution: "dompurify@npm:3.1.7"
@@ -4118,6 +4161,17 @@ __metadata:
languageName: node
linkType: hard
+"domutils@npm:^3.0.1":
+ version: 3.1.0
+ resolution: "domutils@npm:3.1.0"
+ dependencies:
+ dom-serializer: "npm:^2.0.0"
+ domelementtype: "npm:^2.3.0"
+ domhandler: "npm:^5.0.3"
+ checksum: 10c0/342d64cf4d07b8a0573fb51e0a6312a88fb520c7fefd751870bf72fa5fc0f2e0cb9a3958a573610b1d608c6e2a69b8e9b4b40f0bfb8f87a71bce4f180cca1887
+ languageName: node
+ linkType: hard
+
"dot-case@npm:^3.0.4":
version: 3.0.4
resolution: "dot-case@npm:3.0.4"
@@ -4315,7 +4369,7 @@ __metadata:
languageName: node
linkType: hard
-"entities@npm:^4.4.0, entities@npm:^4.5.0":
+"entities@npm:^4.2.0, entities@npm:^4.4.0, entities@npm:^4.5.0":
version: 4.5.0
resolution: "entities@npm:4.5.0"
checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250
@@ -6253,6 +6307,18 @@ __metadata:
languageName: node
linkType: hard
+"htmlparser2@npm:^8.0.0":
+ version: 8.0.2
+ resolution: "htmlparser2@npm:8.0.2"
+ dependencies:
+ domelementtype: "npm:^2.3.0"
+ domhandler: "npm:^5.0.3"
+ domutils: "npm:^3.0.1"
+ entities: "npm:^4.4.0"
+ checksum: 10c0/609cca85886d0bf2c9a5db8c6926a89f3764596877492e2caa7a25a789af4065bc6ee2cdc81807fe6b1d03a87bf8a373b5a754528a4cc05146b713c20575aab4
+ languageName: node
+ linkType: hard
+
"http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.0, http-cache-semantics@npm:^4.1.1":
version: 4.1.1
resolution: "http-cache-semantics@npm:4.1.1"
@@ -6903,6 +6969,13 @@ __metadata:
languageName: node
linkType: hard
+"is-plain-object@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "is-plain-object@npm:5.0.0"
+ checksum: 10c0/893e42bad832aae3511c71fd61c0bf61aa3a6d853061c62a307261842727d0d25f761ce9379f7ba7226d6179db2a3157efa918e7fe26360f3bf0842d9f28942c
+ languageName: node
+ linkType: hard
+
"is-promise@npm:~1, is-promise@npm:~1.0.0":
version: 1.0.1
resolution: "is-promise@npm:1.0.1"
@@ -7993,6 +8066,7 @@ __metadata:
"@types/klaw-sync": "npm:^6.0.5"
"@types/node": "npm:^20.16.11"
"@types/pretty-bytes": "npm:^5.2.0"
+ "@types/sanitize-html": "npm:^2"
"@typescript-eslint/eslint-plugin": "npm:^7.18.0"
"@typescript-eslint/parser": "npm:^7.18.0"
adm-zip: "npm:^0.5.16"
@@ -8026,6 +8100,7 @@ __metadata:
process: "npm:^0.11.10"
quasar: "npm:^2.17.0"
sanitize-filename: "npm:^1.6.3"
+ sanitize-html: "npm:^2.13.1"
typescript: "npm:~5.5.4"
upath: "npm:^2.0.1"
vue: "npm:^3.5.12"
@@ -8722,6 +8797,13 @@ __metadata:
languageName: node
linkType: hard
+"parse-srcset@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "parse-srcset@npm:1.0.2"
+ checksum: 10c0/2f268e3d110d4c53d06ed2a8e8ee61a7da0cee13bf150819a6da066a8ca9b8d15b5600d6e6cae8be940e2edc50ee7c1e1052934d6ec858324065ecef848f0497
+ languageName: node
+ linkType: hard
+
"parseurl@npm:~1.3.3":
version: 1.3.3
resolution: "parseurl@npm:1.3.3"
@@ -8972,7 +9054,7 @@ __metadata:
languageName: node
linkType: hard
-"postcss@npm:^8.4.13, postcss@npm:^8.4.47":
+"postcss@npm:^8.3.11, postcss@npm:^8.4.13, postcss@npm:^8.4.47":
version: 8.4.47
resolution: "postcss@npm:8.4.47"
dependencies:
@@ -9668,6 +9750,20 @@ __metadata:
languageName: node
linkType: hard
+"sanitize-html@npm:^2.13.1":
+ version: 2.13.1
+ resolution: "sanitize-html@npm:2.13.1"
+ dependencies:
+ deepmerge: "npm:^4.2.2"
+ escape-string-regexp: "npm:^4.0.0"
+ htmlparser2: "npm:^8.0.0"
+ is-plain-object: "npm:^5.0.0"
+ parse-srcset: "npm:^1.0.2"
+ postcss: "npm:^8.3.11"
+ checksum: 10c0/306c811a254e48eb45e9c523fb91cced893d77786323a64fb47f4bb3f1237b4d29e3722c0723c329e6cb6ac674ae903e961d446c3636b9db5961c83b2c0995fe
+ languageName: node
+ linkType: hard
+
"sass@npm:^1.79.1":
version: 1.79.5
resolution: "sass@npm:1.79.5"