diff --git a/package-lock.json b/package-lock.json index 15a9be2f5..7bd2bd6ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,20 @@ { "name": "stremio", - "version": "5.0.0-beta.13", + "version": "5.0.0-beta.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "stremio", - "version": "5.0.0-beta.13", + "version": "5.0.0-beta.15", "license": "gpl-2.0", "dependencies": { "@babel/runtime": "7.26.0", "@sentry/browser": "8.42.0", "@stremio/stremio-colors": "5.2.0", - "@stremio/stremio-core-web": "0.48.1", - "@stremio/stremio-icons": "5.4.0", - "@stremio/stremio-video": "0.0.46", + "@stremio/stremio-core-web": "0.48.3", + "@stremio/stremio-icons": "5.4.1", + "@stremio/stremio-video": "0.0.48", "a-color-picker": "1.2.1", "bowser": "2.11.0", "buffer": "6.0.3", @@ -67,6 +67,7 @@ "postcss-loader": "8.1.1", "readdirp": "4.0.2", "terser-webpack-plugin": "5.3.10", + "thread-loader": "^4.0.4", "ts-loader": "^9.5.1", "typescript": "^5.7.2", "typescript-eslint": "^8.17.0", @@ -1869,7 +1870,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", - "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1880,8 +1880,7 @@ "node_modules/@babel/runtime/node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/@babel/template": { "version": "7.25.9", @@ -3261,7 +3260,6 @@ "version": "8.42.0", "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.42.0.tgz", "integrity": "sha512-xzgRI0wglKYsPrna574w1t38aftuvo44gjOKFvPNGPnYfiW9y4m+64kUz3JFbtanvOrKPcaITpdYiB4DeJXEbA==", - "license": "MIT", "dependencies": { "@sentry/core": "8.42.0" }, @@ -3273,7 +3271,6 @@ "version": "8.42.0", "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.42.0.tgz", "integrity": "sha512-dkIw5Wdukwzngg5gNJ0QcK48LyJaMAnBspqTqZ3ItR01STi6Z+6+/Bt5XgmrvDgRD+FNBinflc5zMmfdFXXhvw==", - "license": "MIT", "dependencies": { "@sentry/core": "8.42.0" }, @@ -3285,7 +3282,6 @@ "version": "8.42.0", "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.42.0.tgz", "integrity": "sha512-oNcJEBlDfXnRFYC5Mxj5fairyZHNqlnU4g8kPuztB9G5zlsyLgWfPxzcn1ixVQunth2/WZRklDi4o1ZfyHww7w==", - "license": "MIT", "dependencies": { "@sentry-internal/browser-utils": "8.42.0", "@sentry/core": "8.42.0" @@ -3298,7 +3294,6 @@ "version": "8.42.0", "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.42.0.tgz", "integrity": "sha512-XrPErqVhPsPh/oFLVKvz7Wb+Fi2J1zCPLeZCxWqFuPWI2agRyLVu0KvqJyzSpSrRAEJC/XFzuSVILlYlXXSfgA==", - "license": "MIT", "dependencies": { "@sentry-internal/replay": "8.42.0", "@sentry/core": "8.42.0" @@ -3311,7 +3306,6 @@ "version": "8.42.0", "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.42.0.tgz", "integrity": "sha512-lStrEk609KJHwXfDrOgoYVVoFFExixHywxSExk7ZDtwj2YPv6r6Y1gogvgr7dAZj7jWzadHkxZ33l9EOSJBfug==", - "license": "MIT", "dependencies": { "@sentry-internal/browser-utils": "8.42.0", "@sentry-internal/feedback": "8.42.0", @@ -3327,7 +3321,6 @@ "version": "8.42.0", "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.42.0.tgz", "integrity": "sha512-ac6O3pgoIbU6rpwz6LlwW0wp3/GAHuSI0C5IsTgIY6baN8rOBnlAtG6KrHDDkGmUQ2srxkDJu9n1O6Td3cBCqw==", - "license": "MIT", "engines": { "node": ">=14.18" } @@ -3375,13 +3368,12 @@ "node_modules/@stremio/stremio-colors": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@stremio/stremio-colors/-/stremio-colors-5.2.0.tgz", - "integrity": "sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg==", - "license": "MIT" + "integrity": "sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg==" }, "node_modules/@stremio/stremio-core-web": { - "version": "0.48.1", - "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.48.1.tgz", - "integrity": "sha512-bdWxBuuOOC0NdG1Mg60lEhpK7Bw/Ea6D89bRcvIvM3WnJrUpGA4jbx4xWj3KQRM08PM3WWCY9/FzctlWCxFMRg==", + "version": "0.48.3", + "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.48.3.tgz", + "integrity": "sha512-JL8pOLOEVACYG+33Dtp/mrB2/vuc7RoYZdxX1BQa5MPR8EzsODjpvL5uETmdxo/swgtMZyx2A6/e1B53eKA4oQ==", "dependencies": { "@babel/runtime": "7.24.1" } @@ -3405,9 +3397,9 @@ "license": "MIT" }, "node_modules/@stremio/stremio-icons": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@stremio/stremio-icons/-/stremio-icons-5.4.0.tgz", - "integrity": "sha512-rRWNER+wLgMjxd6sKT0MMq4lzXDOobY3GNdT3NDeeymBtB/CD0YmYqQuUOyYDjEZ1btIbNaniUOBoPW9d3ZQ8A==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@stremio/stremio-icons/-/stremio-icons-5.4.1.tgz", + "integrity": "sha512-7g4JP7tPRT1UDZxbuH/Urq7fc6te3joy8qyx/NGWIW7wO169TTISO7ZWdejzESvUVgZ/7i6rzkRmXZ3wefWcBg==", "workspaces": [ "react", "react-native", @@ -3416,9 +3408,10 @@ ] }, "node_modules/@stremio/stremio-video": { - "version": "0.0.46", - "resolved": "https://registry.npmjs.org/@stremio/stremio-video/-/stremio-video-0.0.46.tgz", - "integrity": "sha512-U15CGB6CrUZKq3IKcEouAEH2RQoLy2+BI/hDStEYEACxlRlFaavKPI2opl37muh9TY089RnZVBYAM3yDidBZdg==", + "version": "0.0.48", + "resolved": "https://registry.npmjs.org/@stremio/stremio-video/-/stremio-video-0.0.48.tgz", + "integrity": "sha512-6ALGXCZC4NPsfhPcrwFWQzvH6UMMRsgSkHetnOhv9WmZ5ubiyUdbBzj9atGiGuuQz8pRcze66ztrub+dsaQbpw==", + "license": "MIT", "dependencies": { "buffer": "6.0.3", "color": "4.2.3", @@ -10161,6 +10154,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "license": "MIT" + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -13938,6 +13938,29 @@ "node": ">=0.2.6" } }, + "node_modules/thread-loader": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/thread-loader/-/thread-loader-4.0.4.tgz", + "integrity": "sha512-tXagu6Hivd03wB2tiS1bqvw345sc7mKei32EgpYpq31ZLes9FN0mEK2nKzXLRFgwt3PsBB0E/MZDp159rDoqwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.1.0", + "neo-async": "^2.6.2", + "schema-utils": "^4.2.0" + }, + "engines": { + "node": ">= 16.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", diff --git a/package.json b/package.json old mode 100755 new mode 100644 index f44b53702..d1709095e --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "stremio", "displayName": "Stremio", - "version": "5.0.0-beta.13", + "version": "5.0.0-beta.15", "author": "Smart Code OOD", "private": true, "license": "gpl-2.0", @@ -16,9 +16,9 @@ "@babel/runtime": "7.26.0", "@sentry/browser": "8.42.0", "@stremio/stremio-colors": "5.2.0", - "@stremio/stremio-core-web": "0.48.1", - "@stremio/stremio-icons": "5.4.0", - "@stremio/stremio-video": "0.0.46", + "@stremio/stremio-core-web": "0.48.3", + "@stremio/stremio-icons": "5.4.1", + "@stremio/stremio-video": "0.0.48", "a-color-picker": "1.2.1", "bowser": "2.11.0", "buffer": "6.0.3", @@ -71,6 +71,7 @@ "postcss-loader": "8.1.1", "readdirp": "4.0.2", "terser-webpack-plugin": "5.3.10", + "thread-loader": "^4.0.4", "ts-loader": "^9.5.1", "typescript": "^5.7.2", "typescript-eslint": "^8.17.0", diff --git a/src/App/styles.less b/src/App/styles.less index 6210a8bdf..edff6e66d 100644 --- a/src/App/styles.less +++ b/src/App/styles.less @@ -38,7 +38,7 @@ --quaternary-accent-color: rgba(18, 69, 166, 1); --overlay-color: rgba(255, 255, 255, 0.05); --modal-background-color: rgba(15, 13, 32, 1); - --outer-glow: 0px 0px 30px rgba(123, 91, 245, 0.37); + --outer-glow: 0px 0px 15px rgba(123, 91, 245, 0.37); --border-radius: 0.75rem; } @@ -112,7 +112,7 @@ html { left: auto; z-index: 1; padding: 0 calc(0.5 * var(--horizontal-nav-bar-size)); - overflow-y: auto; + overflow: visible; scrollbar-width: none; pointer-events: none; diff --git a/src/common/BottomSheet/BottomSheet.less b/src/common/BottomSheet/BottomSheet.less index e0d756477..4ac68ead6 100644 --- a/src/common/BottomSheet/BottomSheet.less +++ b/src/common/BottomSheet/BottomSheet.less @@ -87,7 +87,13 @@ } } -@media only screen and (min-width: @xsmall) { +@media only screen and (min-width: @small) and (orientation: portait) { + .bottom-sheet { + display: none; + } +} + +@media only screen and (min-width: @xsmall) and (orientation: landscape) { .bottom-sheet { display: none; } diff --git a/src/common/Button/styles.less b/src/common/Button/styles.less index 6a26b3b7f..6baf8b7aa 100644 --- a/src/common/Button/styles.less +++ b/src/common/Button/styles.less @@ -6,6 +6,7 @@ outline-width: var(--focus-outline-size); outline-color: @color-surface-light5; outline-offset: calc(-1 * var(--focus-outline-size)); + -webkit-tap-highlight-color: transparent; cursor: pointer; &:focus { diff --git a/src/common/ColorInput/styles.less b/src/common/ColorInput/styles.less index 7ed494061..56bd1f601 100644 --- a/src/common/ColorInput/styles.less +++ b/src/common/ColorInput/styles.less @@ -17,7 +17,6 @@ align-items: center; justify-content: center; padding: 0 0.5rem; - border: thin solid @color-surface-light5-20; pointer-events: none; .transparent-label { diff --git a/src/common/EventModal/styles.less b/src/common/EventModal/styles.less index 67cfabb34..b251175e5 100644 --- a/src/common/EventModal/styles.less +++ b/src/common/EventModal/styles.less @@ -19,26 +19,30 @@ flex-direction: column; align-items: center; overflow: visible; + position: relative; - .modal-dialog-content { + .body-container { overflow-y: visible; } - + .image { - width: 100%; - height: 100%; - margin-top: -10rem; + position: absolute; + top: -10rem; + left: 50%; + transform: translateX(-50%); + object-fit: cover; + width: 30rem; + height: 30rem; } - + .info-container { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2.5rem; - padding: 1rem 4rem; - margin-top: -7rem; - + padding: 10rem 4rem 0; + .title-container { display: flex; flex-direction: column; @@ -50,7 +54,7 @@ text-align: center; padding: 0 6rem; } - + .label { color: var(--primary-foreground-color); font-size: 1rem; @@ -58,7 +62,7 @@ opacity: 0.5; } } - + .addon-container { display: flex; align-items: center; @@ -76,19 +80,19 @@ color: var(--primary-foreground-color); } } - + .action-button { background-color: var(--primary-foreground-color); border: 2px solid var(--primary-foreground-color); padding: 0.8rem 2rem; border-radius: 2rem; - + .button-label { color: var(--primary-accent-color); font-size: 1rem; font-weight: 700; } - + &:hover { background-color: transparent; } @@ -96,15 +100,34 @@ } } } +} - @media only screen and (max-width: @minimum) { +@media (orientation: landscape) and (max-height: @minimum) { + .event-modal { .modal-dialog-container { .modal-dialog-content { - .image { - height: 125%; - width: 125%; + overflow-y: auto; + + .body-container { + overflow-y: auto; } + .image { + display: none; + } + + .info-container { + padding: 1rem 4rem 0; + } + } + } + } +} + +@media only screen and (max-width: @minimum) { + .event-modal { + .modal-dialog-container { + .modal-dialog-content { .info-container { .title-container { .title { @@ -120,4 +143,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/common/MainNavBars/MainNavBars.js b/src/common/MainNavBars/MainNavBars.js index 3ccf200ec..6bcde9031 100644 --- a/src/common/MainNavBars/MainNavBars.js +++ b/src/common/MainNavBars/MainNavBars.js @@ -24,7 +24,6 @@ const MainNavBars = React.memo(({ className, route, query, children }) => { query={query} backButton={false} searchBar={true} - addonsButton={true} fullscreenButton={true} navMenu={true} /> diff --git a/src/common/MetaItem/styles.less b/src/common/MetaItem/styles.less index c2d094ac9..17c7c4884 100644 --- a/src/common/MetaItem/styles.less +++ b/src/common/MetaItem/styles.less @@ -166,6 +166,7 @@ object-position: center; object-fit: cover; opacity: 0.9; + overflow-clip-margin: unset; } .placeholder-icon { diff --git a/src/common/ModalDialog/styles.less b/src/common/ModalDialog/styles.less index bde17932d..ce03cfa84 100644 --- a/src/common/ModalDialog/styles.less +++ b/src/common/ModalDialog/styles.less @@ -82,7 +82,7 @@ .body-container { flex: 1; align-self: stretch; - overflow-y: auto; + overflow: visible; padding: 2rem 0; &:last-child { diff --git a/src/common/Multiselect/styles.less b/src/common/Multiselect/styles.less index b82fd06c5..cfb0c3234 100644 --- a/src/common/Multiselect/styles.less +++ b/src/common/Multiselect/styles.less @@ -7,6 +7,8 @@ popup-menu-container: menu-container; } +@parent-height: 10rem; + .label-container { display: flex; flex-direction: row; @@ -48,6 +50,8 @@ .modal-container, .popup-menu-container { .menu-container { + max-height: calc(3.2rem * 7); + .option-container { display: flex; flex-direction: row; @@ -101,4 +105,12 @@ } } } +} + +@media (orientation: landscape) and (max-width: @xsmall) { + .modal-container, .popup-menu-container { + .menu-container { + max-height: calc(100dvh - var(--horizontal-nav-bar-size) - @parent-height); + } + } } \ No newline at end of file diff --git a/src/common/MultiselectMenu/Dropdown/Dropdown.less b/src/common/MultiselectMenu/Dropdown/Dropdown.less index 57840ca22..3bea17d22 100644 --- a/src/common/MultiselectMenu/Dropdown/Dropdown.less +++ b/src/common/MultiselectMenu/Dropdown/Dropdown.less @@ -2,6 +2,8 @@ @import (reference) '~stremio/common/screen-sizes.less'; +@parent-height: 10rem; + .dropdown { background: var(--modal-background-color); display: none; @@ -16,7 +18,7 @@ &.open { display: block; - max-height: calc(3.2rem * 10); + max-height: calc(3.3rem * 7); overflow: auto; } @@ -33,10 +35,10 @@ } } -@media only screen and (max-width: @minimum) { +@media (orientation: landscape) and (max-width: @xsmall) { .dropdown { &.open { - max-height: calc(3.2rem * 7); + max-height: calc(100dvh - var(--horizontal-nav-bar-size) - @parent-height); } } } \ No newline at end of file diff --git a/src/common/NavBar/HorizontalNavBar/HorizontalNavBar.js b/src/common/NavBar/HorizontalNavBar/HorizontalNavBar.js index 7a992fb45..0df4e833f 100644 --- a/src/common/NavBar/HorizontalNavBar/HorizontalNavBar.js +++ b/src/common/NavBar/HorizontalNavBar/HorizontalNavBar.js @@ -13,7 +13,7 @@ const NavMenu = require('./NavMenu'); const styles = require('./styles'); const { t } = require('i18next'); -const HorizontalNavBar = React.memo(({ className, route, query, title, backButton, searchBar, addonsButton, fullscreenButton, navMenu, ...props }) => { +const HorizontalNavBar = React.memo(({ className, route, query, title, backButton, searchBar, fullscreenButton, navMenu, ...props }) => { const backButtonOnClick = React.useCallback(() => { window.history.back(); }, []); @@ -54,14 +54,6 @@ const HorizontalNavBar = React.memo(({ className, route, query, title, backButto null }
- { - addonsButton ? - - : - null - } { !isIOSPWA && fullscreenButton ? {
: remoteAddons.catalog.content.type === 'Loading' ? -
- Loading! +
+ {Array.from({ length: 6 }).map((_, index) => ( + + ))}
:
@@ -179,8 +182,10 @@ const Addons = ({ urlParams, queryParams }) => { }
: -
- No select +
+ {Array.from({ length: 6 }).map((_, index) => ( + + ))}
}
@@ -205,7 +210,7 @@ const Addons = ({ urlParams, queryParams }) => { title={t('ADD_ADDON')} buttons={addAddonModalButtons} onCloseRequest={closeAddAddonModal}> -
{ t('ADD_ADDON_DESCRIPTION') }
+
{t('ADD_ADDON_DESCRIPTION')}
{ { items.map(({ id, name, poster, deepLinks }) => ( - - @@ -162,7 +155,7 @@ const ControlBar = ({ { metaItem?.content?.videos?.length > 0 ? - : @@ -200,9 +193,8 @@ ControlBar.propTypes = { onVolumeChangeRequested: PropTypes.func, onSeekRequested: PropTypes.func, onToggleSubtitlesMenu: PropTypes.func, - onToggleInfoMenu: PropTypes.func, onToggleSpeedMenu: PropTypes.func, - onToggleVideosMenu: PropTypes.func, + onToggleSideDrawer: PropTypes.func, onToggleOptionsMenu: PropTypes.func, onToggleStatisticsMenu: PropTypes.func, }; diff --git a/src/routes/Player/ControlBar/styles.less b/src/routes/Player/ControlBar/styles.less index 147a3f0a2..bcfbbdaef 100644 --- a/src/routes/Player/ControlBar/styles.less +++ b/src/routes/Player/ControlBar/styles.less @@ -100,14 +100,16 @@ .control-bar-buttons-menu-container { position: absolute; - right: 0.15rem; + right: 0rem; bottom: 4.5rem; - flex-direction: column; padding: 0.5rem; + margin: 0.5rem; + max-width: calc(100dvw - 1rem); border-radius: var(--border-radius); background-color: var(--modal-background-color); box-shadow: 0 1.35rem 2.7rem @color-background-dark5-40, 0 1.1rem 0.85rem @color-background-dark5-20; + overflow-x: auto; &:not(:global(.open)) { display: none; diff --git a/src/routes/Player/InfoMenu/InfoMenu.js b/src/routes/Player/InfoMenu/InfoMenu.js deleted file mode 100644 index eec5e7286..000000000 --- a/src/routes/Player/InfoMenu/InfoMenu.js +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const React = require('react'); -const PropTypes = require('prop-types'); -const classnames = require('classnames'); -// const Stream = require('stremio/routes/MetaDetails/StreamsList/Stream'); -// const AddonDetails = require('stremio/common/AddonDetailsModal/AddonDetails'); -const { MetaPreview, CONSTANTS } = require('stremio/common'); -const styles = require('./styles'); - -const InfoMenu = ({ className, ...props }) => { - const metaItem = React.useMemo(() => { - return props.metaItem !== null ? - { - ...props.metaItem, - links: props.metaItem.links.filter(({ category }) => category === CONSTANTS.SHARE_LINK_CATEGORY) - } - : - null; - }, [props.metaItem]); - const onMouseDown = React.useCallback((event) => { - event.nativeEvent.infoMenuClosePrevented = true; - }, []); - return ( -
- { - metaItem !== null ? - - : - null - } - {/* { - props.stream !== null ? - - : - null - } */} - {/* { - props.addon !== null ? - - : - null - } */} -
- ); -}; - -InfoMenu.propTypes = { - className: PropTypes.string, - metaItem: PropTypes.object, - addon: PropTypes.object, - stream: PropTypes.object -}; - -module.exports = InfoMenu; diff --git a/src/routes/Player/InfoMenu/index.js b/src/routes/Player/InfoMenu/index.js deleted file mode 100644 index 8dae65490..000000000 --- a/src/routes/Player/InfoMenu/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const InfoMenu = require('./InfoMenu'); - -module.exports = InfoMenu; diff --git a/src/routes/Player/InfoMenu/styles.less b/src/routes/Player/InfoMenu/styles.less deleted file mode 100644 index 32a72b77d..000000000 --- a/src/routes/Player/InfoMenu/styles.less +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -.info-menu-container { - width: 30rem; - padding: 2rem; - - .stream { - pointer-events: none; - } -} \ No newline at end of file diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index 5ace96f77..b086d1706 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -8,18 +8,18 @@ const langs = require('langs'); const { useTranslation } = require('react-i18next'); const { useRouteFocused } = require('stremio-router'); const { useServices } = require('stremio/services'); -const { HorizontalNavBar, useFullscreen, useBinaryState, useToast, useStreamingServer, withCoreSuspender } = require('stremio/common'); +const { HorizontalNavBar, Transition, useFullscreen, useBinaryState, useToast, useStreamingServer, withCoreSuspender } = require('stremio/common'); const BufferingLoader = require('./BufferingLoader'); const VolumeChangeIndicator = require('./VolumeChangeIndicator'); const Error = require('./Error'); const ControlBar = require('./ControlBar'); const NextVideoPopup = require('./NextVideoPopup'); const StatisticsMenu = require('./StatisticsMenu'); -const InfoMenu = require('./InfoMenu'); const OptionsMenu = require('./OptionsMenu'); -const VideosMenu = require('./VideosMenu'); const SubtitlesMenu = require('./SubtitlesMenu'); const SpeedMenu = require('./SpeedMenu'); +const { default: SideDrawerButton } = require('./SideDrawerButton'); +const { default: SideDrawer } = require('./SideDrawer'); const usePlayer = require('./usePlayer'); const useSettings = require('./useSettings'); const useStatistics = require('./useStatistics'); @@ -54,23 +54,21 @@ const Player = ({ urlParams, queryParams }) => { const [optionsMenuOpen, , closeOptionsMenu, toggleOptionsMenu] = useBinaryState(false); const [subtitlesMenuOpen, , closeSubtitlesMenu, toggleSubtitlesMenu] = useBinaryState(false); - const [infoMenuOpen, , closeInfoMenu, toggleInfoMenu] = useBinaryState(false); const [speedMenuOpen, , closeSpeedMenu, toggleSpeedMenu] = useBinaryState(false); - const [videosMenuOpen, , closeVideosMenu, toggleVideosMenu] = useBinaryState(false); const [statisticsMenuOpen, , closeStatisticsMenu, toggleStatisticsMenu] = useBinaryState(false); const [nextVideoPopupOpen, openNextVideoPopup, closeNextVideoPopup] = useBinaryState(false); + const [sideDrawerOpen, , closeSideDrawer, toggleSideDrawer] = useBinaryState(false); const menusOpen = React.useMemo(() => { - return optionsMenuOpen || subtitlesMenuOpen || infoMenuOpen || speedMenuOpen || videosMenuOpen || statisticsMenuOpen; - }, [optionsMenuOpen, subtitlesMenuOpen, infoMenuOpen, speedMenuOpen, videosMenuOpen, statisticsMenuOpen]); + return optionsMenuOpen || subtitlesMenuOpen || speedMenuOpen || statisticsMenuOpen || sideDrawerOpen; + }, [optionsMenuOpen, subtitlesMenuOpen, speedMenuOpen, statisticsMenuOpen, sideDrawerOpen]); const closeMenus = React.useCallback(() => { closeOptionsMenu(); closeSubtitlesMenu(); - closeInfoMenu(); closeSpeedMenu(); - closeVideosMenu(); closeStatisticsMenu(); + closeSideDrawer(); }, []); const overlayHidden = React.useMemo(() => { @@ -237,18 +235,14 @@ const Player = ({ urlParams, queryParams }) => { if (!event.nativeEvent.subtitlesMenuClosePrevented) { closeSubtitlesMenu(); } - if (!event.nativeEvent.infoMenuClosePrevented) { - closeInfoMenu(); - } if (!event.nativeEvent.speedMenuClosePrevented) { closeSpeedMenu(); } - if (!event.nativeEvent.videosMenuClosePrevented) { - closeVideosMenu(); - } if (!event.nativeEvent.statisticsMenuClosePrevented) { closeStatisticsMenu(); } + + closeSideDrawer(); }, []); const onContainerMouseMove = React.useCallback((event) => { @@ -271,10 +265,9 @@ const Player = ({ urlParams, queryParams }) => { React.useEffect(() => { setError(null); - if (player.selected === null) { - video.unload(); - } else if (streamingServer.settings !== null && streamingServer.settings.type !== 'Loading' && - (player.selected.metaRequest === null || (player.metaItem !== null && player.metaItem.type !== 'Loading'))) { + video.unload(); + + if (player.selected && streamingServer.settings?.type !== 'Loading') { video.load({ stream: { ...player.selected.stream, @@ -309,7 +302,7 @@ const Player = ({ urlParams, queryParams }) => { shellTransport: shell.active ? shell.transport : null, }); } - }, [streamingServer.baseUrl, player.selected, player.metaItem, forceTranscoding, casting]); + }, [streamingServer.baseUrl, player.selected, forceTranscoding, casting]); React.useEffect(() => { if (video.state.stream !== null) { const tracks = player.subtitles.map((subtitles) => ({ @@ -412,13 +405,6 @@ const Player = ({ urlParams, queryParams }) => { } }, [video.state.audioTracks, video.state.subtitlesTracks, video.state.extraSubtitlesTracks]); - React.useEffect(() => { - if (player.metaItem === null || player.metaItem.type !== 'Ready') { - closeInfoMenu(); - closeVideosMenu(); - } - }, [player.metaItem]); - React.useEffect(() => { if (video.state.playbackSpeed === null) { closeSpeedMenu(); @@ -521,7 +507,7 @@ const Player = ({ urlParams, queryParams }) => { case 'KeyI': { closeMenus(); if (player.metaItem !== null && player.metaItem.type === 'Ready') { - toggleInfoMenu(); + toggleSideDrawer(); } break; @@ -534,14 +520,6 @@ const Player = ({ urlParams, queryParams }) => { break; } - case 'KeyV': { - closeMenus(); - if (player.metaItem !== null && player.metaItem.type === 'Ready' && player.metaItem?.content?.videos?.length > 0) { - toggleVideosMenu(); - } - - break; - } case 'KeyD': { closeMenus(); if (streamingServer.statistics !== null && streamingServer.statistics.type !== 'Err' && player.selected && typeof player.selected.stream.infoHash === 'string' && typeof player.selected.stream.fileIdx === 'number') { @@ -582,7 +560,7 @@ const Player = ({ urlParams, queryParams }) => { window.removeEventListener('keyup', onKeyUp); window.removeEventListener('wheel', onWheel); }; - }, [player.metaItem, player.selected, streamingServer.statistics, settings.seekTimeDuration, settings.seekShortTimeDuration, routeFocused, menusOpen, nextVideoPopupOpen, video.state.paused, video.state.time, video.state.volume, video.state.audioTracks, video.state.subtitlesTracks, video.state.extraSubtitlesTracks, video.state.playbackSpeed, toggleSubtitlesMenu, toggleInfoMenu, toggleVideosMenu, toggleStatisticsMenu]); + }, [player.metaItem, player.selected, streamingServer.statistics, settings.seekTimeDuration, settings.seekShortTimeDuration, routeFocused, menusOpen, nextVideoPopupOpen, video.state.paused, video.state.time, video.state.volume, video.state.audioTracks, video.state.subtitlesTracks, video.state.extraSubtitlesTracks, video.state.playbackSpeed, toggleSubtitlesMenu, toggleStatisticsMenu, toggleSideDrawer]); React.useEffect(() => { video.events.on('error', onError); @@ -667,6 +645,15 @@ const Player = ({ urlParams, queryParams }) => { onMouseMove={onBarMouseMove} onMouseOver={onBarMouseMove} /> + { + player.metaItem?.type === 'Ready' ? + + : + null + } { onSeekRequested={onSeekRequested} onToggleOptionsMenu={toggleOptionsMenu} onToggleSubtitlesMenu={toggleSubtitlesMenu} - onToggleInfoMenu={toggleInfoMenu} onToggleSpeedMenu={toggleSpeedMenu} - onToggleVideosMenu={toggleVideosMenu} onToggleStatisticsMenu={toggleStatisticsMenu} + onToggleSideDrawer={toggleSideDrawer} onMouseMove={onBarMouseMove} onMouseOver={onBarMouseMove} /> @@ -719,6 +705,14 @@ const Player = ({ urlParams, queryParams }) => { : null } + + + { subtitlesMenuOpen ? { : null } - { - infoMenuOpen ? - - : - null - } { speedMenuOpen ? { : null } - { - videosMenuOpen ? - - : - null - } { optionsMenuOpen ? void; +}; + +const SideDrawer = memo(forwardRef(({ seriesInfo, className, closeSideDrawer, ...props }: Props, ref) => { + const { core } = useServices(); + const [season, setSeason] = useState(seriesInfo?.season); + const metaItem = useMemo(() => { + return seriesInfo ? + { + ...props.metaItem, + links: props.metaItem.links.filter(({ category }) => category === CONSTANTS.SHARE_LINK_CATEGORY) + } + : + props.metaItem; + }, [props.metaItem]); + const videos = useMemo(() => { + return Array.isArray(metaItem.videos) ? + metaItem.videos.filter((video) => video.season === season) + : + metaItem.videos; + }, [metaItem, season]); + const seasons = useMemo(() => { + return props.metaItem.videos + .map(({ season }) => season) + .filter((season, index, seasons) => { + return seasons.indexOf(season) === index; + }) + .sort((a, b) => (a || Number.MAX_SAFE_INTEGER) - (b || Number.MAX_SAFE_INTEGER)); + }, [props.metaItem.videos]); + + const seasonOnSelect = useCallback((event: { value: string }) => { + setSeason(parseInt(event.value)); + }, []); + + const onMarkVideoAsWatched = useCallback((video: Video, watched: boolean) => { + core.transport.dispatch({ + action: 'Player', + args: { + action: 'MarkVideoAsWatched', + args: [video, !watched] + } + }); + }, []); + + const onMouseDown = (event: React.MouseEvent) => { + event.stopPropagation(); + }; + + return ( +
+
+ +
+
+ +
+ { + seriesInfo ? +
+ +
+ {videos.map((video, index) => ( +
+
+ : null + } + +
+ ); +})); + +export default SideDrawer; diff --git a/src/routes/Player/SideDrawer/index.ts b/src/routes/Player/SideDrawer/index.ts new file mode 100644 index 000000000..e19e268d3 --- /dev/null +++ b/src/routes/Player/SideDrawer/index.ts @@ -0,0 +1,2 @@ +import SideDrawer from './SideDrawer'; +export default SideDrawer; diff --git a/src/routes/Player/SideDrawerButton/SideDrawerButton.less b/src/routes/Player/SideDrawerButton/SideDrawerButton.less new file mode 100644 index 000000000..e7e86027f --- /dev/null +++ b/src/routes/Player/SideDrawerButton/SideDrawerButton.less @@ -0,0 +1,47 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +@import (reference) '~stremio/common/screen-sizes.less'; + +.side-drawer-button { + height: 12.5rem; + width: 7.5rem; + display: flex; + align-items: center; + justify-content: start; + padding-left: 0.5rem; + border-radius: 50%; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + background-color: var(--modal-background-color); + -webkit-tap-highlight-color: transparent; + cursor: pointer; + opacity: 1; + will-change: opacity; + transition: opacity 0.3s ease-in-out, border-radius 0.3s ease-in-out; + + .icon { + position: relative; + width: 2.5rem; + height: 2.5rem; + color: var(--primary-foreground-color); + opacity: 0.6; + transition: 0.3s opacity ease-in-out; + } + + &:hover { + .icon { + opacity: 1; + } + } +} + +@media screen and (max-width: @xsmall) { + .side-drawer-button { + height: 8rem; + width: 4.5rem; + + .icon { + width: 2rem; + height: 2rem; + } + } +} \ No newline at end of file diff --git a/src/routes/Player/SideDrawerButton/SideDrawerButton.tsx b/src/routes/Player/SideDrawerButton/SideDrawerButton.tsx new file mode 100644 index 000000000..81409f434 --- /dev/null +++ b/src/routes/Player/SideDrawerButton/SideDrawerButton.tsx @@ -0,0 +1,21 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React from 'react'; +import classNames from 'classnames'; +import Icon from '@stremio/stremio-icons/react'; +import styles from './SideDrawerButton.less'; + +type Props = { + className: string, + onClick: () => void, +}; + +const SideDrawerButton = ({ className, onClick }: Props) => { + return ( +
+ +
+ ); +}; + +export default SideDrawerButton; diff --git a/src/routes/Player/SideDrawerButton/index.ts b/src/routes/Player/SideDrawerButton/index.ts new file mode 100644 index 000000000..73585e555 --- /dev/null +++ b/src/routes/Player/SideDrawerButton/index.ts @@ -0,0 +1,2 @@ +import SideDrawerButton from './SideDrawerButton'; +export default SideDrawerButton; diff --git a/src/routes/Player/SpeedMenu/styles.less b/src/routes/Player/SpeedMenu/styles.less index 12c3ea725..4305d5d01 100644 --- a/src/routes/Player/SpeedMenu/styles.less +++ b/src/routes/Player/SpeedMenu/styles.less @@ -1,10 +1,9 @@ -// Copyright (C) 2017-2023 Smart code 203358507 +// Copyright (C) 2017-2024 Smart code 203358507 @import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; .speed-menu-container { width: 14rem; - overflow: visible !important; .title { flex: none; @@ -18,7 +17,6 @@ flex: 0 1 auto; max-height: calc(3.2rem * 8); padding: 0 1rem 0.5rem; - overflow-y: auto; .option { height: 3.2rem; diff --git a/src/routes/Player/SubtitlesMenu/SubtitlesMenu.js b/src/routes/Player/SubtitlesMenu/SubtitlesMenu.js index c65cb9c9e..24cccb7fc 100644 --- a/src/routes/Player/SubtitlesMenu/SubtitlesMenu.js +++ b/src/routes/Player/SubtitlesMenu/SubtitlesMenu.js @@ -129,19 +129,19 @@ const SubtitlesMenu = React.memo((props) => { const onSubtitlesOffsetChanged = React.useCallback((event) => { const delta = event.value === 'increment' ? 1 : -1; if (typeof props.selectedSubtitlesTrackId === 'string') { - if (props.extraSubtitlesOffset !== null && !isNaN(props.extraSubtitlesOffset)) { - const offset = Math.max(0, Math.min(100, Math.floor(props.extraSubtitlesOffset + delta))); - if (typeof props.onExtraSubtitlesOffsetChanged === 'function') { - props.onExtraSubtitlesOffsetChanged(offset); - } - } - } else if (typeof props.selectedExtraSubtitlesTrackId === 'string') { if (props.subtitlesOffset !== null && !isNaN(props.subtitlesOffset)) { const offset = Math.max(0, Math.min(100, Math.floor(props.subtitlesOffset + delta))); if (typeof props.onSubtitlesOffsetChanged === 'function') { props.onSubtitlesOffsetChanged(offset); } } + } else if (typeof props.selectedExtraSubtitlesTrackId === 'string') { + if (props.extraSubtitlesOffset !== null && !isNaN(props.extraSubtitlesOffset)) { + const offset = Math.max(0, Math.min(100, Math.floor(props.extraSubtitlesOffset + delta))); + if (typeof props.onExtraSubtitlesOffsetChanged === 'function') { + props.onExtraSubtitlesOffsetChanged(offset); + } + } } }, [props.selectedSubtitlesTrackId, props.selectedExtraSubtitlesTrackId, props.subtitlesOffset, props.extraSubtitlesOffset, props.onSubtitlesOffsetChanged, props.onExtraSubtitlesOffsetChanged]); const audioTrackOnClick = React.useCallback((event) => { diff --git a/src/routes/Player/VideosMenu/VideosMenu.js b/src/routes/Player/VideosMenu/VideosMenu.js index 9d5819db7..d418b3f31 100644 --- a/src/routes/Player/VideosMenu/VideosMenu.js +++ b/src/routes/Player/VideosMenu/VideosMenu.js @@ -3,19 +3,34 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); -const Video = require('../../MetaDetails/VideosList/Video'); +const { useServices } = require('stremio/services'); +const { Video } = require('stremio/common'); const styles = require('./styles'); const VideosMenu = ({ className, metaItem, seriesInfo }) => { + const { core } = useServices(); + const onMouseDown = React.useCallback((event) => { event.nativeEvent.videosMenuClosePrevented = true; }, []); + const videos = React.useMemo(() => { return seriesInfo && typeof seriesInfo.season === 'number' && Array.isArray(metaItem.videos) ? metaItem.videos.filter(({ season }) => season === seriesInfo.season) : metaItem.videos; }, [metaItem, seriesInfo]); + + const onMarkVideoAsWatched = (video, watched) => { + core.transport.dispatch({ + action: 'Player', + args: { + action: 'MarkVideoAsWatched', + args: [video, !watched] + } + }); + }; + return (
{ @@ -32,6 +47,7 @@ const VideosMenu = ({ className, metaItem, seriesInfo }) => { progress={video.progress} deepLinks={video.deepLinks} scheduled={video.scheduled} + onMarkVideoAsWatched={onMarkVideoAsWatched} /> )) } diff --git a/src/routes/Player/VideosMenu/index.js b/src/routes/Player/VideosMenu/index.js deleted file mode 100644 index c2fa21666..000000000 --- a/src/routes/Player/VideosMenu/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const VideosMenu = require('./VideosMenu'); - -module.exports = VideosMenu; diff --git a/src/routes/Player/VideosMenu/styles.less b/src/routes/Player/VideosMenu/styles.less deleted file mode 100644 index 8cc7e4805..000000000 --- a/src/routes/Player/VideosMenu/styles.less +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -.videos-menu-container { - width: 30rem; - padding: 1rem; - padding-bottom: 0; -} \ No newline at end of file diff --git a/src/routes/Player/styles.less b/src/routes/Player/styles.less index 8bff42fe1..e74604294 100644 --- a/src/routes/Player/styles.less +++ b/src/routes/Player/styles.less @@ -1,6 +1,7 @@ // Copyright (C) 2017-2023 Smart code 203358507 @import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; +@import (reference) '~stremio/common/screen-sizes.less'; :import('~stremio/common/Slider/styles.less') { active-slider-within: active-slider-within; @@ -18,7 +19,7 @@ html:not(.active-slider-within) { .player-container.overlayHidden { cursor: none; - .nav-bar-layer, .control-bar-layer, .menu-layer { + .nav-bar-layer, .control-bar-layer, .menu-layer, .side-drawer-button-layer { opacity: 0; transition: opacity 200ms; } @@ -83,6 +84,13 @@ html:not(.active-slider-within) { } } + &.side-drawer-button-layer { + top: 50%; + right: -4rem; + left: initial; + transform: translateY(-50%); + } + &.control-bar-layer { top: initial; overflow: visible; @@ -101,7 +109,7 @@ html:not(.active-slider-within) { &.menu-layer { top: initial; left: initial; - right: 2rem; + right: 4rem; bottom: 8rem; max-height: calc(100% - 13.5rem); max-width: calc(100% - 4rem); @@ -112,5 +120,33 @@ html:not(.active-slider-within) { backdrop-filter: blur(15px); overflow: auto; } + + &.side-drawer-layer { + bottom: 0; + right: 0; + left: initial; + bottom: initial; + } } -} \ No newline at end of file +} + +@media screen and (max-width: @xsmall) { + .player-container { + .layer { + &.side-drawer-button-layer { + right: -2rem; + } + } + } +} + +@media (orientation: portrait) and (max-width: @minimum) { + .player-container { + .layer { + &.menu-layer { + right: 2.5rem; + bottom: 11rem; + } + } + } +} diff --git a/src/routes/Settings/URLsManager/AddItem/AddItem.less b/src/routes/Settings/URLsManager/AddItem/AddItem.less index b31ce9ac8..e8de1ecf6 100644 --- a/src/routes/Settings/URLsManager/AddItem/AddItem.less +++ b/src/routes/Settings/URLsManager/AddItem/AddItem.less @@ -4,11 +4,10 @@ .add-item { display: flex; - padding: 0.5rem 1.5rem; - gap: 1rem; - border-radius: var(--border-radius); + padding: 0.35rem 1.5rem; + border-radius: 2.5rem; transition: 0.3s all ease-in-out; - background-color: transparent; + background-color: var(--overlay-color); border: 2px solid transparent; justify-content: space-between; position: relative; @@ -77,13 +76,12 @@ } &:hover { - border: 2px solid transparent; - background-color: var(--overlay-color); + border: 2px solid var(--overlay-color); } } @media only screen and (max-width: @minimum) { .add-item { - padding: 0.5rem; + padding: 0.35rem 0.5rem; } } \ No newline at end of file diff --git a/src/routes/Settings/URLsManager/Item/Item.less b/src/routes/Settings/URLsManager/Item/Item.less index 81c6d6c17..1205555cc 100644 --- a/src/routes/Settings/URLsManager/Item/Item.less +++ b/src/routes/Settings/URLsManager/Item/Item.less @@ -4,10 +4,10 @@ .item { display: flex; - padding: 1rem 1.5rem; - border-radius: var(--border-radius); + padding: 0.7rem 1.5rem; + border-radius: 2.5rem; transition: 0.3s all ease-in-out; - background-color: transparent; + background-color: var(--overlay-color); border: 2px solid transparent; justify-content: space-between; position: relative; @@ -34,7 +34,7 @@ .actions { display: flex; gap: 1rem; - margin-right: 5rem; + padding-right: 4rem; .status { display: flex; @@ -100,7 +100,7 @@ } &:hover { - background-color: var(--overlay-color); + border: 2px solid var(--overlay-color); .actions { .delete { @@ -114,13 +114,11 @@ @media only screen and (max-width: @minimum) { .item { - padding: 1rem 0.5rem; + padding: 0.7rem 1rem; .actions { - margin-right: 4rem; - .delete { - right: 0.5rem; + right: 1rem; .icon { opacity: 0.6; diff --git a/src/routes/Settings/URLsManager/Item/Item.tsx b/src/routes/Settings/URLsManager/Item/Item.tsx index 7f840686c..319592f02 100644 --- a/src/routes/Settings/URLsManager/Item/Item.tsx +++ b/src/routes/Settings/URLsManager/Item/Item.tsx @@ -27,8 +27,8 @@ const Item = ({ url }: Props) => { const handleDelete = useCallback(() => { deleteServerUrl(url); - selectServerUrl(DEFAULT_STREAMING_SERVER_URL); - }, [url]); + selected && selectServerUrl(DEFAULT_STREAMING_SERVER_URL); + }, [url, selected]); const handleSelect = useCallback(() => { selectServerUrl(url); diff --git a/src/routes/Settings/URLsManager/URLsManager.less b/src/routes/Settings/URLsManager/URLsManager.less index 440ec39b3..fd0055d1c 100644 --- a/src/routes/Settings/URLsManager/URLsManager.less +++ b/src/routes/Settings/URLsManager/URLsManager.less @@ -8,7 +8,8 @@ .header { display: flex; - justify-content: space-around; + justify-content: space-between; + padding: 0 3rem; align-items: center; .label { @@ -16,6 +17,10 @@ color: var(--primary-foreground-color); font-weight: 400; opacity: 0.6; + + &:last-of-type { + padding-right: 3rem; + } } } diff --git a/src/routes/Settings/styles.less b/src/routes/Settings/styles.less index a8dd1a990..37103540f 100644 --- a/src/routes/Settings/styles.less +++ b/src/routes/Settings/styles.less @@ -286,7 +286,6 @@ } .multiselect-menu-container { - max-height: calc(3.2rem * 7); overflow: auto; } } @@ -316,7 +315,14 @@ } &.color-input-container { - padding: 1.75rem 1rem; + padding: 1.3rem 1rem; + border-radius: 3rem; + border: 2px solid transparent; + transition: 0.3s all ease-in-out; + + &:hover { + border-color: var(--overlay-color); + } } &.info-container { diff --git a/src/types/MetaItem.d.ts b/src/types/MetaItem.d.ts index 0d692a580..56e7db3c7 100644 --- a/src/types/MetaItem.d.ts +++ b/src/types/MetaItem.d.ts @@ -15,7 +15,7 @@ type MetaItemPreview = { posterShape: PosterShape, releaseInfo: string | null, runtime: string | null, - released: string | null, + released: Date | null | undefined, trailerStreams: TrailerStream[], links: Link[], behaviorHints: BehaviorHints, diff --git a/src/types/Video.d.ts b/src/types/Video.d.ts index 92bc704f5..7ed3d0fac 100644 --- a/src/types/Video.d.ts +++ b/src/types/Video.d.ts @@ -14,4 +14,9 @@ type Video = { episode?: number, streams: Stream[], trailerStreams: TrailerStream[], + watched: boolean, + progress: number, + upcoming: boolean, + deepLinks: VideoDeepLinks, + scheduled: boolean, }; diff --git a/src/types/models/Player.d.ts b/src/types/models/Player.d.ts index 6664e83f5..2add1456b 100644 --- a/src/types/models/Player.d.ts +++ b/src/types/models/Player.d.ts @@ -25,6 +25,11 @@ type Subtitle = { url: string, }; +type SeriesInfo = { + episode: number, + season: number, +}; + type Player = { addon: Addon | null, libraryItem: LibraryItemPlayer | null, @@ -36,10 +41,7 @@ type Player = { streamRequest: ResourceRequest, subtitlesPath: ResourceRequestPath, } | null, - seriesInfo: { - season: number, - episode: number, - } | null, + seriesInfo: SeriesInfo | null, subtitles: Subtitle[], title: string | null, }; diff --git a/webpack.config.js b/webpack.config.js index 1b6c6601b..b23ee4c15 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,8 +1,10 @@ // Copyright (C) 2017-2023 Smart code 203358507 const path = require('path'); +const os = require('os'); const { execSync } = require('child_process'); const webpack = require('webpack'); +const threadLoader = require('thread-loader'); const HtmlWebPackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); @@ -14,6 +16,25 @@ const pachageJson = require('./package.json'); const COMMIT_HASH = execSync('git rev-parse HEAD').toString().trim(); +const THREAD_LOADER = { + loader: 'thread-loader', + options: { + name: 'shared-pool', + workers: os.cpus().length, + }, +}; + +threadLoader.warmup( + THREAD_LOADER.options, + [ + 'babel-loader', + 'ts-loader', + 'css-loader', + 'postcss-loader', + 'less-loader', + ], +); + module.exports = (env, argv) => ({ mode: argv.mode, devtool: argv.mode === 'production' ? 'source-map' : 'eval-source-map', @@ -30,20 +51,31 @@ module.exports = (env, argv) => ({ { test: /\.js$/, exclude: /node_modules/, - use: { - loader: 'babel-loader', - options: { - presets: [ - '@babel/preset-env', - '@babel/preset-react' - ], + use: [ + THREAD_LOADER, + { + loader: 'babel-loader', + options: { + presets: [ + '@babel/preset-env', + '@babel/preset-react' + ], + } } - } + ] }, { test: /\.(ts|tsx)$/, exclude: /node_modules/, - use: 'ts-loader', + use: [ + THREAD_LOADER, + { + loader: 'ts-loader', + options: { + happyPackMode: true, + } + } + ] }, { test: /\.less$/, @@ -55,6 +87,7 @@ module.exports = (env, argv) => ({ esModule: false } }, + THREAD_LOADER, { loader: 'css-loader', options: {