From c3a13ea340e45d1a9f6be1f1c8dd3567df5cb12d Mon Sep 17 00:00:00 2001 From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com> Date: Mon, 11 Nov 2024 13:23:42 -0800 Subject: [PATCH 1/4] feat: vip --- .vscode/settings.json | 3 ++- src/App.tsx | 8 ++++++-- src/components/setting/DeveloperSettings.tsx | 8 ++++++++ src/hooks/useSetupPlayer.ts | 8 ++++---- src/hooks/useVIP.ts | 20 ++++++++++++++++++++ src/types/component.d.ts | 3 +++ 6 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 src/hooks/useVIP.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index acb5f933..72bceb9a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,6 @@ "editor.formatOnSave": true, "search.exclude": { "MusicFreePlugins": true - } + }, + "editor.tabSize": 2 } diff --git a/src/App.tsx b/src/App.tsx index aea14652..7d16ca0e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,6 +16,7 @@ import MainBackground from './components/background/MainBackground'; import useTheme from './hooks/useTheme'; // eslint-disable-next-line import/no-unresolved import { TRACKING } from '@env'; +import useVIP from './hooks/useVIP'; if (TRACKING) { Sentry.init({ @@ -51,9 +52,12 @@ const APM = ({ PIP, isLandscape }: { PIP: boolean; isLandscape: boolean }) => { }; export default function App(appProps: NoxComponent.AppProps) { - const isSplashReady = useSplash(__DEV__ || appProps.intentData ? 1 : 2500); + const { vip } = useVIP(); + const isSplashReady = useSplash( + __DEV__ || appProps.intentData || vip ? 1 : 2500, + ); const [isSplashAnimReady, setIsSplashReady] = React.useState(false); - const isPlayerReady = useSetupPlayer(appProps); + const isPlayerReady = useSetupPlayer({ ...appProps, vip }); const isLandscape = useIsLandscape(); const PIPMode = useStore(appStore, state => state.pipMode); // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/src/components/setting/DeveloperSettings.tsx b/src/components/setting/DeveloperSettings.tsx index 00baa7b1..36f6c264 100644 --- a/src/components/setting/DeveloperSettings.tsx +++ b/src/components/setting/DeveloperSettings.tsx @@ -32,6 +32,7 @@ import { enableTanaka, } from '@hooks/useTanakaAmazingCommodities'; import { isAndroid } from '@utils/RNUtils'; +import { purchaseVIP } from '@hooks/useVIP'; enum Icons { setlog = 'console', @@ -44,6 +45,7 @@ enum Icons { fade = 'cosine-wave', plugins = 'puzzle', Tanaka = 'emoticon-devil', + VIP = 'cash', } enum VIEW { @@ -322,6 +324,12 @@ const Home = ({ navigation }: NoxComponent.StackNavigationProps) => { } settingCategory="DeveloperSettings" /> + { export const appStartupInit = initializePlayer(); -export default ({ intentData }: NoxComponent.AppProps) => { +export default ({ intentData, vip }: NoxComponent.SetupPlayerProps) => { const [playerReady, setPlayerReady] = useState(false); const { updateVersion, checkVersion } = useVersionCheck(); const setIntentData = useNoxSetting(state => state.setIntentData); const { checkPlayStoreUpdates } = usePlayStore(); useEffect(() => { - // TODO: if non VIP, call NoxModule?.loadRN() to start loading while displaying - // splash screen; else, stuff loading in the native splashsceren - NoxModule?.loadRN(); + if (!vip) { + NoxModule?.loadRN(); + } let unmounted = false; (async () => { await appStartupInit; diff --git a/src/hooks/useVIP.ts b/src/hooks/useVIP.ts new file mode 100644 index 00000000..dbd4fec2 --- /dev/null +++ b/src/hooks/useVIP.ts @@ -0,0 +1,20 @@ +import * as SecureStore from 'expo-secure-store'; +import { useState } from 'react'; + +const VIPKey = 'APMVIP'; + +export const purchaseVIP = () => { + SecureStore.setItemAsync(VIPKey, '1'); +}; + +export const loseVIP = () => { + SecureStore.deleteItemAsync(VIPKey); +}; + +const useVIP = () => { + const [vip, setVip] = useState(SecureStore.getItem(VIPKey) !== null); + + return { vip }; +}; + +export default useVIP; diff --git a/src/types/component.d.ts b/src/types/component.d.ts index 31a467d5..acd4ae8c 100644 --- a/src/types/component.d.ts +++ b/src/types/component.d.ts @@ -14,6 +14,9 @@ declare global { intentBundle: null | any; rootTag: number; } + interface SetupPlayerProps extends AppProps { + vip?: boolean; + } interface NavigationProps { navigation: DrawerNavigationProp; } From 6ca453190bcd2f7845b03c65e6ef7ee01c30cebf Mon Sep 17 00:00:00 2001 From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com> Date: Mon, 11 Nov 2024 14:16:02 -0800 Subject: [PATCH 2/4] feat: vip --- src/components/billing/bill.ts | 4 ++++ src/utils/Bilibili/BiliUser.ts | 22 +++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/components/billing/bill.ts diff --git a/src/components/billing/bill.ts b/src/components/billing/bill.ts new file mode 100644 index 00000000..21b39dd7 --- /dev/null +++ b/src/components/billing/bill.ts @@ -0,0 +1,4 @@ +import { getHasGuard } from '@utils/Bilibili/BiliUser'; + +//暗精灵和小孩梓尊享APM VIP服务 +const getBiliVIPStatus = () => getHasGuard([529249, 7706705]); diff --git a/src/utils/Bilibili/BiliUser.ts b/src/utils/Bilibili/BiliUser.ts index 613cb925..4133cf09 100644 --- a/src/utils/Bilibili/BiliUser.ts +++ b/src/utils/Bilibili/BiliUser.ts @@ -5,7 +5,7 @@ import { logger } from '@utils/Logger'; * as "authentication." returns the currently logged in bilibili username. * @returns dict. */ -export default async () => { +const getUser = async () => { try { const val = await fetch('https://api.bilibili.com/x/web-interface/nav'); const res = await val.json(); @@ -17,3 +17,23 @@ export default async () => { return { uname: '' }; } }; + +const getUserGuard = async () => { + const uid = (await getUser()).mid; + const res = await fetch( + `https://api.live.bilibili.com/xlive/web-ucenter/user/MedalWall?target_id=${uid}`, + ); + const data = await res.json(); + + return data.data.list; +}; + +// simple function that filters is user has guard > 0. +export const getHasGuard = async (hasGuard: number[] = []) => { + const guards = await getUserGuard(); + return guards.filter( + (guard: any) => guard.guard_level > 0 && hasGuard.includes(guard.target_id), + ); +}; + +export default getUser; From b81d601146ce91be3d76bb95fb7c7767057bbdf9 Mon Sep 17 00:00:00 2001 From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com> Date: Mon, 11 Nov 2024 14:46:55 -0800 Subject: [PATCH 3/4] chore: patch --- ...eact-native-draggable-flatlist+4.0.1.patch | 90 +++++++++++++++++++ patches/react-native-reanimated+3.16.1.patch | 17 ---- src/enums/Playlist.ts | 2 +- src/hooks/usePlayback.migrate.ts | 6 +- src/hooks/usePlaybackAA.ts | 4 +- src/hooks/usePlaybackCarplay.ts | 4 +- 6 files changed, 98 insertions(+), 25 deletions(-) create mode 100644 patches/react-native-draggable-flatlist+4.0.1.patch delete mode 100644 patches/react-native-reanimated+3.16.1.patch diff --git a/patches/react-native-draggable-flatlist+4.0.1.patch b/patches/react-native-draggable-flatlist+4.0.1.patch new file mode 100644 index 00000000..8a3b54b0 --- /dev/null +++ b/patches/react-native-draggable-flatlist+4.0.1.patch @@ -0,0 +1,90 @@ +diff --git a/node_modules/react-native-draggable-flatlist/src/components/DraggableFlatList.tsx b/node_modules/react-native-draggable-flatlist/src/components/DraggableFlatList.tsx +index d7d98c2..2f59c7a 100644 +--- a/node_modules/react-native-draggable-flatlist/src/components/DraggableFlatList.tsx ++++ b/node_modules/react-native-draggable-flatlist/src/components/DraggableFlatList.tsx +@@ -295,7 +295,7 @@ function DraggableFlatListInner(props: DraggableFlatListProps) { + const springTo = placeholderOffset.value - activeCellOffset.value; + touchTranslate.value = withSpring( + springTo, +- animationConfigRef.current, ++ animationConfigRef.value, + () => { + runOnJS(onDragEnd)({ + from: activeIndexAnim.value, +diff --git a/node_modules/react-native-draggable-flatlist/src/context/refContext.tsx b/node_modules/react-native-draggable-flatlist/src/context/refContext.tsx +index ea21575..66c5eed 100644 +--- a/node_modules/react-native-draggable-flatlist/src/context/refContext.tsx ++++ b/node_modules/react-native-draggable-flatlist/src/context/refContext.tsx +@@ -1,14 +1,14 @@ + import React, { useContext } from "react"; + import { useMemo, useRef } from "react"; + import { FlatList } from "react-native-gesture-handler"; +-import Animated, { WithSpringConfig } from "react-native-reanimated"; ++import Animated, { type SharedValue, useSharedValue, WithSpringConfig } from "react-native-reanimated"; + import { DEFAULT_PROPS } from "../constants"; + import { useProps } from "./propsContext"; + import { CellData, DraggableFlatListProps } from "../types"; + + type RefContextValue = { + propsRef: React.MutableRefObject>; +- animationConfigRef: React.MutableRefObject; ++ animationConfigRef: SharedValue; + cellDataRef: React.MutableRefObject>; + keyToIndexRef: React.MutableRefObject>; + containerRef: React.RefObject; +@@ -54,8 +54,8 @@ function useSetupRefs({ + ...DEFAULT_PROPS.animationConfig, + ...animationConfig, + } as WithSpringConfig; +- const animationConfigRef = useRef(animConfig); +- animationConfigRef.current = animConfig; ++ const animationConfigRef = useSharedValue(animConfig); ++ animationConfigRef.value = animConfig; + + const cellDataRef = useRef(new Map()); + const keyToIndexRef = useRef(new Map()); +diff --git a/node_modules/react-native-draggable-flatlist/src/hooks/useCellTranslate.tsx b/node_modules/react-native-draggable-flatlist/src/hooks/useCellTranslate.tsx +index ce4ab68..efea240 100644 +--- a/node_modules/react-native-draggable-flatlist/src/hooks/useCellTranslate.tsx ++++ b/node_modules/react-native-draggable-flatlist/src/hooks/useCellTranslate.tsx +@@ -101,7 +101,7 @@ export function useCellTranslate({ cellIndex, cellSize, cellOffset }: Params) { + ? activeCellSize.value * (isAfterActive ? -1 : 1) + : 0; + +- return withSpring(translationAmt, animationConfigRef.current); ++ return withSpring(translationAmt, animationConfigRef.value); + }, [activeKey, cellIndex]); + + return translate; +diff --git a/node_modules/react-native-draggable-flatlist/src/hooks/useOnCellActiveAnimation.ts b/node_modules/react-native-draggable-flatlist/src/hooks/useOnCellActiveAnimation.ts +index 7c20587..cfc6a4f 100644 +--- a/node_modules/react-native-draggable-flatlist/src/hooks/useOnCellActiveAnimation.ts ++++ b/node_modules/react-native-draggable-flatlist/src/hooks/useOnCellActiveAnimation.ts +@@ -1,6 +1,7 @@ + import { useRef } from "react"; + import Animated, { + useDerivedValue, ++ useSharedValue, + withSpring, + WithSpringConfig, + } from "react-native-reanimated"; +@@ -15,8 +16,8 @@ type Params = { + export function useOnCellActiveAnimation( + { animationConfig }: Params = { animationConfig: {} } + ) { +- const animationConfigRef = useRef(animationConfig); +- animationConfigRef.current = animationConfig; ++ const animationConfigRef = useSharedValue(animationConfig); ++ animationConfigRef.value = animationConfig; + + const isActive = useIsActive(); + +@@ -26,7 +27,7 @@ export function useOnCellActiveAnimation( + const toVal = isActive && isTouchActiveNative.value ? 1 : 0; + return withSpring(toVal, { + ...DEFAULT_ANIMATION_CONFIG, +- ...animationConfigRef.current, ++ ...animationConfigRef.value, + }); + }, [isActive]); + diff --git a/patches/react-native-reanimated+3.16.1.patch b/patches/react-native-reanimated+3.16.1.patch deleted file mode 100644 index 89fb7a41..00000000 --- a/patches/react-native-reanimated+3.16.1.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/node_modules/react-native-reanimated/src/shareables.ts b/node_modules/react-native-reanimated/src/shareables.ts -index 44e961f..11bf641 100644 ---- a/node_modules/react-native-reanimated/src/shareables.ts -+++ b/node_modules/react-native-reanimated/src/shareables.ts -@@ -343,11 +343,7 @@ function freezeObjectIfDev(value: T) { - return element; - }, - set() { -- logger.warn( -- `Tried to modify key \`${key}\` of an object which has been already passed to a worklet. See --https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#tried-to-modify-key-of-an-object-which-has-been-converted-to-a-shareable --for more details.` -- ); -+ - }, - }); - }); diff --git a/src/enums/Playlist.ts b/src/enums/Playlist.ts index 772aea7f..38ff9693 100644 --- a/src/enums/Playlist.ts +++ b/src/enums/Playlist.ts @@ -21,4 +21,4 @@ export enum SortOptions { PreviousOrder = 'PREVIOUS_ORDER', } -export const PLAYLIST_MEDIAID = 'playlist-'; +export const PlaylistMediaID = 'playlist-'; diff --git a/src/hooks/usePlayback.migrate.ts b/src/hooks/usePlayback.migrate.ts index 69417a12..96452650 100644 --- a/src/hooks/usePlayback.migrate.ts +++ b/src/hooks/usePlayback.migrate.ts @@ -13,7 +13,7 @@ import { import { NoxRepeatMode } from '@enums/RepeatMode'; import noxPlayingList, { setPlayingIndex } from '@stores/playingList'; import { dataSaverPlaylist, dataSaverSongs } from '@utils/Cache'; -import { PLAYLIST_MEDIAID, PlaylistTypes } from '@enums/Playlist'; +import { PlaylistMediaID, PlaylistTypes } from '@enums/Playlist'; import { fetchCurrentMusicTop } from '@utils/mediafetch/biliMusicTop'; const { getState } = noxPlayingList; @@ -102,8 +102,8 @@ export const _playFromMediaId = async ({ playlistIds, }: PlayFromMediaID) => { logger.info(`[playFromMediaId]: ${mediaId}`); - if (mediaId.startsWith(PLAYLIST_MEDIAID)) { - mediaId = mediaId.substring(PLAYLIST_MEDIAID.length); + if (mediaId.startsWith(PlaylistMediaID)) { + mediaId = mediaId.substring(PlaylistMediaID.length); // play a playlist. if (playlists[mediaId] === undefined) { logger.warn(`[Playback] ${mediaId} doesnt exist.`); diff --git a/src/hooks/usePlaybackAA.ts b/src/hooks/usePlaybackAA.ts index 41a82285..ce198de2 100644 --- a/src/hooks/usePlaybackAA.ts +++ b/src/hooks/usePlaybackAA.ts @@ -4,7 +4,7 @@ import TrackPlayer from 'react-native-track-player'; import { useTranslation } from 'react-i18next'; import i18n from 'i18next'; -import { PLAYLIST_MEDIAID } from '@enums/Playlist'; +import { PlaylistMediaID } from '@enums/Playlist'; import usePlayback from './usePlayback'; import { useNoxSetting } from '@stores/useApp'; import { IntentData } from '@enums/Intent'; @@ -28,7 +28,7 @@ export const buildBrowseTree = ( ], PlaylistTab: Object.keys(playlists).map(key => { return { - mediaId: `${PLAYLIST_MEDIAID}${key}`, + mediaId: `${PlaylistMediaID}${key}`, title: playlists[key].title, playable: '0', }; diff --git a/src/hooks/usePlaybackCarplay.ts b/src/hooks/usePlaybackCarplay.ts index 1101fcd5..f577e646 100644 --- a/src/hooks/usePlaybackCarplay.ts +++ b/src/hooks/usePlaybackCarplay.ts @@ -7,7 +7,7 @@ import { } from 'react-native-carplay'; import { useTranslation } from 'react-i18next'; -import { PLAYLIST_MEDIAID } from '@enums/Playlist'; +import { PlaylistMediaID } from '@enums/Playlist'; import usePlayback from './usePlayback'; import { cycleThroughPlaymodeIOS as cyclePlaymode } from '@stores/playingList'; import { isIOS } from '@utils/RNUtils'; @@ -47,7 +47,7 @@ export default () => { return pushNowPlayingTemplate(); } playFromMediaId( - `${PLAYLIST_MEDIAID}${playlistIds[item.index - 1]}`, + `${PlaylistMediaID}${playlistIds[item.index - 1]}`, ).then(() => pushNowPlayingTemplate()); }, }); From 0eaf8aa0cb828ec2992544536548f03b22da7fda Mon Sep 17 00:00:00 2001 From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com> Date: Mon, 11 Nov 2024 16:05:21 -0800 Subject: [PATCH 4/4] fix: color --- src/AzusaPlayer.tsx | 1 - src/components/playlists/Playlists.tsx | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/AzusaPlayer.tsx b/src/AzusaPlayer.tsx index 702020f0..c3d4d81f 100644 --- a/src/AzusaPlayer.tsx +++ b/src/AzusaPlayer.tsx @@ -53,7 +53,6 @@ interface Props extends NoxComponent.NavigationProps { } const NoxPlayer = ({ navigation, setNavigation = () => undefined }: Props) => { const Tab = createMaterialTopTabNavigator(); - useEffect(() => setNavigation(navigation), []); return ( diff --git a/src/components/playlists/Playlists.tsx b/src/components/playlists/Playlists.tsx index 73e1340e..89bc8bb2 100644 --- a/src/components/playlists/Playlists.tsx +++ b/src/components/playlists/Playlists.tsx @@ -95,8 +95,8 @@ export default () => { backgroundColor: currentPlaylist.id === item ? // this is a special high contrast color than primaryContainer. - (playerStyle.colors.playlistDrawerBackgroundColor ?? - playerStyle.customColors.primaryContainer) + (playerStyle.customColors.playlistDrawerBackgroundColor ?? + playerStyle.colors.primaryContainer) : undefined, }, ]} @@ -145,7 +145,7 @@ export default () => { { backgroundColor: currentPlaylist.id === - playlists[StorageKeys.SEARCH_PLAYLIST_KEY]?.id + playlists[StorageKeys.SEARCH_PLAYLIST_KEY]?.id ? (playerStyle.colors.primaryContainer ?? playerStyle.customColors.playlistDrawerBackgroundColor) : undefined, @@ -161,7 +161,7 @@ export default () => { } leadColor={ currentPlayingList.id === - playlists[StorageKeys.SEARCH_PLAYLIST_KEY].id + playlists[StorageKeys.SEARCH_PLAYLIST_KEY].id ? playerStyle.colors.primary : undefined }