Added option to change invidious server #5

main
Guus van Meerveld 2 years ago
parent 0edd0afb2a
commit 44f2db7c25
Signed by: Guusvanmeerveld
GPG Key ID: 2BA7D7912771966E

@ -22,6 +22,8 @@ import { abbreviateNumber } from "@src/utils";
import { Video as VideoModel } from "@interfaces/video";
import { useSettings } from "@utils/hooks";
interface Channel {
authorThumbnails: { url: string; width: number; height: number }[];
}
@ -34,7 +36,7 @@ const Video: FC<VideoModel> = ({
views,
published
}) => {
const requestFields = ["authorThumbnails"];
const [settings] = useSettings();
const { isLoading, error, data, refetch, isFetched } = useQuery<
Channel,
@ -43,11 +45,14 @@ const Video: FC<VideoModel> = ({
["channelData", author.id],
() =>
axios
.get(`https://invidious.privacy.gd/api/v1/channels/${author.id}`, {
params: {
fields: requestFields.join(",")
.get(
`https://${settings.invidiousServer}/api/v1/channels/${author.id}`,
{
params: {
fields: ["authorThumbnails"].join(",")
}
}
})
)
.then((res) => res.data),
{ enabled: false }
);

@ -0,0 +1,79 @@
export interface ServerInstance {
flag?: string;
region?: string;
stats?: Stats;
cors?: boolean;
api?: boolean;
type: ServerInstanceType;
uri: string;
monitor?: Monitor;
}
interface Monitor {
monitorId: number;
createdAt: number;
statusClass: StatusClass;
name: string;
url: null;
type: MonitorType;
dailyRatios: Ratio[];
"90dRatio": Ratio;
"30dRatio": Ratio;
}
interface Ratio {
ratio: string;
label: StatusClass;
}
export enum StatusClass {
Black = "black",
Success = "success",
Warning = "warning"
}
export enum MonitorType {
HTTPS = "HTTP(s)"
}
export interface Stats {
version: string;
software: Software;
openRegistrations: boolean;
usage: Usage;
metadata: Metadata;
}
interface Metadata {
updatedAt: number;
lastChannelRefreshedAt: number;
}
interface Software {
name: Name;
version: string;
branch: Branch;
}
export enum Branch {
Master = "master"
}
export enum Name {
Invidious = "invidious"
}
interface Usage {
users: Users;
}
interface Users {
total: number;
activeHalfyear: number;
activeMonth: number;
}
export enum ServerInstanceType {
HTTPS = "https",
Onion = "onion"
}

@ -2,6 +2,7 @@ interface Settings {
theme?: "light" | "dark";
primaryColor: string;
accentColor: string;
invidiousServer: string;
}
export default Settings;

@ -1,12 +1,22 @@
import axios from "axios";
import { NextPage } from "next";
import { FC } from "react";
import { FC, useState } from "react";
import { useQuery } from "react-query";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import ButtonGroup from "@mui/material/ButtonGroup";
import CircularProgress from "@mui/material/CircularProgress";
import Container from "@mui/material/Container";
import Divider from "@mui/material/Divider";
import FormControl from "@mui/material/FormControl";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import Modal from "@mui/material/Modal";
import Select from "@mui/material/Select";
import Typography from "@mui/material/Typography";
import {
blue,
@ -19,8 +29,17 @@ import {
} from "@mui/material/colors/";
import { useTheme } from "@mui/material/styles/";
import Done from "@mui/icons-material/Done";
import Error from "@mui/icons-material/Error";
import { toCamelCase } from "@src/utils";
import {
ServerInstance,
ServerInstanceType,
Stats
} from "@interfaces/api/instances";
import { useSettings } from "@utils/hooks";
import Layout from "@components/Layout";
@ -28,12 +47,29 @@ import Layout from "@components/Layout";
const Settings: NextPage = () => {
const [settings, setSettings] = useSettings();
const theme = useTheme();
const setSetting = (key: string, value?: string): void => {
setSettings({ ...settings, [key]: value });
};
const [modalIsOpen, setModalState] = useState(false);
const theme = useTheme();
const instances = useQuery<[string, ServerInstance][]>(
"invidiousInstances",
() =>
axios
.get("https://api.invidious.io/instances.json")
.then((res) => res.data),
{ retry: false }
);
const invidiousServerResponse = useQuery<Stats>("invidiousInstance", () =>
axios
.get(`https://${settings.invidiousServer}/api/v1/stats`)
.then((res) => res.data)
);
const ColorSetting: FC<{ type: string }> = ({ type }) => {
const camelCase = toCamelCase(type) as "primaryColor" | "accentColor";
@ -77,6 +113,55 @@ const Settings: NextPage = () => {
);
};
const InfoModal: FC = () => {
const data = invidiousServerResponse.data!;
const lastUpdated = new Date(data.metadata.updatedAt * 1000);
return (
<Modal
open={modalIsOpen}
onClose={() => setModalState(false)}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box
sx={{
p: 4,
position: "absolute",
left: "50%",
top: "50%",
transform: "translate(-50%, -50%)",
backgroundColor: theme.palette.background.paper,
borderRadius: 1,
outline: "none"
}}
>
<Typography id="modal-modal-title" variant="h4">
Stats for {settings.invidiousServer}
</Typography>
<Typography id="modal-modal-description" sx={{ mt: 2 }}>
Version: {data.version} <br /> <br />
Software name: {data.software.name} <br />
Software version: {data.software.version} <br />
Software branch: {data.software.branch} <br /> <br />
Is accepting registrations: {data.openRegistrations
? "Yes"
: "No"}{" "}
<br /> <br />
Total users: {data.usage.users.total} <br />
Active in the past half year: {data.usage.users.activeHalfyear}
<br />
Active in the past month: {data.usage.users.activeMonth} <br />{" "}
<br />
Stats updated at: {lastUpdated.toLocaleDateString()} -{" "}
{lastUpdated.toLocaleTimeString()}
</Typography>
</Box>
</Modal>
);
};
return (
<Layout>
<Container>
@ -114,6 +199,56 @@ const Settings: NextPage = () => {
<Divider sx={{ my: 4 }} />
<Typography variant="h4">Miscellaneous</Typography>
<Box sx={{ my: 3, display: "flex", alignItems: "center" }}>
<Typography variant="h5" sx={{ flexGrow: 1 }}>
Invidious Server
</Typography>
<Box sx={{ mr: 2 }}>
{invidiousServerResponse.data &&
!invidiousServerResponse.isLoading && (
<>
<Done
onClick={() => setModalState(true)}
sx={{ color: green[800], cursor: "pointer" }}
/>
<InfoModal />
</>
)}
{invidiousServerResponse.error && (
<Error sx={{ color: red[800] }} />
)}
{invidiousServerResponse.isLoading && <CircularProgress />}
</Box>
<FormControl sx={{ minWidth: 200 }}>
<InputLabel id="server-select-label">Server</InputLabel>
<Select
labelId="server-select-label"
id="server-select"
value={settings.invidiousServer}
label="Server"
onChange={(e) => {
const server = e.target.value;
setSetting("invidiousServer", server);
}}
MenuProps={{ sx: { maxHeight: 300 } }}
>
{instances.data &&
instances.data
.filter(
([, server]) =>
server.type != ServerInstanceType.Onion &&
server.api == true
)
.map(([uri, server]) => (
<MenuItem key={uri} value={uri}>
{server.flag} {uri}
</MenuItem>
))}
</Select>
</FormControl>
</Box>
</Container>
</Layout>
);

@ -15,6 +15,7 @@ import { Error } from "@interfaces/api";
import TrendingModel from "@interfaces/api/trending";
import { trendingToVideo } from "@utils/conversions";
import { useSettings } from "@utils/hooks";
import Layout from "@components/Layout";
import Loading from "@components/Loading";
@ -23,12 +24,14 @@ import Grid from "@components/Video/Grid";
const Trending: NextPage = () => {
const [selectedCategory, setCategory] = useState<string | undefined>();
const [settings] = useSettings();
const { isLoading, error, data } = useQuery<
TrendingModel[],
AxiosError<Error>
>("trendingData", () =>
axios
.get("https://invidious.privacy.gd/api/v1/trending", {
.get(`https://${settings.invidiousServer}/api/v1/trending`, {
params: {
fields: [
"title",

@ -13,6 +13,7 @@ import { Error } from "@interfaces/api";
import Video from "@interfaces/api/video";
import { videoToVideo } from "@utils/conversions";
import { useSettings } from "@utils/hooks";
import Layout from "@components/Layout";
import Loading from "@components/Loading";
@ -22,6 +23,8 @@ const Watch: NextPage = () => {
const videoId = router.query["v"];
const [settings] = useSettings();
const { isLoading, error, data, refetch } = useQuery<
Video,
AxiosError<Error>
@ -29,7 +32,7 @@ const Watch: NextPage = () => {
["videoData", videoId],
() =>
axios
.get(`https://invidious.privacy.gd/api/v1/videos/${videoId}`, {
.get(`https://${settings.invidiousServer}/api/v1/videos/${videoId}`, {
params: {}
})
.then((res) => res.data),

@ -8,7 +8,8 @@ import Settings from "@interfaces/settings";
const defaultSettings: Settings = {
primaryColor: red[800],
accentColor: red[800]
accentColor: red[800],
invidiousServer: "vid.puffyan.us"
};
export const useSettings = (): [

Loading…
Cancel
Save