mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-03-11 21:27:05 +00:00
parent
447fab71d2
commit
22b8a54c4a
9 changed files with 54 additions and 279 deletions
|
|
@ -194,50 +194,34 @@ const MetaPreview = ({ className, compact, name, logo, background, runtime, rele
|
|||
}
|
||||
</div>
|
||||
<div className={styles['action-buttons-container']}>
|
||||
<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 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
|
||||
}
|
||||
{
|
||||
typeof showHref === 'string' && compact ?
|
||||
<ActionButton
|
||||
className={`${styles['action-button']} ${styles['show-button']}`}
|
||||
className={styles['action-button']}
|
||||
icon={'play'}
|
||||
label={t('SHOW')}
|
||||
tabIndex={compact ? -1 : 0}
|
||||
|
|
|
|||
|
|
@ -156,35 +156,9 @@
|
|||
align-self: stretch;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
max-height: 10rem;
|
||||
padding-top: 2rem;
|
||||
flex-wrap: wrap;
|
||||
overflow-x: visible;
|
||||
max-height: 10rem;
|
||||
|
||||
.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;
|
||||
|
|
@ -200,12 +174,6 @@
|
|||
&:not(:last-child) {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
&.show-button {
|
||||
&:hover, &:focus {
|
||||
background-color: var( --secondary-accent-color);
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -230,16 +198,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
.action-buttons-container {
|
||||
flex-shrink: 0;
|
||||
margin-top: 3rem;
|
||||
overflow: visible;
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.action-buttons-container {
|
||||
flex-wrap: nowrap;
|
||||
margin-top: 3rem;
|
||||
overflow-x: visible;
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.share-prompt {
|
||||
|
|
|
|||
|
|
@ -4,20 +4,16 @@ const React = require('react');
|
|||
const PropTypes = require('prop-types');
|
||||
const classnames = require('classnames');
|
||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { Button, Image, useProfile, platform, useStreamingServer, useToast } = require('stremio/common');
|
||||
const { Button, Image, PlayIconCircleCentered, 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 ?
|
||||
|
|
@ -83,7 +79,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?.replace(/\|/g, '') || addonName?.replace(/\|/g, '')}>
|
||||
<div className={styles['thumbnail-container']} title={name || addonName}>
|
||||
<Image
|
||||
className={styles['thumbnail']}
|
||||
src={thumbnail}
|
||||
|
|
@ -92,23 +88,12 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio
|
|||
/>
|
||||
</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 className={styles['addon-name-container']} title={name || addonName}>
|
||||
<div className={styles['addon-name']}>{name || addonName}</div>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
typeof description === 'string' && description.length > 0 ?
|
||||
<StreamInfo
|
||||
streamName={streamName}
|
||||
streamProvider={streamProvider}
|
||||
streamSeeders={streamSeeders}
|
||||
streamSize={streamSize}
|
||||
streamFlags={streamFlags}
|
||||
/>
|
||||
:
|
||||
null
|
||||
}
|
||||
<Icon className={styles['icon']} name={'play'} />
|
||||
<div className={styles['info-container']} title={description}>{description}</div>
|
||||
<PlayIconCircleCentered className={styles['play-icon']} />
|
||||
{
|
||||
progress !== null && !isNaN(progress) && progress > 0 ?
|
||||
<div className={styles['progress-bar-container']}>
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
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;
|
||||
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const StreamInfo = require('./StreamInfo');
|
||||
|
||||
module.exports = StreamInfo;
|
||||
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
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;
|
||||
|
||||
|
|
@ -70,39 +70,26 @@
|
|||
flex: 1;
|
||||
max-height: 3.6em;
|
||||
padding: 0 0.5rem 0 1.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
display: -webkit-box;
|
||||
-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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
.play-icon {
|
||||
flex: none;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
padding: 0.7rem;
|
||||
border-radius: 50%;
|
||||
color: var(--primary-foreground-color);
|
||||
background-color: var(--secondary-accent-color);
|
||||
width: 3.5rem;
|
||||
height: 5rem;
|
||||
opacity: 0;
|
||||
|
||||
.play-icon-circle-centered-background {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.play-icon-circle-centered-icon {
|
||||
fill: var(--primary-foreground-color);
|
||||
}
|
||||
}
|
||||
|
||||
.progress-bar-container {
|
||||
|
|
|
|||
|
|
@ -123,7 +123,6 @@
|
|||
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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue