@saooti/octopus-sdk 38.0.16 → 38.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saooti/octopus-sdk",
3
- "version": "38.0.16",
3
+ "version": "38.0.19",
4
4
  "private": false,
5
5
  "description": "Javascript SDK for using octopus",
6
6
  "author": "Saooti",
@@ -111,6 +111,7 @@ body{
111
111
  margin: 1rem 0;
112
112
  }
113
113
  }
114
+
114
115
  .flex-super-grow{
115
116
  flex-grow: 2;
116
117
  }
@@ -20,6 +20,19 @@
20
20
  background-color: $octopus-primary-color;
21
21
  transition: width 0.6s ease;
22
22
  }
23
+ .octopus-chapter{
24
+ position: absolute;
25
+ background: transparent;
26
+ background-clip: content-box;
27
+ padding: 0 5px;
28
+ box-shadow: inset -2px 1px 0px 0px rgb(0 0 0),
29
+ inset 2px 1px 0px 0px rgb(0 0 0);
30
+
31
+ &:hover{
32
+ background: rgba(255, 255, 255, 0.4);
33
+ box-shadow: -4px 1px 0px 0px rgb(0 0 0);
34
+ }
35
+ }
23
36
  &,.octopus-progress-bar{
24
37
  height: 4px;
25
38
  @media (max-width: 960px) {
@@ -18,7 +18,7 @@
18
18
  <div :class="button.icon" />
19
19
  </a>
20
20
  </template>
21
- <router-link
21
+ <!-- <router-link
22
22
  v-if="!isPodcastmaker && authenticated && podcast && isProduction"
23
23
  :class="getClass('saooti-share')"
24
24
  :title="$t('Advanced sharing')"
@@ -26,7 +26,7 @@
26
26
  name: 'advancedShare',
27
27
  params: { podcastId: podcast.podcastId },
28
28
  }"
29
- />
29
+ /> -->
30
30
  </div>
31
31
  </div>
32
32
  <div v-if="podcast || emission || playlist" class="d-flex flex-column me-2">
@@ -5,7 +5,7 @@
5
5
  ref="popover"
6
6
  tabindex="0"
7
7
  class="octopus-popover"
8
- :class="onlyClick ? 'octopus-dropdown' : ''"
8
+ :class="[onlyClick ? 'octopus-dropdown' : '', popoverClass]"
9
9
  :style="positionInlineStyle"
10
10
  @blur="clearDataBlur"
11
11
  >
@@ -28,10 +28,12 @@ export default defineComponent({
28
28
  target: { type: String, required: true },
29
29
  disable: { type: Boolean, default: false },
30
30
  onlyClick: { type: Boolean, default: false },
31
+ onlyMouse: { type: Boolean, default: false },
31
32
  isFixed: { type: Boolean, default: false },
32
33
  relativeClass: { type: String, default: undefined },
33
34
  leftPos: { type: Boolean, default: false },
34
35
  topPos: { type: Boolean, default: false },
36
+ popoverClass: { type: String, default: undefined },
35
37
  },
36
38
  data() {
37
39
  return {
@@ -67,7 +69,9 @@ export default defineComponent({
67
69
  );
68
70
  this.targetElement.addEventListener("mouseleave", this.clearData);
69
71
  }
70
- this.targetElement.addEventListener("click", this.setPopoverData);
72
+ if (!this.onlyMouse) {
73
+ this.targetElement.addEventListener("click", this.setPopoverData);
74
+ }
71
75
  this.targetElement.addEventListener("blur", this.clearDataBlur);
72
76
  }
73
77
  },
@@ -80,7 +84,9 @@ export default defineComponent({
80
84
  );
81
85
  this.targetElement.removeEventListener("mouseleave", this.clearData);
82
86
  }
83
- this.targetElement.removeEventListener("click", this.setPopoverData);
87
+ if (!this.onlyMouse) {
88
+ this.targetElement.removeEventListener("click", this.setPopoverData);
89
+ }
84
90
  this.targetElement.addEventListener("blur", this.clearDataBlur);
85
91
  }
86
92
  },
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="octopus-progress">
2
+ <div v-if="display" id="test-menu-dropdown" class="octopus-progress">
3
3
  <div
4
4
  v-if="secondaryProgress"
5
5
  class="octopus-progress-bar bg-light"
@@ -48,18 +48,50 @@
48
48
  />
49
49
  <div
50
50
  v-if="isProgressCursor"
51
- class="progress-bar-cursor"
51
+ class="octopus-progress-bar-cursor"
52
52
  :style="'left:' + mainProgress + '%'"
53
53
  />
54
+ <template v-if="playerChapteringPercent">
55
+ <template v-for="chapter in playerChapteringPercent" :key="chapter">
56
+ <div
57
+ :id="'chapter-' + chapter.startPercent"
58
+ class="octopus-progress-bar octopus-chapter"
59
+ role="progressbar"
60
+ aria-valuenow="0"
61
+ aria-valuemin="0"
62
+ aria-valuemax="100"
63
+ :style="{
64
+ left: chapter.startPercent + '%',
65
+ right: 100 - chapter.endPercent + '%',
66
+ }"
67
+ />
68
+ <Teleport to="#octopus-player-component">
69
+ <ClassicPopover
70
+ :target="'chapter-' + chapter.startPercent"
71
+ :is-fixed="true"
72
+ relative-class="player-container"
73
+ :only-mouse="true"
74
+ popover-class="octopus-small-popover"
75
+ :content="chapter.title"
76
+ />
77
+ </Teleport>
78
+ </template>
79
+ </template>
54
80
  </div>
55
81
  </template>
56
82
 
57
83
  <script lang="ts">
58
84
  import { usePlayerStore } from "@/stores/PlayerStore";
59
85
  import { mapState } from "pinia";
60
- import { defineComponent } from "vue";
86
+ import { defineAsyncComponent, defineComponent } from "vue";
87
+ const ClassicPopover = defineAsyncComponent(
88
+ () => import("../misc/ClassicPopover.vue"),
89
+ );
61
90
  export default defineComponent({
62
91
  name: "ProgressBar",
92
+ components: {
93
+ ClassicPopover,
94
+ },
63
95
  props: {
64
96
  alertBar: { default: undefined, type: Number },
65
97
  mainProgress: { default: 0, type: Number },
@@ -73,7 +105,14 @@ export default defineComponent({
73
105
  };
74
106
  },
75
107
  computed: {
76
- ...mapState(usePlayerStore, ["playerMedia"]),
108
+ ...mapState(usePlayerStore, [
109
+ "playerMedia",
110
+ "playerChapteringPercent",
111
+ "playerStatus",
112
+ ]),
113
+ display() {
114
+ return "STOPPED" !== this.playerStatus;
115
+ },
77
116
  },
78
117
  watch: {
79
118
  playerMedia: {
@@ -104,4 +143,15 @@ export default defineComponent({
104
143
 
105
144
  <style lang="scss">
106
145
  @import "../../assets/progressbar.scss";
146
+ .octopus-app .player-container {
147
+ .octopus-small-popover {
148
+ font-size: 0.7rem;
149
+ background: #282828;
150
+ color: white;
151
+ border: 0;
152
+ .p-2 {
153
+ padding: 0.2rem !important;
154
+ }
155
+ }
156
+ }
107
157
  </style>
@@ -0,0 +1,79 @@
1
+ <template>
2
+ <ClassicModal
3
+ id-modal="chaptering-modal"
4
+ :title-modal="$t('Chaptering')"
5
+ @close="closePopup"
6
+ >
7
+ <template #body>
8
+ <div class="d-flex flex-column">
9
+ <a
10
+ v-for="(chapter, index) in playerChapteringPercent"
11
+ :key="chapter"
12
+ class="c-hand text-truncate mb-1"
13
+ @click="goToChapter(index)"
14
+ >
15
+ {{ chapter.startTime + " - " + chapter.title }}
16
+ </a>
17
+ </div>
18
+ </template>
19
+ <template #footer>
20
+ <button class="btn m-1" @click="closePopup">
21
+ {{ $t("Close") }}
22
+ </button>
23
+ </template>
24
+ </ClassicModal>
25
+ </template>
26
+
27
+ <script lang="ts">
28
+ import { usePlayerStore } from "@/stores/PlayerStore";
29
+ import { mapState, mapActions } from "pinia";
30
+ import ClassicModal from "../modal/ClassicModal.vue";
31
+ import { defineComponent } from "vue";
32
+ export default defineComponent({
33
+ name: "ChapteringModal",
34
+ components: {
35
+ ClassicModal,
36
+ },
37
+ props: {},
38
+ emits: ["close"],
39
+ data() {
40
+ return {
41
+ audioPlayer: null as HTMLAudioElement | null,
42
+ };
43
+ },
44
+ computed: {
45
+ ...mapState(usePlayerStore, [
46
+ "playerPodcast",
47
+ "playerLive",
48
+ "playerChapteringPercent",
49
+ "playerTotal",
50
+ "playerElapsed",
51
+ ]),
52
+ },
53
+ created() {
54
+ this.audioPlayer = document.querySelector("#audio-player");
55
+ },
56
+ methods: {
57
+ ...mapActions(usePlayerStore, [
58
+ "playerUpdateSeekTime",
59
+ "playerUpdateElapsed",
60
+ ]),
61
+ closePopup(): void {
62
+ this.$emit("close");
63
+ },
64
+ goToChapter(index: number) {
65
+ if (!this.playerChapteringPercent || !this.audioPlayer) {
66
+ return;
67
+ }
68
+ const seekTime =
69
+ this.playerTotal *
70
+ (this.playerChapteringPercent[index].startPercent / 100);
71
+ this.playerUpdateSeekTime(seekTime);
72
+ if (0 === seekTime) {
73
+ this.playerUpdateElapsed(0);
74
+ }
75
+ this.audioPlayer.currentTime = seekTime;
76
+ },
77
+ },
78
+ });
79
+ </script>
@@ -0,0 +1,72 @@
1
+ <template>
2
+ <div v-if="actualChapter" class="d-flex mb-1">
3
+ <button
4
+ class="btn-transparent d-flex align-items-center text-truncate medium-text text-light"
5
+ @click="showChaptering = !showChaptering"
6
+ >
7
+ <div class="text-truncate">{{ "• " + actualChapter.title }}</div>
8
+ <span class="saooti-right small-text" />
9
+ </button>
10
+ <ChapteringModal v-if="showChaptering" @close="showChaptering = false" />
11
+ </div>
12
+ </template>
13
+ <script lang="ts">
14
+ import { ChapterPercent } from "@/stores/class/chaptering/chaptering";
15
+ import { usePlayerStore } from "@/stores/PlayerStore";
16
+ import { mapState } from "pinia";
17
+ import { defineAsyncComponent, defineComponent } from "vue";
18
+ const ChapteringModal = defineAsyncComponent(
19
+ () => import("./ChapteringModal.vue"),
20
+ );
21
+ export default defineComponent({
22
+ name: "PlayerChaptering",
23
+
24
+ components: {
25
+ ChapteringModal,
26
+ },
27
+ data() {
28
+ return {
29
+ actualChapter: undefined as ChapterPercent | undefined,
30
+ showChaptering: false as boolean,
31
+ };
32
+ },
33
+ computed: {
34
+ ...mapState(usePlayerStore, ["playerChapteringPercent", "playerElapsed"]),
35
+ },
36
+ watch: {
37
+ playerElapsed: {
38
+ immediate: true,
39
+ handler() {
40
+ if (!this.playerChapteringPercent) {
41
+ this.actualChapter = undefined;
42
+ return;
43
+ }
44
+ const progressPercent = (this.playerElapsed ?? 0) * 100;
45
+ if (
46
+ this.actualChapter &&
47
+ this.isInChapter(progressPercent, this.actualChapter)
48
+ ) {
49
+ return;
50
+ }
51
+ for (
52
+ let i = 0, len = this.playerChapteringPercent.length;
53
+ i < len;
54
+ i++
55
+ ) {
56
+ if (
57
+ this.isInChapter(progressPercent, this.playerChapteringPercent[i])
58
+ ) {
59
+ this.actualChapter = this.playerChapteringPercent[i];
60
+ return;
61
+ }
62
+ }
63
+ },
64
+ },
65
+ },
66
+ methods: {
67
+ isInChapter(val: number, chapter: ChapterPercent) {
68
+ return chapter.startPercent <= val && val < chapter.endPercent;
69
+ },
70
+ },
71
+ });
72
+ </script>
@@ -34,6 +34,7 @@
34
34
  {{ playedTime }} / {{ totalTime }}
35
35
  </div>
36
36
  </div>
37
+ <PlayerChaptering />
37
38
  <PlayerProgressBar
38
39
  v-if="!radioUrl"
39
40
  :show-timeline="showTimeline"
@@ -69,6 +70,7 @@ import { playerDisplay } from "../../mixins/player/playerDisplay";
69
70
  import imageProxy from "../../mixins/imageProxy";
70
71
  import ClassicSpinner from "../ClassicSpinner.vue";
71
72
  import PlayerTimeline from "./PlayerTimeline.vue";
73
+ import PlayerChaptering from "./PlayerChaptering.vue";
72
74
  import { defineAsyncComponent, defineComponent } from "vue";
73
75
  const RadioProgressBar = defineAsyncComponent(
74
76
  () => import("./radio/RadioProgressBar.vue"),
@@ -84,6 +86,7 @@ export default defineComponent({
84
86
  RadioProgressBar,
85
87
  PlayerTimeline,
86
88
  ClassicSpinner,
89
+ PlayerChaptering,
87
90
  },
88
91
  mixins: [playerDisplay, imageProxy],
89
92
 
@@ -1,11 +1,12 @@
1
1
  <template>
2
2
  <div
3
+ id="octopus-player-component"
3
4
  class="player-container"
4
5
  :class="playerVideo ? 'player-video' : ''"
5
6
  :style="{ height: playerHeight }"
6
7
  @transitionend="onHidden"
7
8
  >
8
- <template v-if="display">
9
+ <template v-if="displayWithTimeout">
9
10
  <PlayerVideo v-if="playerVideo" />
10
11
  <template v-else>
11
12
  <audio
@@ -86,6 +87,7 @@ export default defineComponent({
86
87
  comments: [] as Array<CommentPodcast>,
87
88
  audioUrlToPlay: "" as string,
88
89
  hlsReady: false as boolean,
90
+ displayWithTimeout: false as boolean,
89
91
  };
90
92
  },
91
93
  computed: {
@@ -104,6 +106,15 @@ export default defineComponent({
104
106
  playerHeight(): void {
105
107
  this.$emit("hide", 0 === this.playerHeight);
106
108
  },
109
+ display(): void {
110
+ if (this.display) {
111
+ this.displayWithTimeout = this.display;
112
+ } else {
113
+ setTimeout(() => {
114
+ this.displayWithTimeout = this.display;
115
+ }, 3000);
116
+ }
117
+ },
107
118
  },
108
119
 
109
120
  methods: {
@@ -141,6 +152,12 @@ export default defineComponent({
141
152
  transition: height 1s;
142
153
  background: #282828 !important;
143
154
  font-size: 1rem;
155
+ .medium-text {
156
+ font-size: 0.75rem;
157
+ }
158
+ .small-text {
159
+ font-size: 0.6rem;
160
+ }
144
161
 
145
162
  @media (max-width: 960px) {
146
163
  .d-flex {
@@ -24,6 +24,7 @@
24
24
  {{ podcastTitle }}
25
25
  </div>
26
26
  </div>
27
+ <PlayerChaptering class="justify-content-center w-100" />
27
28
  <div class="player-grow-large-content">
28
29
  <PlayerProgressBar
29
30
  v-if="!radioUrl"
@@ -86,6 +87,7 @@ import ClassicSpinner from "../ClassicSpinner.vue";
86
87
  import { playerDisplay } from "../../mixins/player/playerDisplay";
87
88
  import imageProxy from "../../mixins/imageProxy";
88
89
  import PlayerTimeline from "./PlayerTimeline.vue";
90
+ import PlayerChaptering from "./PlayerChaptering.vue";
89
91
  import { defineAsyncComponent, defineComponent } from "vue";
90
92
  import { CommentPodcast } from "@/stores/class/general/comment";
91
93
  const RadioProgressBar = defineAsyncComponent(
@@ -106,6 +108,7 @@ export default defineComponent({
106
108
  PlayerTimeline,
107
109
  ClassicSpinner,
108
110
  RadioHistory,
111
+ PlayerChaptering,
109
112
  },
110
113
  mixins: [playerDisplay, imageProxy],
111
114
 
@@ -41,7 +41,7 @@ export const playerLogicProgress = defineComponent({
41
41
  );
42
42
  },
43
43
  playerSeekTime() {
44
- if (!this.playerSeekTime) {
44
+ if (undefined===this.playerSeekTime) {
45
45
  return;
46
46
  }
47
47
  if (this.playerPodcast || this.playerLive) {
@@ -91,7 +91,8 @@ export default defineComponent({
91
91
  computed: {
92
92
  editRight(): boolean {
93
93
  return (
94
- (true === this.authenticated && true === state.generalParameters.isRadio &&
94
+ (true === this.authenticated &&
95
+ true === state.generalParameters.isRadio &&
95
96
  this.myOrganisationId === this.radio?.organisationId) ||
96
97
  true === state.generalParameters.isAdmin
97
98
  );
@@ -1,20 +1,18 @@
1
1
  export default {
2
+ convertTimestamptoSeconds(timestamp: string){
3
+ const [hours, minutes, seconds] = timestamp.split(':');
4
+ return Number(hours) * 60 * 60 + Number(minutes) * 60 + Number(seconds);
5
+ },
2
6
  formatToString(value: number) {
3
7
  if (value < 10) {
4
8
  return "0" + value;
5
9
  }
6
10
  return value.toString();
7
11
  },
8
- formatDuration(totalSeconds: number): string {
12
+ formatDuration(totalSeconds: number, separator="'", isLast=true): string {
9
13
  const hours = Math.floor(totalSeconds / 3600);
10
14
  const minutes = Math.floor((totalSeconds - hours * 3600) / 60);
11
15
  const seconds = totalSeconds - hours * 3600 - minutes * 60;
12
- return (
13
- (hours > 0 ? this.formatToString(hours) + "'" : "") +
14
- this.formatToString(minutes) +
15
- "'" +
16
- this.formatToString(seconds) +
17
- "''"
18
- );
16
+ return (hours > 0? this.formatToString(hours)+separator:"") + this.formatToString(minutes) +separator+ this.formatToString(seconds) + (isLast?separator:separator );
19
17
  },
20
18
  };
package/src/locale/de.ts CHANGED
@@ -350,4 +350,5 @@ export default {
350
350
  "Trigger automatic reading if this is possible":"Wenn möglich, automatisches Auslesen auslösen",
351
351
  "High version":"Hohe Version",
352
352
  "Advanced sharing":"Erweitertes Teilen",
353
+ "Chaptering":"Kapitelaufteilung",
353
354
  }
package/src/locale/en.ts CHANGED
@@ -350,4 +350,5 @@ export default {
350
350
  "Trigger automatic reading if this is possible":"Trigger automatic reading if this is possible",
351
351
  "High version":"High version",
352
352
  "Advanced sharing":"Advanced sharing",
353
+ "Chaptering":"Chaptering",
353
354
  };
package/src/locale/es.ts CHANGED
@@ -351,4 +351,5 @@ export default {
351
351
  "Trigger automatic reading if this is possible":"Activar la lectura automática si esto es posible",
352
352
  "High version":"Versión alta",
353
353
  "Advanced sharing":"Reparto adelantado",
354
+ "Chaptering":"Capítulos",
354
355
  }
package/src/locale/fr.ts CHANGED
@@ -357,4 +357,5 @@ export default {
357
357
  "Trigger automatic reading if this is possible":"Déclencher la lecture automatique si celle ci est possible",
358
358
  "High version":"Version en hauteur",
359
359
  "Advanced sharing":"Partage avancé",
360
+ "Chaptering":"Chapitrage",
360
361
  };
package/src/locale/it.ts CHANGED
@@ -343,4 +343,5 @@ export default{
343
343
  "Trigger automatic reading if this is possible":"Attivare la lettura automatica, se possibile",
344
344
  "High version":"Versione alta",
345
345
  "Advanced sharing":"Condivisione avanzata",
346
+ "Chaptering":"Capitolazione",
346
347
  };
package/src/locale/sl.ts CHANGED
@@ -340,4 +340,5 @@ export default {
340
340
  "Trigger automatic reading if this is possible":"Sprožite samodejno branje, če je to mogoče",
341
341
  "High version":"Visoka različica",
342
342
  "Advanced sharing":"Napredno deljenje",
343
+ "Chaptering":"Poglavje",
343
344
  }
@@ -13,7 +13,7 @@ const state: ParamStore = {
13
13
  isProduction: false,
14
14
  isContribution: false,
15
15
  isRadio: false,
16
- ApiUri: "https://api.staging.saooti.org/",
16
+ ApiUri: "https://api.dev2.saooti.org/",
17
17
  podcastmaker: false,
18
18
  buttonPlus: true,
19
19
  allCategories: [],
@@ -27,8 +27,8 @@ const state: ParamStore = {
27
27
  SharePlayer: true,
28
28
  ShareButtons: true,
29
29
  ShareDistribution: true,
30
- MiniplayerUri: "https://playerbeta.staging.saooti.org/",
31
- hlsUri: "https://hls.live.staging.saooti.org/",
30
+ MiniplayerUri: "https://playerbeta.dev2.saooti.org/",
31
+ hlsUri: "https://hls.live.dev2.saooti.org/",
32
32
  mainRubrique: 0,
33
33
  resourceUrl: undefined,
34
34
  podcastItemShowEmission: false,
@@ -80,14 +80,14 @@ const state: ParamStore = {
80
80
  userName: "",
81
81
  },
82
82
  octopusApi: {
83
- url: "https://api.staging.saooti.org/",
84
- commentsUrl: "https://comments.staging.saooti.org/",
85
- imageUrl: "https://imageproxy.staging.saooti.org/",
86
- studioUrl: "https://studio.staging.saooti.org/",
87
- playerUrl: "https://playerbeta.staging.saooti.org/",
88
- speechToTextUrl: "https://speech2text.staging.saooti.org/",
89
- radioUrl:"https://radio.staging.saooti.org/",
90
- recoUrl: "https://reco.staging.saooti.org/",
83
+ url: "https://api.dev2.saooti.org/",
84
+ commentsUrl: "https://comments.dev2.saooti.org/",
85
+ imageUrl: "https://imageproxy.dev2.saooti.org/",
86
+ studioUrl: "https://studio.dev2.saooti.org/",
87
+ playerUrl: "https://playerbeta.dev2.saooti.org/",
88
+ speechToTextUrl: "https://speech2text.dev2.saooti.org/",
89
+ radioUrl:"https://radio.dev2.saooti.org/",
90
+ recoUrl: "https://reco.dev2.saooti.org/",
91
91
  organisationId: undefined,
92
92
  rubriqueIdFilter: undefined,
93
93
  },
@@ -3,6 +3,8 @@ import { Media } from "@/stores/class/general/media";
3
3
  import { MediaRadio, Radio } from "@/stores/class/general/player";
4
4
  import { Podcast } from "@/stores/class/general/podcast";
5
5
  import { defineStore } from "pinia";
6
+ import { Chaptering, ChapteringPercent } from "./class/chaptering/chaptering";
7
+ import octopusApi from "@saooti/octopus-api";
6
8
  interface Transcript {
7
9
  actual: number;
8
10
  actualText: string;
@@ -22,6 +24,7 @@ interface PlayerState {
22
24
  playerTranscript?: Transcript;
23
25
  playerLargeVersion: boolean;
24
26
  playerVideo: boolean;
27
+ playerChaptering?: Chaptering;
25
28
  }
26
29
  export const usePlayerStore = defineStore("PlayerStore", {
27
30
  state: (): PlayerState => ({
@@ -36,13 +39,33 @@ export const usePlayerStore = defineStore("PlayerStore", {
36
39
  playerSeekTime: 0,
37
40
  playerLargeVersion: false,
38
41
  playerVideo: false,
42
+ playerChaptering: undefined,
39
43
  }),
40
44
  getters: {
45
+ playerChapteringPercent(): ChapteringPercent|undefined{
46
+ if(!this.playerChaptering || 0===this.playerTotal){
47
+ return;
48
+ }
49
+ const chapteringKeys = Object.keys(this.playerChaptering);
50
+ let chapteringPercent: ChapteringPercent = [];
51
+ for (let i = 0, len = chapteringKeys.length; i < len; i++) {
52
+ chapteringPercent.push({
53
+ startTime : chapteringKeys[i],
54
+ startPercent: (DurationHelper.convertTimestamptoSeconds(chapteringKeys[i]) * 100 ) / (Math.round(this.playerTotal)),
55
+ endPercent:100,
56
+ title: this.playerChaptering[chapteringKeys[i]]
57
+ });
58
+ }
59
+ for (let i = 0, len = chapteringPercent.length; i < len; i++) {
60
+ chapteringPercent[i].endPercent = chapteringPercent[i].startPercent + ((chapteringPercent[i+1]?.startPercent ?? 100) - chapteringPercent[i].startPercent);
61
+ }
62
+ return chapteringPercent;
63
+ },
41
64
  playerHeight() {
42
65
  if ("STOPPED" === this.playerStatus) return 0;
43
66
  if (this.playerVideo) return "0px"/* "281px" */;
44
67
  if (this.playerLargeVersion) return "27rem";
45
- if (window.innerWidth > 450) return "5rem";
68
+ if (window.innerWidth > 450) return "6rem";
46
69
  return "3.5rem";
47
70
  },
48
71
  playedTime(): string {
@@ -91,7 +114,7 @@ export const usePlayerStore = defineStore("PlayerStore", {
91
114
  },
92
115
  },
93
116
  actions: {
94
- playerPlay(param?: any, isVideo = false) {
117
+ async playerPlay(param?: any, isVideo = false) {
95
118
  if (!param) {
96
119
  this.playerStatus = "STOPPED";
97
120
  this.playerPodcast = undefined;
@@ -100,6 +123,7 @@ export const usePlayerStore = defineStore("PlayerStore", {
100
123
  this.playerRadio = undefined;
101
124
  this.playerElapsed = 0;
102
125
  this.playerVideo = false;
126
+ this.playerChaptering=undefined;
103
127
  return;
104
128
  }
105
129
  if (
@@ -118,16 +142,26 @@ export const usePlayerStore = defineStore("PlayerStore", {
118
142
  this.playerRadio = undefined;
119
143
  this.playerVideo = isVideo;
120
144
  this.playerElapsed = 0;
145
+ this.playerChaptering=undefined;
121
146
  if (
122
147
  param.conferenceId &&
123
148
  (!param.podcastId || param.processingStatus !== "READY")
124
149
  ) {
125
150
  this.playerLive = param;
126
- } else if (param.podcastId) {
151
+ return;
152
+ }
153
+ if (param.podcastId) {
127
154
  this.playerPodcast = param;
128
- } else if (param.mediaId) {
155
+ if(param.annotations?.chaptering){
156
+ this.playerChaptering = await octopusApi.fetchDataPublic<Chaptering>(4, (param.annotations.chaptering as string));
157
+ }
158
+ return;
159
+ }
160
+ if (param.mediaId) {
129
161
  this.playerMedia = param;
130
- } else if (param.canalId) {
162
+ return;
163
+ }
164
+ if (param.canalId) {
131
165
  this.playerRadio = { ...param, ...{ isInit: false } };
132
166
  }
133
167
  },
@@ -158,9 +192,11 @@ export const usePlayerStore = defineStore("PlayerStore", {
158
192
  this.playerRadio.podcast = podcast;
159
193
  },
160
194
 
161
- playerUpdateElapsed(elapsed: number, total: number) {
195
+ playerUpdateElapsed(elapsed: number, total?: number) {
162
196
  this.playerElapsed = elapsed;
163
- this.playerTotal = total;
197
+ if(total){
198
+ this.playerTotal = total;
199
+ }
164
200
  },
165
201
 
166
202
  playerUpdateTranscript(transcript?: Transcript) {
@@ -0,0 +1,12 @@
1
+ export interface Chaptering {
2
+ [startTime: string] : string;
3
+ }
4
+
5
+ export interface ChapterPercent {
6
+ startTime: string;
7
+ startPercent: number;
8
+ endPercent: number;
9
+ title: string;
10
+ }
11
+
12
+ export type ChapteringPercent = Array<ChapterPercent>;