@playpilot/tpi 6.0.0-beta.explore.24 → 6.0.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": "6.0.0-beta.explore.24",
3
+ "version": "6.0.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -7,11 +7,6 @@ const cookieName = 'EncryptedToken'
7
7
  const urlParam = 'articleReplacementEditToken'
8
8
  const editorialParam = 'playpilot-editorial-mode'
9
9
 
10
- /**
11
- * Authorize the user
12
- * @param href The current window.location.href
13
- * @returns Whether the user is authorized or not
14
- */
15
10
  export async function authorize(href: string = window.location.href): Promise<boolean> {
16
11
  try {
17
12
  const apiToken = getApiToken()
@@ -41,11 +36,6 @@ export async function authorize(href: string = window.location.href): Promise<bo
41
36
  return false
42
37
  }
43
38
 
44
- /**
45
- * Get the auth token from the URL, a stored cookie, or from the window object
46
- * @param [href] URL that the param is extracted from
47
- * @returns Auth token
48
- */
49
39
  export function getAuthToken(href: string = ''): string {
50
40
  // @ts-ignore
51
41
  const configToken = window?.PlayPilotLinkInjections?.editorial_token
@@ -60,10 +50,6 @@ export function getAuthToken(href: string = ''): string {
60
50
  return cookieToken || ''
61
51
  }
62
52
 
63
- /**
64
- * Set auth cookie equal to given value
65
- * @param value The auth token value
66
- */
67
53
  function setAuthCookie(value: string): void {
68
54
  const time = new Date()
69
55
  const days = 30
@@ -78,10 +64,6 @@ export function removeAuthCookie(): void {
78
64
  document.cookie = cookieName + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/'
79
65
  }
80
66
 
81
- /**
82
- * Returns whether or not the user has requested editorial mode to be enabled.
83
- * This won't enable editorial mode by itself, as that also requires authentication.
84
- */
85
67
  export function isEditorialModeEnabled(): boolean {
86
68
  const windowToken = window?.PlayPilotLinkInjections?.editorial_token
87
69
  return new URLSearchParams(window.location.search).get(editorialParam) === 'true' || !!windowToken
@@ -11,11 +11,6 @@ let pollTimeout: ReturnType<typeof setTimeout> | null = null
11
11
 
12
12
  /**
13
13
  * Fetch link injections for a URL. This will be either a POST or a GET request depending on whether on not the AI should run.
14
- * @param pageText Text content of the article
15
- * @param options
16
- * @param [options.url] URL of the given article
17
- * @param [options.hash] unique key to identify the HTML
18
- * @param [options.params] Any rest params to include in the request body
19
14
  */
20
15
  export async function fetchLinkInjections(
21
16
  pageText: string | null,
@@ -41,7 +36,6 @@ export async function fetchLinkInjections(
41
36
  params.metadata = getPageMetaData()
42
37
  }
43
38
 
44
- // Always add the given URL, this is used to match the article to the API record
45
39
  params.url = url
46
40
 
47
41
  response = await api<LinkInjectionResponse>(apiUrl, {
@@ -77,11 +71,6 @@ export async function pollLinkInjections(
77
71
  // This is mostly handy during HMR, but also during navigation changes
78
72
  if (pollTimeout) clearTimeout(pollTimeout)
79
73
 
80
- /**
81
- * Polls the endpoint recursively until it is ready.
82
- * @param resolve Injections are ready and returned as expected
83
- * @param reject Injections are not yet ready
84
- */
85
74
  const poll = async (resolve: Function, reject: Function): Promise<void> => {
86
75
  let response
87
76
  try {
@@ -134,7 +123,6 @@ export async function pollLinkInjections(
134
123
  export async function runAiBasedOnResponse(pageText: string, response: LinkInjectionResponse): Promise<LinkInjectionResponse> {
135
124
  if (!pageText) return response
136
125
  if (!response.ai_enabled) return response
137
- // Stop if ai is already running, no need to run it while it's already running
138
126
  if (response.ai_running) return response
139
127
 
140
128
  const currentModifiedTime = getPageMetaData().content_modified_time
@@ -149,7 +137,7 @@ export async function runAiBasedOnResponse(pageText: string, response: LinkInjec
149
137
  export async function saveLinkInjections(linkInjections: LinkInjection[], pageText: string): Promise<LinkInjection[]> {
150
138
  const selector = window.PlayPilotLinkInjections?.selector
151
139
 
152
- // Only save manual injections, AI injections should be left intact.
140
+ // Only save manual injections, AI injections should be left intact and can't be saved over
153
141
  const filteredLinkInjections = linkInjections.filter((i: LinkInjection) => i.manual)
154
142
 
155
143
  const newLinkInjections = filteredLinkInjections.map((linkInjection: LinkInjection) => ({
@@ -180,7 +168,7 @@ export async function saveLinkInjections(linkInjections: LinkInjection[], pageTe
180
168
  }
181
169
 
182
170
  /**
183
- * Insert random keys into link injections. These are used to identify the links on the page.
171
+ * These are used to identify the links on the page.
184
172
  * We can't just use SIDs, as a page might include multiple links of the same title
185
173
  */
186
174
  function insertRandomKeys(linkInjections: LinkInjection[]): LinkInjection[] {
@@ -2,9 +2,6 @@ import { getApiToken } from '$lib/token'
2
2
  import type { TitleData } from '../types/title'
3
3
  import { api } from './api'
4
4
 
5
- /**
6
- * Search for movies & shows. Requires valid API token.
7
- */
8
5
  export async function searchTitles(query: string): Promise<TitleData[]> {
9
6
  const apiToken = getApiToken()
10
7
 
@@ -73,17 +73,10 @@ export function isAllowedToEdit(responseSessionId: string | null, responseSessio
73
73
  return currentSessionId === responseSessionId
74
74
  }
75
75
 
76
- /**
77
- * The user's session id is stored in local storage. Of it is not present we generate a new id and store it,
78
- * returning it immediately.
79
- */
80
76
  export function getSessionId(): string {
81
77
  return sessionStorage.getItem(sessionKey) || setSessionId()
82
78
  }
83
79
 
84
- /**
85
- * Store a session id in local storage. If the id is already present in local storage we use that instead.
86
- */
87
80
  export function setSessionId(): string {
88
81
  const id = sessionStorage.getItem(sessionKey) || generateRandomHash()
89
82
  sessionStorage.setItem(sessionKey, id)
@@ -8,6 +8,11 @@ export async function fetchTitles(params: Record<string, string | number> = {}):
8
8
 
9
9
  if (!apiToken) throw new Error('No token was provided')
10
10
 
11
+ params = {
12
+ ...params,
13
+ include_count: 'false'
14
+ }
15
+
11
16
  const paramsAsString = Object.entries(params).map(([key, value]) => `${key}=${value}`).join('&')
12
17
  const response = await api<APIPaginatedResult<TitleData>>(`/titles/browse?api-token=${apiToken}&` + paramsAsString)
13
18
 
package/src/lib/array.ts CHANGED
@@ -1,8 +1,5 @@
1
1
  import type { Range } from './types/range'
2
2
 
3
- /**
4
- * Returns the largest number in an array of numbers. Returns 0 if the array has no entries.
5
- */
6
3
  export function getLargestValueInArray(array: number[]): number {
7
4
  let largest = 0
8
5
 
@@ -1,6 +1,3 @@
1
- /**
2
- * Detect whether the user is a bot or crawler simply by their user agent.
3
- */
4
1
  export function isCrawler(): boolean {
5
2
  const userAgent = navigator.userAgent.toLowerCase()
6
3
  return /bot|crawl|spider|google|baidu|bing|msn|teoma|slurp|yandex|facebookexternalhit|facebot/i.test(userAgent)
package/src/lib/event.ts CHANGED
@@ -1,6 +1,3 @@
1
- /**
2
- * Returns true when user performs event that should open a link in a new tab
3
- */
4
1
  export function isHoldingSpecialKey(event: MouseEvent): boolean {
5
2
  return event.ctrlKey || event.metaKey || event.button !== 0
6
3
  }
package/src/lib/html.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Returns a string with decoded html characters. For instance & -> &amp;
2
+ * For instance & -> &amp;
3
3
  */
4
4
  export function encodeHtmlEntities(string: string): string {
5
5
  const tempElement = document.createElement('div')
@@ -9,7 +9,7 @@ export function encodeHtmlEntities(string: string): string {
9
9
  }
10
10
 
11
11
  /**
12
- * Returns a string with encoded html characters. For instance &amp; -> &
12
+ * For instance &amp; -> &
13
13
  */
14
14
  export function decodeHtmlEntities(string: string): string {
15
15
  const tempElement = document.createElement('div')
package/src/lib/image.ts CHANGED
@@ -10,9 +10,6 @@ export function removeImageUrlPrefix(url: string | null): string | null {
10
10
  return url.replace('/src/img', '')
11
11
  }
12
12
 
13
- /**
14
- * Creates a CDN image URL from a UUID.
15
- */
16
13
  export function imageFromUUID(uuid: string | null, dimensions: (typeof ImageDimensions)[keyof typeof ImageDimensions] | null = null): string {
17
14
  if (!uuid?.length) return ''
18
15
 
@@ -420,9 +420,6 @@ function addLinkInjectionEventListeners(injections: LinkInjection[]): void {
420
420
  })
421
421
  }
422
422
 
423
- /**
424
- * Clear link injections from the page
425
- */
426
423
  export function clearLinkInjections(): void {
427
424
  const elements = document.querySelectorAll(keySelector)
428
425
  elements.forEach((element) => clearLinkInjection(element.getAttribute(keyDataAttribute) || ''))
@@ -464,16 +461,10 @@ export function removePlayPilotTitleLinks(): void {
464
461
  })
465
462
  }
466
463
 
467
- /**
468
- * Merge different injection types
469
- */
470
464
  export function mergeInjectionTypes({ aiInjections, manualInjections }: LinkInjectionTypes): LinkInjection[] {
471
465
  return [...manualInjections.map(i => ({ ...i, manual: true })), ...aiInjections]
472
466
  }
473
467
 
474
- /**
475
- * Separate an array of flat injections into ai and manual arrays.
476
- */
477
468
  export function separateLinkInjectionTypes(injections: LinkInjection[]): LinkInjectionTypes {
478
469
  return {
479
470
  aiInjections: injections.filter(i => !i.manual),
@@ -481,9 +472,6 @@ export function separateLinkInjectionTypes(injections: LinkInjection[]): LinkInj
481
472
  }
482
473
  }
483
474
 
484
- /**
485
- * Returns whether or not an injection would be valid for any sort of injection, text or after_article
486
- */
487
475
  export function isValidInjection(injection: LinkInjection): boolean {
488
476
  return !injection.inactive && !injection.removed && !injection.duplicate && !!injection.title_details && isValidPlaylinkType(injection)
489
477
  }
@@ -541,18 +529,12 @@ export function sortInjections(injections: LinkInjection[]): LinkInjection[] {
541
529
  })
542
530
  }
543
531
 
544
- /**
545
- * Return whether or not an injection is also available as manual injection
546
- */
547
532
  export function isAvailableAsManualInjection(injection: LinkInjection, injectionIndex: number, injections: LinkInjection[]): boolean {
548
533
  return injections.some((i, index) => {
549
534
  return injectionIndex !== index && i.manual && isEquivalentInjection(i, injection)
550
535
  })
551
536
  }
552
537
 
553
- /**
554
- * Returns whether or not 2 injections match in title and sentence
555
- */
556
538
  export function isEquivalentInjection(injection1: LinkInjection, injection2: LinkInjection): boolean {
557
539
  return injection1.title === injection2.title && cleanPhrase(injection1.sentence) === cleanPhrase(injection2.sentence)
558
540
  }
@@ -2,9 +2,6 @@ import { translations } from './data/translations'
2
2
  import { Language } from './enums/Language'
3
3
  import type { LanguageCode } from './types/language'
4
4
 
5
- /**
6
- * Super basic implementation to get a string for the given key and language
7
- */
8
5
  export function t(key: string, language: LanguageCode = getLanguage()): string {
9
6
  // @ts-ignore It's fine if it's undefined
10
7
  return translations[key]?.[language] || key
package/src/lib/meta.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import { getLinkInjectionsParentElement } from './injection'
2
2
  import type { ArticleMetaData } from './types/injection'
3
3
 
4
- /**
5
- * Returns meta data to be included with injections.
6
- */
7
4
  export function getPageMetaData(): ArticleMetaData {
8
5
  const parent = getLinkInjectionsParentElement()
9
6
 
@@ -62,9 +59,6 @@ export function getPagePublishedTime(parent: HTMLElement): string | null {
62
59
  return getDatetime(datetime)
63
60
  }
64
61
 
65
- /**
66
- * Get datetime string as ISO datetime string
67
- */
68
62
  export function getDatetime(datetime: string): string | null {
69
63
  try {
70
64
  return new Date(datetime).toISOString()
package/src/lib/modal.ts CHANGED
@@ -11,8 +11,6 @@ import { getPlayPilotWrapperElement, keyDataAttribute, keySelector } from "./inj
11
11
  import { playFallbackViewTransition } from "./viewTransition"
12
12
  import { destroyLinkPopover } from "./popover"
13
13
  import { prefersReducedMotion } from "svelte/motion"
14
- import { trackSplitTestAction } from "./splitTest"
15
- import { SplitTest } from "./enums/SplitTest"
16
14
 
17
15
  type ModalType = 'title' | 'participant' | 'explore'
18
16
 
@@ -47,9 +47,6 @@ export async function destroyLinkPopover(outro: boolean = true) {
47
47
  document.querySelectorAll<HTMLElement>('[data-playpilot-title-popover]').forEach(element => element.remove())
48
48
  }
49
49
 
50
- /**
51
- * Destroy active the popover when the mouse leaves any popover element
52
- */
53
50
  export function destroyLinkPopoverOnMouseleave(event: MouseEvent): void {
54
51
  if (!activePopoverInsertedComponent) return
55
52
 
package/src/lib/routes.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import { playPilotBaseUrl } from "./constants"
2
2
  import type { TitleData } from "./types/title"
3
3
 
4
- /**
5
- * @returns Full url to PlayPilot page for the given title
6
- */
7
4
  export function titleUrl(title: TitleData): string {
8
5
  return `${playPilotBaseUrl}/${title.type}/${title.slug}/`
9
6
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Get the index of the selection. The returned index will be exclusing any leading or trailing spaces. We contain it to actual phrases.
2
+ * The returned index will be exclusing any leading or trailing spaces. We contain it to actual phrases.
3
3
  */
4
4
  export function getIndexOfSelection(selection: Selection, node: Node | null = selection.anchorNode): { start: number, end: number } {
5
5
  if (!selection.anchorNode || !node) return { start: -1, end: -1 }
@@ -54,8 +54,7 @@ export function trackSplitTestView(test: SplitTest): void {
54
54
  }
55
55
 
56
56
  /**
57
- * @param action The given action for whatever the user is doing. This can be just about anything,
58
- * but will often be as simple as 'click'. Could be any string, though. Whatever fits the use case.
57
+ * @param action This can be just about anything, but will often be as simple as 'click'. Could be any string, though. Whatever fits the use case.
59
58
  */
60
59
  export function trackSplitTestAction(test: SplitTest, action: string): void {
61
60
  const variant = getSplitTestVariantName(test)
package/src/lib/text.ts CHANGED
@@ -20,9 +20,6 @@ export function findTextNodeContaining(text: string, element: HTMLElement, ignor
20
20
  return node
21
21
  }
22
22
 
23
- /**
24
- * Returns whether or not the node itself is a link or is inside of a link tag.
25
- */
26
23
  export function isNodeInLink(node: Node): boolean {
27
24
  const parentNode = node.parentNode as HTMLElement | null
28
25
 
@@ -55,9 +52,6 @@ export function replaceBetween(text: string, replacement: string, startIndex: nu
55
52
  return text.substring(0, startIndex) + replacement + text.substring(endIndex)
56
53
  }
57
54
 
58
- /**
59
- * Returns a string for most consistent string comparisons, decoding Html symbols and removing spaces.
60
- */
61
55
  export function cleanPhrase(phrase: string): string {
62
56
  return decodeHtmlEntities(phrase)
63
57
  .toLowerCase()
@@ -117,7 +111,7 @@ export function reverseString(string: string): string {
117
111
  }
118
112
 
119
113
  /**
120
- * Get the first x words in a string. Only returning full words, but can contain special characters like &, commas, period, etc.
114
+ * Only returns full words, but can contain special characters like &, commas, period, etc.
121
115
  */
122
116
  export function getFirstNumberOfWordsInString(sentence: string, numberOfWords = 1): string {
123
117
  const match = sentence.match(/[^\s]+/g)
@@ -190,10 +184,6 @@ export function getNumberOfLeadingAndTrailingSpaces(text: string): { leadingSpac
190
184
  }
191
185
  }
192
186
 
193
- /**
194
- * Get the index of a phrase inside of an element based on a specific word boundary. Returns either the first match
195
- * or the index of the given occurrence.
196
- */
197
187
  export function getIndexOfPhraseInElement(phrase: string, element: Element, occurrence = 0): number {
198
188
  const sentence = element.innerHTML
199
189
  const matches = []
@@ -239,7 +229,6 @@ export function getRangesOfTextNodesInElement(element: Element): Range[] {
239
229
  continue
240
230
  }
241
231
 
242
-
243
232
  // We are inside of an element and a qoute was given, signaling that we're either opening or closing and attribute.
244
233
  // We need to keep track of this in case an attribute value contains ">" or "<"
245
234
  if (isInsideElement && character === '"') isInsideAttribute = !isInsideAttribute
@@ -265,9 +254,6 @@ export function getRangesOfTextNodesInElement(element: Element): Range[] {
265
254
  return ranges
266
255
  }
267
256
 
268
- /**
269
- * Attempt to find a phrase inside a word boundary, only matching phrases between given characters.
270
- */
271
257
  export function getIndexOfPhraseInBoundary(phrase: string, text: string): number {
272
258
  const boundaryCharacters = [' ', '.', ',', '<', '>']
273
259
 
@@ -26,6 +26,7 @@ export async function track(event: string, title: TitleData | null = null, paylo
26
26
  if (title) {
27
27
  payload = {
28
28
  original_title: title.original_title,
29
+ title: title.title,
29
30
  title_sid: title.sid,
30
31
  title_type: title.type,
31
32
  providers: [...new Set(title.providers?.map(p => p.name) || [])],
@@ -35,8 +36,8 @@ export async function track(event: string, title: TitleData | null = null, paylo
35
36
 
36
37
  payload.version = __SCRIPT_VERSION__
37
38
  payload.url = getFullUrlPath()
38
- payload.organization_sid = window.PlayPilotLinkInjections?.organization_sid
39
- payload.domain_sid = window.PlayPilotLinkInjections?.domain_sid
39
+ payload.organization_sid = window.PlayPilotLinkInjections?.organization_sid || 'undefined'
40
+ payload.domain_sid = window.PlayPilotLinkInjections?.domain_sid || 'undefined'
40
41
  payload.device = {
41
42
  type: window.innerWidth > mobileBreakpoint ? 'desktop' : 'mobile',
42
43
  width: window.innerWidth,
@@ -46,9 +46,11 @@ export type ConfigResponse = {
46
46
  * `explore_navigation_label` will end up being the label of the navigation item, defaults to `Streaming Guide`.
47
47
  * `explore_navigation_path` is the path that the navigation item will lead to, this will be set up by the third party.
48
48
  * `explore_navigation_insert_position` is used to determine if the navigation item should be inserted before or after the given selector.
49
+ * `explore_insert_cta_in_tpi` is used to insert a call to action in modals which opens the explore page as a modal.
49
50
  */
50
51
  explore_navigation_selector?: string
51
52
  explore_navigation_label?: string
52
53
  explore_navigation_path?: string
53
54
  explore_navigation_insert_position?: InsertPosition
55
+ explore_insert_cta_in_tpi: boolean
54
56
  }
@@ -18,7 +18,7 @@ export type TitleData = {
18
18
  medium_poster: string
19
19
  standing_poster: string
20
20
  title: string
21
- original_title: string
21
+ original_title: string | null
22
22
  embeddable_url: string | null
23
23
  length?: number
24
24
  blurb?: string
package/src/main.ts CHANGED
@@ -47,7 +47,7 @@ window.PlayPilotLinkInjections = {
47
47
  this.domain_sid = options.domain_sid
48
48
  this.require_consent = options.require_consent
49
49
 
50
- if (!this.require_consent) {
50
+ if (this.require_consent === false) {
51
51
  setConsent({
52
52
  ads: true,
53
53
  pixels: true,
@@ -10,8 +10,6 @@
10
10
  import { fetchConfig } from '$lib/api/config'
11
11
  import { insertExplore, insertExploreIntoNavigation } from '$lib/explore'
12
12
  import { authorize, getAuthToken, isEditorialModeEnabled, removeAuthCookie, setEditorialParamInUrl } from '$lib/api/auth'
13
- import { getSplitTestVariantName } from '$lib/splitTest'
14
- import { SplitTest } from '$lib/enums/SplitTest'
15
13
  import type { LinkInjectionResponse, LinkInjection, LinkInjectionTypes } from '$lib/types/injection'
16
14
  import Editor from './components/Editorial/Editor.svelte'
17
15
  import EditorTrigger from './components/Editorial/EditorTrigger.svelte'
@@ -37,10 +35,8 @@
37
35
 
38
36
  const pageText = $derived(getPageText(elements))
39
37
 
40
- // Store initializing promise for later, we'll need that to be awaited after the user has given or refused consent.
41
38
  const initializePromise = initialize()
42
39
 
43
- // Rerender link injections when linkInjections change. This is only relevant for editiorial mode.
44
40
  $effect(() => {
45
41
  if (isEditorialMode && !loading) rerender()
46
42
  })
@@ -76,7 +72,6 @@
76
72
 
77
73
  window.PlayPilotLinkInjections.config = config
78
74
 
79
- // If the URL was marked as being excluded in the config, we stop injections here.
80
75
  isUrlExcluded = !!(config?.exclude_urls_pattern && url.match(new RegExp(config.exclude_urls_pattern)))
81
76
  if (isUrlExcluded) return
82
77
 
@@ -85,7 +80,7 @@
85
80
 
86
81
  setElements(config?.html_selector || '', config?.exclude_elements_selector || '')
87
82
  } catch(error) {
88
- // We also return if the config did not get fetched properly, as we can't determine what should and should
83
+ // We return if the config did not get fetched properly, as we can't determine what should and should
89
84
  // get injected without it.
90
85
  track(TrackingEvent.FetchingConfigFailed)
91
86
  console.error('TPI Config failed to fetch', error)
@@ -103,16 +98,11 @@
103
98
 
104
99
  setTrackingSids({ organizationSid: response.organization_sid, domainSid: response.domain_sid })
105
100
 
106
- // We only show results once they are fully processed. We only inject if AI is no longer running, or isn't
107
- // meant to run to begin with.
108
101
  if (!response.ai_running || !response.ai_enabled) {
109
102
  inject({ aiInjections, manualInjections })
110
103
  return
111
104
  }
112
105
 
113
- // A response was previous returned, but injections were still being generated in the backend.
114
- // With this second request we wait until AI links are ready. We only do this in editorial
115
- // so as not to suddenly insert new links while a user is reading the article.
116
106
  if (!isEditorialMode || isCrawler()) return
117
107
 
118
108
  response = await pollLinkInjections(pageText, { requireCompletedResult: true, onpoll: (update) => response = update })
@@ -137,8 +127,6 @@
137
127
  }
138
128
 
139
129
  function inject(injections: LinkInjectionTypes = { aiInjections, manualInjections }): void {
140
- // Get filtered injections as they are shown on the page.
141
- // Only update state if it they are different from current injections.
142
130
  const filteredInjections = injectLinksInDocument(elements, injections)
143
131
 
144
132
  if (JSON.stringify(filteredInjections) !== JSON.stringify(linkInjections)) {
@@ -1,6 +1,5 @@
1
1
  <script lang="ts">
2
2
  import { SplitTest } from '$lib/enums/SplitTest'
3
- import { insertExplore } from '$lib/explore'
4
3
  import { getFullUrlPath } from '$lib/url'
5
4
  import { onDestroy } from 'svelte'
6
5
 
@@ -85,6 +84,7 @@
85
84
  })
86
85
  }
87
86
 
87
+ // Replace the current script with the beta version of the script
88
88
  function replaceWithBetaScript() {
89
89
  const currentScriptTag: HTMLScriptElement | null = document.querySelector('script[src*="scripts.playpilot.com/link-injection"]')
90
90
  if (!currentScriptTag) return
@@ -108,43 +108,6 @@
108
108
  currentScriptTag.insertAdjacentElement('afterend', newScriptTag)
109
109
  currentScriptTag.remove()
110
110
  }
111
-
112
- function replacePageWithExplore() {
113
- const element = document.querySelector("main, article")
114
-
115
- element!.innerHTML = `
116
- <div data-playpilot-explore style="
117
- background: white;
118
- --playpilot-dark: white;
119
- --playpilot-light: white;
120
- --playpilot-lighter: #e1e1e1;
121
- --playpilot-content: #e5e5e5;
122
- --playpilot-content-light: #c1c1c1;
123
- --playpilot-text-color: black;
124
- --playpilot-text-color-alt: black;
125
- --playpilot-border-radius: 0;
126
- --playpilot-playlink-border-radius: 0;
127
- --playpilot-explore-search-border: 1px solid black;
128
- --playpilot-explore-search-background: white;
129
- --playpilot-explore-divider-height: 4px;
130
- --playpilot-explore-divider-background: linear-gradient(to right,#51B3E0,#51B3E0 2.5rem,#E5ADAE 2.5rem,#E5ADAE 5rem,#E5E54F 5rem,#E5E54F 7.5rem,black 7.5rem,black);">
131
- <div style="padding: 64px 32px; min-height: 100vh; color: black; max-width: 1264px; margin: 0 auto">
132
- <div class="divider" style="width: 100%; max-width: 600px; height: 0.25rem;background-image: var(--playpilot-explore-divider-background)"></div>
133
-
134
- <div class="heading" style="margin: 4px 0; font-size: clamp(24px, 5vw, 32px); line-height: 1.5; font-weight: bold; text-transform: uppercase;">
135
- Streaming Guide
136
- </div>
137
-
138
- <div role="status" aria-live="polite">
139
- <svg fill="currentColor" viewBox="0 0 24 24" width="72"><path fill="currentColor" d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"><animateTransform attributeName="transform" type="rotate" dur="500ms" values="0 12 12;360 12 12" repeatCount="indefinite"/></path></svg>
140
- <div style="margin: 12px 0; font-weight: bold; text-transform: uppercase;">Loading…</div>
141
- <noscript>Sorry, this page requires JavaScript to be enabled.</noscript>
142
- </div>
143
- </div>
144
- </div>`
145
-
146
- insertExplore()
147
- }
148
111
  </script>
149
112
 
150
113
  <svelte:window {onkeydown} />
@@ -201,14 +164,6 @@
201
164
  {:else}
202
165
  <button onclick={replaceWithBetaScript}>Use beta script</button>
203
166
  {/if}
204
-
205
- <hr />
206
-
207
- <button onclick={replacePageWithExplore}>Replace page with explore</button>
208
-
209
- <hr />
210
-
211
- <button onclick={() => shown = false}>Close debugger</button>
212
167
  </div>
213
168
  {/if}
214
169
 
@@ -21,7 +21,7 @@
21
21
  const items = [{
22
22
  label: 'Services',
23
23
  param: 'provider',
24
- data: [{ label: 'Apple TV', value: 'apple-TV' }, { label: 'Netflix', value: 'netflix' }, { label: 'Disney+', value: 'disney-plus' }, { label: 'Amazon Prime', value: 'prime-video' }, { label: 'HBO Max', value: 'max' }, { label: 'SkyShowtime', value: 'skyshowtime' }],
24
+ data: [{ label: 'Netflix', value: 'netflix' }, { label: 'Disney+', value: 'disney-plus' }],
25
25
  }, {
26
26
  label: 'Genres',
27
27
  param: 'genres',
@@ -43,7 +43,7 @@
43
43
 
44
44
  function onclick(event: MouseEvent, participant: ParticipantData): void {
45
45
  openModal({ event, type: 'participant', data: participant })
46
- track(TrackingEvent.ParticipantClick, null, { title_source: title.original_title, participant: participant.name })
46
+ track(TrackingEvent.ParticipantClick, null, { title_source: title.original_title || title.title, participant: participant.name })
47
47
  }
48
48
  </script>
49
49
 
@@ -15,4 +15,7 @@
15
15
  const titles = fetchSimilarTitles(title)
16
16
  </script>
17
17
 
18
- <TitlesRail {titles} heading={t('Similar Titles')} onclick={(targetTitle) => track(TrackingEvent.SimilarTitleClick, targetTitle, { title_source: title.original_title })} />
18
+ <TitlesRail
19
+ {titles}
20
+ heading={t('Similar Titles')}
21
+ onclick={(targetTitle) => track(TrackingEvent.SimilarTitleClick, targetTitle, { title_source: title.original_title || title.title })} />
@@ -19,6 +19,7 @@
19
19
 
20
20
  const topScrollAd = getFirstAdOfType('top_scroll')
21
21
  const displayAd = getFirstAdOfType('card')
22
+ const insertExploreCta = window.PlayPilotLinkInjections?.config?.explore_insert_cta_in_tpi
22
23
 
23
24
  let hasTrackedScrolling = false
24
25
 
@@ -52,6 +53,6 @@
52
53
  {/if}
53
54
  {/snippet}
54
55
 
55
- <Modal {onscroll} {initialScrollPosition} {bubble} prepend={displayAd ? prepend : null} tall>
56
+ <Modal {onscroll} {initialScrollPosition} bubble={!!topScrollAd || insertExploreCta ? bubble : null} prepend={displayAd ? prepend : null} tall>
56
57
  <Title {title} />
57
58
  </Modal>