@saooti/octopus-sdk 40.2.9 → 40.2.10

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": "40.2.9",
3
+ "version": "40.2.10",
4
4
  "private": false,
5
5
  "description": "Javascript SDK for using octopus",
6
6
  "author": "Saooti",
package/src/App.vue CHANGED
@@ -40,7 +40,7 @@ export default defineComponent({
40
40
  CategoryFilter,
41
41
  FooterOctopus,
42
42
  PlayerComponent,
43
- ClassicLazy,
43
+ ClassicLazy
44
44
  },
45
45
 
46
46
  setup(){
@@ -7,6 +7,7 @@
7
7
  <div>{{ $t("Advanced filters") }}</div>
8
8
  <ChevronDownIcon :class="{ 'arrow-transform': showFilters }" />
9
9
  </button>
10
+ <Transition name="advanced-search">
10
11
  <div
11
12
  v-if="firstLoaded"
12
13
  v-show="showFilters"
@@ -76,6 +77,7 @@
76
77
  @update:sort="updateSort"
77
78
  />
78
79
  </div>
80
+ </Transition>
79
81
  </div>
80
82
  </template>
81
83
 
@@ -282,12 +284,28 @@ export default defineComponent({
282
284
  background: var(--octopus-background);
283
285
  display: flex;
284
286
  width: 100%;
285
- margin-bottom: 1rem;
287
+ padding-bottom: 1rem;
286
288
  justify-content: space-around;
287
289
 
288
290
  @media (width <= 720px) {
289
291
  flex-wrap: wrap;
290
292
  }
291
293
  }
294
+
295
+ .advanced-search-enter-active,
296
+ .advanced-search-leave-active {
297
+ transition: 0.3s all;
298
+ opacity: 1;
299
+ max-height: 900px;
300
+ height: auto;
301
+ overflow: hidden;
302
+ }
303
+
304
+ .advanced-search-enter-from,
305
+ .advanced-search-leave-to {
306
+ opacity: 0;
307
+ max-height: 0;
308
+ overflow: hidden;
309
+ }
292
310
  }
293
311
  </style>
@@ -40,7 +40,7 @@
40
40
  <div v-if="isLiveReady" class="text-danger">
41
41
  {{ $t("Episode record in live") }}
42
42
  </div>
43
- <div class="d-flex flex-column align-items-end flex-grow-1">
43
+ <div class="d-flex flex-column align-items-end">
44
44
  <time :datetime="durationIso">
45
45
  {{ duration }}
46
46
  </time>
@@ -1,13 +1,13 @@
1
1
  <template>
2
2
  <div
3
- v-if="undefined !== tagList && 0 !== tagList.length"
3
+ v-if="undefined !== tagListFiltered && 0 !== tagListFiltered.length"
4
4
  class="tag-list-component d-flex align-items-center flex-wrap mb-3 small-text"
5
5
  >
6
6
  <div class="fw-bold me-3">
7
7
  {{ $t("Podcast tags") + " : " }}
8
8
  </div>
9
9
  <router-link
10
- v-for="(tag, index) in tagList"
10
+ v-for="(tag, index) in tagListFiltered"
11
11
  :key="tag"
12
12
  class="d-flex align-items-center border p-1 m-1 text-dark"
13
13
  :to="{
@@ -72,6 +72,11 @@ export default defineComponent({
72
72
  },
73
73
  computed: {
74
74
  ...mapState(useFilterStore, ["filterOrgaId"]),
75
+ tagListFiltered(): Array<string>{
76
+ return this.tagList.filter((tag: string) => {
77
+ return !tag.match(/^\[\[.*\]\]$/);
78
+ });
79
+ },
75
80
  organisationQuery(){
76
81
  if(this.filterOrgaId){
77
82
  return undefined;
@@ -25,7 +25,7 @@
25
25
  :margin="2"
26
26
  />
27
27
  <div class="d-flex align-items-center my-3">
28
- <FormatSwitch class="me-3" v-model:isSvg="isSvg"/>
28
+ <FormatSwitch v-model:is-svg="isSvg" class="me-3"/>
29
29
  <button class="btn btn-primary" @click="download">
30
30
  {{ $t("Download") }}
31
31
  </button>
@@ -4,7 +4,7 @@
4
4
  class="d-flex align-items-center justify-content-center"
5
5
  >
6
6
  <ClassicSpinner class="me-3" />
7
- <div class="h3 mt-2">
7
+ <div class="h3">
8
8
  {{ loadingText }}
9
9
  </div>
10
10
  </div>
@@ -1,5 +1,7 @@
1
1
  <template>
2
- <div class="octopus-spinner" :class="small ? 'small' : ''" />
2
+ <div class="octopus-spinner" :style="small ? '--size-spinner:1rem;' : ''" >
3
+ <div v-for="index of 12" :key="index"></div>
4
+ </div>
3
5
  </template>
4
6
 
5
7
  <script lang="ts">
@@ -13,7 +15,89 @@ export default defineComponent({
13
15
  </script>
14
16
  <style lang="scss">
15
17
  .octopus-app .octopus-spinner {
18
+
19
+ --size-spinner: 3rem;
20
+ --size-spinner-section: calc(var(--size-spinner) / 20);
21
+ --half-size-spinner: calc(var(--size-spinner) / 2);
22
+
23
+ color: #000000;
16
24
  display: inline-block;
25
+ position: relative;
26
+ width: var(--size-spinner);
27
+ height: var(--size-spinner);
28
+
29
+ div {
30
+ transform-origin: var(--half-size-spinner) var(--half-size-spinner);
31
+ animation: octopus-spinner 1.2s linear infinite;
32
+ }
33
+ div:after {
34
+ content: " ";
35
+ display: block;
36
+ position: absolute;
37
+ top: 3px;
38
+ left: calc(var(--half-size-spinner) - calc(var(--size-spinner-section) / 2));
39
+ width: var(--size-spinner-section);
40
+ height: calc(var(--half-size-spinner) / 3);
41
+ border-radius: 20%;
42
+ background: currentColor;
43
+ }
44
+ div:nth-child(1) {
45
+ transform: rotate(0deg);
46
+ animation-delay: -1.1s;
47
+ }
48
+ div:nth-child(2) {
49
+ transform: rotate(30deg);
50
+ animation-delay: -1s;
51
+ }
52
+ div:nth-child(3) {
53
+ transform: rotate(60deg);
54
+ animation-delay: -0.9s;
55
+ }
56
+ div:nth-child(4) {
57
+ transform: rotate(90deg);
58
+ animation-delay: -0.8s;
59
+ }
60
+ div:nth-child(5) {
61
+ transform: rotate(120deg);
62
+ animation-delay: -0.7s;
63
+ }
64
+ div:nth-child(6) {
65
+ transform: rotate(150deg);
66
+ animation-delay: -0.6s;
67
+ }
68
+ div:nth-child(7) {
69
+ transform: rotate(180deg);
70
+ animation-delay: -0.5s;
71
+ }
72
+ div:nth-child(8) {
73
+ transform: rotate(210deg);
74
+ animation-delay: -0.4s;
75
+ }
76
+ div:nth-child(9) {
77
+ transform: rotate(240deg);
78
+ animation-delay: -0.3s;
79
+ }
80
+ div:nth-child(10) {
81
+ transform: rotate(270deg);
82
+ animation-delay: -0.2s;
83
+ }
84
+ div:nth-child(11) {
85
+ transform: rotate(300deg);
86
+ animation-delay: -0.1s;
87
+ }
88
+ div:nth-child(12) {
89
+ transform: rotate(330deg);
90
+ animation-delay: 0s;
91
+ }
92
+ @keyframes octopus-spinner {
93
+ 0% {
94
+ opacity: 1;
95
+ }
96
+ 100% {
97
+ opacity: 0;
98
+ }
99
+ }
100
+ /* display: inline-block;
17
101
  width: 2rem;
18
102
  height: 2rem;
19
103
  border-radius: 50%;
@@ -31,6 +115,6 @@ export default defineComponent({
31
115
  to {
32
116
  transform: rotate(360deg);
33
117
  }
34
- }
118
+ } */
35
119
  }
36
120
  </style>
@@ -308,12 +308,15 @@ export default defineComponent({
308
308
  color: white;
309
309
  font-weight: bold;
310
310
  font-size: 0.93rem;
311
+ text-decoration: underline;
312
+ text-decoration-color: transparent;
313
+ transition: text-decoration-color 250ms;
314
+ text-underline-offset: 8px;
311
315
 
312
316
  &.link-hover:hover,
313
317
  &.link-hover.router-link-exact-active.router-link-active {
314
318
  color: white;
315
- text-decoration: underline;
316
- text-underline-offset: 8px;
319
+ text-decoration-color: white;
317
320
  }
318
321
  }
319
322
 
@@ -5,13 +5,15 @@
5
5
  <WindowCloseIcon />
6
6
  </button>
7
7
  <div class="video-wrapper">
8
- <PlayerVideoDigiteka v-if="!playerLive" :video-id="videoId" />
8
+ <PlayerYoutubeEmbed v-if="youtubeId" :youtube-id="youtubeId" />
9
+ <PlayerVideoDigiteka v-else-if="!playerLive" :video-id="playerPodcast?.video?.videoId" />
9
10
  <PlayerVideoHls v-else :hls-url="hlsVideoUrl" />
10
11
  </div>
11
12
  </template>
12
13
  </teleport>
13
14
  </template>
14
15
  <script lang="ts">
16
+ import youtubeVideoHelper from "../../../../helper/youtubeVideoHelper";
15
17
  import WindowCloseIcon from "vue-material-design-icons/WindowClose.vue";
16
18
  import { usePlayerStore } from "../../../../stores/PlayerStore";
17
19
  import { useApiStore } from "../../../../stores/ApiStore";
@@ -23,16 +25,22 @@ const PlayerVideoDigiteka = defineAsyncComponent(
23
25
  const PlayerVideoHls = defineAsyncComponent(
24
26
  () => import("../video/PlayerVideoHls.vue"),
25
27
  );
28
+ const PlayerYoutubeEmbed = defineAsyncComponent(
29
+ () => import("../video/PlayerYoutubeEmbed.vue"),
30
+ );
26
31
  export default defineComponent({
27
32
  name: "PlayerVideo",
28
33
 
29
34
  components: {
30
35
  PlayerVideoDigiteka,
31
36
  PlayerVideoHls,
37
+ PlayerYoutubeEmbed,
32
38
  WindowCloseIcon,
33
39
  },
34
40
  data() {
35
- return {};
41
+ return {
42
+ youtubeId: undefined as string|undefined,
43
+ };
36
44
  },
37
45
  computed: {
38
46
  ...mapState(useApiStore, ["hlsUrl"]),
@@ -43,9 +51,9 @@ export default defineComponent({
43
51
  }
44
52
  return `${this.hlsUrl}live/video_dev.${this.playerLive.conferenceId}/index.m3u8`;
45
53
  },
46
- videoId(): string | undefined {
47
- return this.playerPodcast?.video?.videoId;
48
- },
54
+ },
55
+ created(){
56
+ this.youtubeId = youtubeVideoHelper.getYoutubeId((this.playerPodcast ?? this.playerLive )?.tags ?? []);
49
57
  },
50
58
 
51
59
  methods: {
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <iframe
3
+ width="500"
4
+ height="281"
5
+ :title="$t('Video')"
6
+ class="youtube-iframe"
7
+ :src="'https://www.youtube.com/embed/'+youtubeId"
8
+ frameborder="0"
9
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
10
+ referrerpolicy="strict-origin-when-cross-origin"
11
+ allowfullscreen>
12
+ </iframe>
13
+ </template>
14
+
15
+ <script lang="ts">
16
+ import { defineComponent } from "vue";
17
+ export default defineComponent({
18
+ name: "PlayerYoutubeEmbed",
19
+ components: {
20
+ },
21
+ props: {
22
+ youtubeId: { default: undefined, type: String },
23
+ },
24
+
25
+ });
26
+ </script>
27
+ <style lang="scss">
28
+ @use "../../../../style/videoPlayer";
29
+ </style>
@@ -21,7 +21,7 @@
21
21
  :organisation-id="podcast.organisation.id"
22
22
  />
23
23
  <SharePlayer
24
- v-if="!isPodcastmaker && editRight"
24
+ v-if="!isPodcastmaker && editRight && !youtubeId"
25
25
  :podcast="podcast"
26
26
  :emission="podcast?.emission"
27
27
  :organisation-id="authOrgaId"
@@ -68,6 +68,7 @@
68
68
  </template>
69
69
 
70
70
  <script lang="ts">
71
+ import youtubeVideoHelper from "../../helper/youtubeVideoHelper";
71
72
  import {useOrgaComputed} from "../composable/useOrgaComputed";
72
73
  import PodcastInlineList from "../display/podcasts/PodcastInlineList.vue";
73
74
  import PodcastModuleBox from "../display/podcasts/PodcastModuleBox.vue";
@@ -135,6 +136,7 @@ export default defineComponent({
135
136
  error: false as boolean,
136
137
  fetchConference: undefined as Conference | undefined,
137
138
  infoReload: undefined as ReturnType<typeof setTimeout> | undefined,
139
+ youtubeId: undefined as string|undefined,
138
140
  };
139
141
  },
140
142
 
@@ -312,6 +314,9 @@ export default defineComponent({
312
314
  this.podcastInProcessing();
313
315
  this.updatePathParams(this.podcast.title);
314
316
  await this.getCommentsConfig(this.podcast);
317
+ if((this.fetchConference?.videoProfile?.includes("video_") && "READY_TO_RECORD" === this.podcast.processingStatus) || undefined !== this.podcast.video?.videoId){
318
+ this.youtubeId = youtubeVideoHelper.getYoutubeId(this.podcast?.tags ?? []);
319
+ }
315
320
  this.loaded = true;
316
321
  } catch (error) {
317
322
  this.handle403(error as AxiosError);
@@ -0,0 +1,13 @@
1
+ export default {
2
+ getYoutubeId(tags: Array<string>){
3
+ let youtubeId = undefined;
4
+ for(const tag of tags){
5
+ const regexExec = /^\[\[https:\/\/(?:www.)?youtube.com\/(?:watch\?v=|live\/)(?<id>\S+)\]\]$/.exec(tag);
6
+ if(regexExec?.groups?.id){
7
+ youtubeId = regexExec.groups.id;
8
+ break;
9
+ }
10
+ }
11
+ return youtubeId;
12
+ }
13
+ }
@@ -47,8 +47,8 @@
47
47
  }
48
48
 
49
49
  .img-box-podcast{
50
- height: calc(var(--octopus-podcast-size) - 4px);
51
- width: calc(var(--octopus-podcast-size) - 4px);
50
+ height: calc(var(--octopus-podcast-size) - 2px);
51
+ width: calc(var(--octopus-podcast-size) - 2px);
52
52
  }
53
53
 
54
54
  .img-box,.img-box.img-box-podcast{