mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Fix some android issues (#368)
This commit is contained in:
commit
d26934b602
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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}
|
||||||
|
@ -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({
|
||||||
|
@ -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 },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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({
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user