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",
|
||||
"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": {
|
||||
"message": "Site whitelist",
|
||||
|
||||
@@ -58,6 +58,8 @@ export interface Options {
|
||||
receiverSelectorWaitForConnection: boolean;
|
||||
/** Auto-expand active sessions managed by the extension. */
|
||||
receiverSelectorExpandActive: boolean;
|
||||
/** Show media images in receiver selector. */
|
||||
receiverSelectorShowMediaImages: boolean;
|
||||
|
||||
/** User agent replacement whitelist enabled. */
|
||||
siteWhitelistEnabled: boolean;
|
||||
@@ -97,6 +99,7 @@ export default {
|
||||
receiverSelectorCloseIfFocusLost: true,
|
||||
receiverSelectorWaitForConnection: true,
|
||||
receiverSelectorExpandActive: true,
|
||||
receiverSelectorShowMediaImages: false,
|
||||
|
||||
siteWhitelistEnabled: true,
|
||||
siteWhitelist: [{ pattern: "https://www.netflix.com/*", isEnabled: true }],
|
||||
|
||||
@@ -362,22 +362,6 @@
|
||||
</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__control">
|
||||
<input
|
||||
@@ -393,6 +377,41 @@
|
||||
{_("optionsReceiverSelectorExpandActive")}
|
||||
</label>
|
||||
</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>
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -467,6 +467,7 @@
|
||||
<div class="receiver__expanded">
|
||||
<ReceiverMedia
|
||||
status={mediaStatus}
|
||||
showImage={opts?.receiverSelectorShowMediaImages}
|
||||
{device}
|
||||
{textTracks}
|
||||
on:togglePlayback={() => handleMediaPlayPause()}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import type { ReceiverDevice } from "../../types";
|
||||
|
||||
import { MediaStatus, _MediaCommand } from "../../cast/sdk/types";
|
||||
import type { Image, Volume } from "../../cast/sdk/classes";
|
||||
import type { Volume } from "../../cast/sdk/classes";
|
||||
import {
|
||||
MetadataType,
|
||||
PlayerState,
|
||||
@@ -27,6 +27,7 @@
|
||||
export let status: MediaStatus;
|
||||
export let device: ReceiverDevice;
|
||||
export let textTracks: Track[] = [];
|
||||
export let showImage = false;
|
||||
|
||||
$: isPlayingOrPaused =
|
||||
status.playerState === PlayerState.PLAYING ||
|
||||
@@ -38,14 +39,13 @@
|
||||
|
||||
let mediaTitle: Optional<string>;
|
||||
let mediaSubtitle: Optional<string>;
|
||||
let mediaImage: Optional<Image>;
|
||||
let mediaImageSet: Optional<string>;
|
||||
|
||||
// Choose subset of metadata depending on metadata type
|
||||
$: {
|
||||
const metadata = status?.media?.metadata;
|
||||
|
||||
mediaTitle = metadata?.title;
|
||||
mediaImage = metadata?.images?.[0];
|
||||
mediaSubtitle = undefined;
|
||||
|
||||
if (metadata) {
|
||||
@@ -71,6 +71,18 @@
|
||||
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
|
||||
@@ -155,17 +167,22 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="media" style:--media-image="url({mediaImage?.url})">
|
||||
<div class="media">
|
||||
{#if mediaTitle}
|
||||
<div class="media__metadata">
|
||||
<div class="media__title" title={mediaTitle}>
|
||||
{mediaTitle}
|
||||
</div>
|
||||
{#if mediaSubtitle}
|
||||
<div class="media__subtitle">
|
||||
{mediaSubtitle}
|
||||
</div>
|
||||
{#if mediaImageSet}
|
||||
<img class="media__image" srcset={mediaImageSet} alt="" />
|
||||
{/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>
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -163,10 +163,24 @@ body {
|
||||
|
||||
.media__metadata,
|
||||
.media__controls {
|
||||
padding: 5px 10px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.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;
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -177,7 +191,6 @@ body {
|
||||
.media__subtitle {
|
||||
color: var(--secondary-color);
|
||||
}
|
||||
.media__title,
|
||||
.media__subtitle {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
Reference in New Issue
Block a user