Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/nextjs-with-typescript/pages/MuxPlayerAds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ function MuxPlayerAdsPage() {
video_title: "Elephants Dream",
viewer_user_id: "user-id-6789",
}}
// allow playback with ad blocker
allowAdBlocker={true}
streamType="on-demand"
// envKey="mux-data-env-key"
autoPlay={autoplay}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ function MuxVideoPage() {
setSdkLoaded(true); // Mark SDK as loaded
console.log("Google IMA SDK loaded");
};
script.onerror = () => {
setSdkLoaded(true);
};
document.head.appendChild(script);
};

Expand Down Expand Up @@ -75,6 +78,8 @@ function MuxVideoPage() {
ref={mediaElRef}
playbackId="23s11nz72DsoN657h4314PjKKjsF2JG33eBQQt6B95I"
controls
// allow playback with ad blocker
allowAdBlocker={true}
autoplay={autoplay}
muted={muted}
playsInline={true}
Expand Down
13 changes: 10 additions & 3 deletions examples/nextjs-with-typescript/pages/playlist-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ function MuxVideoPage() {
setSdkLoaded(true); // Mark SDK as loaded
console.log("Google IMA SDK loaded");
};
script.onerror = () => {
setSdkLoaded(true);
};
document.head.appendChild(script);
};

Expand Down Expand Up @@ -58,11 +61,15 @@ function MuxVideoPage() {
return (
<>
<Head>
<title>&lt;Playlist/&gt; Demo</title>
<title>&lt;Playlist/&gt; Demo 3</title>
</Head>

{sdkLoaded && <MuxNewsPlayer videoList={relatedVideos} />}

{sdkLoaded &&
<MuxNewsPlayer
// allow playback with ad blocker
allowAdBlocker={true}
videoList={relatedVideos}
/>}
</>
);
}
Expand Down
6 changes: 6 additions & 0 deletions packages/mux-player-react/MuxNewsPlayer.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ export default function YourComponent() {
setSdkLoaded(true);
console.log("Google IMA SDK loaded");
};
script.onerror = () => {
setSdkLoaded(true);
};
document.head.appendChild(script);
};

Expand Down Expand Up @@ -142,6 +145,9 @@ export default function VideoMuxNewsPlayerPage() {
setSdkLoaded(true);
console.log("Google IMA SDK loaded");
};
script.onerror = () => {
setSdkLoaded(true);
};
document.head.appendChild(script);
};

Expand Down
1 change: 1 addition & 0 deletions packages/mux-player-react/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ type MuxMediaPropTypes = {
};

export type MuxPlayerProps = {
allowAdBlocker?: boolean;
className?: string;
hotkeys?: string;
nohotkeys?: boolean;
Expand Down
9 changes: 6 additions & 3 deletions packages/mux-player-react/src/mux-news-player.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint @typescript-eslint/triple-slash-reference: "off" */
/// <reference types="google_interactive_media_ads_types" preserve="true"/>
import React, { useRef, useState } from 'react';
import type { MuxPlayerProps } from '@mux/mux-player-react'; // ✅ import prop types
import PlaylistEndScreen from './playlist-end-screen';
import '@mux/mux-video-ads';
import MuxPlayer from '@mux/mux-player-react';
Expand All @@ -18,16 +19,16 @@ export interface VideoItem {

export type PlaylistVideos = VideoItem[];

export interface PlaylistProps {
export interface PlaylistProps extends Omit<MuxPlayerProps, 'playbackId' | 'adTagUrl'> {
videoList: PlaylistVideos;
allowAdBlocker?: boolean;
}

export const MuxNewsPlayer = ({ videoList }: PlaylistProps) => {
export const MuxNewsPlayer = ({ videoList, allowAdBlocker: allowAdBlocker, ...muxPlayerProps }: PlaylistProps) => {
const mediaElRef = useRef<any>(null);
const [autoplay, setAutoplay] = useState<'muted' | boolean>(INITIAL_AUTOPLAY);
const [muted, setMuted] = useState(INITIAL_MUTED);
const [paused, setPaused] = useState<boolean | undefined>(true);
const [sdkLoaded, setSdkLoaded] = useState(false);
const [currentIndex, setCurrentIndex] = useState(0);
const [isEndScreenVisible, setIsEndScreenVisible] = useState(false);
const [playerKey, setPlayerKey] = useState(0);
Expand All @@ -52,6 +53,8 @@ export const MuxNewsPlayer = ({ videoList }: PlaylistProps) => {
<div>
<NewsTheme />
<MuxPlayer
{...muxPlayerProps}
allowAdBlocker={allowAdBlocker}
ref={mediaElRef}
theme="news-theme"
themeProps={{ controlBarVertical: true, controlBarPlace: 'start start' }}
Expand Down
6 changes: 3 additions & 3 deletions packages/mux-player-react/src/themes/news-theme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export default function NewsTheme() {

<!-- Rendition Menu -->
<style>
media-rendition-menu {
media-rendition-menu, media-captions-menu {
position: absolute;
border-radius: 0.3rem;
right: 12px;
Expand Down Expand Up @@ -149,7 +149,7 @@ export default function NewsTheme() {

<media-rendition-menu anchor="auto" hidden>
</media-rendition-menu>

<media-captions-menu hidden anchor="auto"></media-captions-menu>
<!-- Time Range / Progress Bar -->

<style>
Expand Down Expand Up @@ -496,6 +496,7 @@ export default function NewsTheme() {
</svg>

</media-rendition-menu-button>
<media-captions-menu-button></media-captions-menu-button>
</template>

<!-- Fullscreen Button -->
Expand Down Expand Up @@ -584,7 +585,6 @@ export default function NewsTheme() {
</g>
</svg>
</media-fullscreen-button>

</media-control-bar>`,
}}
/>
Expand Down
2 changes: 2 additions & 0 deletions packages/mux-player/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ function getProps(el: MuxPlayerElement, state?: any): MuxTemplateProps {
// NOTE: since the attribute value is used as the "source of truth" for the property getter,
// moving this below the `...state` spread so it resolves to the default value when unset (CJP)
extraSourceParams: el.extraSourceParams,
allowAdBlocker: el.getAttribute('allow-ad-blocker'),
};

return props;
Expand Down Expand Up @@ -343,6 +344,7 @@ class MuxPlayerElement extends VideoApiElement implements MuxPlayerElement {
if (!isFocusedElementInPlayer) event.preventDefault();
},
};
allowAdBlocker: any;

static get NAME() {
return playerSoftwareName;
Expand Down
1 change: 1 addition & 0 deletions packages/mux-player/src/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ const getTagSpecificProps = (tag: string, props: MuxTemplateProps) => {
'cast-src': !!props.src ? props.src : props.playbackId ? toMuxVideoURL(props) : false,
'cast-receiver': props.castReceiver ?? false,
'drm-token': props.tokens?.drm ?? false,
'allow-ad-blocker': props.allowAdBlocker ?? false,
exportparts: 'video',
};

Expand Down
1 change: 1 addition & 0 deletions packages/mux-player/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export type MuxTemplateProps = Partial<MuxPlayerProps> & {
muxVideoElement: string;
adTagUrl: string | undefined;
adBreak: boolean;
allowAdBlocker?: boolean;
};

export type DialogOptions = {
Expand Down
42 changes: 32 additions & 10 deletions packages/mux-video-ads/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const serializeAttributes = (attrs = {}) => {
const Attributes = {
AD_TAG_URL: 'adtagurl',
AD_BREAK: 'adbreak',
ALLOW_AD_BLOCKER: 'allow-ad-blocker',
} as const;

class MuxVideoAds extends MuxVideoElement {
Expand Down Expand Up @@ -69,19 +70,24 @@ video::-webkit-media-text-track-container {
}
#imaUnavailableMessage {
position: absolute;
top: 40%;
left: 50%;
transform: translateX(-50%);
top: 0;
left: 0;
z-index: 10;
background: rgba(0, 0, 0, 0.75);
color: white;
padding: 1em 1.5em;
border-radius: 6px;
font-size: 0.9em;
text-align: center;
max-width: 90%;
line-height: 1.4;
box-shadow: 0 4px 12px rgba(0,0,0,0.5);
width: 100%;
height: 100%;
align-items: center;
align-content: center;
cursor: not-allowed;

h4{
font-size: 1rem;
margin:0;
}
}
</style>
<div id="mainContainer">
Expand Down Expand Up @@ -114,7 +120,11 @@ video::-webkit-media-text-track-container {

if (!MuxAdManager.isGoogleImaSDKAvailable()) {
console.error('Missing google.ima SDK. Make sure you include it via a script tag.');
this.#showAdBlockedMessage();
if (!this.allowAdBlocker) {
this.#showAdBlockedMessage();
} else {
this.#adBreak = false;
}
return;
}

Expand All @@ -137,7 +147,7 @@ video::-webkit-media-text-track-container {
const fallback = document.createElement('div');
fallback.id = 'imaUnavailableMessage';
fallback.innerHTML = `
<strong>Ad experience unavailable.</strong><br />
<h4>Ad experience unavailable.</h4>
<span>This may be due to a missing SDK, network issue, or ad blocker.</span>
`;
this.shadowRoot?.getElementById('mainContainer')?.appendChild(fallback);
Expand Down Expand Up @@ -265,7 +275,11 @@ video::-webkit-media-text-track-container {
return Promise.resolve();
}

if (this.adTagUrl) {
const adBlockerDetected = !this.#muxAdManager?.adsLoader;

const adBlockerAndAllowed = adBlockerDetected && this.allowAdBlocker;

if (this.adTagUrl && !adBlockerAndAllowed) {
this.#lastCurrentime = this.nativeEl.currentTime;
this.#adBreak = true;
this.dispatchEvent(new Event('durationchange'));
Expand Down Expand Up @@ -394,6 +408,14 @@ video::-webkit-media-text-track-container {
get muxDataKeepSession(): boolean {
return this.hasAttribute('mux-data-keep-session');
}

get allowAdBlocker(): boolean {
return this.hasAttribute(Attributes.ALLOW_AD_BLOCKER);
}

set allowAdBlocker(val: boolean) {
this.toggleAttribute(Attributes.ALLOW_AD_BLOCKER, !!val);
}
}

type MuxVideoAdsElementType = typeof MuxVideoAds;
Expand Down
1 change: 1 addition & 0 deletions packages/mux-video/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export const Attributes = {
LIVE_EDGE_OFFSET: 'live-edge-offset',
TYPE: 'type',
LOGO: 'logo',
ALLOW_AD_BLOCKER: 'allow-ad-blocker',
} as const;

const AttributeNameValues = Object.values(Attributes);
Expand Down
Loading