Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c2e3331b8 | ||
|
|
50573ba31e | ||
|
|
02bd4c0cb6 |
No files matched your search
@@ -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;
|
||||
@@ -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
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user