From dcb0353f926cd2e72e5cd0d3e823d8436a4064ef Mon Sep 17 00:00:00 2001 From: Viren070 Date: Fri, 17 Jan 2025 15:05:11 +0000 Subject: [PATCH] feat: support customising which streams to proxy, fix duplication check bypasses by setting falsy/false values to undefined to match intial state, refactor multi select component usage closes #8 closes #17 closes #18 --- packages/addon/src/addon.ts | 31 ++- .../src/app/configure/page.module.css | 22 +- packages/frontend/src/app/configure/page.tsx | 219 ++++++++++-------- .../frontend/src/components/AddonsList.tsx | 8 +- .../frontend/src/components/MutliSelect.tsx | 47 +++- packages/types/src/types.ts | 2 + packages/utils/src/mediaflow.ts | 2 + 7 files changed, 211 insertions(+), 120 deletions(-) diff --git a/packages/addon/src/addon.ts b/packages/addon/src/addon.ts index a6dc5e64..540d4eae 100644 --- a/packages/addon/src/addon.ts +++ b/packages/addon/src/addon.ts @@ -434,6 +434,31 @@ export class AIOStreams { }; } + private shouldProxyStream(stream: ParsedStream): boolean { + const mediaFlowConfig = getMediaFlowConfig(this.config); + if (!mediaFlowConfig.mediaFlowEnabled) return false; + if (!stream.url) return false; + // now check if mediaFlowConfig.proxiedAddons or mediaFlowConfig.proxiedServices is not null + + if ( + mediaFlowConfig.proxiedAddons && + !mediaFlowConfig.proxiedAddons.includes(stream.addon.id) + ) + return false; + + if ( + (mediaFlowConfig.proxiedServices && + stream.provider && + !mediaFlowConfig.proxiedServices.includes(stream.provider.id)) || + (mediaFlowConfig.proxiedServices && + !stream.provider && + !mediaFlowConfig.proxiedServices.includes('none')) + ) + return false; + + return true; + } + private async createStreamObject( parsedStream: ParsedStream ): Promise { @@ -476,10 +501,8 @@ export class AIOStreams { ]; let stream: Stream; - const isMediaFlowEnabled = - this.config.mediaFlowConfig?.mediaFlowEnabled || - Settings.DEFAULT_MEDIAFLOW_URL; - if (isMediaFlowEnabled && parsedStream?.url) { + const shouldProxy = this.shouldProxyStream(parsedStream); + if (shouldProxy) { try { const mediaFlowStream = this.createMediaFlowStream( parsedStream, diff --git a/packages/frontend/src/app/configure/page.module.css b/packages/frontend/src/app/configure/page.module.css index a1a7c0fb..119ec07c 100644 --- a/packages/frontend/src/app/configure/page.module.css +++ b/packages/frontend/src/app/configure/page.module.css @@ -137,23 +137,27 @@ } .mediaFlowConfig { - border-width: 1px; - border-style: solid; - border-radius: var(--borderRadius); - border-color: #777777; - padding: 10px; transition: - margin-top 0.4s, - opacity 0.3s, - transform 0.6s; + margin-top 0.6s, + opacity 0.6s, + transform 1s; } .mediaFlowConfig.hidden { opacity: 0; - margin-top: -340px; + margin-top: -655px; transform: scale(0); transition: margin-top 0.5s, opacity 0.2s, transform 0.4s; } + +.mediaFlowSection { + padding: 10px; + margin: 5px; + border-width: 1px; + border-style: solid; + border-radius: var(--borderRadius); + border-color: #777777; +} diff --git a/packages/frontend/src/app/configure/page.tsx b/packages/frontend/src/app/configure/page.tsx index fb011ab2..9cc4e116 100644 --- a/packages/frontend/src/app/configure/page.tsx +++ b/packages/frontend/src/app/configure/page.tsx @@ -137,7 +137,6 @@ const defaultServices = serviceDetails.map((service) => ({ })); export default function Configure() { - const [isClient, setIsClient] = useState(false); const [resolutions, setResolutions] = useState(defaultResolutions); const [qualities, setQualities] = useState(defaultQualities); @@ -175,6 +174,12 @@ export default function Configure() { const [mediaFlowProxyUrl, setmediaFlowProxyUrl] = useState(''); const [mediaFlowApiPassword, setmediaFlowApiPassword] = useState(''); const [mediaFlowPublicIp, setMediaFlowPublicIp] = useState(''); + const [mediaFlowProxiedAddons, setMediaFlowProxiedAddons] = useState< + string[] | null + >(null); + const [mediaFlowProxiedServices, setMediaFlowProxiedServices] = useState< + string[] | null + >(null); const [disableButtons, setDisableButtons] = useState(false); const [manualManifestUrl, setManualManifestUrl] = useState( null @@ -227,6 +232,8 @@ export default function Configure() { proxyUrl: mediaFlowProxyUrl, apiPassword: mediaFlowApiPassword, publicIp: mediaFlowPublicIp, + proxiedAddons: mediaFlowProxiedAddons, + proxiedServices: mediaFlowProxiedServices, }, addons, services, @@ -311,6 +318,7 @@ export default function Configure() { const config = createConfig(); const { valid, errorCode, errorMessage } = validateConfig(config); + console.log('Config', config, 'was valid:', valid); if (!valid) { showToast( errorMessage || 'Invalid config', @@ -526,7 +534,6 @@ export default function Configure() { // Load config from the window path if it exists useEffect(() => { - setIsClient(true); async function decodeConfig(config: string) { let decodedConfig: Config; if (config.startsWith('E-')) { @@ -837,28 +844,12 @@ export default function Configure() {

- {isClient ? ( // https://github.com/JedWatson/react-select/issues/5859 - a.localeCompare(b)) - .map((language) => ({ value: language, label: language }))} - setValues={setPrioritisedLanguages} - /> - ) : ( - // render a fake select box until the actual one is rendered -
-

Select...

-
- )} + a.localeCompare(b)) + .map((language) => ({ value: language, label: language }))} + setValues={setPrioritisedLanguages} + />
@@ -873,28 +864,12 @@ export default function Configure() {

- {isClient ? ( - a.localeCompare(b)) - .map((language) => ({ value: language, label: language }))} - setValues={setExcludedLanguages} - /> - ) : ( - // render a fake select box until the actual one is rendered -
-

Select...

-
- )} + a.localeCompare(b)) + .map((language) => ({ value: language, label: language }))} + setValues={setExcludedLanguages} + />
@@ -1100,61 +1075,119 @@ export default function Configure() {
-
+
-

Proxy URL

-

- The URL of the MediaFlow proxy server -

+
+

Proxy URL

+

+ The URL of the MediaFlow proxy server +

+
+
+ +
- +
+

API Password

+

+ Your MediaFlow's API password +

+
+
+ +
+
+
+
+

Public IP (Optional)

+

+ Configure this only when running MediaFlow locally with a + proxy service. Leave empty if MediaFlow is configured + locally without a proxy server or if it's hosted on a + remote server. +

+
+
+ +
-
+
-

API Password

-

- Your MediaFlow's API password -

+
+

Proxy Addons (Optional)

+

+ By default, all streams from every addon are proxied. + Choose specific addons here to proxy only their streams. +

+
+
+ ({ + value: `${addon.id}-${JSON.stringify(addon.options)}`, + label: + addon.options.addonName || + addon.options.overrideName || + addon.options.name || + addon.id.charAt(0).toUpperCase() + + addon.id.slice(1), + })) || [] + } + setValues={(selectedAddons) => { + setMediaFlowProxiedAddons(selectedAddons); + }} + /> +
- -
-
-
-
-

Public IP (Optional)

-

- Configure this only when running MediaFlow locally with a - proxy service. Leave empty if MediaFlow is configured - locally without a proxy server or if it's hosted on a - remote server. -

-
-
- +
+

+ Proxy Services (Optional) +

+

+ By default, all streams whether they are from a serivce or + not are proxied. Choose which services you want to proxy + through MediaFlow. Selecting None will also proxy streams + that are not (detected to be) from a service. +

+
+
+ ({ + value: service.id, + label: service.name, + })), + ]} + setValues={(selectedServices) => { + setMediaFlowProxiedServices(selectedServices); + }} + /> +
diff --git a/packages/frontend/src/components/AddonsList.tsx b/packages/frontend/src/components/AddonsList.tsx index 6cb04583..f35669f9 100644 --- a/packages/frontend/src/components/AddonsList.tsx +++ b/packages/frontend/src/components/AddonsList.tsx @@ -175,7 +175,7 @@ const AddonsList: React.FC = ({ updateOption( index, option.id, - e.target.checked ? 'true' : 'false' + e.target.checked ? 'true' : undefined ) } className={styles.checkbox} @@ -188,7 +188,11 @@ const AddonsList: React.FC = ({ - updateOption(index, option.id, value) + updateOption( + index, + option.id, + value ? value : undefined + ) } /> ) : ( diff --git a/packages/frontend/src/components/MutliSelect.tsx b/packages/frontend/src/components/MutliSelect.tsx index f52a8623..c9676792 100644 --- a/packages/frontend/src/components/MutliSelect.tsx +++ b/packages/frontend/src/components/MutliSelect.tsx @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import { useEffect, useState } from 'react'; import Select, { StylesConfig } from 'react-select'; const selectStyles: StylesConfig = { @@ -79,19 +80,41 @@ interface MultiSelectProps { } const MultiSelect: React.FC = ({ options, setValues }) => { + const [isClient, setIsClient] = useState(false); + useEffect(() => { + setIsClient(true); + }, []); return ( - { + const selectedLanguages = selectedOptions.map( + (option: any) => option.value + ); + setValues(selectedLanguages); + }} + styles={selectStyles} + /> + ) : ( +
+

Select...

+
+ )} + ); }; diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index 160dcf48..e24a57b0 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -154,6 +154,8 @@ export interface Config { proxyUrl: string; apiPassword: string; publicIp: string; + proxiedAddons: string[] | null; + proxiedServices: string[] | null; }; addons: { id: string; diff --git a/packages/utils/src/mediaflow.ts b/packages/utils/src/mediaflow.ts index 43cff750..75484459 100644 --- a/packages/utils/src/mediaflow.ts +++ b/packages/utils/src/mediaflow.ts @@ -138,5 +138,7 @@ export function getMediaFlowConfig(userConfig: Config) { apiPassword: mediaFlowConfig?.apiPassword || Settings.DEFAULT_MEDIAFLOW_API_PASSWORD, publicIp: mediaFlowConfig?.publicIp || Settings.DEFAULT_MEDIAFLOW_PUBLIC_IP, + proxiedAddons: mediaFlowConfig?.proxiedAddons || null, + proxiedServices: mediaFlowConfig?.proxiedServices || null, }; }