Browse Source

Merge branch 'learn-store'

boyska 6 months ago
parent
commit
2cd6bc8fc7

+ 67 - 2
package-lock.json

@@ -18,6 +18,7 @@
         "howler": "^2.2.3",
         "isomorphic-fetch": "^3.0.0",
         "material-icons": "^1.13.1",
+        "pinia": "^2.1.7",
         "podparse": "^1.5.1",
         "skeleton-elements": "^4.0.1",
         "swiper": "^8.4.6",
@@ -607,6 +608,10 @@
         "@vue/shared": "3.3.4"
       }
     },
+    "node_modules/@vue/devtools-api": {
+      "version": "6.5.1",
+      "integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA=="
+    },
     "node_modules/@vue/reactivity": {
       "version": "3.3.4",
       "integrity": "sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==",
@@ -1743,6 +1748,18 @@
       "version": "1.0.0",
       "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
     },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
     "node_modules/function-bind": {
       "version": "1.1.1",
       "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
@@ -2597,6 +2614,54 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/pinia": {
+      "version": "2.1.7",
+      "integrity": "sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==",
+      "dependencies": {
+        "@vue/devtools-api": "^6.5.0",
+        "vue-demi": ">=0.14.5"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/posva"
+      },
+      "peerDependencies": {
+        "@vue/composition-api": "^1.4.0",
+        "typescript": ">=4.4.4",
+        "vue": "^2.6.14 || ^3.3.0"
+      },
+      "peerDependenciesMeta": {
+        "@vue/composition-api": {
+          "optional": true
+        },
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/pinia/node_modules/vue-demi": {
+      "version": "0.14.6",
+      "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
+      "hasInstallScript": true,
+      "bin": {
+        "vue-demi-fix": "bin/vue-demi-fix.js",
+        "vue-demi-switch": "bin/vue-demi-switch.js"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "@vue/composition-api": "^1.0.0-rc.1",
+        "vue": "^3.0.0-0 || ^2.6.0"
+      },
+      "peerDependenciesMeta": {
+        "@vue/composition-api": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/pirates": {
       "version": "4.0.6",
       "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
@@ -2615,8 +2680,8 @@
       }
     },
     "node_modules/postcss": {
-      "version": "8.4.29",
-      "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==",
+      "version": "8.4.31",
+      "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
       "funding": [
         {
           "type": "opencollective",

+ 1 - 0
package.json

@@ -27,6 +27,7 @@
     "howler": "^2.2.3",
     "isomorphic-fetch": "^3.0.0",
     "material-icons": "^1.13.1",
+    "pinia": "^2.1.7",
     "podparse": "^1.5.1",
     "skeleton-elements": "^4.0.1",
     "swiper": "^8.4.6",

+ 1 - 1
src/components/Player.vue

@@ -51,7 +51,7 @@ export default {
       player: null,
     };
   },
-  destroyed() {
+  unmounted() {
     eventBus.$off("play:now");
   },
   mounted() {

+ 2 - 2
src/components/app.vue

@@ -1,7 +1,7 @@
 <script setup>
 import Player from "../components/Player.vue";
 import routes from "../js/routes.js";
-import store from "../js/store";
+import { useRadioStore } from "../js/store";
 
 // Framework7 Parameters
 const f7params = {
@@ -17,7 +17,7 @@ const f7params = {
 
   // passRouteParamsToRequest: true,
   // App store
-  store,
+  store: useRadioStore(),
 
   // App routes
   routes,

+ 3 - 0
src/js/app.js

@@ -1,5 +1,6 @@
 // Import Vue
 import { createApp } from "vue";
+import { createPinia } from "pinia";
 
 // Import Framework7
 import Framework7 from "framework7/lite-bundle";
@@ -22,6 +23,8 @@ Framework7.use(Framework7Vue);
 
 // Init App
 const app = createApp(App);
+const pinia = createPinia();
+app.use(pinia);
 
 // Register Framework7 Vue components
 registerComponents(app);

+ 11 - 22
src/js/radiomanifest.js

@@ -1,39 +1,28 @@
 import radiomanifest from "@radiomanifest/radiomanifest";
 
-const knownRadios = {
-    "https://www.ondarossa.info": {
-      "name": "ror"
-    },
-    "https://radiospore.oziosi.org": {},
-    // "https://radiowombat.net": {},
-    // "https://test.radiogramma.org": {},
-    "https://radioblackout.org": {},
-  }
 class Controller {
   constructor() {
-    this.cache = {}
-    this.currentRadio = null
+    this.cache = {};
+    this.currentRadio = null;
+  }
 
-    for(let r in knownRadios) {
-      this.get(r);
+  getFromCache(url) {
+    console.log("cache", Object.keys(this.cache));
+    if (this.cache[url]) {
+      this.currentRadio = this.cache[url];
+      return this.cache[url];
     }
   }
-
   async get(url) {
-    if(this.cache[url]) {
+    if (this.cache[url]) {
       this.currentRadio = this.cache[url];
       return this.cache[url];
     }
-    this.cache[url] = knownRadios[url];
-    // fetch more data in background
-    radiomanifest.get(url).then((rm) => {
-      console.log("arrivato", url)
-      this.cache[url] = rm
-    })
+    this.cache[url] = await radiomanifest.get(url);
+    return this.cache[url];
   }
 }
 
 const ControllerSingleton = new Controller();
-// console.log(ControllerSingleton);
 
 export default ControllerSingleton;

+ 4 - 4
src/js/routes.js

@@ -14,22 +14,22 @@ var routes = [
     detailRoutes: [
       {
         name: "Radio",
-        path: "/radio/:radioName",
+        path: "/radio/:radioUrl",
         component: RadioPage,
       },
       {
         name: "RadioLive",
-        path: "/radio/:radioName/live",
+        path: "/radio/:radioUrl/live",
         component: RadioLivePage,
       },
       {
         name: "RadioShows",
-        path: "/radio/:radioName/shows",
+        path: "/radio/:radioUrl/shows",
         component: RadioShowsPage,
       },
       {
         name: "ShowPage",
-        path: "/radio/:radioId/shows/:showId",
+        path: "/radio/:radioUrl/shows/:showId",
         component: ShowPage,
       },
     ],

+ 35 - 18
src/js/store.js

@@ -1,22 +1,39 @@
-import { createStore } from "framework7/lite";
+import { defineStore } from "pinia";
 
-const store = createStore({
-  state: {
-    radios: [
-      {
-        id: 1,
-        name: "Radio Onda Rossa",
-        description: "un segnale che disturba",
-        url: "https://www.ondarossa.info",
+export const useRadioStore = defineStore("radio", {
+  state: () => {
+    return {
+      radios: {
+        "https://www.ondarossa.info": {
+          name: "ROR",
+        },
+        "https://radiospore.oziosi.org": {
+          name: "Spore",
+        },
       },
-      {
-        id: 2,
-        name: "Radio Spore",
-        description: "una voce senza padrone",
-        url: "https://radiospore.oziosi.org",
-      },
-    ],
+    };
+  },
+  getters: {
+    isRadioReady: (state) => {
+      return (url) => {
+        if (state.radios[url] === undefined) {
+          return false;
+        }
+        if (state.radios[url].lastFetch === undefined) {
+          return false;
+        }
+        // XXX: if lastFetch is very old, return false
+        return true;
+      };
+    },
+  },
+  actions: {
+    startFetchingRadio(url) {
+      return;
+    },
+    updateRadio(url, data) {
+      this.radios[url] = data;
+      this.radios[url].lastFetch = Date.now();
+    },
   },
-  actions: {},
 });
-export default store;

+ 29 - 20
src/pages/Radio.vue

@@ -1,18 +1,24 @@
 <template>
   <f7-page name="radio">
-    <img :src="Radio.logo" id="logo" />
-    <f7-block-title>{{ Radio.name }}</f7-block-title>
-    <f7-block-header>{{ Radio.description }}</f7-block-header>
+    <img :src="radio().logo" id="logo" />
+    <f7-block-title>{{ radio().name }}</f7-block-title>
+    <f7-block-header>{{ radio().description }}</f7-block-header>
 
-    <div v-if="loading" strong class="text-align-center">
-      <f7-preloader v-if="loading" />
+    <div v-if="loading()" strong class="text-align-center">
+      <f7-preloader v-if="loading()" />
     </div>
     <f7-list v-else>
-      <f7-list-item title="Diretta" :link="`/radio/${radioId}/live`" />
-      <f7-list-item title="Trasmissioni" :link="`/radio/${radioId}/shows`" />
+      <f7-list-item
+        title="Diretta"
+        :link="`/radio/${encodeURIComponent(radioUrl)}/live`"
+      />
+      <f7-list-item
+        title="Trasmissioni"
+        :link="`/radio/${encodeURIComponent(radioUrl)}/shows`"
+      />
       <f7-list-item
         title="Contatti"
-        :link="`/radio/${radioId}/contacts`"
+        :link="`/radio/${encodeURIComponent(radioUrl)}/contacts`"
         disabled
       />
     </f7-list>
@@ -20,27 +26,30 @@
 </template>
 
 <script>
-import radiomanifest from "../js/radiomanifest";
+import { useRadioStore } from "../js/store";
+import { storeToRefs } from "pinia";
 
 export default {
   name: "radio",
   data() {
     return {
-      loading: true,
-      radioId: null,
-      radio: { name: "" },
-      Radio: {},
+      isRadioReady: null,
+      radioUrl: null,
+      store: useRadioStore(),
+      radio: () => {
+        return this.store.radios[this.radioUrl] || {};
+      },
+      loading: () => {
+        return this.isRadioReady === null || !this.isRadioReady(this.radioUrl);
+      },
     };
   },
   props: { f7route: Object, f7router: Object },
   async mounted() {
-    this.radioId = this.f7route.params.radioName;
-    try {
-      this.Radio = await radiomanifest.get(this.f7route.params.radioName);
-      this.loading = false;
-    } catch (e) {
-      console.error("le cose non vanno mai sempre bene!", e);
-    }
+    this.radioUrl = decodeURIComponent(this.f7route.params.radioUrl);
+
+    const { isRadioReady } = storeToRefs(this.store);
+    this.isRadioReady = isRadioReady;
   },
 };
 </script>

+ 29 - 22
src/pages/RadioLive.vue

@@ -1,14 +1,14 @@
 <template>
   <f7-page name="RadioLive">
-    <img :src="Radio.logo" id="logo" />
-    <f7-block-title>{{ Radio.name }}</f7-block-title>
-    <f7-block-header>{{ Radio.description }}</f7-block-header>
+    <img :src="radio.logo" id="logo" />
+    <f7-block-title>{{ radio.name }}</f7-block-title>
+    <f7-block-header>{{ radio.description }}</f7-block-header>
 
-    <div v-if="loading" strong class="text-align-center">
+    <div v-if="loading()" strong class="text-align-center">
       <f7-preloader />
     </div>
     <f7-block v-else>
-      {{ currentShowName }}
+      {{ currentShowName() }}
 
       <f7-button class="block" large outline @click="playLive"
         >Ascolta la diretta</f7-button
@@ -20,37 +20,44 @@
 <script>
 import radiomanifest from "../js/radiomanifest";
 import eventBus from "../js/eventBus";
+import { useRadioStore } from "../js/store";
+import { storeToRefs } from "pinia";
 
 export default {
   name: "radio",
   data() {
     return {
-      loading: true,
-      radioId: null,
-      radio: { name: "" },
-      currentShowName: "",
-      Radio: {},
+      radioUrl: null,
+      isRadioReady: null,
+      store: useRadioStore(),
+      radio: () => {
+        return this.store.radios[this.radioUrl];
+      },
+      loading: () => {
+        return this.isRadioReady === null || !this.isRadioReady(this.radioUrl);
+      },
+      currentShowName: () => {
+        if (this.loading()) {
+          return "";
+        }
+        const radio = this.store.radios[this.radioUrl];
+        const currentShow = radio.getShowAtTime();
+        return currentShow == null ? "live" : currentShow.getName();
+      },
     };
   },
   props: { f7route: Object, f7router: Object },
   async mounted() {
-    this.radioId = this.f7route.params.radioName;
-    try {
-      this.Radio = await radiomanifest.get(this.f7route.params.radioName);
-      const currentShow = this.Radio.getShowAtTime();
-      this.currentShowName =
-        currentShow == null ? "live" : currentShow.getName();
-      this.loading = false;
-    } catch (e) {
-      console.error("le cose non vanno mai sempre bene!", e);
-    }
+    this.radioUrl = decodeURIComponent(this.f7route.params.radioUrl);
+    const { isRadioReady } = storeToRefs(this.store);
+    this.isRadioReady = isRadioReady;
   },
   methods: {
     async playLive() {
-      const urls = await this.Radio.getStreaming().pickURLs();
+      const urls = await this.radio().getStreaming().pickURLs();
       eventBus.$emit("play:now", urls, {
         live: true,
-        title: this.Radio.getName() + " - live",
+        title: this.radio().getName() + " - live",
       });
     },
   },

+ 3 - 3
src/pages/RadioShows.vue

@@ -12,7 +12,7 @@
         v-for="show in Radio.shows"
         :key="show.name"
         :title="show.name"
-        :link="`/radio/${radioId}/shows/${show.name}`"
+        :link="`/radio/${encodeURIComponent(radioId)}/shows/${show.name}`"
         :footer="show.description"
       />
     </f7-list>
@@ -34,9 +34,9 @@ export default {
   },
   props: { f7route: Object, f7router: Object },
   async mounted() {
-    this.radioId = this.f7route.params.radioName;
+    this.radioId = decodeURIComponent(this.f7route.params.radioUrl);
     try {
-      this.Radio = await radiomanifest.get(this.f7route.params.radioName);
+      this.Radio = await radiomanifest.get(this.radioId);
       this.loading = false;
     } catch (e) {
       console.error("le cose non vanno mai sempre bene!", e);

+ 5 - 3
src/pages/Show.vue

@@ -39,20 +39,22 @@ export default {
     return {
       loading_meta: true,
       loading: true,
-      radioId: null,
+      radioUrl: null,
       showId: null,
       Show: null,
     };
   },
   props: { f7route: Object, f7router: Object },
   async mounted() {
-    this.radioId = this.f7route.params.radioId;
+    this.radioUrl = decodeURIComponent(this.f7route.params.radioUrl);
     this.showId = this.f7route.params.showId;
     this.ShowBasicInfo = {};
 
     try {
-      this.Radio = await radiomanifest.get(this.f7route.params.radioId);
+      this.Radio = await radiomanifest.get(this.radioUrl);
+      console.log("Radio =", this.Radio);
       this.ShowBasicInfo = this.Radio.getShowByName(this.showId);
+      console.log("ShowBasicInfo =", this.ShowBasicInfo);
       this.loading_meta = false;
       this.Show = await getPodcast(this.ShowBasicInfo.getFeed());
       console.log("Show =", this.Show);

+ 18 - 4
src/pages/home.vue

@@ -1,5 +1,19 @@
 <script setup>
-import radiomanifest from "../js/radiomanifest";
+import radiomanifest from "@radiomanifest/radiomanifest";
+import { useRadioStore } from "../js/store";
+const store = useRadioStore();
+setTimeout(() => {
+  let i = 0;
+  for (const url of Object.keys(store.radios)) {
+    i++;
+    store.startFetchingRadio(url);
+    setTimeout(() => {
+      radiomanifest.get(url).then((data) => {
+        store.updateRadio(url, data);
+      });
+    }, i * 200);
+  }
+}, 100);
 </script>
 <template>
   <f7-page name="home">
@@ -7,9 +21,9 @@ import radiomanifest from "../js/radiomanifest";
     <f7-block-title>Radio</f7-block-title>
     <f7-list>
       <f7-list-item
-        v-for="(radio, url) in radiomanifest.cache"
-        :key="radio.ts"
-        :link="`/radio/${url}`"
+        v-for="(radio, url) in store.radios"
+        :key="radio.name"
+        :link="`/radio/${encodeURIComponent(url)}`"
         :title="radio.name"
       />
     </f7-list>