@saooti/octopus-sdk 38.0.22 → 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 +1 -1
- package/src/assets/general.scss +0 -1
- package/src/assets/progressbar.scss +0 -13
- package/src/components/display/sharing/ShareButtonsIntern.vue +2 -2
- package/src/components/misc/ClassicPopover.vue +3 -9
- package/src/components/misc/HomeDropdown.vue +2 -2
- package/src/components/misc/ProgressBar.vue +4 -54
- package/src/components/misc/player/PlayerCompact.vue +0 -3
- package/src/components/misc/player/PlayerComponent.vue +1 -18
- package/src/components/misc/player/PlayerLarge.vue +0 -3
- package/src/components/mixins/handle403.ts +1 -1
- package/src/components/mixins/player/playerLogicProgress.ts +1 -1
- package/src/components/pages/Error403Page.vue +1 -1
- package/src/components/pages/RadioPage.vue +1 -2
- package/src/helper/duration.ts +8 -6
- package/src/locale/de.ts +0 -1
- package/src/locale/en.ts +0 -1
- package/src/locale/es.ts +0 -1
- package/src/locale/fr.ts +0 -1
- package/src/locale/it.ts +0 -1
- package/src/locale/sl.ts +0 -1
- package/src/stores/ParamSdkStore.ts +11 -11
- package/src/stores/PlayerStore.ts +7 -43
- package/src/components/misc/player/ChapteringModal.vue +0 -95
- package/src/components/misc/player/PlayerChaptering.vue +0 -86
- package/src/stores/class/chaptering/chaptering.ts +0 -23
package/package.json
CHANGED
package/src/assets/general.scss
CHANGED
|
@@ -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
|
-
|
|
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="
|
|
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
|
-
|
|
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
|
-
|
|
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="/
|
|
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="/
|
|
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
|
|
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="
|
|
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 {
|
|
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="
|
|
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 + "/
|
|
13
|
+
window.location.href = window.location.origin + "/login";
|
|
14
14
|
} else {
|
|
15
15
|
this.$router.push({
|
|
16
16
|
path: "/main/pub/error",
|
|
@@ -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
|
);
|
package/src/helper/duration.ts
CHANGED
|
@@ -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
|
|
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 (
|
|
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
package/src/locale/en.ts
CHANGED
package/src/locale/es.ts
CHANGED
package/src/locale/fr.ts
CHANGED
package/src/locale/it.ts
CHANGED
package/src/locale/sl.ts
CHANGED
|
@@ -13,7 +13,7 @@ const state: ParamStore = {
|
|
|
13
13
|
isProduction: false,
|
|
14
14
|
isContribution: false,
|
|
15
15
|
isRadio: false,
|
|
16
|
-
ApiUri: "https://api.
|
|
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.
|
|
31
|
-
hlsUri: "https://hls.live.
|
|
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.
|
|
84
|
-
commentsUrl: "https://comments.
|
|
85
|
-
imageUrl: "https://imageproxy.
|
|
86
|
-
studioUrl: "https://studio.
|
|
87
|
-
playerUrl: "https://playerbeta.
|
|
88
|
-
speechToTextUrl: "https://speech2text.
|
|
89
|
-
radioUrl:"https://radio.
|
|
90
|
-
recoUrl: "https://reco.
|
|
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 "
|
|
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
|
-
|
|
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
|
-
|
|
152
|
-
}
|
|
153
|
-
if (param.podcastId) {
|
|
126
|
+
} else if (param.podcastId) {
|
|
154
127
|
this.playerPodcast = param;
|
|
155
|
-
|
|
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
|
-
|
|
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
|
|
161
|
+
playerUpdateElapsed(elapsed: number, total: number) {
|
|
196
162
|
this.playerElapsed = elapsed;
|
|
197
|
-
|
|
198
|
-
this.playerTotal = total;
|
|
199
|
-
}
|
|
163
|
+
this.playerTotal = total;
|
|
200
164
|
},
|
|
201
165
|
|
|
202
166
|
playerUpdateTranscript(transcript?: Transcript) {
|
|
@@ -1,95 +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"
|
|
13
|
-
:class="actualChapter === index ? 'chapter-selected':'border'"
|
|
14
|
-
@click="goToChapter(index)"
|
|
15
|
-
>
|
|
16
|
-
<div class="d-flex align-items-center me-auto">
|
|
17
|
-
<svg v-if="actualChapter === index" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-soundwave" viewBox="0 0 16 16">
|
|
18
|
-
<path fill-rule="evenodd" d="M8.5 2a.5.5 0 0 1 .5.5v11a.5.5 0 0 1-1 0v-11a.5.5 0 0 1 .5-.5m-2 2a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5m4 0a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5m-6 1.5A.5.5 0 0 1 5 6v4a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m8 0a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m-10 1A.5.5 0 0 1 3 7v2a.5.5 0 0 1-1 0V7a.5.5 0 0 1 .5-.5m12 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0V7a.5.5 0 0 1 .5-.5"/>
|
|
19
|
-
</svg>
|
|
20
|
-
<div v-else>{{ index + 1 }}</div>
|
|
21
|
-
<div class="ms-2">{{ "- " + chapter.title }}</div>
|
|
22
|
-
</div>
|
|
23
|
-
<div>{{ chapter.startDisplay }}</div>
|
|
24
|
-
</button>
|
|
25
|
-
</div>
|
|
26
|
-
</template>
|
|
27
|
-
<template #footer>
|
|
28
|
-
<button class="btn m-1" @click="closePopup">
|
|
29
|
-
{{ $t("Close") }}
|
|
30
|
-
</button>
|
|
31
|
-
</template>
|
|
32
|
-
</ClassicModal>
|
|
33
|
-
</template>
|
|
34
|
-
|
|
35
|
-
<script lang="ts">
|
|
36
|
-
import { usePlayerStore } from "@/stores/PlayerStore";
|
|
37
|
-
import { mapState, mapActions } from "pinia";
|
|
38
|
-
import ClassicModal from "../modal/ClassicModal.vue";
|
|
39
|
-
import { defineComponent } from "vue";
|
|
40
|
-
export default defineComponent({
|
|
41
|
-
name: "ChapteringModal",
|
|
42
|
-
components: {
|
|
43
|
-
ClassicModal,
|
|
44
|
-
},
|
|
45
|
-
props: {actualChapter: {default: -1, type: Number}},
|
|
46
|
-
emits: ["close"],
|
|
47
|
-
data() {
|
|
48
|
-
return {
|
|
49
|
-
audioPlayer: null as HTMLAudioElement | null,
|
|
50
|
-
};
|
|
51
|
-
},
|
|
52
|
-
computed: {
|
|
53
|
-
...mapState(usePlayerStore, [
|
|
54
|
-
"playerPodcast",
|
|
55
|
-
"playerLive",
|
|
56
|
-
"playerChapteringPercent",
|
|
57
|
-
"playerTotal",
|
|
58
|
-
"playerElapsed",
|
|
59
|
-
]),
|
|
60
|
-
},
|
|
61
|
-
created() {
|
|
62
|
-
this.audioPlayer = document.querySelector("#audio-player");
|
|
63
|
-
},
|
|
64
|
-
methods: {
|
|
65
|
-
...mapActions(usePlayerStore, [
|
|
66
|
-
"playerUpdateSeekTime",
|
|
67
|
-
"playerUpdateElapsed",
|
|
68
|
-
]),
|
|
69
|
-
closePopup(): void {
|
|
70
|
-
this.$emit("close");
|
|
71
|
-
},
|
|
72
|
-
goToChapter(index: number) {
|
|
73
|
-
if (!this.playerChapteringPercent || !this.audioPlayer) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const seekTime =
|
|
77
|
-
this.playerTotal *
|
|
78
|
-
(this.playerChapteringPercent[index].startPercent / 100);
|
|
79
|
-
this.playerUpdateSeekTime(seekTime);
|
|
80
|
-
if (0 === seekTime) {
|
|
81
|
-
this.playerUpdateElapsed(0);
|
|
82
|
-
}
|
|
83
|
-
this.audioPlayer.currentTime = seekTime;
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
</script>
|
|
88
|
-
<style lang="scss">
|
|
89
|
-
@import "@scss/_variables.scss";
|
|
90
|
-
.octopus-app {
|
|
91
|
-
.chapter-selected{
|
|
92
|
-
border: $octopus-primary-color 3px solid;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
</style>
|
|
@@ -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" :actual-chapter="actualIndex" />
|
|
13
|
-
</div>
|
|
14
|
-
<div v-else-if="playerChapteringPercent" 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: -1 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 = -1;
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
methods: {
|
|
74
|
-
isInChapter(val: number, chapter: ChapterPercent) {
|
|
75
|
-
return Math.floor(chapter.startPercent) <= val && val < Math.floor(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>;
|