diff --git a/package.json b/package.json
index 4f1f16806..23fe229df 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,7 @@
"@babel/runtime": "7.26.0",
"@sentry/browser": "8.42.0",
"@stremio/stremio-colors": "5.2.0",
- "@stremio/stremio-core-web": "0.55.0",
+ "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/upgrade-user-addons/stremio-stremio-core-web-0.55.0.tgz",
"@stremio/stremio-icons": "5.8.0",
"@stremio/stremio-video": "0.0.70",
"a-color-picker": "1.2.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 321a4110b..bf8d3c6e4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -18,8 +18,8 @@ importers:
specifier: 5.2.0
version: 5.2.0
'@stremio/stremio-core-web':
- specifier: 0.55.0
- version: 0.55.0
+ specifier: https://stremio.github.io/stremio-core/stremio-core-web/feat/upgrade-user-addons/stremio-stremio-core-web-0.55.0.tgz
+ version: https://stremio.github.io/stremio-core/stremio-core-web/feat/upgrade-user-addons/stremio-stremio-core-web-0.55.0.tgz
'@stremio/stremio-icons':
specifier: 5.8.0
version: 5.8.0
@@ -1120,8 +1120,9 @@ packages:
'@stremio/stremio-colors@5.2.0':
resolution: {integrity: sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg==}
- '@stremio/stremio-core-web@0.55.0':
- resolution: {integrity: sha512-MdalnThEwnA8osQh+3/5OMzVIYZOoYmd94dN3nmCeT4rfV7IZXRFUg/uyCY+5bqigStlE3SfKEaGiSc6UnNtlQ==}
+ '@stremio/stremio-core-web@https://stremio.github.io/stremio-core/stremio-core-web/feat/upgrade-user-addons/stremio-stremio-core-web-0.55.0.tgz':
+ resolution: {tarball: https://stremio.github.io/stremio-core/stremio-core-web/feat/upgrade-user-addons/stremio-stremio-core-web-0.55.0.tgz}
+ version: 0.55.0
'@stremio/stremio-icons@5.8.0':
resolution: {integrity: sha512-IVUvQbIWfA4YEHCTed7v/sdQJCJ+OOCf84LTWpkE2W6GLQ+15WHcMEJrVkE1X3ekYJnGg3GjT0KLO6tKSU0P4w==}
@@ -5870,7 +5871,7 @@ snapshots:
'@stremio/stremio-colors@5.2.0': {}
- '@stremio/stremio-core-web@0.55.0':
+ '@stremio/stremio-core-web@https://stremio.github.io/stremio-core/stremio-core-web/feat/upgrade-user-addons/stremio-stremio-core-web-0.55.0.tgz':
dependencies:
'@babel/runtime': 7.24.1
diff --git a/src/App/ServicesToaster.js b/src/App/ServicesToaster.js
index a12757169..6e6b22789 100644
--- a/src/App/ServicesToaster.js
+++ b/src/App/ServicesToaster.js
@@ -1,15 +1,40 @@
// Copyright (C) 2017-2023 Smart code 203358507
const React = require('react');
+const { useTranslation } = require('react-i18next');
const { useServices } = require('stremio/services');
const { useToast } = require('stremio/common');
const ServicesToaster = () => {
+ const { t } = useTranslation();
const { core, dragAndDrop } = useServices();
const toast = useToast();
React.useEffect(() => {
const onCoreEvent = ({ event, args }) => {
switch (event) {
+ case 'UserAddonsUpgraded': {
+ const upgradedCount = args?.upgraded?.length ?? 0;
+ toast.show({
+ type: 'success',
+ title: upgradedCount > 0
+ ? t('ADDONS_CHECK_FOR_UPDATES_COUNT', {
+ count: upgradedCount,
+ })
+ : t('ADDONS_CHECK_FOR_UPDATES_UP_TO_DATE'),
+ timeout: 5000,
+ dataset: { type: 'CoreEvent' }
+ });
+ break;
+ }
+ case 'AddonUpgraded': {
+ toast.show({
+ type: 'success',
+ title: t('ADDON_UPDATED'),
+ timeout: 4000,
+ dataset: { type: 'CoreEvent' }
+ });
+ break;
+ }
case 'Error': {
if (args.source.event === 'UserPulledFromAPI' && args.source.args.uid === null) {
break;
@@ -23,6 +48,16 @@ const ServicesToaster = () => {
break;
}
+ if (args.error.type === 'Other' && args.error.code === 3 && args.source.event === 'AddonUpgraded') {
+ toast.show({
+ type: 'success',
+ title: t('ADDON_UP_TO_DATE'),
+ timeout: 4000,
+ dataset: { type: 'CoreEvent' }
+ });
+ break;
+ }
+
toast.show({
type: 'error',
title: args.source.event,
@@ -74,7 +109,7 @@ const ServicesToaster = () => {
core.transport.off('CoreEvent', onCoreEvent);
dragAndDrop.off('error', onDragAndDropError);
};
- }, []);
+ }, [t]);
return null;
};
diff --git a/src/components/AddonDetailsModal/AddonDetailsModal.js b/src/components/AddonDetailsModal/AddonDetailsModal.js
index a89a68b77..dafd88525 100644
--- a/src/components/AddonDetailsModal/AddonDetailsModal.js
+++ b/src/components/AddonDetailsModal/AddonDetailsModal.js
@@ -85,6 +85,28 @@ const AddonDetailsModal = ({ transportUrl, onCloseRequest }) => {
}
:
null;
+ const updateButton = addonDetails.localAddon !== null &&
+ addonDetails.remoteAddon !== null &&
+ addonDetails.remoteAddon.content.type === 'Ready' &&
+ !addonDetails.remoteAddon.content.content.flags.protected &&
+ !addonDetails.remoteAddon.content.content.manifest.behaviorHints.configurationRequired ?
+ {
+ className: styles['update-button'],
+ label: t('ADDON_REFRESH'),
+ props: {
+ onClick: () => {
+ core.transport.dispatch({
+ action: 'Ctx',
+ args: {
+ action: 'UpgradeAddon',
+ args: addonDetails.remoteAddon.content.content
+ }
+ });
+ }
+ }
+ }
+ :
+ null;
const toggleButton = addonDetails.localAddon !== null ?
{
className: styles['uninstall-button'],
@@ -137,7 +159,7 @@ const AddonDetailsModal = ({ transportUrl, onCloseRequest }) => {
}
:
null;
- return configureButton && toggleButton ? [cancelButton, configureButton, toggleButton] : configureButton ? [cancelButton, configureButton] : toggleButton ? [cancelButton, toggleButton] : [cancelButton];
+ return [cancelButton, configureButton, updateButton, toggleButton].filter(Boolean);
}, [addonDetails, onCloseRequest]);
const modalBackground = React.useMemo(() => {
return addonDetails.remoteAddon?.content.type === 'Ready' ? addonDetails.remoteAddon.content.content.manifest.background : null;
diff --git a/src/components/AddonDetailsModal/styles.less b/src/components/AddonDetailsModal/styles.less
index 7182d0528..6ee200194 100644
--- a/src/components/AddonDetailsModal/styles.less
+++ b/src/components/AddonDetailsModal/styles.less
@@ -29,7 +29,7 @@
.uninstall-button {
background-color: var(--overlay-color);
-
+
&:hover {
outline: var(--focus-outline-size) solid var(--overlay-color);
background-color: transparent;
@@ -39,4 +39,17 @@
outline-color: var(--primary-foreground-color);
}
}
+
+ .update-button {
+ background-color: var(--secondary-accent-color);
+
+ &:hover {
+ outline: var(--focus-outline-size) solid var(--secondary-accent-color);
+ background-color: transparent;
+ }
+
+ &:focus {
+ outline-color: var(--primary-foreground-color);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js
index 86a45374c..b5fc0ccf4 100644
--- a/src/routes/Addons/Addons.js
+++ b/src/routes/Addons/Addons.js
@@ -93,6 +93,23 @@ const Addons = ({ urlParams, queryParams }) => {
const onAddonConfigure = React.useCallback((event) => {
platform.openExternal(event.dataset.addon.transportUrl.replace('manifest.json', 'configure'));
}, []);
+ const hasUpdatableInstalledAddons = React.useMemo(() => {
+ if (installedAddons.selected === null) {
+ return false;
+ }
+ return installedAddons.catalog.some((addon) =>
+ !addon.manifest?.behaviorHints?.configurationRequired && !addon.flags?.protected
+ );
+ }, [installedAddons.selected, installedAddons.catalog]);
+ const onUpdateAllAddons = React.useCallback(() => {
+ if (!hasUpdatableInstalledAddons) {
+ return;
+ }
+ core.transport.dispatch({
+ action: 'Ctx',
+ args: { action: 'UpgradeUserAddons' }
+ });
+ }, [hasUpdatableInstalledAddons]);
const onAddonOpen = React.useCallback((event) => {
setAddonDetailsTransportUrl(event.dataset.addon.transportUrl);
}, [setAddonDetailsTransportUrl]);
@@ -130,12 +147,37 @@ const Addons = ({ urlParams, queryParams }) => {