mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Add optional media thumbnails in popup
This commit is contained in:
@@ -396,6 +396,14 @@
|
|||||||
"message": "Auto-expand media controls for connected devices",
|
"message": "Auto-expand media controls for connected devices",
|
||||||
"description": "Receiver selector expand active checkbox label."
|
"description": "Receiver selector expand active checkbox label."
|
||||||
},
|
},
|
||||||
|
"optionsReceiverSelectorShowMediaImages": {
|
||||||
|
"message": "Show media images",
|
||||||
|
"description": "Receiver selector show media images checkbox label."
|
||||||
|
},
|
||||||
|
"optionsReceiverSelectorShowMediaImagesDescription": {
|
||||||
|
"message": "Loads media thumbnail/branding images from remote servers.",
|
||||||
|
"description": "Receiver selector show media images option description."
|
||||||
|
},
|
||||||
|
|
||||||
"optionsSiteWhitelistCategoryName": {
|
"optionsSiteWhitelistCategoryName": {
|
||||||
"message": "Site whitelist",
|
"message": "Site whitelist",
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ export interface Options {
|
|||||||
receiverSelectorWaitForConnection: boolean;
|
receiverSelectorWaitForConnection: boolean;
|
||||||
/** Auto-expand active sessions managed by the extension. */
|
/** Auto-expand active sessions managed by the extension. */
|
||||||
receiverSelectorExpandActive: boolean;
|
receiverSelectorExpandActive: boolean;
|
||||||
|
/** Show media images in receiver selector. */
|
||||||
|
receiverSelectorShowMediaImages: boolean;
|
||||||
|
|
||||||
/** User agent replacement whitelist enabled. */
|
/** User agent replacement whitelist enabled. */
|
||||||
siteWhitelistEnabled: boolean;
|
siteWhitelistEnabled: boolean;
|
||||||
@@ -97,6 +99,7 @@ export default {
|
|||||||
receiverSelectorCloseIfFocusLost: true,
|
receiverSelectorCloseIfFocusLost: true,
|
||||||
receiverSelectorWaitForConnection: true,
|
receiverSelectorWaitForConnection: true,
|
||||||
receiverSelectorExpandActive: true,
|
receiverSelectorExpandActive: true,
|
||||||
|
receiverSelectorShowMediaImages: false,
|
||||||
|
|
||||||
siteWhitelistEnabled: true,
|
siteWhitelistEnabled: true,
|
||||||
siteWhitelist: [{ pattern: "https://www.netflix.com/*", isEnabled: true }],
|
siteWhitelist: [{ pattern: "https://www.netflix.com/*", isEnabled: true }],
|
||||||
|
|||||||
@@ -362,22 +362,6 @@
|
|||||||
</div>
|
</div>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<div class="option option--inline">
|
|
||||||
<div class="option__control">
|
|
||||||
<input
|
|
||||||
id="receiverSelectorCloseIfFocusLost"
|
|
||||||
type="checkbox"
|
|
||||||
bind:checked={opts.receiverSelectorCloseIfFocusLost}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<label
|
|
||||||
class="option__label"
|
|
||||||
for="receiverSelectorCloseIfFocusLost"
|
|
||||||
>
|
|
||||||
{_("optionsReceiverSelectorCloseIfFocusLost")}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="option option--inline">
|
<div class="option option--inline">
|
||||||
<div class="option__control">
|
<div class="option__control">
|
||||||
<input
|
<input
|
||||||
@@ -393,6 +377,41 @@
|
|||||||
{_("optionsReceiverSelectorExpandActive")}
|
{_("optionsReceiverSelectorExpandActive")}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="option option--inline">
|
||||||
|
<div class="option__control">
|
||||||
|
<input
|
||||||
|
id="receiverSelectorShowMediaImages"
|
||||||
|
type="checkbox"
|
||||||
|
bind:checked={opts.receiverSelectorShowMediaImages}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<label
|
||||||
|
class="option__label"
|
||||||
|
for="receiverSelectorShowMediaImages"
|
||||||
|
>
|
||||||
|
{_("optionsReceiverSelectorShowMediaImages")}
|
||||||
|
</label>
|
||||||
|
<div class="option__description">
|
||||||
|
{_("optionsReceiverSelectorShowMediaImagesDescription")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="option option--inline">
|
||||||
|
<div class="option__control">
|
||||||
|
<input
|
||||||
|
id="receiverSelectorCloseIfFocusLost"
|
||||||
|
type="checkbox"
|
||||||
|
bind:checked={opts.receiverSelectorCloseIfFocusLost}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<label
|
||||||
|
class="option__label"
|
||||||
|
for="receiverSelectorCloseIfFocusLost"
|
||||||
|
>
|
||||||
|
{_("optionsReceiverSelectorCloseIfFocusLost")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|||||||
@@ -467,6 +467,7 @@
|
|||||||
<div class="receiver__expanded">
|
<div class="receiver__expanded">
|
||||||
<ReceiverMedia
|
<ReceiverMedia
|
||||||
status={mediaStatus}
|
status={mediaStatus}
|
||||||
|
showImage={opts?.receiverSelectorShowMediaImages}
|
||||||
{device}
|
{device}
|
||||||
{textTracks}
|
{textTracks}
|
||||||
on:togglePlayback={() => handleMediaPlayPause()}
|
on:togglePlayback={() => handleMediaPlayPause()}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import type { ReceiverDevice } from "../../types";
|
import type { ReceiverDevice } from "../../types";
|
||||||
|
|
||||||
import { MediaStatus, _MediaCommand } from "../../cast/sdk/types";
|
import { MediaStatus, _MediaCommand } from "../../cast/sdk/types";
|
||||||
import type { Image, Volume } from "../../cast/sdk/classes";
|
import type { Volume } from "../../cast/sdk/classes";
|
||||||
import {
|
import {
|
||||||
MetadataType,
|
MetadataType,
|
||||||
PlayerState,
|
PlayerState,
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
export let status: MediaStatus;
|
export let status: MediaStatus;
|
||||||
export let device: ReceiverDevice;
|
export let device: ReceiverDevice;
|
||||||
export let textTracks: Track[] = [];
|
export let textTracks: Track[] = [];
|
||||||
|
export let showImage = false;
|
||||||
|
|
||||||
$: isPlayingOrPaused =
|
$: isPlayingOrPaused =
|
||||||
status.playerState === PlayerState.PLAYING ||
|
status.playerState === PlayerState.PLAYING ||
|
||||||
@@ -38,14 +39,13 @@
|
|||||||
|
|
||||||
let mediaTitle: Optional<string>;
|
let mediaTitle: Optional<string>;
|
||||||
let mediaSubtitle: Optional<string>;
|
let mediaSubtitle: Optional<string>;
|
||||||
let mediaImage: Optional<Image>;
|
let mediaImageSet: Optional<string>;
|
||||||
|
|
||||||
// Choose subset of metadata depending on metadata type
|
// Choose subset of metadata depending on metadata type
|
||||||
$: {
|
$: {
|
||||||
const metadata = status?.media?.metadata;
|
const metadata = status?.media?.metadata;
|
||||||
|
|
||||||
mediaTitle = metadata?.title;
|
mediaTitle = metadata?.title;
|
||||||
mediaImage = metadata?.images?.[0];
|
|
||||||
mediaSubtitle = undefined;
|
mediaSubtitle = undefined;
|
||||||
|
|
||||||
if (metadata) {
|
if (metadata) {
|
||||||
@@ -71,6 +71,18 @@
|
|||||||
mediaSubtitle = metadata.subtitle;
|
mediaSubtitle = metadata.subtitle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (showImage && metadata?.images?.length) {
|
||||||
|
let imageSet: string[] = [];
|
||||||
|
for (const image of metadata.images) {
|
||||||
|
let sizeString = image.url;
|
||||||
|
if (image.width) sizeString += ` ${image.width}w`;
|
||||||
|
imageSet.push(sizeString);
|
||||||
|
}
|
||||||
|
mediaImageSet = imageSet.join(",");
|
||||||
|
} else {
|
||||||
|
mediaImageSet = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep track of update times for currentTime estimations
|
// Keep track of update times for currentTime estimations
|
||||||
@@ -155,17 +167,22 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="media" style:--media-image="url({mediaImage?.url})">
|
<div class="media">
|
||||||
{#if mediaTitle}
|
{#if mediaTitle}
|
||||||
<div class="media__metadata">
|
<div class="media__metadata">
|
||||||
<div class="media__title" title={mediaTitle}>
|
{#if mediaImageSet}
|
||||||
{mediaTitle}
|
<img class="media__image" srcset={mediaImageSet} alt="" />
|
||||||
</div>
|
|
||||||
{#if mediaSubtitle}
|
|
||||||
<div class="media__subtitle">
|
|
||||||
{mediaSubtitle}
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
<div class="media__metadata-text">
|
||||||
|
<div class="media__title" title={mediaTitle}>
|
||||||
|
{mediaTitle}
|
||||||
|
</div>
|
||||||
|
{#if mediaSubtitle}
|
||||||
|
<div class="media__subtitle">
|
||||||
|
{mediaSubtitle}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|||||||
@@ -163,10 +163,24 @@ body {
|
|||||||
|
|
||||||
.media__metadata,
|
.media__metadata,
|
||||||
.media__controls {
|
.media__controls {
|
||||||
padding: 5px 10px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media__metadata {
|
.media__metadata {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media__image {
|
||||||
|
align-self: start;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
flex-grow: 0;
|
||||||
|
max-height: 70px;
|
||||||
|
max-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media__metadata-text {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@@ -177,7 +191,6 @@ body {
|
|||||||
.media__subtitle {
|
.media__subtitle {
|
||||||
color: var(--secondary-color);
|
color: var(--secondary-color);
|
||||||
}
|
}
|
||||||
.media__title,
|
|
||||||
.media__subtitle {
|
.media__subtitle {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|||||||
Reference in New Issue
Block a user