Revert "Revert "stream info design update""

This reverts commit 22b8a54c4a.
This commit is contained in:
kKaskak 2023-10-03 12:41:00 +03:00
parent 22b8a54c4a
commit b669fe08fc
9 changed files with 279 additions and 54 deletions

View file

@ -194,34 +194,50 @@ const MetaPreview = ({ className, compact, name, logo, background, runtime, rele
}
</div>
<div className={styles['action-buttons-container']}>
{
typeof toggleInLibrary === 'function' ?
<ActionButton
className={styles['action-button']}
icon={inLibrary ? 'remove-from-library' : 'add-to-library'}
label={compact ? null : inLibrary ? t('REMOVE_FROM_LIB') : t('ADD_TO_LIB')}
tabIndex={compact ? -1 : 0}
onClick={toggleInLibrary}
/>
:
null
}
{
typeof trailerHref === 'string' ?
<ActionButton
className={styles['action-button']}
icon={'trailer'}
label={compact ? null : t('TRAILER')}
tabIndex={compact ? -1 : 0}
href={trailerHref}
/>
:
null
}
<div className={styles['action-button-wrapper']}>
{
typeof toggleInLibrary === 'function' ?
<ActionButton
className={styles['action-button']}
icon={inLibrary ? 'remove-from-library' : 'add-to-library'}
label={compact ? null : inLibrary ? t('REMOVE_FROM_LIB') : t('ADD_TO_LIB')}
tabIndex={compact ? -1 : 0}
onClick={toggleInLibrary}
/>
:
null
}
{
typeof toggleInLibrary === 'function' && compact ?
<div className={styles['label']}>{inLibrary ? t('REMOVE_FROM_LIB') : t('ADD_TO_LIB')}</div>
:
null
}
</div>
<div className={styles['action-button-wrapper']}>
{
typeof trailerHref === 'string' ?
<ActionButton
className={styles['action-button']}
icon={'trailer'}
label={compact ? null : t('TRAILER')}
tabIndex={compact ? -1 : 0}
href={trailerHref}
/>
:
null
}
{
typeof trailerHref === 'string' && compact ?
<div className={styles['label']}>{t('WATCH_TRAILER')}</div>
:
null
}
</div>
{
typeof showHref === 'string' && compact ?
<ActionButton
className={styles['action-button']}
className={`${styles['action-button']} ${styles['show-button']}`}
icon={'play'}
label={t('SHOW')}
tabIndex={compact ? -1 : 0}

View file

@ -156,9 +156,35 @@
align-self: stretch;
display: flex;
flex-direction: row;
flex-wrap: wrap;
max-height: 10rem;
padding-top: 2rem;
flex-wrap: wrap;
overflow-x: visible;
.action-button-wrapper {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
.label {
opacity: 0;
transition: opacity 0.3s ease;
max-width: 6rem;
text-align: center;
color: var(--primary-foreground-color);
opacity: 0;
}
&:not(:last-child) {
margin-right: 1rem;
}
&:hover .label {
opacity: 0.7;
}
}
.action-button {
flex: none;
width: 4rem;
@ -174,6 +200,12 @@
&:not(:last-child) {
margin-right: 1rem;
}
&.show-button {
&:hover, &:focus {
background-color: var( --secondary-accent-color);
outline: none;
}
}
}
}
}
@ -198,16 +230,16 @@
}
}
.action-buttons-container {
flex-wrap: nowrap;
margin-top: 3rem;
overflow-x: visible;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
.action-buttons-container {
flex-shrink: 0;
margin-top: 3rem;
overflow: visible;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
}
}
.share-prompt {

View file

@ -4,16 +4,20 @@ const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const { default: Icon } = require('@stremio/stremio-icons/react');
const { Button, Image, PlayIconCircleCentered, useProfile, platform, useStreamingServer, useToast } = require('stremio/common');
const { Button, Image, useProfile, platform, useStreamingServer, useToast } = require('stremio/common');
const { useServices } = require('stremio/services');
const StreamPlaceholder = require('./StreamPlaceholder');
const styles = require('./styles');
const parseTorrentInfo = require('./parseTorrentInfo');
const StreamInfo = require('./StreamInfo');
const Stream = ({ className, videoId, videoReleased, addonName, name, description, thumbnail, progress, deepLinks, ...props }) => {
const profile = useProfile();
const streamingServer = useStreamingServer();
const { core } = useServices();
const toast = useToast();
const torrentInfo = parseTorrentInfo(description);
const {streamName, streamSeeders, streamSize, streamProvider, streamFlags } = torrentInfo;
const href = React.useMemo(() => {
const haveStreamingServer = streamingServer.settings !== null && streamingServer.settings.type === 'Ready';
return deepLinks ?
@ -79,7 +83,7 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio
<Button href={href} download={forceDownload} {...props} onClick={onClick} className={classnames(className, styles['stream-container'])} title={addonName}>
{
typeof thumbnail === 'string' && thumbnail.length > 0 ?
<div className={styles['thumbnail-container']} title={name || addonName}>
<div className={styles['thumbnail-container']} title={name?.replace(/\|/g, '') || addonName?.replace(/\|/g, '')}>
<Image
className={styles['thumbnail']}
src={thumbnail}
@ -88,12 +92,23 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio
/>
</div>
:
<div className={styles['addon-name-container']} title={name || addonName}>
<div className={styles['addon-name']}>{name || addonName}</div>
<div className={styles['addon-name-container']} title={name?.replace(/\|/g, '') || addonName?.replace(/\|/g, '')}>
<div className={styles['addon-name']}>{name?.replace(/\|/g, '') || addonName?.replace(/\|/g, '')}</div>
</div>
}
<div className={styles['info-container']} title={description}>{description}</div>
<PlayIconCircleCentered className={styles['play-icon']} />
{
typeof description === 'string' && description.length > 0 ?
<StreamInfo
streamName={streamName}
streamProvider={streamProvider}
streamSeeders={streamSeeders}
streamSize={streamSize}
streamFlags={streamFlags}
/>
:
null
}
<Icon className={styles['icon']} name={'play'} />
{
progress !== null && !isNaN(progress) && progress > 0 ?
<div className={styles['progress-bar-container']}>

View file

@ -0,0 +1,61 @@
const React = require('react');
const PropTypes = require('prop-types');
const { default: Icon } = require('@stremio/stremio-icons/react');
const styles = require('./styles');
const StreamInfo = ({ streamSize, streamProvider, streamName, streamFlags, streamSeeders }) => {
return (
<div className={styles['info-container']}>
<div className={styles['stream-name']}>{streamName}</div>
<div className={styles['description-container']}>
<div className={styles['stream-properties']}>
{
typeof streamSeeders === 'number' && streamSeeders > 0 ?
<div className={styles['property-container']}>
<Icon className={styles['icon']} name={'person'} />
<div className={styles['property']}>{streamSeeders}</div>
</div>
:
null
}
{
typeof streamSize === 'string' && streamSize.length > 0 ?
<div className={styles['property-container']}>
<Icon className={styles['icon']} name={'memory'} />
<div className={styles['property']}>{streamSize}</div>
</div>
:
null
}
{
typeof streamProvider === 'string' && streamProvider.length > 0 ?
<div className={styles['property-container']}>
<Icon className={styles['icon']} name={'settings-outline'} />
<div className={styles['property overflow']}>{streamProvider}</div>
</div>
:
null
}
{
typeof streamFlags === 'string' && streamFlags.length > 0 ?
<div className={styles['property-container']}>
<div className={styles['property']}>{streamFlags}</div>
</div>
:
null
}
</div>
</div>
</div>
);
};
StreamInfo.propTypes = {
streamFlags: PropTypes.string,
streamSize: PropTypes.string,
streamProvider: PropTypes.string,
streamSeeders: PropTypes.number,
streamName: PropTypes.string
};
module.exports = StreamInfo;

View file

@ -0,0 +1,6 @@
// Copyright (C) 2017-2023 Smart code 203358507
const StreamInfo = require('./StreamInfo');
module.exports = StreamInfo;

View file

@ -0,0 +1,45 @@
.info-container {
flex: 1;
max-height: 3.6em;
padding: 0 0.5rem 0 1.5rem;
display: flex;
flex-direction: column;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
color: var(--primary-foreground-color);
white-space: pre;
.stream-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.stream-properties {
display: flex;
flex-direction: row;
gap: 0 0.5em;
flex-wrap: wrap;
.property-container {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
color: var(--primary-foreground-color);
.icon {
width: 1em;
height: 1em;
padding: 0;
color: var(--primary-foreground-color);
background-color: transparent;
}
.property {
opacity: 0.9;
}
.overflow {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}

View file

@ -0,0 +1,36 @@
const parseTorrent = (description) => {
const isEmoji = (str) => {
const emojiRegex = /[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]/g;
return [...str.matchAll(emojiRegex)];
};
const streamName = description.split(/\u{1F464}/u)[0].trim();
const seedersMatch = description.match(/\u{1F464}\s(\d+)/u);
const streamSeeders = seedersMatch ? parseInt(seedersMatch[1]) : null;
const sizeMatch = description.match(/(?<=\uD83D\uDCBE).*?(?=\u2699\uFE0F?)/);
const streamSize = sizeMatch ? sizeMatch[0] : null;
const providerMatch = description.match(/\u2699\uFE0F\s(\S+?)\s/);
const streamProvider = providerMatch ? providerMatch[1].trim() : null;
const flagMatches = isEmoji(description);
let streamFlags = '';
for (const match of flagMatches) {
streamFlags += match[0];
}
const torrentInfo = {
streamName,
streamSeeders,
streamSize,
streamProvider,
streamFlags
};
return torrentInfo;
};
module.exports = parseTorrent;

View file

@ -70,26 +70,39 @@
flex: 1;
max-height: 3.6em;
padding: 0 0.5rem 0 1.5rem;
display: -webkit-box;
display: flex;
flex-direction: column;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
color: var(--primary-foreground-color);
white-space: pre;
.stream-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.stream-properties {
display: flex;
flex-direction: row;
.icon {
width: 1em;
height: 1em;
padding: 0;
color: var(--primary-foreground-color);
background-color: transparent;
}
}
}
.play-icon {
.icon {
flex: none;
width: 3.5rem;
height: 5rem;
opacity: 0;
.play-icon-circle-centered-background {
fill: none;
}
.play-icon-circle-centered-icon {
fill: var(--primary-foreground-color);
}
width: 3rem;
height: 3rem;
padding: 0.7rem;
border-radius: 50%;
color: var(--primary-foreground-color);
background-color: var(--secondary-accent-color);
}
.progress-bar-container {

View file

@ -123,6 +123,7 @@
padding: 1.5rem 1rem;
border-radius: var(--border-radius);
background-color: var(--secondary-accent-color);
border-radius: 3rem;
&:hover {
outline: var(--focus-outline-size) solid var(--secondary-accent-color);