diff --git a/package.json b/package.json index 96f11af..a8a42b5 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ }, "license": "AGPL-3.0-only", "dependencies": { - "@exhumer/f1tv-api": "^2.1.0", + "@exhumer/f1tv-api": "^2.2.1", "@reduxjs/toolkit": "^2.3.0", "bitmovin-player": "^8.185.0", "bitmovin-player-ui": "^3.73.0", diff --git a/src/Index.ts b/src/Index.ts index 656b2ea..8e32200 100644 --- a/src/Index.ts +++ b/src/Index.ts @@ -37,7 +37,7 @@ const playerCtxMenuPopup = (playerWindow: BrowserWindow, cursorLocation?: { x: n } : undefined); }; -const createPlayerWindow = (container: F1TV.ContentVideoContainer) => { +const createPlayerWindow = (container: F1TV.ContentVideoContainer, platform: string) => { const playerWindow = new BrowserWindow({ minHeight: 270, minWidth: 480, @@ -61,7 +61,7 @@ const createPlayerWindow = (container: F1TV.ContentVideoContainer) => { }) playerWindow.on('ready-to-show', () => { - playerWindow.webContents.send(IPCChannel.PLAYER_READY_TO_SHOW, container, f1tv.ascendon, f1tv.config); + playerWindow.webContents.send(IPCChannel.PLAYER_READY_TO_SHOW, container, f1tv.ascendon, f1tv.config, platform); }); playerWindow.on('closed', () => { @@ -245,13 +245,13 @@ ipcMain.handle(IPCChannel.PLAYER_CONTEXT_MENU, async (e, cursorLocation: { x: nu playerCtxMenuPopup(senderWindow, cursorLocation); }); -ipcMain.handle(IPCChannel.MAIN_WINDOW_NEW_PLAYER, async (e, contentId: number) => { +ipcMain.handle(IPCChannel.MAIN_WINDOW_NEW_PLAYER, async (e, contentId: number, platform: string) => { if (f1tv.ascendon === null) return; const apiRes = await f1tv.contentVideo(contentId); - createPlayerWindow(apiRes); + createPlayerWindow(apiRes, platform); }); ipcMain.handle(IPCChannel.F1TV_LOGIN, async () => { diff --git a/src/MainWindow/Global.d.ts b/src/MainWindow/Global.d.ts index 44b6ed2..7b3cb9f 100644 --- a/src/MainWindow/Global.d.ts +++ b/src/MainWindow/Global.d.ts @@ -16,7 +16,7 @@ declare interface F1TV { } declare interface MainWindow { - newPlayer: (contentId: number) => Promise; + newPlayer: (contentId: number, platform: string) => Promise; onReadyToShow: (cb: (e: IpcRendererEvent, decodedAscendon: DecodedAscendonToken | null, entitlement: string | null, config: F1TV.Config | null, location: F1TV.LocationResult | null) => void) => void; offReadyToShow: (cb: (e: IpcRendererEvent, decodedAscendon: DecodedAscendonToken | null, entitlement: string | null, config: F1TV.Config | null, location: F1TV.LocationResult | null) => void) => void; } diff --git a/src/MainWindow/Preload.ts b/src/MainWindow/Preload.ts index 1cfdf76..258ea82 100644 --- a/src/MainWindow/Preload.ts +++ b/src/MainWindow/Preload.ts @@ -29,7 +29,7 @@ contextBridge.exposeInMainWorld('f1tv', { }); contextBridge.exposeInMainWorld('mainWindow', { - newPlayer: (contentId: number) => ipcRenderer.invoke(IPCChannel.MAIN_WINDOW_NEW_PLAYER, contentId), + newPlayer: (contentId: number, platform: string) => ipcRenderer.invoke(IPCChannel.MAIN_WINDOW_NEW_PLAYER, contentId, platform), onReadyToShow: (cb: (e: Electron.IpcRendererEvent, decodedAscendon: DecodedAscendonToken | null, entitlement: string | null, diff --git a/src/MainWindow/React/Component/LoggedInView.tsx b/src/MainWindow/React/Component/LoggedInView.tsx index 5931333..6224e5e 100644 --- a/src/MainWindow/React/Component/LoggedInView.tsx +++ b/src/MainWindow/React/Component/LoggedInView.tsx @@ -1,11 +1,13 @@ import { useRef } from 'react'; import { useAppSelector } from '../Hook'; +import { F1TVPlatform } from '../Type'; const LoggedInView = () => { const inputRef = useRef(null); const config = useAppSelector(state => state.f1tv.config); const location = useAppSelector(state => state.f1tv.location); const isReady = config !== null && location !== null; + const platformRef = useRef(null); return ( <> @@ -20,6 +22,16 @@ const LoggedInView = () => { e.target.value = e.target.value.replace(/\D/g, ''); }} /> + diff --git a/src/MainWindow/React/Component/LoggedOutView.tsx b/src/MainWindow/React/Component/LoggedOutView.tsx index 156e7af..b04e61f 100644 --- a/src/MainWindow/React/Component/LoggedOutView.tsx +++ b/src/MainWindow/React/Component/LoggedOutView.tsx @@ -1,8 +1,10 @@ const LoggedOutView = () => { return ( <> -

Please login to start watching content.

- +

You must be logged into F1TV to use this application

+ ); }; diff --git a/src/MainWindow/React/Type.ts b/src/MainWindow/React/Type.ts new file mode 100644 index 0000000..5299ebe --- /dev/null +++ b/src/MainWindow/React/Type.ts @@ -0,0 +1,10 @@ +export enum F1TVPlatform { + BIG_SCREEN_DASH = 'BIG_SCREEN_DASH', + BIG_SCREEN_HLS = 'BIG_SCREEN_HLS', + MOBILE_DASH = 'MOBILE_DASH', + MOBILE_HLS = 'MOBILE_HLS', + TABLET_DASH = 'TABLET_DASH', + TABLET_HLS = 'TABLET_HLS', + WEB_DASH = 'WEB_DASH', + WEB_HLS = 'WEB_HLS', +}; diff --git a/src/Player/Global.d.ts b/src/Player/Global.d.ts index 301a7a9..0fa8025 100644 --- a/src/Player/Global.d.ts +++ b/src/Player/Global.d.ts @@ -1,10 +1,11 @@ import { F1TV } from '@exhumer/f1tv-api'; +import { F1TVPlatform } from '../MainWindow/React/Type'; declare interface Player { - contentPlay: (contentId: number, channelId?: number) => Promise; + contentPlay: (contentId: number, channelId?: number, platform: F1TVPlatform) => Promise; contextMenu: (cursor_location: { x: number, y: number }) => Promise; - onReadyToShow: (cb: (e: IpcRendererEvent, videoContainer: F1TV.ContentVideoContainer, ascendon: string, config: F1TV.Config | null) => void) => void; - offReadyToShow: (cb: (e: IpcRendererEvent, videoContainer: F1TV.ContentVideoContainer, ascendon: string, config: F1TV.Config | null) => void) => void; + onReadyToShow: (cb: (e: IpcRendererEvent, videoContainer: F1TV.ContentVideoContainer, ascendon: string, config: F1TV.Config | null, platform: F1TVPlatform) => void) => void; + offReadyToShow: (cb: (e: IpcRendererEvent, videoContainer: F1TV.ContentVideoContainer, ascendon: string, config: F1TV.Config | null, platform: F1TVPlatform) => void) => void; } declare global { diff --git a/src/Player/Preload.ts b/src/Player/Preload.ts index 69a2941..c76aa2f 100644 --- a/src/Player/Preload.ts +++ b/src/Player/Preload.ts @@ -10,11 +10,13 @@ contextBridge.exposeInMainWorld('player', { onReadyToShow: (cb: (e: Electron.IpcRendererEvent, videoContainer: F1TV.ContentVideoContainer, ascendon: string, - config: F1TV.Config) => void) => + config: F1TV.Config, + platform: F1TV.Platform) => void) => ipcRenderer.on(IPCChannel.PLAYER_READY_TO_SHOW, cb), offReadyToShow: (cb: (e: Electron.IpcRendererEvent, videoContainer: F1TV.ContentVideoContainer, ascendon: string, - config: F1TV.Config) => void) => + config: F1TV.Config, + platform: F1TV.Platform) => void) => ipcRenderer.off(IPCChannel.PLAYER_READY_TO_SHOW, cb), }); diff --git a/src/Player/React/App.tsx b/src/Player/React/App.tsx index 9b589d3..25d7826 100644 --- a/src/Player/React/App.tsx +++ b/src/Player/React/App.tsx @@ -7,20 +7,23 @@ import styles from './App.module.scss'; import BitmovinPlayer, { BitmovinPlayerRef } from './Component/BitmovinPlayer'; import Overlay from './Component/Overlay'; -import { updateAscendon, updateConfig, updateVideoContainer } from './Slice/Player'; +import { updateAscendon, updateConfig, updatePlatform, updateVideoContainer } from './Slice/Player'; import { usePlayerDispatch, usePlayerSelector } from './Hook'; import { author, productName } from '../../../package.json'; +import { F1TVPlatform } from '../../MainWindow/React/Type'; const App = () => { const ascendon = usePlayerSelector(state => state.player.ascendon); const config = usePlayerSelector(state => state.player.config); + const platform = usePlayerSelector(state => state.player.platform); const videoContainer = usePlayerSelector(state => state.player.videoContainer); const dispatch = usePlayerDispatch(); - const playerReadyToShowCB = (e: IpcRendererEvent, videoContainer: F1TV.ContentVideoContainer, ascendon: string, config: F1TV.Config) => { + const playerReadyToShowCB = (e: IpcRendererEvent, videoContainer: F1TV.ContentVideoContainer, ascendon: string, config: F1TV.Config, platform: string) => { dispatch(updateAscendon(ascendon)); dispatch(updateConfig(config)); + dispatch(updatePlatform(platform)); dispatch(updateVideoContainer(videoContainer)); }; @@ -35,7 +38,7 @@ const App = () => { null; player - .contentPlay(videoContainer.contentId, stream && stream.identifier !== 'WIF' ? channelId : undefined) + .contentPlay(videoContainer.contentId, stream && stream.identifier !== 'WIF' ? channelId : undefined, platform as F1TVPlatform) .then(playData => { const currentRef = playerRef.current; diff --git a/src/Player/React/Slice/Player.ts b/src/Player/React/Slice/Player.ts index 94dd02c..7475074 100644 --- a/src/Player/React/Slice/Player.ts +++ b/src/Player/React/Slice/Player.ts @@ -5,12 +5,14 @@ export type PlayerState = { ascendon: string | null; config: F1TV.Config | null; videoContainer: F1TV.ContentVideoContainer | null; + platform: string | null; }; const initialState: PlayerState = { ascendon: null, config: null, videoContainer: null, + platform: null, }; export const configSlice = createSlice({ @@ -23,12 +25,15 @@ export const configSlice = createSlice({ updateConfig: (state, action: PayloadAction) => { state.config = action.payload; }, + updatePlatform: (state, action: PayloadAction) => { + state.platform = action.payload; + }, updateVideoContainer: (state, action: PayloadAction) => { state.videoContainer = action.payload; }, }, }); -export const { updateAscendon, updateConfig, updateVideoContainer } = configSlice.actions; +export const { updateAscendon, updateConfig, updatePlatform, updateVideoContainer } = configSlice.actions; export default configSlice.reducer; diff --git a/yarn.lock b/yarn.lock index a3fa6dd..ce268e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -503,14 +503,14 @@ dependencies: levn "^0.4.1" -"@exhumer/f1tv-api@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@exhumer/f1tv-api/-/f1tv-api-2.1.0.tgz#807d98f674171f532c52088cd71e955c8f104a4d" - integrity sha512-HJuHy0+uV92lLrDHEeIOcZrQii4v9sfr4bHBwHjXWe6vIRSN6jId09nSizL43Hbh5KlxksYEuHeqwe94SRMwUQ== +"@exhumer/f1tv-api@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@exhumer/f1tv-api/-/f1tv-api-2.2.1.tgz#c180435407b2e0a044c596ae47b0aae1e9cd4696" + integrity sha512-m9T0r8UZ+sA8JwzPwXTS6FsAwO19ZlHMaH1g7yz3HuLVCrFxXNvDwwiV2SUh+qcJOQOZslMQk2xsxrHwa/zIYA== dependencies: "@tiny-libs/typed-event-emitter" "^1.0.0" jwt-decode "^4.0.0" - undici "^6.19.8" + undici "^6.20.1" "@gar/promisify@^1.1.3": version "1.1.3" @@ -6536,7 +6536,7 @@ undici-types@~6.19.2: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== -undici@^6.19.8: +undici@^6.20.1: version "6.20.1" resolved "https://registry.yarnpkg.com/undici/-/undici-6.20.1.tgz#fbb87b1e2b69d963ff2d5410a40ffb4c9e81b621" integrity sha512-AjQF1QsmqfJys+LXfGTNum+qw4S88CojRInG/6t31W/1fk6G59s92bnAvGz5Cmur+kQv2SURXEvvudLmbrE8QA==