Compare commits
1 Commits
0541b0b776
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
| dac2b0e8dc |
18
cast-receiver/README.md
Normal file
18
cast-receiver/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Radio Player - Custom Cast Receiver
|
||||
|
||||
This folder contains a minimal Google Cast Web Receiver that displays a purple gradient background, station artwork, title and subtitle. It accepts `customData` hints sent from the sender (your app) for `backgroundImage`, `backgroundGradient` and `appName`.
|
||||
|
||||
Hosting requirements
|
||||
- The receiver must be served over HTTPS and be publicly accessible.
|
||||
- Recommended: host under GitHub Pages (`gh-pages` branch or `/docs` folder) or any static host (Netlify, Vercel, S3 + CloudFront).
|
||||
|
||||
Registering with Google Cast Console
|
||||
1. Go to the Cast SDK Developer Console and create a new Application.
|
||||
2. Choose "Custom Receiver" and provide the public HTTPS URL to `index.html` (e.g. `https://example.com/cast-receiver/index.html`).
|
||||
3. Note the generated Application ID.
|
||||
|
||||
Sender changes
|
||||
- After obtaining the Application ID, update your sender (sidecar) to launch that app ID instead of the DefaultMediaReceiver. The sidecar already supports passing `metadata.appId` when launching.
|
||||
|
||||
Testing locally
|
||||
- You can serve this folder locally during development, but Chromecast devices require public HTTPS endpoints to use a registered app.
|
||||
23
cast-receiver/index.html
Normal file
23
cast-receiver/index.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Radio Player Receiver</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="bg" class="bg"></div>
|
||||
<div id="app" class="app">
|
||||
<div class="artwork"><img id="art" alt="Artwork"></div>
|
||||
<div class="meta">
|
||||
<div id="appName" class="app-name">Radio Player</div>
|
||||
<h1 id="title">Radio Player</h1>
|
||||
<h2 id="subtitle"></h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
|
||||
<script src="receiver.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
50
cast-receiver/receiver.js
Normal file
50
cast-receiver/receiver.js
Normal file
@@ -0,0 +1,50 @@
|
||||
// Minimal CAF receiver that applies customData theming and shows media metadata.
|
||||
const context = cast.framework.CastReceiverContext.getInstance();
|
||||
const playerManager = context.getPlayerManager();
|
||||
|
||||
function applyBranding(customData, metadata) {
|
||||
try {
|
||||
const bgEl = document.getElementById('bg');
|
||||
const art = document.getElementById('art');
|
||||
const title = document.getElementById('title');
|
||||
const subtitle = document.getElementById('subtitle');
|
||||
const appName = document.getElementById('appName');
|
||||
|
||||
if (customData) {
|
||||
if (customData.backgroundImage) {
|
||||
bgEl.style.backgroundImage = `url(${customData.backgroundImage})`;
|
||||
bgEl.style.backgroundSize = 'cover';
|
||||
bgEl.style.backgroundPosition = 'center';
|
||||
} else if (customData.backgroundGradient) {
|
||||
bgEl.style.background = customData.backgroundGradient;
|
||||
}
|
||||
if (customData.appName) appName.textContent = customData.appName;
|
||||
}
|
||||
|
||||
if (metadata) {
|
||||
if (metadata.title) title.textContent = metadata.title;
|
||||
const sub = metadata.subtitle || metadata.artist || '';
|
||||
subtitle.textContent = sub;
|
||||
if (metadata.images && metadata.images.length) {
|
||||
art.src = metadata.images[0].url || '';
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// swallow UI errors
|
||||
console.warn('Branding apply failed', e);
|
||||
}
|
||||
}
|
||||
|
||||
playerManager.setMessageInterceptor(cast.framework.messages.MessageType.LOAD, (request) => {
|
||||
const media = request.media || {};
|
||||
const customData = media.customData || {};
|
||||
applyBranding(customData, media.metadata || {});
|
||||
return request;
|
||||
});
|
||||
|
||||
playerManager.addEventListener(cast.framework.events.EventType.MEDIA_STATUS, () => {
|
||||
const media = playerManager.getMediaInformation();
|
||||
if (media) applyBranding(media.customData || {}, media.metadata || {});
|
||||
});
|
||||
|
||||
context.start();
|
||||
11
cast-receiver/styles.css
Normal file
11
cast-receiver/styles.css
Normal file
@@ -0,0 +1,11 @@
|
||||
:root{--primary:#6a0dad;--accent:#b36cf3}
|
||||
html,body{height:100%;margin:0;font-family:Inter,system-ui,Arial,Helvetica,sans-serif}
|
||||
body{background:linear-gradient(135deg,var(--primary),var(--accent));color:#fff}
|
||||
.bg{position:fixed;inset:0;background-size:cover;background-position:center;filter:blur(10px) saturate(120%);opacity:0.9}
|
||||
.app{position:relative;z-index:2;display:flex;align-items:center;gap:24px;padding:48px}
|
||||
.artwork{width:320px;height:320px;flex:0 0 320px;background:rgba(255,255,255,0.06);display:flex;align-items:center;justify-content:center;border-radius:8px;overflow:hidden}
|
||||
.artwork img{width:100%;height:100%;object-fit:cover}
|
||||
.meta{display:flex;flex-direction:column}
|
||||
.app-name{font-weight:600;opacity:0.9}
|
||||
h1{margin:6px 0 0 0;font-size:28px}
|
||||
h2{margin:6px 0 0 0;font-size:18px;opacity:0.9}
|
||||
@@ -140,7 +140,8 @@ function play(ip, url, metadata) {
|
||||
function launchPlayer(url, metadata, didStopFirst) {
|
||||
if (!activeClient) return;
|
||||
|
||||
activeClient.launch(DefaultMediaReceiver, (err, player) => {
|
||||
const launchApp = (metadata && metadata.appId) ? metadata.appId : DefaultMediaReceiver;
|
||||
activeClient.launch(launchApp, (err, player) => {
|
||||
if (err) {
|
||||
const details = `Launch error: ${err && err.message ? err.message : String(err)}${err && err.code ? ` (code: ${err.code})` : ''}`;
|
||||
// If launch fails with NOT_ALLOWED, the device may be busy with another app/session.
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"version": "0.1.1",
|
||||
"debug": false,
|
||||
"builtAt": "2026-01-13T12:34:31.351Z"
|
||||
}
|
||||
Reference in New Issue
Block a user