@saooti/octopus-sdk 38.0.21 → 38.1.0

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.21",
3
+ "version": "38.1.0",
4
4
  "private": false,
5
5
  "description": "Javascript SDK for using octopus",
6
6
  "author": "Saooti",
@@ -111,7 +111,6 @@ body{
111
111
  margin: 1rem 0;
112
112
  }
113
113
  }
114
-
115
114
  .flex-super-grow{
116
115
  flex-grow: 2;
117
116
  }
@@ -20,19 +20,6 @@
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
- }
36
23
  &,.octopus-progress-bar{
37
24
  height: 4px;
38
25
  @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' : '', popoverClass]"
8
+ :class="onlyClick ? 'octopus-dropdown' : ''"
9
9
  :style="positionInlineStyle"
10
10
  @blur="clearDataBlur"
11
11
  >
@@ -28,12 +28,10 @@ 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 },
32
31
  isFixed: { type: Boolean, default: false },
33
32
  relativeClass: { type: String, default: undefined },
34
33
  leftPos: { type: Boolean, default: false },
35
34
  topPos: { type: Boolean, default: false },
36
- popoverClass: { type: String, default: undefined },
37
35
  },
38
36
  data() {
39
37
  return {
@@ -69,9 +67,7 @@ export default defineComponent({
69
67
  );
70
68
  this.targetElement.addEventListener("mouseleave", this.clearData);
71
69
  }
72
- if (!this.onlyMouse) {
73
- this.targetElement.addEventListener("click", this.setPopoverData);
74
- }
70
+ this.targetElement.addEventListener("click", this.setPopoverData);
75
71
  this.targetElement.addEventListener("blur", this.clearDataBlur);
76
72
  }
77
73
  },
@@ -84,9 +80,7 @@ export default defineComponent({
84
80
  );
85
81
  this.targetElement.removeEventListener("mouseleave", this.clearData);
86
82
  }
87
- if (!this.onlyMouse) {
88
- this.targetElement.removeEventListener("click", this.setPopoverData);
89
- }
83
+ this.targetElement.removeEventListener("click", this.setPopoverData);
90
84
  this.targetElement.addEventListener("blur", this.clearDataBlur);
91
85
  }
92
86
  },
@@ -24,7 +24,7 @@
24
24
  :left-pos="true"
25
25
  >
26
26
  <template v-if="!isAuthenticated">
27
- <a class="octopus-dropdown-item" href="/sso/login" realLink="true">
27
+ <a class="octopus-dropdown-item" href="/login" realLink="true">
28
28
  {{ $t("Login") }}
29
29
  </a>
30
30
  <router-link
@@ -60,7 +60,7 @@
60
60
  </template>
61
61
  </template>
62
62
  <hr />
63
- <a class="octopus-dropdown-item" href="/sso/logout" realLink="true">
63
+ <a class="octopus-dropdown-item" href="/logout" realLink="true">
64
64
  {{ $t("Logout") }}
65
65
  </a>
66
66
  </template>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div v-if="display" id="test-menu-dropdown" class="octopus-progress">
2
+ <div class="octopus-progress">
3
3
  <div
4
4
  v-if="secondaryProgress"
5
5
  class="octopus-progress-bar bg-light"
@@ -48,50 +48,18 @@
48
48
  />
49
49
  <div
50
50
  v-if="isProgressCursor"
51
- class="octopus-progress-bar-cursor"
51
+ class="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>
80
54
  </div>
81
55
  </template>
82
56
 
83
57
  <script lang="ts">
84
58
  import { usePlayerStore } from "@/stores/PlayerStore";
85
59
  import { mapState } from "pinia";
86
- import { defineAsyncComponent, defineComponent } from "vue";
87
- const ClassicPopover = defineAsyncComponent(
88
- () => import("../misc/ClassicPopover.vue"),
89
- );
60
+ import { defineComponent } from "vue";
90
61
  export default defineComponent({
91
62
  name: "ProgressBar",
92
- components: {
93
- ClassicPopover,
94
- },
95
63
  props: {
96
64
  alertBar: { default: undefined, type: Number },
97
65
  mainProgress: { default: 0, type: Number },
@@ -105,14 +73,7 @@ export default defineComponent({
105
73
  };
106
74
  },
107
75
  computed: {
108
- ...mapState(usePlayerStore, [
109
- "playerMedia",
110
- "playerChapteringPercent",
111
- "playerStatus",
112
- ]),
113
- display() {
114
- return "STOPPED" !== this.playerStatus;
115
- },
76
+ ...mapState(usePlayerStore, ["playerMedia"]),
116
77
  },
117
78
  watch: {
118
79
  playerMedia: {
@@ -143,15 +104,4 @@ export default defineComponent({
143
104
 
144
105
  <style lang="scss">
145
106
  @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
- }
157
107
  </style>
@@ -34,7 +34,6 @@
34
34
  {{ playedTime }} / {{ totalTime }}
35
35
  </div>
36
36
  </div>
37
- <PlayerChaptering />
38
37
  <PlayerProgressBar
39
38
  v-if="!radioUrl"
40
39
  :show-timeline="showTimeline"
@@ -70,7 +69,6 @@ import { playerDisplay } from "../../mixins/player/playerDisplay";
70
69
  import imageProxy from "../../mixins/imageProxy";
71
70
  import ClassicSpinner from "../ClassicSpinner.vue";
72
71
  import PlayerTimeline from "./PlayerTimeline.vue";
73
- import PlayerChaptering from "./PlayerChaptering.vue";
74
72
  import { defineAsyncComponent, defineComponent } from "vue";
75
73
  const RadioProgressBar = defineAsyncComponent(
76
74
  () => import("./radio/RadioProgressBar.vue"),
@@ -86,7 +84,6 @@ export default defineComponent({
86
84
  RadioProgressBar,
87
85
  PlayerTimeline,
88
86
  ClassicSpinner,
89
- PlayerChaptering,
90
87
  },
91
88
  mixins: [playerDisplay, imageProxy],
92
89
 
@@ -1,12 +1,11 @@
1
1
  <template>
2
2
  <div
3
- id="octopus-player-component"
4
3
  class="player-container"
5
4
  :class="playerVideo ? 'player-video' : ''"
6
5
  :style="{ height: playerHeight }"
7
6
  @transitionend="onHidden"
8
7
  >
9
- <template v-if="displayWithTimeout">
8
+ <template v-if="display">
10
9
  <PlayerVideo v-if="playerVideo" />
11
10
  <template v-else>
12
11
  <audio
@@ -87,7 +86,6 @@ export default defineComponent({
87
86
  comments: [] as Array<CommentPodcast>,
88
87
  audioUrlToPlay: "" as string,
89
88
  hlsReady: false as boolean,
90
- displayWithTimeout: false as boolean,
91
89
  };
92
90
  },
93
91
  computed: {
@@ -106,15 +104,6 @@ export default defineComponent({
106
104
  playerHeight(): void {
107
105
  this.$emit("hide", 0 === this.playerHeight);
108
106
  },
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
- },
118
107
  },
119
108
 
120
109
  methods: {
@@ -152,12 +141,6 @@ export default defineComponent({
152
141
  transition: height 1s;
153
142
  background: #282828 !important;
154
143
  font-size: 1rem;
155
- .medium-text {
156
- font-size: 0.65rem;
157
- }
158
- .small-text {
159
- font-size: 0.5rem;
160
- }
161
144
 
162
145
  @media (max-width: 960px) {
163
146
  .d-flex {
@@ -24,7 +24,6 @@
24
24
  {{ podcastTitle }}
25
25
  </div>
26
26
  </div>
27
- <PlayerChaptering class="justify-content-center w-100" />
28
27
  <div class="player-grow-large-content">
29
28
  <PlayerProgressBar
30
29
  v-if="!radioUrl"
@@ -87,7 +86,6 @@ import ClassicSpinner from "../ClassicSpinner.vue";
87
86
  import { playerDisplay } from "../../mixins/player/playerDisplay";
88
87
  import imageProxy from "../../mixins/imageProxy";
89
88
  import PlayerTimeline from "./PlayerTimeline.vue";
90
- import PlayerChaptering from "./PlayerChaptering.vue";
91
89
  import { defineAsyncComponent, defineComponent } from "vue";
92
90
  import { CommentPodcast } from "@/stores/class/general/comment";
93
91
  const RadioProgressBar = defineAsyncComponent(
@@ -108,7 +106,6 @@ export default defineComponent({
108
106
  PlayerTimeline,
109
107
  ClassicSpinner,
110
108
  RadioHistory,
111
- PlayerChaptering,
112
109
  },
113
110
  mixins: [playerDisplay, imageProxy],
114
111
 
@@ -10,7 +10,7 @@ export const handle403 = defineComponent({
10
10
  handle403(error: AxiosError): void {
11
11
  if (403 === error.response?.status) {
12
12
  if (undefined === this.authOrgaId) {
13
- window.location.href = window.location.origin + "/sso/login";
13
+ window.location.href = window.location.origin + "/login";
14
14
  } else {
15
15
  this.$router.push({
16
16
  path: "/main/pub/error",
@@ -41,7 +41,7 @@ export const playerLogicProgress = defineComponent({
41
41
  );
42
42
  },
43
43
  playerSeekTime() {
44
- if (undefined===this.playerSeekTime) {
44
+ if (!this.playerSeekTime) {
45
45
  return;
46
46
  }
47
47
  if (this.playerPodcast || this.playerLive) {
@@ -22,7 +22,7 @@
22
22
 
23
23
  <a
24
24
  class="btn btn-primary"
25
- :href="authenticated ? '/sso/logout' : '/sso/login'"
25
+ :href="authenticated ? '/logout' : '/login'"
26
26
  >{{ authText }}</a
27
27
  >
28
28
  </div>
@@ -91,8 +91,7 @@ export default defineComponent({
91
91
  computed: {
92
92
  editRight(): boolean {
93
93
  return (
94
- (true === this.authenticated &&
95
- true === state.generalParameters.isRadio &&
94
+ (true === this.authenticated && true === state.generalParameters.isRadio &&
96
95
  this.myOrganisationId === this.radio?.organisationId) ||
97
96
  true === state.generalParameters.isAdmin
98
97
  );
@@ -1,18 +1,20 @@
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
- },
6
2
  formatToString(value: number) {
7
3
  if (value < 10) {
8
4
  return "0" + value;
9
5
  }
10
6
  return value.toString();
11
7
  },
12
- formatDuration(totalSeconds: number, separator="'", isLast=true): string {
8
+ formatDuration(totalSeconds: number): string {
13
9
  const hours = Math.floor(totalSeconds / 3600);
14
10
  const minutes = Math.floor((totalSeconds - hours * 3600) / 60);
15
11
  const seconds = totalSeconds - hours * 3600 - minutes * 60;
16
- return (hours > 0? this.formatToString(hours)+separator:"") + this.formatToString(minutes) +separator+ this.formatToString(seconds) + (isLast?separator:'' );
12
+ return (
13
+ (hours > 0 ? this.formatToString(hours) + "'" : "") +
14
+ this.formatToString(minutes) +
15
+ "'" +
16
+ this.formatToString(seconds) +
17
+ "''"
18
+ );
17
19
  },
18
20
  };
package/src/locale/de.ts CHANGED
@@ -350,5 +350,4 @@ 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",
354
353
  }
package/src/locale/en.ts CHANGED
@@ -350,5 +350,4 @@ 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",
354
353
  };
package/src/locale/es.ts CHANGED
@@ -351,5 +351,4 @@ 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",
355
354
  }
package/src/locale/fr.ts CHANGED
@@ -357,5 +357,4 @@ 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",
361
360
  };
package/src/locale/it.ts CHANGED
@@ -343,5 +343,4 @@ 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",
347
346
  };
package/src/locale/sl.ts CHANGED
@@ -340,5 +340,4 @@ 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",
344
343
  }
@@ -13,7 +13,7 @@ const state: ParamStore = {
13
13
  isProduction: false,
14
14
  isContribution: false,
15
15
  isRadio: false,
16
- ApiUri: "https://api.dev2.saooti.org/",
16
+ ApiUri: "https://api.staging.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.dev2.saooti.org/",
31
- hlsUri: "https://hls.live.dev2.saooti.org/",
30
+ MiniplayerUri: "https://playerbeta.staging.saooti.org/",
31
+ hlsUri: "https://hls.live.staging.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.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/",
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/",
91
91
  organisationId: undefined,
92
92
  rubriqueIdFilter: undefined,
93
93
  },
@@ -3,8 +3,6 @@ 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";
8
6
  interface Transcript {
9
7
  actual: number;
10
8
  actualText: string;
@@ -24,7 +22,6 @@ interface PlayerState {
24
22
  playerTranscript?: Transcript;
25
23
  playerLargeVersion: boolean;
26
24
  playerVideo: boolean;
27
- playerChaptering?: Chaptering;
28
25
  }
29
26
  export const usePlayerStore = defineStore("PlayerStore", {
30
27
  state: (): PlayerState => ({
@@ -39,33 +36,13 @@ export const usePlayerStore = defineStore("PlayerStore", {
39
36
  playerSeekTime: 0,
40
37
  playerLargeVersion: false,
41
38
  playerVideo: false,
42
- playerChaptering: undefined,
43
39
  }),
44
40
  getters: {
45
- playerChapteringPercent(): ChapteringPercent|undefined{
46
- if(!this.playerChaptering || 0===this.playerTotal){
47
- return;
48
- }
49
- let chapteringPercent: ChapteringPercent = [];
50
- for (let i = 0, len = this.playerChaptering.chapters.length; i < len; i++) {
51
- chapteringPercent.push({
52
- startTime : this.playerChaptering.chapters[i].startTime,
53
- startDisplay: DurationHelper.formatDuration(this.playerChaptering.chapters[i].startTime, ':', false),
54
- startPercent: (this.playerChaptering.chapters[i].startTime * 100 ) / (Math.round(this.playerTotal)),
55
- endPercent:100,
56
- title: this.playerChaptering.chapters[i].title
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
- },
64
41
  playerHeight() {
65
42
  if ("STOPPED" === this.playerStatus) return 0;
66
43
  if (this.playerVideo) return "0px"/* "281px" */;
67
44
  if (this.playerLargeVersion) return "27rem";
68
- if (window.innerWidth > 450) return "6rem";
45
+ if (window.innerWidth > 450) return "5rem";
69
46
  return "3.5rem";
70
47
  },
71
48
  playedTime(): string {
@@ -114,7 +91,7 @@ export const usePlayerStore = defineStore("PlayerStore", {
114
91
  },
115
92
  },
116
93
  actions: {
117
- async playerPlay(param?: any, isVideo = false) {
94
+ playerPlay(param?: any, isVideo = false) {
118
95
  if (!param) {
119
96
  this.playerStatus = "STOPPED";
120
97
  this.playerPodcast = undefined;
@@ -123,7 +100,6 @@ export const usePlayerStore = defineStore("PlayerStore", {
123
100
  this.playerRadio = undefined;
124
101
  this.playerElapsed = 0;
125
102
  this.playerVideo = false;
126
- this.playerChaptering=undefined;
127
103
  return;
128
104
  }
129
105
  if (
@@ -142,26 +118,16 @@ export const usePlayerStore = defineStore("PlayerStore", {
142
118
  this.playerRadio = undefined;
143
119
  this.playerVideo = isVideo;
144
120
  this.playerElapsed = 0;
145
- this.playerChaptering=undefined;
146
121
  if (
147
122
  param.conferenceId &&
148
123
  (!param.podcastId || param.processingStatus !== "READY")
149
124
  ) {
150
125
  this.playerLive = param;
151
- return;
152
- }
153
- if (param.podcastId) {
126
+ } else if (param.podcastId) {
154
127
  this.playerPodcast = param;
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) {
128
+ } else if (param.mediaId) {
161
129
  this.playerMedia = param;
162
- return;
163
- }
164
- if (param.canalId) {
130
+ } else if (param.canalId) {
165
131
  this.playerRadio = { ...param, ...{ isInit: false } };
166
132
  }
167
133
  },
@@ -192,11 +158,9 @@ export const usePlayerStore = defineStore("PlayerStore", {
192
158
  this.playerRadio.podcast = podcast;
193
159
  },
194
160
 
195
- playerUpdateElapsed(elapsed: number, total?: number) {
161
+ playerUpdateElapsed(elapsed: number, total: number) {
196
162
  this.playerElapsed = elapsed;
197
- if(total){
198
- this.playerTotal = total;
199
- }
163
+ this.playerTotal = total;
200
164
  },
201
165
 
202
166
  playerUpdateTranscript(transcript?: Transcript) {
@@ -1,80 +0,0 @@
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
- <button
10
- v-for="(chapter, index) in playerChapteringPercent"
11
- :key="chapter"
12
- class="btn d-flex flex-nowrap align-items-center p-2 mt-1 c-hand text-truncate mb-1 border"
13
- @click="goToChapter(index)"
14
- >
15
- <div class="me-auto">{{ index + 1 + " - " + chapter.title }}</div>
16
- <div>{{ chapter.startDisplay }}</div>
17
- </button>
18
- </div>
19
- </template>
20
- <template #footer>
21
- <button class="btn m-1" @click="closePopup">
22
- {{ $t("Close") }}
23
- </button>
24
- </template>
25
- </ClassicModal>
26
- </template>
27
-
28
- <script lang="ts">
29
- import { usePlayerStore } from "@/stores/PlayerStore";
30
- import { mapState, mapActions } from "pinia";
31
- import ClassicModal from "../modal/ClassicModal.vue";
32
- import { defineComponent } from "vue";
33
- export default defineComponent({
34
- name: "ChapteringModal",
35
- components: {
36
- ClassicModal,
37
- },
38
- props: {},
39
- emits: ["close"],
40
- data() {
41
- return {
42
- audioPlayer: null as HTMLAudioElement | null,
43
- };
44
- },
45
- computed: {
46
- ...mapState(usePlayerStore, [
47
- "playerPodcast",
48
- "playerLive",
49
- "playerChapteringPercent",
50
- "playerTotal",
51
- "playerElapsed",
52
- ]),
53
- },
54
- created() {
55
- this.audioPlayer = document.querySelector("#audio-player");
56
- },
57
- methods: {
58
- ...mapActions(usePlayerStore, [
59
- "playerUpdateSeekTime",
60
- "playerUpdateElapsed",
61
- ]),
62
- closePopup(): void {
63
- this.$emit("close");
64
- },
65
- goToChapter(index: number) {
66
- if (!this.playerChapteringPercent || !this.audioPlayer) {
67
- return;
68
- }
69
- const seekTime =
70
- this.playerTotal *
71
- (this.playerChapteringPercent[index].startPercent / 100);
72
- this.playerUpdateSeekTime(seekTime);
73
- if (0 === seekTime) {
74
- this.playerUpdateElapsed(0);
75
- }
76
- this.audioPlayer.currentTime = seekTime;
77
- },
78
- },
79
- });
80
- </script>
@@ -1,86 +0,0 @@
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">
8
- {{ actualIndex + 1 + " - " + actualChapter.title }}
9
- </div>
10
- <span class="saooti-right small-text" />
11
- </button>
12
- <ChapteringModal v-if="showChaptering" @close="showChaptering = false" />
13
- </div>
14
- <div v-else class="margin-chaptering"></div>
15
- </template>
16
- <script lang="ts">
17
- import { ChapterPercent } from "@/stores/class/chaptering/chaptering";
18
- import { usePlayerStore } from "@/stores/PlayerStore";
19
- import { mapState } from "pinia";
20
- import { defineAsyncComponent, defineComponent } from "vue";
21
- const ChapteringModal = defineAsyncComponent(
22
- () => import("./ChapteringModal.vue"),
23
- );
24
- export default defineComponent({
25
- name: "PlayerChaptering",
26
-
27
- components: {
28
- ChapteringModal,
29
- },
30
- data() {
31
- return {
32
- actualChapter: undefined as ChapterPercent | undefined,
33
- actualIndex: 0 as number,
34
- showChaptering: false as boolean,
35
- };
36
- },
37
- computed: {
38
- ...mapState(usePlayerStore, ["playerChapteringPercent", "playerElapsed"]),
39
- },
40
- watch: {
41
- playerElapsed: {
42
- immediate: true,
43
- handler() {
44
- if (!this.playerChapteringPercent) {
45
- this.actualChapter = undefined;
46
- return;
47
- }
48
- const progressPercent = (this.playerElapsed ?? 0) * 100;
49
- if (
50
- this.actualChapter &&
51
- this.isInChapter(progressPercent, this.actualChapter)
52
- ) {
53
- return;
54
- }
55
- for (
56
- let i = 0, len = this.playerChapteringPercent.length;
57
- i < len;
58
- i++
59
- ) {
60
- if (
61
- this.isInChapter(progressPercent, this.playerChapteringPercent[i])
62
- ) {
63
- this.actualChapter = this.playerChapteringPercent[i];
64
- this.actualIndex = i;
65
- return;
66
- }
67
- }
68
- this.actualChapter = undefined;
69
- this.actualIndex = 0;
70
- },
71
- },
72
- },
73
- methods: {
74
- isInChapter(val: number, chapter: ChapterPercent) {
75
- return chapter.startPercent <= val && val < chapter.endPercent;
76
- },
77
- },
78
- });
79
- </script>
80
- <style lang="scss">
81
- .octopus-app {
82
- .margin-chaptering{
83
- height: 23px;
84
- }
85
- }
86
- </style>
@@ -1,23 +0,0 @@
1
- //https://github.com/Podcastindex-org/podcast-namespace/blob/main/chapters/jsonChapters.md
2
- export interface Chaptering {
3
- version: string;
4
- chapters: Array<Chapter>;
5
- }
6
-
7
- export interface Chapter{
8
- startTime: number;
9
- title: string;
10
- img?: string;
11
- url?:string
12
- }
13
-
14
- export interface ChapterPercent {
15
- startTime: number;
16
- startDisplay: string;
17
- startPercent: number;
18
- endPercent: number;
19
- title: string;
20
- }
21
-
22
-
23
- export type ChapteringPercent = Array<ChapterPercent>;