@saooti/octopus-sdk 41.9.3 → 41.9.5
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/CHANGELOG.md +25 -0
- package/index.ts +1 -1
- package/package.json +1 -1
- package/src/api/transcriptionApi.ts +1 -1
- package/src/components/composable/useDayjs.ts +9 -0
- package/src/components/composable/useTranslation.ts +3 -6
- package/src/components/display/playlist/PodcastPlaylistInlineList.vue +0 -1
- package/src/components/display/podcasts/PodcastItemInfo.vue +7 -38
- package/src/components/display/podcasts/PodcastPlayButton.vue +17 -12
- package/src/components/display/podcasts/PodcastSeasonInfo.vue +45 -0
- package/src/components/display/sharing/SubscribeButtons.vue +75 -17
- package/src/components/misc/ProgressBar.vue +14 -12
- package/src/components/misc/player/PlayerCompact.vue +8 -4
- package/src/components/misc/player/PlayerLarge.vue +8 -4
- package/src/components/misc/player/elements/PlayerTitle.vue +6 -3
- package/src/components/pages/HomePage.vue +1 -0
- package/src/stores/PlayerStore.ts +2 -1
- package/src/stores/class/general/emission.ts +4 -0
- package/src/style/_variables.scss +6 -0
- package/src/style/general.scss +1 -1
- package/tests/components/composable/useTranslation.spec.ts +20 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 41.9.5 (17/04/2026)
|
|
4
|
+
|
|
5
|
+
**Fixes**
|
|
6
|
+
|
|
7
|
+
- **14433** - Correction problème lecture vidéo
|
|
8
|
+
|
|
9
|
+
## 41.9.4 (16/04/2026)
|
|
10
|
+
|
|
11
|
+
**Features**
|
|
12
|
+
|
|
13
|
+
- Ajout fonction de formattage de date dans `useDayjs`
|
|
14
|
+
- Ajout props de configuration pour `SubscribeButtons`
|
|
15
|
+
- Ajout de définition de nouvelles annotations d'émission
|
|
16
|
+
- Ajout de variables CSS pour la configuration de l'aspect du player
|
|
17
|
+
|
|
18
|
+
**Fixes**
|
|
19
|
+
|
|
20
|
+
- **14433** - Rétablissement bouton play vidéo
|
|
21
|
+
- **14442** - Correction anomalie calcul langues
|
|
22
|
+
- **14445** - Correction appel génération transcription
|
|
23
|
+
|
|
24
|
+
**Misc**
|
|
25
|
+
|
|
26
|
+
- Mise à jour dépendances avec vulnérabilités
|
|
27
|
+
|
|
3
28
|
## 41.9.3 (10/04/2026)
|
|
4
29
|
|
|
5
30
|
**Features**
|
package/index.ts
CHANGED
|
@@ -71,7 +71,7 @@ export const getShareAnonymous = () => import("./src/components/display/sharing/
|
|
|
71
71
|
export const getShareNewsletter = () => import("./src/components/display/sharing/ShareNewsletter.vue");
|
|
72
72
|
export const getQrCode = () => import("./src/components/display/sharing/QrCode.vue");
|
|
73
73
|
export const SubscribeButtons = defineAsyncComponent(() => import("./src/components/display/sharing/SubscribeButtons.vue"));
|
|
74
|
-
|
|
74
|
+
export const PodcastSeasonInfo = defineAsyncComponent(() => import("./src/components/display/podcasts/PodcastSeasonInfo.vue"));
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
export const getEmissionInlineList = () => import("./src/components/display/emission/EmissionInlineList.vue");
|
package/package.json
CHANGED
|
@@ -108,7 +108,7 @@ async function getRawTranscription(podcastId: number): Promise<string> {
|
|
|
108
108
|
* @param params Transcription parameters
|
|
109
109
|
*/
|
|
110
110
|
async function generateTranscription(podcastId: number, language: string, params: ModifyPodcastConfig): Promise<void> {
|
|
111
|
-
await classicApi.
|
|
111
|
+
await classicApi.postData({
|
|
112
112
|
api: ModuleApi.SPEECHTOTEXT,
|
|
113
113
|
path: `convert/${language}/${podcastId}`,
|
|
114
114
|
dataToSend: params
|
|
@@ -13,6 +13,8 @@ dayjs.extend(duration);
|
|
|
13
13
|
import localizedFormat from "dayjs/plugin/localizedFormat";
|
|
14
14
|
dayjs.extend(localizedFormat);
|
|
15
15
|
|
|
16
|
+
import { state } from "../../stores/ParamSdkStore";
|
|
17
|
+
|
|
16
18
|
export const useDayjs = () => {
|
|
17
19
|
const { locale } = useI18n();
|
|
18
20
|
|
|
@@ -21,7 +23,14 @@ export const useDayjs = () => {
|
|
|
21
23
|
}
|
|
22
24
|
composableDayjs.duration = dayjs.duration;
|
|
23
25
|
|
|
26
|
+
function formatDate(param: string|number|Date|Dayjs, forceTime?: boolean): string {
|
|
27
|
+
const withTime = forceTime ?? state.generalParameters.showTimeWithDates === true;
|
|
28
|
+
const format = withTime ? 'D MMMM YYYY - HH:mm' : 'D MMMM YYYY';
|
|
29
|
+
return composableDayjs(param).format(format);
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
return {
|
|
33
|
+
formatDate,
|
|
25
34
|
dayjs: composableDayjs
|
|
26
35
|
}
|
|
27
36
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { getLanguage } from "../../helper/language";
|
|
2
2
|
import { transcriptionApi, TranslationState, type PodcastTranslationData } from "../../api/transcriptionApi";
|
|
3
|
-
import { useAuthStore } from "../../stores/AuthStore";
|
|
4
3
|
import { CreateTranslation, defaultTranslationConfig, TranslationConfiguration } from "../../stores/class/transcript/transcriptParams";
|
|
5
4
|
import { podcastApi } from "../../api/podcastApi";
|
|
6
5
|
import { Emission } from "../../stores/class/general/emission";
|
|
@@ -22,8 +21,6 @@ enum Availability {
|
|
|
22
21
|
|
|
23
22
|
export const useTranslation = () => {
|
|
24
23
|
|
|
25
|
-
const authStore = useAuthStore();
|
|
26
|
-
|
|
27
24
|
/**
|
|
28
25
|
* Convert SRT data to plain text
|
|
29
26
|
* @param srt The data to convert
|
|
@@ -70,9 +67,9 @@ export const useTranslation = () => {
|
|
|
70
67
|
* @param emission *(optional)* If set, will also check in emission settings
|
|
71
68
|
* @returns Whether the language is available or not
|
|
72
69
|
*/
|
|
73
|
-
function getTranslationConfig(language: string, emission
|
|
74
|
-
const orgAttributes =
|
|
75
|
-
const emissionTranslation = parseOrDefault(emission?.annotations['translation-config'] as string|undefined, true);
|
|
70
|
+
function getTranslationConfig(language: string, emission: Emission): CreateTranslation {
|
|
71
|
+
const orgAttributes = emission.orga.attributes;
|
|
72
|
+
const emissionTranslation = parseOrDefault(emission?.annotations?.['translation-config'] as string|undefined, true);
|
|
76
73
|
const orgTranslation = parseOrDefault(orgAttributes?.['translation-config']);
|
|
77
74
|
|
|
78
75
|
return getConfigurationFor(language, emissionTranslation, orgTranslation);
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
</template>
|
|
31
31
|
|
|
32
32
|
<script setup lang="ts">
|
|
33
|
-
import classicApi from "../../../api/classicApi";
|
|
34
33
|
import PodcastInlineListTemplate from "../podcasts/PodcastInlineListTemplate.vue";
|
|
35
34
|
import PodcastItem from "../podcasts/PodcastItem.vue";
|
|
36
35
|
import SwiperList from "../list/SwiperList.vue";
|
|
@@ -5,17 +5,7 @@
|
|
|
5
5
|
{{ date }}
|
|
6
6
|
</time>
|
|
7
7
|
|
|
8
|
-
<
|
|
9
|
-
{{ formatSeason(podcast) }}
|
|
10
|
-
<BullhornIcon
|
|
11
|
-
v-if="podcast.seasonEpisodeType === PodcastType.TRAILER"
|
|
12
|
-
:title="$t('Podcast type - Trailer')"
|
|
13
|
-
/>
|
|
14
|
-
<GiftIcon
|
|
15
|
-
v-if="podcast.seasonEpisodeType === PodcastType.BONUS"
|
|
16
|
-
:title="$t('Podcast type - Bonus')"
|
|
17
|
-
/>
|
|
18
|
-
</div>
|
|
8
|
+
<PodcastSeasonInfo :podcast="podcast" />
|
|
19
9
|
</div>
|
|
20
10
|
|
|
21
11
|
<router-link
|
|
@@ -61,12 +51,10 @@
|
|
|
61
51
|
import AnimatorsItem from "./AnimatorsItem.vue";
|
|
62
52
|
import {useOrgaComputed} from "../../composable/useOrgaComputed";
|
|
63
53
|
import { computed, defineAsyncComponent } from "vue";
|
|
64
|
-
import { Podcast
|
|
54
|
+
import { Podcast } from "../../../stores/class/general/podcast";
|
|
65
55
|
import { state } from "../../../stores/ParamSdkStore";
|
|
66
56
|
import { useI18n } from "vue-i18n";
|
|
67
|
-
import
|
|
68
|
-
import BullhornIcon from 'vue-material-design-icons/Bullhorn.vue';
|
|
69
|
-
import GiftIcon from 'vue-material-design-icons/Gift.vue';
|
|
57
|
+
import PodcastSeasonInfo from "./PodcastSeasonInfo.vue";
|
|
70
58
|
import { useDayjs } from "../../composable/useDayjs";
|
|
71
59
|
const PodcastPlayBar = defineAsyncComponent(
|
|
72
60
|
() => import("./PodcastPlayBar.vue"),
|
|
@@ -80,16 +68,12 @@ const props = defineProps({
|
|
|
80
68
|
//Composables
|
|
81
69
|
const { t } = useI18n();
|
|
82
70
|
const { isPodcastmaker } = useOrgaComputed();
|
|
83
|
-
const { formatSeason } = useSeasonsManagement();
|
|
84
|
-
const { dayjs } = useDayjs();
|
|
85
71
|
|
|
86
72
|
//Computed
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
return dayjs(props.podcast.pubDate).format(format);
|
|
73
|
+
const { formatDate } = useDayjs();
|
|
74
|
+
|
|
75
|
+
const date = computed((): string => {
|
|
76
|
+
return formatDate(props.podcast.pubDate);
|
|
93
77
|
});
|
|
94
78
|
|
|
95
79
|
const orgaNameDisplay = computed(() =>{
|
|
@@ -120,19 +104,4 @@ const orgaNameDisplay = computed(() =>{
|
|
|
120
104
|
display: flex;
|
|
121
105
|
justify-content: space-between;
|
|
122
106
|
}
|
|
123
|
-
|
|
124
|
-
.podcast-item-season {
|
|
125
|
-
display: flex;
|
|
126
|
-
--icon-size: 0.8rem;
|
|
127
|
-
|
|
128
|
-
.material-design-icon {
|
|
129
|
-
position: relative;
|
|
130
|
-
top: -3px;
|
|
131
|
-
margin-left: 4px;
|
|
132
|
-
|
|
133
|
-
width: var(--icon-size);
|
|
134
|
-
height: var(--icon-size);
|
|
135
|
-
color: var(--octopus-primary);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
107
|
</style>
|
|
@@ -91,7 +91,7 @@ import CancelIcon from "vue-material-design-icons/Cancel.vue";
|
|
|
91
91
|
import AlertIcon from "vue-material-design-icons/Alert.vue";
|
|
92
92
|
import DurationHelper from "../../../helper/durationHelper";
|
|
93
93
|
import { state } from "../../../stores/ParamSdkStore";
|
|
94
|
-
import { Podcast, PodcastProcessingStatus as ProcessingStatus } from "../../../stores/class/general/podcast";
|
|
94
|
+
import { Podcast, PodcastProcessingStatus as ProcessingStatus, SimplifiedPodcast } from "../../../stores/class/general/podcast";
|
|
95
95
|
import { Conference } from "@/stores/class/conference/conference";
|
|
96
96
|
import { usePlayerStore } from "../../../stores/PlayerStore";
|
|
97
97
|
import { computed, defineAsyncComponent, ref } from "vue";
|
|
@@ -100,13 +100,13 @@ import duration from "dayjs/plugin/duration";
|
|
|
100
100
|
import { useI18n } from "vue-i18n";
|
|
101
101
|
import { useRouter } from "vue-router";
|
|
102
102
|
import { useResizePhone } from "../../composable/useResizePhone";
|
|
103
|
+
import { podcastApi } from "../../../api/podcastApi";
|
|
103
104
|
dayjs.extend(duration);
|
|
104
105
|
const PodcastIsPlaying = defineAsyncComponent(() => import("./PodcastIsPlaying.vue"));
|
|
105
106
|
|
|
106
|
-
|
|
107
107
|
//Props
|
|
108
108
|
const props = defineProps({
|
|
109
|
-
podcast: { default: () => ({}), type: Object as () => Podcast },
|
|
109
|
+
podcast: { default: () => ({}), type: Object as () => Podcast|SimplifiedPodcast },
|
|
110
110
|
hidePlay: { default: false, type: Boolean },
|
|
111
111
|
fetchConference: { default: undefined, type: Object as () => Conference },
|
|
112
112
|
justButtons: { default: false, type: Boolean },
|
|
@@ -129,7 +129,8 @@ const isVideoPodcast = computed(() => {
|
|
|
129
129
|
return (
|
|
130
130
|
(props.fetchConference?.videoProfile?.includes("video_") &&
|
|
131
131
|
ProcessingStatus.ReadyToRecord === props.podcast.processingStatus) ||
|
|
132
|
-
undefined !== props.podcast.video?.videoId
|
|
132
|
+
('video' in props.podcast && undefined !== props.podcast.video?.videoId) ||
|
|
133
|
+
('videoId' in props.podcast && undefined !== props.podcast.videoId)
|
|
133
134
|
);
|
|
134
135
|
});
|
|
135
136
|
const playingLive = computed(() => {
|
|
@@ -276,7 +277,7 @@ const durationIso = computed(() => {
|
|
|
276
277
|
});
|
|
277
278
|
|
|
278
279
|
//Methods
|
|
279
|
-
function play(isVideo: boolean): void {
|
|
280
|
+
async function play(isVideo: boolean): Promise<void> {
|
|
280
281
|
if (isLiveToBeRecorded.value) {
|
|
281
282
|
return;
|
|
282
283
|
}
|
|
@@ -288,18 +289,22 @@ function play(isVideo: boolean): void {
|
|
|
288
289
|
router.push("/main/pub/video/" + props.podcast.podcastId);
|
|
289
290
|
return;
|
|
290
291
|
}
|
|
292
|
+
|
|
293
|
+
let podcast: Podcast|SimplifiedPodcast = props.podcast;
|
|
294
|
+
if (isVideo && !('video' in props.podcast)) {
|
|
295
|
+
podcast = await podcastApi.get(props.podcast.podcastId);
|
|
296
|
+
}
|
|
297
|
+
|
|
291
298
|
if (!recordingLive.value) {
|
|
292
|
-
playerStore.playerPlay(
|
|
299
|
+
playerStore.playerPlay(podcast, isVideo);
|
|
293
300
|
} else {
|
|
294
301
|
playerStore.playerPlay(
|
|
295
302
|
{
|
|
296
|
-
...
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
hlsIdentifier: props.fetchConference?.hlsIdentifier,
|
|
300
|
-
},
|
|
303
|
+
...podcast,
|
|
304
|
+
conferenceId: props.fetchConference?.conferenceId,
|
|
305
|
+
hlsIdentifier: props.fetchConference?.hlsIdentifier,
|
|
301
306
|
},
|
|
302
|
-
isVideo
|
|
307
|
+
isVideo
|
|
303
308
|
);
|
|
304
309
|
}
|
|
305
310
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span class="podcast-item-season">
|
|
3
|
+
{{ formatSeason(podcast) }}
|
|
4
|
+
<BullhornIcon
|
|
5
|
+
v-if="podcast.seasonEpisodeType === PodcastType.TRAILER"
|
|
6
|
+
:title="$t('Podcast type - Trailer')"
|
|
7
|
+
/>
|
|
8
|
+
<GiftIcon
|
|
9
|
+
v-if="podcast.seasonEpisodeType === PodcastType.BONUS"
|
|
10
|
+
:title="$t('Podcast type - Bonus')"
|
|
11
|
+
/>
|
|
12
|
+
</span>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import { Podcast, PodcastType } from "../../../stores/class/general/podcast";
|
|
17
|
+
import BullhornIcon from 'vue-material-design-icons/Bullhorn.vue';
|
|
18
|
+
import GiftIcon from 'vue-material-design-icons/Gift.vue';
|
|
19
|
+
import { useSeasonsManagement } from "../../composable/useSeasonsManagement";
|
|
20
|
+
|
|
21
|
+
const { podcast } = defineProps<{
|
|
22
|
+
/** Podcast for which to display info */
|
|
23
|
+
podcast: Podcast;
|
|
24
|
+
}>();
|
|
25
|
+
|
|
26
|
+
const { formatSeason } = useSeasonsManagement();
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<style scoped lang="scss">
|
|
30
|
+
.podcast-item-season {
|
|
31
|
+
display: inline-flex;
|
|
32
|
+
align-items: center;
|
|
33
|
+
--icon-size: 0.8rem;
|
|
34
|
+
|
|
35
|
+
.material-design-icon {
|
|
36
|
+
//position: relative;
|
|
37
|
+
//top: -3px;
|
|
38
|
+
margin-left: 4px;
|
|
39
|
+
|
|
40
|
+
width: var(--icon-size);
|
|
41
|
+
height: var(--icon-size);
|
|
42
|
+
color: var(--octopus-primary);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
</style>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
<div
|
|
3
3
|
v-if="subscriptionsDisplay.length || rssUrl"
|
|
4
4
|
class="subscribe-buttons-container"
|
|
5
|
+
:class="{ 'justify-center': justifyCenter }"
|
|
5
6
|
>
|
|
6
7
|
<div ref="subscribeButtonsContainer">
|
|
7
8
|
<a
|
|
@@ -10,28 +11,34 @@
|
|
|
10
11
|
:key="sub.name"
|
|
11
12
|
rel="noreferrer noopener"
|
|
12
13
|
target="_blank"
|
|
13
|
-
:class="
|
|
14
|
-
0 === index
|
|
15
|
-
subscriptionsDisplay.length - 1 === index
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
:class="{
|
|
15
|
+
first: 0 === index,
|
|
16
|
+
last: subscriptionsDisplay.length - 1 === index,
|
|
17
|
+
mono,
|
|
18
|
+
small
|
|
19
|
+
}"
|
|
20
|
+
class="btn share-btn"
|
|
18
21
|
:href="sub.url"
|
|
19
22
|
:title="t('New window', {text: sub.title})"
|
|
20
23
|
>
|
|
21
|
-
<component :is="sub.icon" :fill-color="sub
|
|
24
|
+
<component :is="sub.icon" :fill-color="fillColor(sub)" :size="iconSize" />
|
|
22
25
|
</a>
|
|
23
26
|
</div>
|
|
24
27
|
<a
|
|
28
|
+
v-if="!noRss"
|
|
25
29
|
id="rss-suscribe-button"
|
|
26
30
|
rel="noreferrer noopener"
|
|
27
31
|
target="_blank"
|
|
28
|
-
class="btn share-btn
|
|
32
|
+
class="btn share-btn"
|
|
33
|
+
:class="{ mono, small }"
|
|
29
34
|
:href="rssUrl"
|
|
30
35
|
:title="t('New window', {text: t('Rss feed')})"
|
|
31
36
|
>
|
|
32
|
-
<RssIcon />
|
|
37
|
+
<RssIcon :fill-color="fillColor()" :size="iconSize" />
|
|
33
38
|
</a>
|
|
39
|
+
|
|
34
40
|
<button
|
|
41
|
+
v-if="limit === undefined"
|
|
35
42
|
v-show="hiddenLinks.length"
|
|
36
43
|
id="subscribe-buttons-dropdown"
|
|
37
44
|
class="btn share-btn mx-2"
|
|
@@ -54,7 +61,11 @@
|
|
|
54
61
|
:href="link.url"
|
|
55
62
|
:title="t('New window', {text: link.title})"
|
|
56
63
|
>
|
|
57
|
-
<component
|
|
64
|
+
<component
|
|
65
|
+
:is="link.icon"
|
|
66
|
+
:fill-color="fillColor(link)"
|
|
67
|
+
class="me-1"
|
|
68
|
+
/>
|
|
58
69
|
{{ link.title }}
|
|
59
70
|
</a>
|
|
60
71
|
</ClassicPopover>
|
|
@@ -71,6 +82,7 @@ import { type Component, computed, onMounted, Ref, ref, useTemplateRef, watch }
|
|
|
71
82
|
import { useI18n } from "vue-i18n";
|
|
72
83
|
import { Playlist } from "@/stores/class/general/playlist";
|
|
73
84
|
import { useSharePlatforms } from "../../composable/share/useSharePlatforms";
|
|
85
|
+
|
|
74
86
|
type Link = {
|
|
75
87
|
name: string;
|
|
76
88
|
icon: Component;
|
|
@@ -84,9 +96,21 @@ const props = withDefaults(defineProps<{
|
|
|
84
96
|
content: Emission|Playlist;
|
|
85
97
|
windowWidth?: number;
|
|
86
98
|
justifyCenter?: boolean;
|
|
99
|
+
/** Display the icons with just the octopus primary color */
|
|
100
|
+
mono?: boolean;
|
|
101
|
+
/** If set, limit the number of icons (will not display plus button) */
|
|
102
|
+
limit?: number;
|
|
103
|
+
/** Disable the RSS icon */
|
|
104
|
+
noRss?: boolean;
|
|
105
|
+
/** Smaller icons */
|
|
106
|
+
small?: boolean;
|
|
87
107
|
}>(), {
|
|
88
108
|
windowWidth: 0,
|
|
89
|
-
justifyCenter: true
|
|
109
|
+
justifyCenter: true,
|
|
110
|
+
mono: false,
|
|
111
|
+
limit: undefined,
|
|
112
|
+
noRss: false,
|
|
113
|
+
small: false
|
|
90
114
|
});
|
|
91
115
|
|
|
92
116
|
//Data
|
|
@@ -116,18 +140,22 @@ const rssUrl = computed(() => {
|
|
|
116
140
|
return undefined;
|
|
117
141
|
});
|
|
118
142
|
|
|
143
|
+
const iconSize = computed((): number => {
|
|
144
|
+
return props.small ? 20 : 24;
|
|
145
|
+
});
|
|
119
146
|
|
|
120
147
|
//Watch
|
|
121
148
|
watch(()=>props.windowWidth, () =>resizeWindow());
|
|
122
149
|
|
|
123
150
|
onMounted(()=>resizeWindow());
|
|
124
151
|
|
|
125
|
-
|
|
126
152
|
//Methods
|
|
127
153
|
function showAllElements() {
|
|
128
154
|
subscriptionsDisplay.value.forEach((element: Link) => {
|
|
129
155
|
const el = subscribeButtonsContainerRef?.value?.querySelector('#subLink' + element.name);
|
|
130
|
-
if (!el)
|
|
156
|
+
if (!el) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
131
159
|
if (el.classList.contains("hid")) {
|
|
132
160
|
el.classList.remove("hid");
|
|
133
161
|
}
|
|
@@ -135,9 +163,11 @@ function showAllElements() {
|
|
|
135
163
|
}
|
|
136
164
|
function hideOnlyNecessaryElements() {
|
|
137
165
|
let parentWidth = 0;
|
|
138
|
-
subscriptionsDisplay.value.forEach((element: Link) => {
|
|
166
|
+
subscriptionsDisplay.value.forEach((element: Link, index: number) => {
|
|
139
167
|
const el = subscribeButtonsContainerRef?.value?.querySelector('#subLink' + element.name);
|
|
140
|
-
if (!el)
|
|
168
|
+
if (!el) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
141
171
|
if (!parentWidth) {
|
|
142
172
|
const buttonMoreWidth = el.clientWidth + 20;
|
|
143
173
|
parentWidth =
|
|
@@ -145,7 +175,7 @@ function hideOnlyNecessaryElements() {
|
|
|
145
175
|
(el.parentElement?.offsetLeft ?? 0) -
|
|
146
176
|
buttonMoreWidth;
|
|
147
177
|
}
|
|
148
|
-
if (el.offsetLeft + el.clientWidth + 20 < parentWidth) {
|
|
178
|
+
if (el.offsetLeft + el.clientWidth + 20 < parentWidth && (props.limit === undefined || index < props.limit)) {
|
|
149
179
|
return;
|
|
150
180
|
}
|
|
151
181
|
hiddenLinks.value.push(element);
|
|
@@ -178,15 +208,27 @@ function resizeWindow() {
|
|
|
178
208
|
}
|
|
179
209
|
subscribeList.style.flexGrow = "0";
|
|
180
210
|
}
|
|
211
|
+
|
|
212
|
+
function fillColor(link?: Link): string|undefined {
|
|
213
|
+
if (props.mono === true) {
|
|
214
|
+
return 'white';
|
|
215
|
+
} else {
|
|
216
|
+
return link?.color;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
181
219
|
</script>
|
|
182
|
-
|
|
220
|
+
|
|
221
|
+
<style scoped lang="scss">
|
|
183
222
|
.octopus-app {
|
|
184
223
|
.subscribe-buttons-container {
|
|
185
224
|
max-width: 420px;
|
|
186
225
|
align-self: center;
|
|
187
226
|
display: inline-flex;
|
|
188
227
|
width: 100%;
|
|
189
|
-
|
|
228
|
+
|
|
229
|
+
&.justify-center {
|
|
230
|
+
justify-content: center;
|
|
231
|
+
}
|
|
190
232
|
|
|
191
233
|
& > div {
|
|
192
234
|
display: inline-flex;
|
|
@@ -200,4 +242,20 @@ function resizeWindow() {
|
|
|
200
242
|
}
|
|
201
243
|
}
|
|
202
244
|
}
|
|
245
|
+
|
|
246
|
+
.share-btn {
|
|
247
|
+
margin-right: .5rem;
|
|
248
|
+
margin-left: .5rem;
|
|
249
|
+
|
|
250
|
+
&.mono {
|
|
251
|
+
background-color: var(--octopus-primary);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
&.small {
|
|
255
|
+
height: 1.8rem !important;
|
|
256
|
+
width: 1.8rem !important;
|
|
257
|
+
margin-right: .2rem;
|
|
258
|
+
margin-left: .2rem;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
203
261
|
</style>
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
/>
|
|
27
27
|
</template>
|
|
28
28
|
<div
|
|
29
|
-
class="octopus-progress-bar
|
|
29
|
+
class="octopus-progress-bar current-progress"
|
|
30
30
|
aria-valuenow="0"
|
|
31
31
|
aria-valuemin="0"
|
|
32
32
|
aria-valuemax="100"
|
|
@@ -135,15 +135,16 @@ function timeMediaToPercent(value: number | null): number {
|
|
|
135
135
|
}
|
|
136
136
|
</script>
|
|
137
137
|
|
|
138
|
-
<style lang="scss">
|
|
138
|
+
<style scoped lang="scss">
|
|
139
139
|
.octopus-app{
|
|
140
140
|
.octopus-progress{
|
|
141
141
|
display: flex;
|
|
142
142
|
overflow: hidden;
|
|
143
|
-
background-color:var(--octopus-
|
|
143
|
+
background-color: var(--octopus-player-progress-background-color);
|
|
144
144
|
border-radius: var(--octopus-border-radius);
|
|
145
145
|
position: relative;
|
|
146
146
|
cursor: pointer;
|
|
147
|
+
|
|
147
148
|
.octopus-progress-bar{
|
|
148
149
|
position: absolute;
|
|
149
150
|
display: flex;
|
|
@@ -154,6 +155,7 @@ function timeMediaToPercent(value: number | null): number {
|
|
|
154
155
|
text-align: center;
|
|
155
156
|
white-space: nowrap;
|
|
156
157
|
background-color: var(--octopus-primary);
|
|
158
|
+
background-color: var(--octopus-player-progress-color-current);
|
|
157
159
|
transition: width 0.6s ease;
|
|
158
160
|
}
|
|
159
161
|
|
|
@@ -205,16 +207,16 @@ function timeMediaToPercent(value: number | null): number {
|
|
|
205
207
|
}
|
|
206
208
|
|
|
207
209
|
.player-container {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
210
|
+
.octopus-small-popover {
|
|
211
|
+
font-size: 0.7rem;
|
|
212
|
+
background: var(--octopus-player-color);
|
|
213
|
+
color: white;
|
|
214
|
+
border: 0;
|
|
215
|
+
|
|
216
|
+
.p-2 {
|
|
217
|
+
padding: 0.2rem !important;
|
|
218
|
+
}
|
|
216
219
|
}
|
|
217
220
|
}
|
|
218
221
|
}
|
|
219
|
-
}
|
|
220
222
|
</style>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="d-flex align-items-center flex-grow-1 ps-2">
|
|
3
3
|
<PlayerImage />
|
|
4
4
|
<PlayerPlayButton :player-error="playerError" />
|
|
5
|
-
<div class="text
|
|
5
|
+
<div class="player-text player-grow-content">
|
|
6
6
|
<div class="d-flex" :class="!radioUrl ? 'mb-1' : ''">
|
|
7
7
|
<PlayerTitle :player-error="playerError" :hls-ready="hlsReady" />
|
|
8
8
|
<div
|
|
@@ -25,14 +25,14 @@
|
|
|
25
25
|
<button
|
|
26
26
|
id="player-up-btn"
|
|
27
27
|
:title="'' != transcriptText ? t('View transcript') : t('Enlarge')"
|
|
28
|
-
class="btn play-button-box btn-transparent text
|
|
28
|
+
class="btn play-button-box btn-transparent player-text me-0"
|
|
29
29
|
@click="changePlayerLargeVersion"
|
|
30
30
|
>
|
|
31
31
|
<ChevronUpIcon />
|
|
32
32
|
</button>
|
|
33
33
|
<button
|
|
34
34
|
:title="t('Close')"
|
|
35
|
-
class="btn play-button-box btn-transparent text
|
|
35
|
+
class="btn play-button-box btn-transparent player-text"
|
|
36
36
|
@click="stopPlayer"
|
|
37
37
|
>
|
|
38
38
|
<WindowCloseIcon />
|
|
@@ -87,7 +87,7 @@ function changePlayerLargeVersion() {
|
|
|
87
87
|
}
|
|
88
88
|
</script>
|
|
89
89
|
|
|
90
|
-
<style lang="scss">
|
|
90
|
+
<style scoped lang="scss">
|
|
91
91
|
.octopus-app .player-grow-content {
|
|
92
92
|
display: flex;
|
|
93
93
|
flex-direction: column;
|
|
@@ -97,4 +97,8 @@ function changePlayerLargeVersion() {
|
|
|
97
97
|
font-size: 0.8rem;
|
|
98
98
|
padding: 0 0.5rem;
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
.player-text {
|
|
102
|
+
color: var(--octopus-player-text-color);
|
|
103
|
+
}
|
|
100
104
|
</style>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
class="d-flex flex-column align-items-center my-2 flex-grow-1 text
|
|
3
|
+
class="d-flex flex-column align-items-center my-2 flex-grow-1 player-text position-relative overflow-y-auto"
|
|
4
4
|
>
|
|
5
5
|
<button
|
|
6
6
|
:title="t('Reduce')"
|
|
7
|
-
class="player-reduce-button btn bg-transparent text
|
|
7
|
+
class="player-reduce-button btn bg-transparent player-text"
|
|
8
8
|
@click="changePlayerLargeVersion"
|
|
9
9
|
>
|
|
10
10
|
<ChevronDownIcon :size="40" />
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
<div class="d-flex align-items-center flex-grow-1">
|
|
65
65
|
<button
|
|
66
66
|
title="-15''"
|
|
67
|
-
class="btn bg-transparent text
|
|
67
|
+
class="btn bg-transparent player-text"
|
|
68
68
|
:disabled="isAdPlaying"
|
|
69
69
|
@click="seekClick(-15)"
|
|
70
70
|
>
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
|
|
75
75
|
<button
|
|
76
76
|
title="+15''"
|
|
77
|
-
class="btn bg-transparent text
|
|
77
|
+
class="btn bg-transparent player-text"
|
|
78
78
|
:disabled="isAdPlaying"
|
|
79
79
|
@click="seekClick(15)"
|
|
80
80
|
>
|
|
@@ -195,4 +195,8 @@ function seekClick(addTime: number): void {
|
|
|
195
195
|
background: var(--octopus-player-transcript-bg-color);
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
|
+
|
|
199
|
+
.player-text {
|
|
200
|
+
color: var(--octopus-player-text-color);
|
|
201
|
+
}
|
|
198
202
|
</style>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
</div>
|
|
5
5
|
<component
|
|
6
6
|
:is="vastStore.linkAdvertising ? 'a' : 'div'"
|
|
7
|
-
class="flex-grow-1 text-truncate
|
|
7
|
+
class="flex-grow-1 text-truncate"
|
|
8
8
|
:class="titleClass"
|
|
9
9
|
:href="vastStore.linkAdvertising"
|
|
10
10
|
rel="noreferrer noopener"
|
|
@@ -54,12 +54,15 @@ const podcastTitle = computed(() => {
|
|
|
54
54
|
if (playerStore.playerPodcast) {
|
|
55
55
|
return playerStore.playerPodcast.title;
|
|
56
56
|
}
|
|
57
|
-
if (playerStore.playerMedia)
|
|
57
|
+
if (playerStore.playerMedia) {
|
|
58
|
+
return playerStore.playerMedia.title;
|
|
59
|
+
}
|
|
58
60
|
if (playerStore.playerLive) {
|
|
59
|
-
if (!props.hlsReady)
|
|
61
|
+
if (!props.hlsReady) {
|
|
60
62
|
return (
|
|
61
63
|
playerStore.playerLive.title + " (" + t("Start in a while") + ")"
|
|
62
64
|
);
|
|
65
|
+
}
|
|
63
66
|
return playerStore.playerLive.title;
|
|
64
67
|
}
|
|
65
68
|
return "";
|
|
@@ -136,8 +136,9 @@ export const usePlayerStore = defineStore("PlayerStore", {
|
|
|
136
136
|
this.playerElapsed > 0 &&
|
|
137
137
|
this.playerTotal &&
|
|
138
138
|
this.playerTotal > 0
|
|
139
|
-
)
|
|
139
|
+
) {
|
|
140
140
|
return DurationHelper.formatDuration(Math.round(this.playerTotal));
|
|
141
|
+
}
|
|
141
142
|
return "--:--";
|
|
142
143
|
},
|
|
143
144
|
isPlaying(): boolean {
|
|
@@ -24,6 +24,10 @@ export interface Emission {
|
|
|
24
24
|
annotations?: Annotations & {
|
|
25
25
|
/** Subtitle of the emission */
|
|
26
26
|
subtitle?: string;
|
|
27
|
+
/** Default animators (ids separated by commas) for newly created podcasts */
|
|
28
|
+
podcastDefaultAnimators?: string;
|
|
29
|
+
/** Default description for newly created podcasts */
|
|
30
|
+
podcastDefaultDescription?: string;
|
|
27
31
|
};
|
|
28
32
|
beneficiaries: string[];
|
|
29
33
|
description: string;
|
|
@@ -46,6 +46,12 @@
|
|
|
46
46
|
// Player
|
|
47
47
|
// Color for the transcript background
|
|
48
48
|
--octopus-player-transcript-bg-color: oklch(from var(--octopus-player-color) calc(l + 0.1) c h);
|
|
49
|
+
// Color for the text
|
|
50
|
+
--octopus-player-text-color: oklch(98.16% 0.0017 247.84deg);
|
|
51
|
+
// Color for the progress bar
|
|
52
|
+
--octopus-player-progress-color-current: var(--octopus-primary);
|
|
53
|
+
// Color for the progress bar background
|
|
54
|
+
--octopus-player-progress-background-color: var(--octopus-secondary-lighter);
|
|
49
55
|
|
|
50
56
|
// Smartlink
|
|
51
57
|
--octopus-smartlink-title-color: var(--octopus-gray-text);
|
package/src/style/general.scss
CHANGED
|
@@ -2,9 +2,9 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
|
2
2
|
import { defineComponent } from 'vue';
|
|
3
3
|
import { mount as _mount } from '@vue/test-utils';
|
|
4
4
|
import { setupPinia } from '@tests/utils';
|
|
5
|
-
import { useAuthStore } from '@/stores/AuthStore';
|
|
6
5
|
import { CreateTranslation } from '@/stores/class/transcript/transcriptParams';
|
|
7
6
|
import { useTranslation } from '@/components/composable/useTranslation';
|
|
7
|
+
import type { Emission } from '@/stores/class/general/emission';
|
|
8
8
|
|
|
9
9
|
vi.mock('@/api/transcriptionApi', () => ({
|
|
10
10
|
transcriptionApi: {
|
|
@@ -15,7 +15,7 @@ vi.mock('@/api/transcriptionApi', () => ({
|
|
|
15
15
|
|
|
16
16
|
vi.mock('@/api/podcastApi', () => ({
|
|
17
17
|
podcastApi: {
|
|
18
|
-
get: vi.fn()
|
|
18
|
+
get: vi.fn(),
|
|
19
19
|
},
|
|
20
20
|
}));
|
|
21
21
|
|
|
@@ -31,15 +31,26 @@ function makeTranslationData(overrides: Partial<PodcastTranslationData> = {}): P
|
|
|
31
31
|
return { podcastId: 1, nativeLanguage: 'fr', translations: [], ...overrides };
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
function makeEmission(orgConfig?: object): Emission {
|
|
35
|
+
return {
|
|
36
|
+
emissionId: 0,
|
|
37
|
+
name: '',
|
|
38
|
+
description: '',
|
|
39
|
+
orga: {
|
|
38
40
|
id: 'test-org',
|
|
39
41
|
imageUrl: '',
|
|
40
|
-
|
|
42
|
+
name: 'Test Org',
|
|
43
|
+
attributes: orgConfig ? { 'translation-config': JSON.stringify(orgConfig) } : undefined,
|
|
41
44
|
},
|
|
42
|
-
|
|
45
|
+
beneficiaries: [],
|
|
46
|
+
rubriqueIds: [],
|
|
47
|
+
monetisable: 'UNDEFINED',
|
|
48
|
+
seasonMode: 'NO_SEASON' as never,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function setOrgTranslationConfig(config: object) {
|
|
53
|
+
vi.mocked(podcastApi.get).mockResolvedValue({ emission: makeEmission(config) } as never);
|
|
43
54
|
}
|
|
44
55
|
|
|
45
56
|
describe('useTranslation', () => {
|
|
@@ -48,7 +59,7 @@ describe('useTranslation', () => {
|
|
|
48
59
|
beforeEach(() => {
|
|
49
60
|
vi.clearAllMocks();
|
|
50
61
|
vi.mocked(transcriptionApi.getTranslation).mockResolvedValue('srt content');
|
|
51
|
-
vi.mocked(podcastApi.get).mockResolvedValue({ emission:
|
|
62
|
+
vi.mocked(podcastApi.get).mockResolvedValue({ emission: makeEmission() } as never);
|
|
52
63
|
vi.mocked(getLanguage).mockReturnValue('fr');
|
|
53
64
|
|
|
54
65
|
let result!: ReturnType<typeof useTranslation>;
|