Compare commits

...
Author SHA1 Message Date
Arthur Jamet 2c2e3331b8 tmp 2026-08-01 15:47:18 +02:00
Arthur Jamet 50573ba31e Mobile: Bump Screens + Gesture Handler 2026-08-01 13:47:30 +02:00
Arthur Jamet 02bd4c0cb6 Mobile: Bump Reanimated, Video, Nitro 2026-08-01 13:22:39 +02:00
4 changed files with 177 additions and 51 deletions

No files matched your search

+6 -5
View File
@@ -34,6 +34,7 @@
"expo-linear-gradient": "^56.0.4",
"expo-linking": "~56.0.15",
"expo-media-control": "patch:expo-media-control@npm%3A1.0.12#~/.yarn/patches/expo-media-control-npm-1.0.12-d7bddfea85.patch",
"expo-network": "^57.0.1",
"expo-router": "~56.2.14",
"expo-screen-orientation": "~56.0.5",
"expo-splash-screen": "~56.0.12",
@@ -54,18 +55,18 @@
"react-native-base64": "^0.2.2",
"react-native-draggable-flatlist": "^4.0.3",
"react-native-edge-to-edge": "^1.8.1",
"react-native-gesture-handler": "~2.31.0",
"react-native-gesture-handler": "~2.31.2",
"react-native-keyboard-controller": "1.22.2",
"react-native-mmkv": "4.3.2",
"react-native-nitro-modules": "0.35.9",
"react-native-nitro-modules": "0.36.4",
"react-native-reanimated": "~4.5.1",
"react-native-safe-area-context": "~5.8.0",
"react-native-screens": "~4.25.2",
"react-native-screens": "~4.26.2",
"react-native-svg": "15.15.5",
"react-native-toast-message": "^2.3.3",
"react-native-unistyles": "3.2.5",
"react-native-unistyles": "3.3.0",
"react-native-uuid": "^2.0.4",
"react-native-video": "^7.0.0-beta.9",
"react-native-video": "^7.0.0-beta.10",
"react-native-worklets": "^0.10.1",
"state": "workspace:^",
"type-fest": "^5.6.0",
@@ -4,9 +4,11 @@ import {
type MediaControlEvent,
PlaybackState,
} from "expo-media-control";
import { getNetworkStateAsync, NetworkStateType } from "expo-network";
import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
import { useEffect, useRef, useState } from "react";
import { Platform } from "react-native";
import Toast from "react-native-toast-message";
import uuid from "react-native-uuid";
import {
type onLoadData,
@@ -34,6 +36,7 @@ import {
queuePrefetchCountAtom,
useDownloadManager,
} from "~/downloads";
import { streamingPreferenceAtom } from "~/state/streaming";
import {
currentTrackAtom,
durationAtom,
@@ -191,8 +194,8 @@ export const PlayerContext = () => {
prefetchCount + 1 + cursor, // NOTE: add one to include current song
);
for (const track of queue) {
if (track.track.type === "Audio")
download(track.track.sourceFileId);
// if (track.track.type === "Audio")
// download(track.track.sourceFileId);
}
}, [playlist, cursor]);
@@ -237,7 +240,7 @@ export const PlayerContext = () => {
return;
}
if (playerRef.current === null) {
mkSource(queryClient, currentTrack).then((source) => {
mkSource(queryClient, currentTrack, "direct").then((source) => {
playerRef.current = new VideoPlayer(source);
playerRef.current.mixAudioMode = "doNotMix";
playerRef.current.ignoreSilentSwitchMode = "ignore";
@@ -336,7 +339,7 @@ export const PlayerContext = () => {
isSwitchingTrack.current = true;
ready.current = false;
playerRef.current!.pause();
mkSource(queryClient, currentTrack).then((source) => {
mkSource(queryClient, currentTrack, "direct").then((source) => {
playerRef.current
?.replaceSourceAsync(source)
.then(() => {
@@ -366,7 +369,11 @@ export const PlayerContext = () => {
}
const timestamp = playerRef.current?.currentTime;
mkSource(queryClient, currentTrack, isHLS).then((source) =>
mkSource(
queryClient,
currentTrack,
isHLS ? "transcoding" : "direct",
).then((source) =>
playerRef.current?.replaceSourceAsync(source).then(() => {
playerRef.current!.play();
if (isHLS) {
@@ -408,40 +415,55 @@ const clientId = uuid.v4();
const mkSource = async (
queryClient: QueryClient,
st: TrackState,
useHLS: boolean = false,
method: "direct" | "transcoding",
) => {
const api = getAPI();
const [dlStatus, localPath] = await getDownloadStatus(
st.track.sourceFileId,
);
const shouldDownload = !useHLS && st.track.type === "Audio";
if (!shouldDownload || dlStatus !== "downloaded") {
if (shouldDownload) {
await downloadFile(queryClient)(st.track.sourceFileId);
}
return _mkSource(st, api, useHLS);
const streamingPreference = store.get(streamingPreferenceAtom);
console.log(streamingPreference);
const streamingQuality =
dlStatus === "downloaded"
? null
: await getNetworkStateAsync().then((st) =>
st.type === NetworkStateType.WIFI
? streamingPreference.wifi
: streamingPreference.cellular,
);
const shouldDownload = method === "direct" && st.track.type === "Audio";
// if (!shouldDownload || dlStatus !== "downloaded") {
if (shouldDownload) {
// await downloadFile(queryClient)(st.track.sourceFileId);
}
return _mkSource(st, api, false, localPath);
const res = _mkSource(st, api, "transcoding");
console.log(res);
if (streamingQuality) {
Toast.show({
text1: "Playing in quality " + streamingQuality?.audio,
});
res.uri = res.uri.replace("/128k/", `/${streamingQuality?.audio}/`);
} else {
Toast.show({ text1: "Streaming quality unspecified" });
}
return res;
// }
// return { uri: localPath };
};
const _mkSource = (
{ track }: TrackState,
api: API,
method: "direct" | "transcoding",
useTranscoding = false,
localPath?: string,
): VideoConfig => ({
uri:
localPath ??
(useTranscoding
? api.getTranscodeStreamURL(track.sourceFileId, track.type)
: api.getDirectStreamURL(track.sourceFileId)),
headers: {
...api.getAuthHeaders(),
...(useTranscoding
? {
"X-CLIENT-ID": clientId,
}
: {}),
},
});
) =>
({
uri:
method === "transcoding"
? api.getTranscodeStreamURL(track.sourceFileId, track.type)
: api.getDirectStreamURL(track.sourceFileId),
headers: {
...api.getAuthHeaders(),
"X-CLIENT-ID": clientId,
},
}) satisfies VideoConfig;
+79
View File
@@ -0,0 +1,79 @@
import { atom } from "jotai";
import * as yup from "yup";
import { storage } from "~/utils/storage";
export const AudioQualities = [
"128k",
"192k",
"256k",
"320k",
"512k",
"original",
] as const;
type AudioQuality = (typeof AudioQualities)[number];
export const VideoQualities = [
"240p",
"480p",
"720p",
"1080p",
"original",
] as const;
type VideoQuality = (typeof VideoQualities)[number];
const StreamingQuality = yup.object({
audio: yup.mixed<AudioQuality>().oneOf(AudioQualities).default("320k"),
video: yup.mixed<VideoQuality>().oneOf(VideoQualities).default("original"),
});
type StreamingQuality = yup.InferType<typeof StreamingQuality>;
const StreamingPreferences = yup.object({
wifi: StreamingQuality.default({
audio: "320k",
video: "1080p",
} satisfies StreamingQuality).required(),
cellular: StreamingQuality.default({
audio: "128k",
video: "720p",
} satisfies StreamingQuality).required(),
download: StreamingQuality.default({
audio: "256k",
video: "720p",
} satisfies StreamingQuality).required(),
});
type StreamingPreferences = yup.InferType<typeof StreamingPreferences>;
export const StreamingPreferenceKey = "streaming-preferences";
const readStreamingPreferences = (): StreamingPreferences => {
const stringPrefs = storage.getString(StreamingPreferenceKey);
if (!stringPrefs) {
return StreamingPreferences.getDefault();
}
try {
const prefs = StreamingPreferences.validateSync(
JSON.parse(stringPrefs),
);
return prefs;
} catch (e) {
// biome-ignore lint/suspicious/noConsole: For debug
console.warn(
`An error occured when reading streaming preferences: ${e}`,
);
return StreamingPreferences.getDefault();
}
};
export const streamingPreferenceAtom = atom<
StreamingPreferences,
[StreamingPreferences],
void
>(
(get) => get(_streamingPreferenceAtom),
(_, set, newPref) => {
// TODO: Validate?
storage.set(StreamingPreferenceKey, JSON.stringify(newPref));
set(_streamingPreferenceAtom, newPref);
},
);
const _streamingPreferenceAtom = atom(readStreamingPreferences());
+40 -16
View File
@@ -6346,6 +6346,16 @@ __metadata:
languageName: node
linkType: hard
"expo-network@npm:^57.0.1":
version: 57.0.1
resolution: "expo-network@npm:57.0.1"
peerDependencies:
expo: "*"
react: "*"
checksum: 10c0/15e2b59a88a500fc803b296fa80988e39659ed618959fa02b370c8b9a70db968e21a62de350a1998ece06819b83c49e8c59ea32fe5d132b325640c98a544a85f
languageName: node
linkType: hard
"expo-router@npm:~56.2.14":
version: 56.2.14
resolution: "expo-router@npm:56.2.14"
@@ -8419,6 +8429,7 @@ __metadata:
expo-linear-gradient: "npm:^56.0.4"
expo-linking: "npm:~56.0.15"
expo-media-control: "patch:expo-media-control@npm%3A1.0.12#~/.yarn/patches/expo-media-control-npm-1.0.12-d7bddfea85.patch"
expo-network: "npm:^57.0.1"
expo-router: "npm:~56.2.14"
expo-screen-orientation: "npm:~56.0.5"
expo-splash-screen: "npm:~56.0.12"
@@ -8439,18 +8450,18 @@ __metadata:
react-native-base64: "npm:^0.2.2"
react-native-draggable-flatlist: "npm:^4.0.3"
react-native-edge-to-edge: "npm:^1.8.1"
react-native-gesture-handler: "npm:~2.31.0"
react-native-gesture-handler: "npm:~2.31.2"
react-native-keyboard-controller: "npm:1.22.2"
react-native-mmkv: "npm:4.3.2"
react-native-nitro-modules: "npm:0.35.9"
react-native-nitro-modules: "npm:0.36.4"
react-native-reanimated: "npm:~4.5.1"
react-native-safe-area-context: "npm:~5.8.0"
react-native-screens: "npm:~4.25.2"
react-native-screens: "npm:~4.26.2"
react-native-svg: "npm:15.15.5"
react-native-toast-message: "npm:^2.3.3"
react-native-unistyles: "npm:3.2.5"
react-native-unistyles: "npm:3.3.0"
react-native-uuid: "npm:^2.0.4"
react-native-video: "npm:^7.0.0-beta.9"
react-native-video: "npm:^7.0.0-beta.10"
react-native-worklets: "npm:^0.10.1"
state: "workspace:^"
type-fest: "npm:^5.6.0"
@@ -9401,7 +9412,7 @@ __metadata:
languageName: node
linkType: hard
"react-native-gesture-handler@npm:~2.31.0":
"react-native-gesture-handler@npm:~2.31.2":
version: 2.31.2
resolution: "react-native-gesture-handler@npm:2.31.2"
dependencies:
@@ -9460,13 +9471,13 @@ __metadata:
languageName: node
linkType: hard
"react-native-nitro-modules@npm:0.35.9":
version: 0.35.9
resolution: "react-native-nitro-modules@npm:0.35.9"
"react-native-nitro-modules@npm:0.36.4":
version: 0.36.4
resolution: "react-native-nitro-modules@npm:0.36.4"
peerDependencies:
react: "*"
react-native: "*"
checksum: 10c0/2e5c1b3eed1d187e7c2bbbf661e6405cb69c6a20b01427ea4c8a3bfe07a4baf2efbeb170a21f8c17fb0e18f022244f4b1fe1ce69a7ec824a7a4cf72441893cf1
checksum: 10c0/609cbb9d3511cba2b60847c64946ae7c33a002cba5c2a7299a661251c63ae30f1750108a437faaeca7653e80af70f259da0aa27d3dd9d581b5b01ebfb1a07902
languageName: node
linkType: hard
@@ -9494,7 +9505,7 @@ __metadata:
languageName: node
linkType: hard
"react-native-screens@npm:^4.25.2, react-native-screens@npm:~4.25.2":
"react-native-screens@npm:^4.25.2":
version: 4.25.2
resolution: "react-native-screens@npm:4.25.2"
dependencies:
@@ -9507,6 +9518,19 @@ __metadata:
languageName: node
linkType: hard
"react-native-screens@npm:~4.26.2":
version: 4.26.2
resolution: "react-native-screens@npm:4.26.2"
dependencies:
react-freeze: "npm:^1.0.0"
warn-once: "npm:^0.1.0"
peerDependencies:
react: "*"
react-native: "*"
checksum: 10c0/3cdc702d8e21c63331e306a2b971307d5d9e13df52d94f435c5bb8d5dcf09fed00f4ef788e85ba87fae1ba5b155f4cdc2ee177a70f1f512adff73f94eef844d1
languageName: node
linkType: hard
"react-native-skia-android@npm:150.0.0":
version: 150.0.0
resolution: "react-native-skia-android@npm:150.0.0"
@@ -9558,9 +9582,9 @@ __metadata:
languageName: node
linkType: hard
"react-native-unistyles@npm:3.2.5":
version: 3.2.5
resolution: "react-native-unistyles@npm:3.2.5"
"react-native-unistyles@npm:3.3.0":
version: 3.3.0
resolution: "react-native-unistyles@npm:3.3.0"
dependencies:
"@babel/types": "npm:7.29.0"
peerDependencies:
@@ -9575,7 +9599,7 @@ __metadata:
optional: true
react-native-reanimated:
optional: true
checksum: 10c0/dcbba53188bff64b422d5d6f9407636846a4076122de4034b912318782717cb7bc0ed7aa84bcac64bc10cd307c33507e8774c24965df1b7998e8dcdaa1343a34
checksum: 10c0/228582bd2833089982ce83044c22c6b61cf53c3b126465761df7087eb11594d518fa075a5d79f65aefbca88ff11d35caf87f316766eeb1ea249082e3f6a8742e
languageName: node
linkType: hard
@@ -9586,7 +9610,7 @@ __metadata:
languageName: node
linkType: hard
"react-native-video@npm:^7.0.0-beta.9":
"react-native-video@npm:^7.0.0-beta.10":
version: 7.0.0-beta.10
resolution: "react-native-video@npm:7.0.0-beta.10"
dependencies: