mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-03-28 12:01:53 +00:00
Merge branch 'feat/audio-select'
This commit is contained in:
@@ -34,6 +34,8 @@ import CastContext, {
|
||||
import { chromecastProfile } from "@/utils/profiles/chromecast";
|
||||
import ios12 from "@/utils/profiles/ios12";
|
||||
import { currentlyPlayingItemAtom } from "@/components/CurrentlyPlayingBar";
|
||||
import { AudioTrackSelector } from "@/components/AudioTrackSelector";
|
||||
import { SubtitleTrackSelector } from "@/components/SubtitleTrackSelector";
|
||||
|
||||
const page: React.FC = () => {
|
||||
const local = useLocalSearchParams();
|
||||
@@ -45,7 +47,9 @@ const page: React.FC = () => {
|
||||
const castDevice = useCastDevice();
|
||||
|
||||
const chromecastReady = useMemo(() => !!castDevice?.deviceId, [castDevice]);
|
||||
|
||||
const [selectedAudioStream, setSelectedAudioStream] = useState<number>(-1);
|
||||
const [selectedSubtitleStream, setSelectedSubtitleStream] =
|
||||
useState<number>(0);
|
||||
const [maxBitrate, setMaxBitrate] = useState<Bitrate>({
|
||||
key: "Max",
|
||||
value: undefined,
|
||||
@@ -95,7 +99,13 @@ const page: React.FC = () => {
|
||||
});
|
||||
|
||||
const { data: playbackUrl } = useQuery({
|
||||
queryKey: ["playbackUrl", item?.Id, maxBitrate, castDevice],
|
||||
queryKey: [
|
||||
"playbackUrl",
|
||||
item?.Id,
|
||||
maxBitrate,
|
||||
castDevice,
|
||||
selectedAudioStream,
|
||||
],
|
||||
queryFn: async () => {
|
||||
if (!api || !user?.Id || !sessionData) return null;
|
||||
|
||||
@@ -107,8 +117,12 @@ const page: React.FC = () => {
|
||||
maxStreamingBitrate: maxBitrate.value,
|
||||
sessionData,
|
||||
deviceProfile: castDevice?.deviceId ? chromecastProfile : ios12,
|
||||
audioStreamIndex: selectedAudioStream,
|
||||
subtitleStreamIndex: selectedSubtitleStream,
|
||||
});
|
||||
|
||||
console.log("Transcode URL: ", url);
|
||||
|
||||
return url;
|
||||
},
|
||||
enabled: !!sessionData,
|
||||
@@ -247,15 +261,23 @@ const page: React.FC = () => {
|
||||
<Text>{item.Overview}</Text>
|
||||
</View>
|
||||
<View className="flex flex-col p-4">
|
||||
<BitrateSelector
|
||||
onChange={(val) => setMaxBitrate(val)}
|
||||
selected={maxBitrate}
|
||||
/>
|
||||
<PlayButton
|
||||
item={item}
|
||||
chromecastReady={chromecastReady}
|
||||
onPress={onPressPlay}
|
||||
/>
|
||||
<View className="flex flex-row items-center space-x-2 w-full">
|
||||
<BitrateSelector
|
||||
onChange={(val) => setMaxBitrate(val)}
|
||||
selected={maxBitrate}
|
||||
/>
|
||||
<AudioTrackSelector
|
||||
item={item}
|
||||
onChange={setSelectedAudioStream}
|
||||
selected={selectedAudioStream}
|
||||
/>
|
||||
<SubtitleTrackSelector
|
||||
item={item}
|
||||
onChange={setSelectedSubtitleStream}
|
||||
selected={selectedSubtitleStream}
|
||||
/>
|
||||
</View>
|
||||
<PlayButton item={item} chromecastReady={false} onPress={onPressPlay} />
|
||||
</View>
|
||||
<ScrollView horizontal className="flex px-4 mb-4">
|
||||
<View className="flex flex-row space-x-2 ">
|
||||
|
||||
@@ -78,7 +78,7 @@ export default function RootLayout() {
|
||||
<JellyfinProvider>
|
||||
<StatusBar style="light" backgroundColor="#000" />
|
||||
<ThemeProvider value={DarkTheme}>
|
||||
<Stack screenOptions={{}}>
|
||||
<Stack>
|
||||
<Stack.Screen
|
||||
name="(auth)/(tabs)"
|
||||
options={{
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Input } from "@/components/common/Input";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { apiAtom, useJellyfin } from "@/providers/JellyfinProvider";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { AxiosError } from "axios";
|
||||
import { useAtom } from "jotai";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { KeyboardAvoidingView, Platform, View } from "react-native";
|
||||
@@ -18,6 +19,7 @@ const Login: React.FC = () => {
|
||||
const [api] = useAtom(apiAtom);
|
||||
|
||||
const [serverURL, setServerURL] = useState<string>("");
|
||||
const [error, setError] = useState<string>("");
|
||||
const [credentials, setCredentials] = useState<{
|
||||
username: string;
|
||||
password: string;
|
||||
@@ -36,7 +38,18 @@ const Login: React.FC = () => {
|
||||
await login(credentials.username, credentials.password);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
const e = error as AxiosError | z.ZodError;
|
||||
if (e instanceof z.ZodError) {
|
||||
setError("An error occured.");
|
||||
} else {
|
||||
if (e.response?.status === 401) {
|
||||
setError("Invalid credentials.");
|
||||
} else {
|
||||
setError(
|
||||
"A network error occurred. Did you enter the correct server URL?",
|
||||
);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -122,6 +135,8 @@ const Login: React.FC = () => {
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Text className="text-red-600 mb-2">{error}</Text>
|
||||
|
||||
<Button onPress={handleLogin} loading={loading}>
|
||||
Log in
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user