Fix some android issues (#368)

This commit is contained in:
Zoe Roux 2024-04-01 00:23:05 +02:00 committed by GitHub
commit d26934b602
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 66 additions and 30 deletions

View File

@ -24,6 +24,7 @@ import { Account, Token, TokenP, getCurrentApiUrl } from "./accounts";
import { UserP } from "./resources"; import { UserP } from "./resources";
import { addAccount, getCurrentAccount, removeAccounts, updateAccount } from "./account-internal"; import { addAccount, getCurrentAccount, removeAccounts, updateAccount } from "./account-internal";
import { Platform } from "react-native"; import { Platform } from "react-native";
import { useEffect, useRef, useState } from "react";
type Result<A, B> = type Result<A, B> =
| { ok: true; value: A; error?: undefined } | { ok: true; value: A; error?: undefined }
@ -137,6 +138,36 @@ export const getTokenWJ = async (
export const getToken = async (): Promise<string | null> => (await getTokenWJ())[0]; export const getToken = async (): Promise<string | null> => (await getTokenWJ())[0];
export const getCurrentToken = () => {
const account = getCurrentAccount();
return account ? `${account.token.token_type} ${account.token.access_token}` : null;
};
export const useToken = () => {
const account = getCurrentAccount();
const refresher = useRef<NodeJS.Timeout | null>(null);
const [token, setToken] = useState(
account ? `${account.token.token_type} ${account.token.access_token}` : null,
);
useEffect(() => {
async function run() {
const nToken = await getTokenWJ();
setToken(nToken[0]);
if (refresher.current) clearTimeout(refresher.current);
if (nToken[1])
refresher.current = setTimeout(run, nToken[1].expire_at.getTime() - Date.now());
}
run();
return () => {
if (refresher.current) clearTimeout(refresher.current);
};
}, [account]);
if (!token) return null;
return token;
};
export const logout = () => { export const logout = () => {
removeAccounts((x) => x.selected); removeAccounts((x) => x.selected);
}; };

View File

@ -25,6 +25,7 @@ import { Blurhash } from "react-native-blurhash";
import { percent, useYoshiki } from "yoshiki/native"; import { percent, useYoshiki } from "yoshiki/native";
import { Props, ImageLayout } from "./base-image"; import { Props, ImageLayout } from "./base-image";
import { Skeleton } from "../skeleton"; import { Skeleton } from "../skeleton";
import { getCurrentToken } from "@kyoo/models";
export const Image = ({ export const Image = ({
src, src,
@ -60,6 +61,7 @@ export const Image = ({
} }
quality ??= "high"; quality ??= "high";
const token = getCurrentToken();
return ( return (
<View {...css([layout, border], props)}> <View {...css([layout, border], props)}>
{state !== "finished" && ( {state !== "finished" && (
@ -72,6 +74,11 @@ export const Image = ({
<FastImage <FastImage
source={{ source={{
uri: src[quality], uri: src[quality],
headers: token
? {
Authorization: token,
}
: {},
priority: FastImage.priority[quality === "medium" ? "normal" : quality], priority: FastImage.priority[quality === "medium" ? "normal" : quality],
}} }}
accessibilityLabel={alt} accessibilityLabel={alt}

View File

@ -46,7 +46,7 @@ export const LoginPage: QueryPage<{ apiUrl?: string; error?: string }> = ({
useEffect(() => { useEffect(() => {
if (!apiUrl && Platform.OS !== "web") if (!apiUrl && Platform.OS !== "web")
router.replace("/server-url", undefined, { router.replace("/server-url", undefined, {
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: true }, experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
}); });
}, [apiUrl, router]); }, [apiUrl, router]);
@ -74,7 +74,7 @@ export const LoginPage: QueryPage<{ apiUrl?: string; error?: string }> = ({
setError(error); setError(error);
if (error) return; if (error) return;
router.replace("/", undefined, { router.replace("/", undefined, {
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: true }, experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
}); });
}} }}
{...css({ {...css({

View File

@ -106,7 +106,7 @@ export const OidcCallbackPage: QueryPage<{
function onError(error: string) { function onError(error: string) {
router.replace({ pathname: "/login", query: { error, apiUrl } }, undefined, { router.replace({ pathname: "/login", query: { error, apiUrl } }, undefined, {
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: true }, experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
}); });
} }
async function run() { async function run() {
@ -114,7 +114,7 @@ export const OidcCallbackPage: QueryPage<{
if (loginError) onError(loginError); if (loginError) onError(loginError);
else { else {
router.replace("/", undefined, { router.replace("/", undefined, {
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: true }, experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
}); });
} }
} }

View File

@ -45,7 +45,7 @@ export const RegisterPage: QueryPage<{ apiUrl?: string }> = ({ apiUrl }) => {
useEffect(() => { useEffect(() => {
if (!apiUrl && Platform.OS !== "web") if (!apiUrl && Platform.OS !== "web")
router.replace("/server-url", undefined, { router.replace("/server-url", undefined, {
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: true }, experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
}); });
}, [apiUrl, router]); }, [apiUrl, router]);
@ -85,7 +85,7 @@ export const RegisterPage: QueryPage<{ apiUrl?: string }> = ({ apiUrl }) => {
setError(error); setError(error);
if (error) return; if (error) return;
router.replace("/", undefined, { router.replace("/", undefined, {
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: true }, experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
}); });
}} }}
{...css({ {...css({

View File

@ -33,7 +33,7 @@ declare module "react-native-video" {
export * from "react-native-video"; export * from "react-native-video";
import { Audio, Subtitle, getToken } from "@kyoo/models"; import { Audio, Subtitle, getToken, useToken } from "@kyoo/models";
import { IconButton, Menu } from "@kyoo/primitives"; import { IconButton, Menu } from "@kyoo/primitives";
import { ComponentProps, forwardRef, useEffect, useRef } from "react"; import { ComponentProps, forwardRef, useEffect, useRef } from "react";
import { atom, useAtom, useAtomValue, useSetAtom } from "jotai"; import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
@ -67,20 +67,13 @@ const Video = forwardRef<VideoRef, VideoProps>(function Video(
ref, ref,
) { ) {
const { css } = useYoshiki(); const { css } = useYoshiki();
const token = useRef<string | null>(null); const token = useToken();
const setInfo = useSetAtom(infoAtom); const setInfo = useSetAtom(infoAtom);
const [video, setVideo] = useAtom(videoAtom); const [video, setVideo] = useAtom(videoAtom);
const audio = useAtomValue(audioAtom); const audio = useAtomValue(audioAtom);
const subtitle = useAtomValue(subtitleAtom); const subtitle = useAtomValue(subtitleAtom);
const mode = useAtomValue(playModeAtom); const mode = useAtomValue(playModeAtom);
useEffect(() => {
async function run() {
token.current = await getToken();
}
run();
}, [source]);
useEffect(() => { useEffect(() => {
if (mode === PlayMode.Hls) setVideo(-1); if (mode === PlayMode.Hls) setVideo(-1);
}, [mode, setVideo]); }, [mode, setVideo]);
@ -92,7 +85,7 @@ const Video = forwardRef<VideoRef, VideoProps>(function Video(
source={{ source={{
...source, ...source,
headers: { headers: {
Authorization: `Bearer: ${token.current}`, ...(token ? { Authorization: token } : {}),
"X-CLIENT-ID": clientId, "X-CLIENT-ID": clientId,
}, },
}} }}
@ -181,17 +174,19 @@ export const QualitiesMenu = (props: CustomMenu) => {
/> />
{/* TODO: Support video tracks when the play mode is not hls. */} {/* TODO: Support video tracks when the play mode is not hls. */}
{/* @ts-expect-error They forgot to type this. */} {/* @ts-expect-error They forgot to type this. */}
{info?.videoTracks.map((x) => ( {info?.videoTracks
<Menu.Item .sort((a: any, b: any) => b.height - a.height)
key={x.height} .map((x: any, i: number) => (
label={`${x.height}p`} <Menu.Item
selected={video === x.height} key={i}
onSelect={() => { label={`${x.height}p`}
setPlayMode(PlayMode.Hls); selected={video === x.height}
setVideo(x.height); onSelect={() => {
}} setPlayMode(PlayMode.Hls);
/> setVideo(x.height);
))} }}
/>
))}
</Menu> </Menu>
); );
}; };

View File

@ -70,7 +70,7 @@ const initHls = (): Hls => {
hls = new Hls({ hls = new Hls({
xhrSetup: async (xhr) => { xhrSetup: async (xhr) => {
const token = await getToken(); const token = await getToken();
if (token) xhr.setRequestHeader("Authorization", `Bearer: ${token}`); if (token) xhr.setRequestHeader("Authorization", token);
xhr.setRequestHeader("X-CLIENT-ID", client_id); xhr.setRequestHeader("X-CLIENT-ID", client_id);
}, },
autoStartLoad: false, autoStartLoad: false,

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"math" "math"
"os" "os"
"strings"
"sync" "sync"
) )
@ -90,10 +91,12 @@ func (fs *FileStream) GetMaster() string {
} }
aspectRatio := float32(fs.Info.Video.Width) / float32(fs.Info.Video.Height) aspectRatio := float32(fs.Info.Video.Width) / float32(fs.Info.Video.Height)
transmux_codec := "avc1.640028" // codec is the prefix + the level, the level is not part of the codec we want to compare for the same_codec check bellow
transmux_prefix := "avc1.6400"
transmux_codec := transmux_prefix + "28"
for _, quality := range Qualities { for _, quality := range Qualities {
same_codec := fs.Info.Video.MimeCodec != nil && *fs.Info.Video.MimeCodec == transmux_codec same_codec := fs.Info.Video.MimeCodec != nil && strings.HasPrefix(*fs.Info.Video.MimeCodec, transmux_prefix)
inc_lvl := quality.Height() < fs.Info.Video.Quality.Height() || inc_lvl := quality.Height() < fs.Info.Video.Quality.Height() ||
(quality.Height() == fs.Info.Video.Quality.Height() && !same_codec) (quality.Height() == fs.Info.Video.Quality.Height() && !same_codec)