-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Experiment/google ima csai ads #986
Draft
cjpillsbury
wants to merge
28
commits into
muxinc:main
Choose a base branch
from
cjpillsbury:experiment/google-ima-csai-ads
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,220
−27
Draft
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
4e33058
WIP mux-video + google ima
cjpillsbury 1bd74f4
example PLUS HACK IN ADTAGURL IN PLAYER TEMPLATE.
cjpillsbury f8868c6
ad basic api for ad break times.
cjpillsbury 91c8ab2
WIP add basic impl for ad tag url to mux-player (probably move to sep…
cjpillsbury ea0005e
first pass on type defs for google ima sdk.
cjpillsbury 7250184
more types cleanup and minor changes.
cjpillsbury d687d12
cleanup google ima types for external consumption and builds (e.g. mu…
cjpillsbury ec2dbc9
more typescriptrobatics.
cjpillsbury b159fff
chore: update vanilla example page title for google ima usage.
cjpillsbury 3530e02
try to see if this fixes silly template test fails.
cjpillsbury b84b95d
volume control for ads.
cjpillsbury d4f0676
basic autoplay and ready state for ads
cjpillsbury e010b3c
basic postroll impl
cjpillsbury c216fae
cleanup ad break code.
cjpillsbury aeaf3e9
ad state and various cleanups.
cjpillsbury 5be7a1d
prove out mux player ad-specific UI.
cjpillsbury 485a57a
update vanilla ads example to demo new UI.
cjpillsbury 0afd4b8
add resizing logic for IMA crud.
cjpillsbury 97fb80a
fix linting errors
cjpillsbury 237c08a
force exit pip on ad play.
cjpillsbury d3100e3
account for user active+inactive (NOTE: Needs followup for ad clicks).
cjpillsbury 6dc93b7
more acrobatics for different playback scenarios
cjpillsbury f12c90b
bug fix for ad counter.
cjpillsbury 7178556
minor cleanup
cjpillsbury 0182a54
for now no autohide of any controls during adbreak.
cjpillsbury 77241f8
general cleanup using more official APIs instead of data structures.
cjpillsbury 5d3d20b
minor improvements for ad state and state change events.
cjpillsbury 9b5bdc5
update example for preroll + MSE (iPhone problem case validation)
cjpillsbury File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<meta name="viewport" content="width=device-width" /> | ||
<title><mux-player> Google IMA CSAI example</title> | ||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.css" /> | ||
<link rel="stylesheet" href="./styles.css" /> | ||
<script type="module" src="./dist/mux-player.js"></script> | ||
<script type="text/javascript" src="https://imasdk.googleapis.com/js/sdkloader/ima3.js"></script> | ||
<style> | ||
mux-player { | ||
display: block; | ||
width: 100%; | ||
margin: 1rem 0 2rem; | ||
background-color: #000; | ||
} | ||
|
||
mux-player:not([audio]) { | ||
aspect-ratio: 16 / 9; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<header> | ||
<div class="left-header"> | ||
<a class="mux-logo" href="https://www.mux.com/player" target="_blank"> | ||
<picture> | ||
<source | ||
media="(prefers-color-scheme: dark)" | ||
srcset=" | ||
https://user-images.githubusercontent.com/360826/233653989-11cd8603-c20f-4008-8bf7-dc15b743c52b.svg | ||
" | ||
/> | ||
<source | ||
media="(prefers-color-scheme: light)" | ||
srcset=" | ||
https://user-images.githubusercontent.com/360826/233653583-50dda726-cbe7-4182-a113-059a91ae83e6.svg | ||
" | ||
/> | ||
<img | ||
alt="Mux Logo" | ||
src="https://user-images.githubusercontent.com/360826/233653583-50dda726-cbe7-4182-a113-059a91ae83e6.svg" | ||
/> | ||
</picture> | ||
</a> | ||
<h1><a href="/">Elements</a></h1> | ||
</div> | ||
<div class="right-header"> | ||
<a class="github-logo" href="https://github.com/muxinc/elements" target="_blank"> | ||
<img width="32" height="32" src="./images/github-logo.svg" alt="Github logo" /> | ||
</a> | ||
</div> | ||
</header> | ||
|
||
<!-- | ||
single preroll skippable | ||
adtagurl="https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=" | ||
|
||
VMAP - Pre-roll Single Ad, Mid-roll Standard Pod with 3 ads, Post-roll Single Ad | ||
adtagurl="https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostpod&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=" | ||
--> | ||
<mux-player | ||
id="muxPlayer" | ||
title="Big Buck Bunny" | ||
stream-type="on-demand" | ||
prefer-playback="mse" | ||
playback-id="VcmKA6aqzIzlg3MayLJDnbF55kX00mds028Z65QxvBYaA" | ||
muted | ||
adtagurl="https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=" | ||
></mux-player> | ||
|
||
<a href="../">Browse Elements</a> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
155 changes: 155 additions & 0 deletions
155
packages/mux-player/src/media-chrome/ads/media-ad-count-display.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import { MediaTextDisplay } from 'media-chrome/dist/media-text-display.js'; | ||
import { getNumericAttr, getStringAttr, setNumericAttr, setStringAttr } from 'media-chrome/dist/utils/element-utils.js'; | ||
import { globalThis } from 'media-chrome/dist/utils/server-safe-globals.js'; | ||
import { MediaUIAttributes as MediaUIAttributesBase } from 'media-chrome/dist/constants.js'; | ||
// import { nouns } from 'media-chrome/dist/labels/labels.js'; | ||
|
||
const MediaUIAttributes = { | ||
...MediaUIAttributesBase, | ||
MEDIA_AD_BREAK_TOTAL_ADS: 'mediaadbreaktotalads', | ||
MEDIA_AD_BREAK_AD_POSITION: 'mediaadbreakadposition', | ||
} as const; | ||
|
||
export const Attributes = { | ||
PREFIX: 'prefix', | ||
}; | ||
|
||
const CombinedAttributes = [ | ||
...Object.values(Attributes), | ||
MediaUIAttributes.MEDIA_AD_BREAK_TOTAL_ADS, | ||
MediaUIAttributes.MEDIA_AD_BREAK_AD_POSITION, | ||
]; | ||
|
||
// Todo: Use data locals: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString | ||
|
||
const DEFAULT_COUNT_SEP = 'of'; | ||
const DEFAULT_PREFIX = 'Advertisement'; | ||
|
||
const formatLabel = (el: MediaAdCountDisplay, { countSep = DEFAULT_COUNT_SEP } = {}): string => { | ||
const prefixPart = el.prefix ? `${el.prefix}: ` : ''; | ||
return `${prefixPart}${el.mediaAdBreakAdPosition} ${countSep} ${el.mediaAdBreakTotalAds}`; | ||
}; | ||
|
||
// const DEFAULT_MISSING_TIME_PHRASE = 'video not loaded, unknown time.'; | ||
|
||
const updateAriaValueText = (el: MediaAdCountDisplay): void => { | ||
const fullPhrase = formatLabel(el); | ||
el.setAttribute('aria-valuetext', fullPhrase); | ||
}; | ||
|
||
/** | ||
* @attr {string} prefix - the prefix string for the display. 'Advertisement' by default. | ||
* @attr {number} mediaadbreaktotalads - (read-only) total number of ads in the current ad break | ||
* @attr {number} mediaadbreakadposition - (read-only) current ad index playing in the current ad break | ||
*/ | ||
class MediaAdCountDisplay extends MediaTextDisplay { | ||
#slot: HTMLSlotElement; | ||
|
||
static get observedAttributes(): string[] { | ||
return [...super.observedAttributes, ...CombinedAttributes, 'disabled']; | ||
} | ||
|
||
constructor() { | ||
super(); | ||
|
||
this.#slot = this.shadowRoot?.querySelector('slot') as HTMLSlotElement; | ||
this.#slot.innerHTML = `${formatLabel(this)}`; | ||
} | ||
|
||
connectedCallback(): void { | ||
if (!this.hasAttribute('disabled')) { | ||
this.enable(); | ||
} | ||
|
||
/** @TODO Implement these */ | ||
this.setAttribute('role', 'progressbar'); | ||
this.setAttribute('aria-label', 'FILL ME IN'); | ||
|
||
super.connectedCallback(); | ||
} | ||
|
||
disconnectedCallback(): void { | ||
this.disable(); | ||
super.disconnectedCallback(); | ||
} | ||
|
||
attributeChangedCallback(attrName: string, oldValue: string | null, newValue: string | null): void { | ||
if (CombinedAttributes.includes(attrName)) { | ||
this.update(); | ||
} else if (attrName === 'disabled' && newValue !== oldValue) { | ||
if (newValue == null) { | ||
this.enable(); | ||
} else { | ||
this.disable(); | ||
} | ||
} | ||
|
||
super.attributeChangedCallback(attrName, oldValue, newValue); | ||
} | ||
|
||
enable(): void { | ||
this.tabIndex = 0; | ||
} | ||
|
||
disable(): void { | ||
this.tabIndex = -1; | ||
} | ||
|
||
// Own props | ||
|
||
/** | ||
* Describe me | ||
*/ | ||
get prefix(): string { | ||
return getStringAttr(this, Attributes.PREFIX, DEFAULT_PREFIX); | ||
} | ||
|
||
set prefix(val: string | undefined) { | ||
/** @TODO inaccurate type def in media chrome. Accepts/expects nullish. (CJP) */ | ||
/** @ts-ignore */ | ||
setStringAttr(this, Attributes.PREFIX, val); | ||
} | ||
|
||
// Props derived from media UI attributes | ||
|
||
/** | ||
* Describe me | ||
*/ | ||
get mediaAdBreakTotalAds(): number | undefined { | ||
return getNumericAttr(this, MediaUIAttributes.MEDIA_AD_BREAK_TOTAL_ADS); | ||
} | ||
|
||
set mediaAdBreakTotalAds(val: number | undefined) { | ||
/** @TODO inaccurate type def in media chrome. Accepts/expects nullish. (CJP) */ | ||
/** @ts-ignore */ | ||
setNumericAttr(this, MediaUIAttributes.MEDIA_AD_BREAK_TOTAL_ADS, val); | ||
} | ||
|
||
/** | ||
* Describe me | ||
*/ | ||
get mediaAdBreakAdPosition(): number | undefined { | ||
return getNumericAttr(this, MediaUIAttributes.MEDIA_AD_BREAK_AD_POSITION); | ||
} | ||
|
||
set mediaAdBreakAdPosition(val: number | undefined) { | ||
/** @TODO inaccurate type def in media chrome. Accepts/expects nullish. (CJP) */ | ||
/** @ts-ignore */ | ||
setNumericAttr(this, MediaUIAttributes.MEDIA_AD_BREAK_AD_POSITION, val); | ||
} | ||
|
||
update(): void { | ||
const label = formatLabel(this); | ||
updateAriaValueText(this); | ||
// Only update if it changed, timeupdate events are called a few times per second. | ||
if (label !== this.#slot.innerHTML) { | ||
this.#slot.innerHTML = label; | ||
} | ||
} | ||
} | ||
|
||
if (!globalThis.customElements.get('media-ad-count-display')) { | ||
globalThis.customElements.define('media-ad-count-display', MediaAdCountDisplay); | ||
} | ||
|
||
export default MediaAdCountDisplay; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
512 changes: 512 additions & 0 deletions
512
packages/mux-video/src/google-ima-video-element-mixin.ts
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { globalThis } from './polyfills'; | ||
|
||
/** @TODO MOVE TO PLAYBACK-CORE TO SHARE ACROSS ELEMENT PACKAGES (CJP) */ | ||
|
||
// Use 1 resize observer instance for many elements for best performance. | ||
// https://groups.google.com/a/chromium.org/g/blink-dev/c/z6ienONUb5A/m/F5-VcUZtBAAJ | ||
|
||
const callbacksMap = new WeakMap<Element, Set<ResizeCallback>>(); | ||
|
||
type ResizeCallback = (entry: ResizeObserverEntry) => void; | ||
|
||
const getCallbacks = (element: Element): Set<ResizeCallback> => { | ||
let callbacks = callbacksMap.get(element); | ||
if (!callbacks) callbacksMap.set(element, (callbacks = new Set<ResizeCallback>())); | ||
return callbacks; | ||
}; | ||
|
||
const observer = new globalThis.ResizeObserver((entries: ResizeObserverEntry[]) => { | ||
for (const entry of entries) { | ||
for (const callback of getCallbacks(entry.target)) { | ||
callback(entry); | ||
} | ||
} | ||
}); | ||
|
||
export function observeResize(element: Element, callback: ResizeCallback): void { | ||
getCallbacks(element).add(callback); | ||
observer.observe(element); | ||
} | ||
|
||
export function unobserveResize(element: Element, callback: ResizeCallback): void { | ||
const callbacks = getCallbacks(element); | ||
callbacks.delete(callback); | ||
|
||
if (!callbacks.size) { | ||
observer.unobserve(element); | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
microsoft/TypeScript#60672
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice find 😎