From 9b0ba285b39a20023b01a17e185534a91adc1876 Mon Sep 17 00:00:00 2001 From: herrrta <73949927+herrrta@users.noreply.github.com> Date: Mon, 10 Mar 2025 01:05:51 -0400 Subject: [PATCH] feat: Ability to consume webhook notifications and forward to clients #595 - forward expo device tokens to users plugin instance - added android notification icon --- app.json | 9 ++++- app/_layout.tsx | 65 +++++++++++++++++++++++++++++---- assets/images/notification.png | Bin 0 -> 22765 bytes augmentations/api.ts | 17 ++++++++- providers/JellyfinProvider.tsx | 5 +++ 5 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 assets/images/notification.png diff --git a/app.json b/app.json index 8867d0cc..ba4584d5 100644 --- a/app.json +++ b/app.json @@ -120,6 +120,13 @@ "image": "./assets/images/StreamyFinFinal.png", "imageWidth": 100 } + ], + [ + "expo-notifications", + { + "icon": "./assets/images/notification.png", + "color": "#9333EA" + } ] ], "experiments": { @@ -133,7 +140,7 @@ "projectId": "e79219d1-797f-4fbe-9fa1-cfd360690a68" } }, - "owner": "fredrikburmester", + "owner": "streamyfin", "runtimeVersion": { "policy": "appVersion" }, diff --git a/app/_layout.tsx b/app/_layout.tsx index 8dfe0786..2d1ab164 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -12,7 +12,7 @@ import { BACKGROUND_FETCH_TASK_SESSIONS, registerBackgroundFetchAsyncSessions, } from "@/utils/background-tasks"; -import { LogProvider, writeToLog } from "@/utils/log"; +import {LogProvider, writeErrorLog, writeToLog} from "@/utils/log"; import { storage } from "@/utils/mmkv"; import { cancelJobById, getAllJobsByDeviceId } from "@/utils/optimize-server"; import { ActionSheetProvider } from "@expo/react-native-action-sheet"; @@ -30,7 +30,7 @@ import * as ScreenOrientation from "@/packages/expo-screen-orientation"; const TaskManager = !Platform.isTV ? require("expo-task-manager") : null; import { getLocales } from "expo-localization"; import { Provider as JotaiProvider } from "jotai"; -import { useEffect, useRef } from "react"; +import {useEffect, useRef, useState} from "react"; import { I18nextProvider } from "react-i18next"; import { Appearance, AppState } from "react-native"; import { SystemBars } from "react-native-edge-to-edge"; @@ -41,6 +41,9 @@ import { useAtom } from "jotai"; import { userAtom } from "@/providers/JellyfinProvider"; import { getSessionApi } from "@jellyfin/sdk/lib/utils/api/session-api"; import { store } from "@/utils/store"; +import {EventSubscription} from "expo-modules-core"; +import {ExpoPushToken} from "expo-notifications/build/Tokens.types"; +import {Notification, NotificationResponse} from "expo-notifications/build/Notifications.types"; if (!Platform.isTV) { Notifications.setNotificationHandler({ @@ -258,6 +261,7 @@ const queryClient = new QueryClient({ function Layout() { const [settings] = useSettings(); const [user] = useAtom(userAtom); + const [api] = useAtom(apiAtom); const appState = useRef(AppState.currentState); const segments = useSegments(); @@ -268,13 +272,58 @@ function Layout() { if (!Platform.isTV) { useNotificationObserver(); + const [expoPushToken, setExpoPushToken] = useState(); + const notificationListener = useRef(); + const responseListener = useRef(); + useEffect(() => { - checkAndRequestPermissions(); - (async () => { - if (!Platform.isTV && user && user.Policy?.IsAdministrator) { - registerBackgroundFetchAsyncSessions(); - } - })(); + if (expoPushToken && api && user) { + api?.post("/Streamyfin/device", { + token: expoPushToken.data, + deviceId: getOrSetDeviceId(), + userId: user.Id + }).then(_ => console.log("Posted expo push token")) + .catch(_ => writeErrorLog("Failed to push expo push token to plugin")) + } + else console.log("No token available") + }, [api, expoPushToken, user]); + + async function registerNotifications() { + if (Platform.OS === 'android') { + console.log("Setting android notification channel 'default'") + await Notifications?.setNotificationChannelAsync('default', { + name: 'default' + }); + } + + await checkAndRequestPermissions(); + + if (!Platform.isTV && user && user.Policy?.IsAdministrator) { + await registerBackgroundFetchAsyncSessions(); + } + + Notifications?.getExpoPushTokenAsync() + .then((token: ExpoPushToken) => token && setExpoPushToken(token)) + .catch((reason: any) => console.log("Failed to get token", reason)); + } + + useEffect(() => { + registerNotifications() + + notificationListener.current = Notifications?.addNotificationReceivedListener((notification: Notification) => { + console.log("Notification received while app running", notification); + }); + + responseListener.current = Notifications?.addNotificationResponseReceivedListener((response: NotificationResponse) => { + console.log("Notification interacted with", response); + }); + + return () => { + notificationListener.current && + Notifications?.removeNotificationSubscription(notificationListener.current); + responseListener.current && + Notifications?.removeNotificationSubscription(responseListener.current); + } }, []); useEffect(() => { diff --git a/assets/images/notification.png b/assets/images/notification.png new file mode 100644 index 0000000000000000000000000000000000000000..b50e56aed4af6f931f3cacc7b9be59276c83cf41 GIT binary patch literal 22765 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 ): Promise>; + delete( + url: string, + config?: AxiosRequestConfig + ): Promise>; getStreamyfinPluginConfig(): Promise>; } } @@ -32,9 +36,18 @@ Api.prototype.post = function ( data: D, config: AxiosRequestConfig ): Promise> { - return this.axiosInstance.post(`${this.basePath}${url}`, { + return this.axiosInstance.post(`${this.basePath}${url}`, data, { + ...(config || {}), + headers: { [AUTHORIZATION_HEADER]: this.authorizationHeader }, + }); +}; + +Api.prototype.delete = function ( + url: string, + config: AxiosRequestConfig +): Promise> { + return this.axiosInstance.delete(`${this.basePath}${url}`, { ...(config || {}), - data, headers: { [AUTHORIZATION_HEADER]: this.authorizationHeader }, }); }; diff --git a/providers/JellyfinProvider.tsx b/providers/JellyfinProvider.tsx index 37b52346..1256d2ae 100644 --- a/providers/JellyfinProvider.tsx +++ b/providers/JellyfinProvider.tsx @@ -25,6 +25,7 @@ import { useTranslation } from "react-i18next"; import { Platform } from "react-native"; import { getDeviceName } from "react-native-device-info"; import uuid from "react-native-uuid"; +import {writeErrorLog, writeInfoLog} from "@/utils/log"; interface Server { address: string; @@ -286,6 +287,10 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({ const logoutMutation = useMutation({ mutationFn: async () => { + api?.delete(`/Streamyfin/device/${deviceId}`) + .then(r => writeInfoLog("Deleted expo push token for device")) + .catch(e => writeErrorLog(`Failed to delete expo push token for device`)) + storage.delete("token"); setUser(null); setApi(null);