diff --git a/package-lock.json b/package-lock.json
index 39a17e5aa..c560b3166 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,8 +12,8 @@
"@babel/runtime": "7.26.0",
"@sentry/browser": "8.42.0",
"@stremio/stremio-colors": "5.2.0",
- "@stremio/stremio-core-web": "0.49.3",
- "@stremio/stremio-icons": "5.4.1",
+ "@stremio/stremio-core-web": "0.49.4",
+ "@stremio/stremio-icons": "5.7.1",
"@stremio/stremio-video": "0.0.60",
"a-color-picker": "1.2.1",
"bowser": "2.11.0",
@@ -3374,10 +3374,9 @@
"integrity": "sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg=="
},
"node_modules/@stremio/stremio-core-web": {
- "version": "0.49.3",
- "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.49.3.tgz",
- "integrity": "sha512-Ql/08LbwU99IUL6fOLy+v1Iv75boHXpunEPScKgXJALdq/OV5tZLG/IycN0O+5+50Nc/NHrI6HslnMNLTWA8JQ==",
- "license": "MIT",
+ "version": "0.49.4",
+ "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.49.4.tgz",
+ "integrity": "sha512-K9LJGKXs8juV3pZOHH6thWTwOShAhjFt9bLL6K1VlORAe6AiieZ2uRp9wdOwFmPX+UgzWLIOd0r2aFXJ4OsJCw==",
"dependencies": {
"@babel/runtime": "7.24.1"
}
@@ -3401,9 +3400,10 @@
"license": "MIT"
},
"node_modules/@stremio/stremio-icons": {
- "version": "5.4.1",
- "resolved": "https://registry.npmjs.org/@stremio/stremio-icons/-/stremio-icons-5.4.1.tgz",
- "integrity": "sha512-7g4JP7tPRT1UDZxbuH/Urq7fc6te3joy8qyx/NGWIW7wO169TTISO7ZWdejzESvUVgZ/7i6rzkRmXZ3wefWcBg==",
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/@stremio/stremio-icons/-/stremio-icons-5.7.1.tgz",
+ "integrity": "sha512-Z96p36LLX3G+ewMnFKmNZVsO/AtcHA33WQ3wGOYFubxiYADPRAkcLVU5rHIfiGSC9IUaUVhxQWTPVB9ScY4Q5Q==",
+ "license": "MIT",
"workspaces": [
"react",
"react-native",
diff --git a/package.json b/package.json
index 9599f3587..082111216 100644
--- a/package.json
+++ b/package.json
@@ -17,8 +17,8 @@
"@babel/runtime": "7.26.0",
"@sentry/browser": "8.42.0",
"@stremio/stremio-colors": "5.2.0",
- "@stremio/stremio-core-web": "0.49.3",
- "@stremio/stremio-icons": "5.4.1",
+ "@stremio/stremio-core-web": "0.49.4",
+ "@stremio/stremio-icons": "5.7.1",
"@stremio/stremio-video": "0.0.60",
"a-color-picker": "1.2.1",
"bowser": "2.11.0",
diff --git a/src/components/MetaPreview/MetaPreview.js b/src/components/MetaPreview/MetaPreview.js
index c0e9fb165..13717919a 100644
--- a/src/components/MetaPreview/MetaPreview.js
+++ b/src/components/MetaPreview/MetaPreview.js
@@ -17,6 +17,7 @@ const ActionButton = require('./ActionButton');
const MetaLinks = require('./MetaLinks');
const MetaPreviewPlaceholder = require('./MetaPreviewPlaceholder');
const styles = require('./styles');
+const { Ratings } = require('./Ratings');
const ALLOWED_LINK_REDIRECTS = [
routesRegexp.search.regexp,
@@ -24,7 +25,7 @@ const ALLOWED_LINK_REDIRECTS = [
routesRegexp.metadetails.regexp
];
-const MetaPreview = React.forwardRef(({ className, compact, name, logo, background, runtime, releaseInfo, released, description, deepLinks, links, trailerStreams, inLibrary, toggleInLibrary }, ref) => {
+const MetaPreview = React.forwardRef(({ className, compact, name, logo, background, runtime, releaseInfo, released, description, deepLinks, links, trailerStreams, inLibrary, toggleInLibrary, ratingInfo }, ref) => {
const { t } = useTranslation();
const [shareModalOpen, openShareModal, closeShareModal] = useBinaryState(false);
const linksGroups = React.useMemo(() => {
@@ -232,6 +233,15 @@ const MetaPreview = React.forwardRef(({ className, compact, name, logo, backgrou
:
null
}
+ {
+ !compact && ratingInfo !== null ?
+
+ :
+ null
+ }
{
linksGroups.has(CONSTANTS.SHARE_LINK_CATEGORY) && !compact ?
@@ -287,7 +297,8 @@ MetaPreview.propTypes = {
})),
trailerStreams: PropTypes.array,
inLibrary: PropTypes.bool,
- toggleInLibrary: PropTypes.func
+ toggleInLibrary: PropTypes.func,
+ ratingInfo: PropTypes.object,
};
module.exports = MetaPreview;
diff --git a/src/components/MetaPreview/Ratings/Ratings.less b/src/components/MetaPreview/Ratings/Ratings.less
new file mode 100644
index 000000000..f4c7d57c2
--- /dev/null
+++ b/src/components/MetaPreview/Ratings/Ratings.less
@@ -0,0 +1,62 @@
+// Copyright (C) 2017-2025 Smart code 203358507
+
+@import (reference) '~stremio/common/screen-sizes.less';
+
+@height: 4rem;
+@width: 4rem;
+@height-mobile: 3rem;
+@width-mobile: 3rem;
+
+
+.ratings-container {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ background-color: var(--overlay-color);
+ border-radius: 2rem;
+ height: @height;
+ width: fit-content;
+
+ .icon-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: @height;
+ width: @width;
+ padding: 0 1rem;
+ cursor: pointer;
+
+ .icon {
+ width: calc(@width / 2);
+ height: calc(@height / 2);
+ color: var(--primary-foreground-color);
+ opacity: 0.7;
+ transition: 0.3s all ease-in-out;
+
+ &:hover {
+ opacity: 1;
+ }
+ }
+
+ &.disabled {
+ pointer-events: none;
+ }
+ }
+}
+
+@media @phone-landscape {
+ .ratings-container {
+ height: @height-mobile;
+
+ .icon-container {
+ height: @height-mobile;
+ width: @width-mobile;
+
+ .icon {
+ width: 1.75rem;
+ height: 1.75rem;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/components/MetaPreview/Ratings/Ratings.tsx b/src/components/MetaPreview/Ratings/Ratings.tsx
new file mode 100644
index 000000000..6bef0cc6d
--- /dev/null
+++ b/src/components/MetaPreview/Ratings/Ratings.tsx
@@ -0,0 +1,31 @@
+// Copyright (C) 2017-2025 Smart code 203358507
+
+import React, { useMemo } from 'react';
+import useRating from './useRating';
+import styles from './Ratings.less';
+import Icon from '@stremio/stremio-icons/react';
+import classNames from 'classnames';
+
+type Props = {
+ metaId?: string;
+ ratingInfo?: Loadable;
+ className?: string;
+};
+
+const Ratings = ({ ratingInfo, className }: Props) => {
+ const { onLiked, onLoved, liked, loved } = useRating(ratingInfo);
+ const disabled = useMemo(() => ratingInfo?.type !== 'Ready', [ratingInfo]);
+
+ return (
+
+ );
+};
+
+export default Ratings;
diff --git a/src/components/MetaPreview/Ratings/index.ts b/src/components/MetaPreview/Ratings/index.ts
new file mode 100644
index 000000000..0a00e9c2f
--- /dev/null
+++ b/src/components/MetaPreview/Ratings/index.ts
@@ -0,0 +1,5 @@
+// Copyright (C) 2017-2025 Smart code 203358507
+
+import Ratings from './Ratings';
+
+export { Ratings };
diff --git a/src/components/MetaPreview/Ratings/useRating.ts b/src/components/MetaPreview/Ratings/useRating.ts
new file mode 100644
index 000000000..286ad7284
--- /dev/null
+++ b/src/components/MetaPreview/Ratings/useRating.ts
@@ -0,0 +1,48 @@
+// Copyright (C) 2017-2025 Smart code 203358507
+
+import { useMemo, useCallback } from 'react';
+import { useServices } from 'stremio/services';
+
+const useRating = (ratingInfo?: Loadable) => {
+ const { core } = useServices();
+
+ const setRating = useCallback((status: Rating) => {
+ core.transport.dispatch({
+ action: 'MetaDetails',
+ args: {
+ action: 'Rate',
+ args: status,
+ },
+ });
+ }, []);
+
+ const status = useMemo(() => {
+ const content = ratingInfo?.type === 'Ready' ? ratingInfo.content as RatingInfo : null;
+ return content?.status;
+ }, [ratingInfo]);
+
+ const liked = useMemo(() => {
+ return status === 'liked';
+ }, [status]);
+
+ const loved = useMemo(() => {
+ return status === 'loved';
+ }, [status]);
+
+ const onLiked = useCallback(() => {
+ setRating(status === 'liked' ? null : 'liked');
+ }, [status]);
+
+ const onLoved = useCallback(() => {
+ setRating(status === 'loved' ? null : 'loved');
+ }, [status]);
+
+ return {
+ onLiked,
+ onLoved,
+ liked,
+ loved,
+ };
+};
+
+export default useRating;
diff --git a/src/components/MetaPreview/styles.less b/src/components/MetaPreview/styles.less
index 0725a384e..a614acf25 100644
--- a/src/components/MetaPreview/styles.less
+++ b/src/components/MetaPreview/styles.less
@@ -159,7 +159,6 @@
display: flex;
flex-direction: row;
align-items: flex-end;
- max-height: 15rem;
flex-wrap: wrap;
padding-top: 3.5rem;
overflow: visible;
@@ -209,6 +208,11 @@
}
}
}
+
+ .ratings {
+ margin-bottom: 1rem;
+ margin-right: 1rem;
+ }
}
.share-prompt {
diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js
index 1fc16c706..6f32d1f9a 100644
--- a/src/routes/Discover/Discover.js
+++ b/src/routes/Discover/Discover.js
@@ -193,6 +193,8 @@ const Discover = ({ urlParams, queryParams }) => {
trailerStreams={selectedMetaItem.trailerStreams}
inLibrary={selectedMetaItem.inLibrary}
toggleInLibrary={selectedMetaItem.inLibrary ? removeFromLibrary : addToLibrary}
+ metaId={selectedMetaItem.id}
+ like={selectedMetaItem.like}
/>
:
discover.catalog !== null && discover.catalog.content.type === 'Loading' ?
diff --git a/src/routes/MetaDetails/MetaDetails.js b/src/routes/MetaDetails/MetaDetails.js
index da79df285..d806ffed5 100644
--- a/src/routes/MetaDetails/MetaDetails.js
+++ b/src/routes/MetaDetails/MetaDetails.js
@@ -168,6 +168,8 @@ const MetaDetails = ({ urlParams, queryParams }) => {
trailerStreams={metaDetails.metaItem.content.content.trailerStreams}
inLibrary={metaDetails.metaItem.content.content.inLibrary}
toggleInLibrary={metaDetails.metaItem.content.content.inLibrary ? removeFromLibrary : addToLibrary}
+ metaId={metaDetails.metaItem.content.content.id}
+ ratingInfo={metaDetails.ratingInfo}
/>
}
diff --git a/src/types/models/MetaDetails.d.ts b/src/types/models/MetaDetails.d.ts
index c7eeafb1b..570ca5e88 100644
--- a/src/types/models/MetaDetails.d.ts
+++ b/src/types/models/MetaDetails.d.ts
@@ -24,4 +24,5 @@ type MetaDetails = {
content: Loadable
}[],
title: string | null,
+ ratingInfo: Loadable | null,
};
diff --git a/src/types/types.d.ts b/src/types/types.d.ts
index 8f6d55730..06bbb0e19 100644
--- a/src/types/types.d.ts
+++ b/src/types/types.d.ts
@@ -68,3 +68,10 @@ type AudioTrack = {
lang: string,
origin: string,
};
+
+type Rating = 'liked' | 'loved' | null;
+
+type RatingInfo = {
+ metaId: string,
+ status: Rating,
+};