@playpilot/tpi 8.23.0-beta.6 → 8.23.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": "@playpilot/tpi",
3
- "version": "8.23.0-beta.6",
3
+ "version": "8.23.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -4,4 +4,9 @@ export const SplitTest = {
4
4
  numberOfVariants: 2,
5
5
  variantNames: ['Separated', 'Inline'] as string[],
6
6
  },
7
+ Reels: {
8
+ key: 'reels',
9
+ numberOfVariants: 2,
10
+ variantNames: ['Default', 'Reel'] as string[],
11
+ },
7
12
  } as const
@@ -8,6 +8,8 @@ type SplitTest = {
8
8
  variantNames?: string[]
9
9
  }
10
10
 
11
+ export const sessionStoragePrefix = 'playpilot_split_test_'
12
+
11
13
  /**
12
14
  * Each split test uses a different split test identifier so a user can be part of one, multiple, or none, tests.
13
15
  * The identifier is saved on the window object so that it is consistent across this session.
@@ -20,10 +22,19 @@ export function getSplitTestIdentifier({ key }: SplitTest): number {
20
22
 
21
23
  if (!window.PlayPilotLinkInjections?.split_test_identifiers) window.PlayPilotLinkInjections.split_test_identifiers = {}
22
24
 
23
- const randomIdentifier = Math.random()
24
- window.PlayPilotLinkInjections.split_test_identifiers[key] = randomIdentifier
25
+ let storedIdentifier = sessionStorage.getItem(sessionStoragePrefix + key)
26
+
27
+ if (!storedIdentifier) {
28
+ const randomIdentifier = Math.random().toString()
29
+ sessionStorage.setItem(sessionStoragePrefix + key, randomIdentifier)
30
+ storedIdentifier = randomIdentifier
31
+ }
32
+
33
+ const parsed = parseFloat(storedIdentifier!)
34
+
35
+ window.PlayPilotLinkInjections.split_test_identifiers[key] = parsed
25
36
 
26
- return randomIdentifier
37
+ return parsed
27
38
  }
28
39
 
29
40
  export function getSplitTestVariantIndex(test: SplitTest): number {
@@ -1,7 +1,9 @@
1
1
  <script lang="ts">
2
2
  import { fetchSimilarTitles, fetchTitleBySid } from '$lib/api/titles'
3
3
  import { mobileBreakpoint } from '$lib/constants'
4
+ import { SplitTest } from '$lib/enums/SplitTest'
4
5
  import { openModal } from '$lib/modal'
6
+ import { getSplitTestVariantName, trackSplitTestView } from '$lib/splitTest'
5
7
  import type { TitleData } from '$lib/types/title'
6
8
 
7
9
  interface Props {
@@ -15,10 +17,15 @@
15
17
  async function openModalViaRoute(): Promise<void> {
16
18
  const currentUrl = new URL(document.location.toString())
17
19
  const sid = currentUrl.searchParams.get('sid')
18
- const type = window.innerWidth > mobileBreakpoint ? 'titles-rail' : 'titles-reel'
19
20
 
20
21
  if (!sid) return
21
22
 
23
+ const isMobile = window.innerWidth < mobileBreakpoint
24
+ const isInReelSplitTest = isMobile && getSplitTestVariantName(SplitTest.Reels) === 'Reel'
25
+ const type = isMobile && isInReelSplitTest ? 'titles-reel' : 'titles-rail'
26
+
27
+ if (isMobile) trackSplitTestView(SplitTest.Reels)
28
+
22
29
  try {
23
30
  const [title, railTitles] = (await Promise.allSettled([
24
31
  fetchTitleBySid(sid),
@@ -49,7 +49,7 @@
49
49
  <Modal>
50
50
  {#snippet dialog()}
51
51
  <div class="slider">
52
- <TinySlider vertical threshold={100} moveThreshold={10} onchange={pauseAndPlay}>
52
+ <TinySlider vertical threshold={50} moveThreshold={10} onchange={pauseAndPlay}>
53
53
  {#snippet children({ currentIndex, setIndex })}
54
54
  {#each titles as title, index}
55
55
  <!-- svelte-ignore a11y_click_events_have_key_events -->
@@ -64,7 +64,9 @@
64
64
  </div>
65
65
 
66
66
  <div class="details">
67
- <Description text={title.description!} blurb={title.blurb} limit={80} />
67
+ {#if title.description}
68
+ <Description text={title.description} blurb={title.blurb} limit={80} />
69
+ {/if}
68
70
 
69
71
  <div class="playlinks-heading" use:heading={3}>{t('Where To Stream Online')}</div>
70
72
 
@@ -97,7 +99,7 @@
97
99
 
98
100
  <style lang="scss">
99
101
  $modal-height: calc(100vh - margin(4.5));
100
- $item-height: calc($modal-height - margin(7));
102
+ $item-height: calc($modal-height - margin(5));
101
103
 
102
104
  .reel {
103
105
  --playpilot-detail-background-height: #{$item-height};
@@ -153,13 +155,14 @@
153
155
  }
154
156
 
155
157
  .header {
156
- position: relative;
157
158
  z-index: 2;
158
- padding: theme(reel-item-padding, margin(2));
159
+ position: relative;
160
+ padding: theme(reel-item-padding, margin(1) margin(2) margin(2));
159
161
  font-size: theme(reel-header-font-size, font-size-small);
160
162
  }
161
163
 
162
164
  .heading {
165
+ padding-right: margin(1.5);
163
166
  margin-bottom: margin(0.5);
164
167
  color: theme(detail-title-text-color, text-color);
165
168
  font-family: theme(detail-title-font-family, inherit);
@@ -173,8 +176,20 @@
173
176
  z-index: 1;
174
177
  position: relative;
175
178
  padding: theme(reel-item-padding, margin(2));
176
- background: linear-gradient(to bottom, transparent, theme(detail-background, light) 4rem);
177
179
  font-size: theme(detail-font-size, font-size-base);
180
+
181
+ &::before {
182
+ z-index: -1;
183
+ content: "";
184
+ display: block;
185
+ position: absolute;
186
+ top: 0;
187
+ right: 0;
188
+ bottom: 0;
189
+ left: 0;
190
+ background: linear-gradient(to bottom, transparent, theme(detail-background, light) 4rem);
191
+ opacity: 0.85;
192
+ }
178
193
  }
179
194
 
180
195
  .playlinks-heading {
@@ -11,12 +11,13 @@
11
11
  captions?: boolean
12
12
  autoplay?: boolean
13
13
  showMuteControls?: boolean
14
+ fallbackStartTime?: number
14
15
  }
15
16
 
16
- const { embeddable_url = '', controls = [], muted = false, loop = false, captions = false, autoplay = true, showMuteControls = false }: Props = $props()
17
+ const { embeddable_url = '', controls = [], muted = false, loop = false, captions = false, autoplay = true, showMuteControls = false, fallbackStartTime = 0 }: Props = $props()
17
18
 
18
19
  const videoId = $derived(getVideoId(embeddable_url))
19
- const startTime = $derived((window?.PlayPilotLinkInjections?.video_playtimes?.[videoId || ''] || 1) - 1)
20
+ const startTime = $derived((window?.PlayPilotLinkInjections?.video_playtimes?.[videoId || ''] || (fallbackStartTime + 1)) - 1)
20
21
  const color = window?.getComputedStyle(document.body).getPropertyValue('--playpilot-primary')?.replace('#', '') || 'fa548a'
21
22
 
22
23
  let iframe: HTMLIFrameElement | null = $state(null)
@@ -15,7 +15,7 @@
15
15
  </script>
16
16
 
17
17
  <div class="video-background" style="--height: {height}px; --width: {clientWidth}px;" bind:clientWidth bind:clientHeight data-testid="video-background">
18
- <YouTubeEmbed {embeddable_url} {autoplay} muted loop showMuteControls />
18
+ <YouTubeEmbed {embeddable_url} {autoplay} fallbackStartTime={5} muted loop showMuteControls />
19
19
  </div>
20
20
 
21
21
  <style lang="scss">
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, vi, afterEach } from 'vitest'
2
- import { getSplitTestIdentifier, getSplitTestVariantIndex, getSplitTestVariantName, isInSplitTestVariant, trackSplitTestAction, trackSplitTestView } from '$lib/splitTest'
2
+ import { getSplitTestIdentifier, getSplitTestVariantIndex, getSplitTestVariantName, isInSplitTestVariant, sessionStoragePrefix, trackSplitTestAction, trackSplitTestView } from '$lib/splitTest'
3
3
  import { track } from '$lib/tracking'
4
4
  import { TrackingEvent } from '$lib/enums/TrackingEvent'
5
5
  import { hasConsentedTo } from '$lib/consent'
@@ -28,7 +28,6 @@ describe('$lib/splitTest', () => {
28
28
  })
29
29
 
30
30
  describe('getSplitTestIdentifier', () => {
31
-
32
31
  it('Should set window object with given key if window object was not set to begin with', () => {
33
32
  // @ts-ignore
34
33
  window.PlayPilotLinkInjections = {}
@@ -66,6 +65,18 @@ describe('$lib/splitTest', () => {
66
65
 
67
66
  expect(getSplitTestIdentifier(splitTest)).toBe(0)
68
67
  })
68
+
69
+ it('Should store value in sessionStorage', () => {
70
+ getSplitTestIdentifier(splitTest)
71
+
72
+ expect(sessionStorage.getItem(sessionStoragePrefix + splitTest.key)).toBeTruthy()
73
+ })
74
+
75
+ it('Should use value stored in sessionStorage', () => {
76
+ sessionStorage.setItem(sessionStoragePrefix + splitTest.key, '0.2')
77
+
78
+ expect(getSplitTestIdentifier(splitTest)).toBe(0.2)
79
+ })
69
80
  })
70
81
 
71
82
  describe('isInSplitTestVariant', () => {
@@ -46,6 +46,12 @@ describe('YouTubeEmbed.svelte', () => {
46
46
  expect(/** @type {HTMLIFrameElement} */ (container.querySelector('iframe')).src).toContain('&autoplay=false')
47
47
  })
48
48
 
49
+ it('Should start at given fallbackStartTime', () => {
50
+ const { container } = render(YouTubeEmbed, { embeddable_url: 'youtube.com/watch?v=abc', fallbackStartTime: 8 })
51
+
52
+ expect(/** @type {HTMLIFrameElement} */ (container.querySelector('iframe')).src).toContain('&start_time=8')
53
+ })
54
+
49
55
  it('Should render error message if embeddable_url is invalid', () => {
50
56
  const { container, getByText } = render(YouTubeEmbed, { embeddable_url: '-' })
51
57
 
@@ -8,6 +8,6 @@ describe('YouTubeEmbedBackground.svelte', () => {
8
8
  const { container } = render(YouTubeEmbedBackground, { embeddable_url: 'youtube.com/watch?v=abc' })
9
9
 
10
10
  // @ts-ignore
11
- expect(container.querySelector('iframe').src).toBe('https://video.playpilot.net/?video_id=abc&color=fa548a&muted=true&loop=true&captions=false&controls=&start_time=0&autoplay=true&playsinline=true')
11
+ expect(container.querySelector('iframe').src).toBe('https://video.playpilot.net/?video_id=abc&color=fa548a&muted=true&loop=true&captions=false&controls=&start_time=5&autoplay=true&playsinline=true')
12
12
  })
13
13
  })