Skip to content

Commit

Permalink
i hate this.
Browse files Browse the repository at this point in the history
  • Loading branch information
TheAlan404 committed Apr 29, 2024
1 parent 7de1558 commit 4176a55
Show file tree
Hide file tree
Showing 41 changed files with 1,014 additions and 335 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
"@mantine/core": "^7.8.1",
"@mantine/hooks": "^7.8.1",
"@mantine/notifications": "^7.8.1",
"@mantine/nprogress": "^7.8.1",
"@tabler/icons-react": "^3.2.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.23.0",
"uifx": "^2.0.7"
},
"devDependencies": {
Expand Down
49 changes: 49 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added public/assets/sfx/deselect.wav
Binary file not shown.
Binary file added public/assets/sfx/key-invalid.wav
Binary file not shown.
Binary file added public/assets/sfx/select-all.wav
Binary file not shown.
Binary file added public/assets/sfx/select-char.wav
Binary file not shown.
Binary file added public/assets/sfx/select-word.wav
Binary file not shown.
Binary file added public/assets/sfx/swoosh.wav
Binary file not shown.
4 changes: 2 additions & 2 deletions src/api/context/APIController.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { createContext, useEffect, useMemo, useState } from "react";
import { Instance } from "../types/instances";
import { APIProvider } from "../types/api";
import { LTAPIProvider } from "../platforms/lighttube";
import { LTAPIProvider } from "../platforms/lt/lighttube";
import { fetchInvidiousPublicInstances, fetchLightTubePublicInstances } from "../platforms/public";
import { InvidiousAPIProvider } from "../platforms/invidious";
import { InvidiousAPIProvider } from "../platforms/invid/invidious";

export interface APIController {
currentInstance: Instance;
Expand Down
4 changes: 2 additions & 2 deletions src/api/context/VideoPlayerContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createContext } from "react";
import { Chapter, VideoFormat, VideoInfo } from "../types/video";
import { Chapter, VideoFormat, VideoData } from "../types/video";

export type PlayState = "loading" | "playing" | "paused" | "error";

Expand All @@ -15,7 +15,7 @@ export interface VideoPlayerAPI {
setVideoID: (id?: string) => void;
fetchVideoInfo: () => void;

videoInfo?: VideoInfo;
videoInfo?: VideoData;
activeChapters: ActiveChapterList;
setActiveChapters: (source: ActiveChapterList["type"], chapters?: Chapter[]) => void;

Expand Down
4 changes: 2 additions & 2 deletions src/api/context/VideoPlayerProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useContext, useEffect, useMemo, useState } from "react";
import { ActiveChapterList, PlayState, VideoPlayerContext } from "./VideoPlayerContext";
import { APIContext } from "./APIController";
import { VideoFormat, VideoInfo } from "../types/video";
import { VideoFormat, VideoData } from "../types/video";
import { useVideoEventListener } from "../../hooks/useVideoEventListener";
import { parseChapters } from "../../utils/parseChapters";
import { clamp } from "@mantine/hooks";
Expand All @@ -18,7 +18,7 @@ export const VideoPlayerProvider = ({
const { api, currentInstance } = useContext(APIContext);

const [videoID, setVideoID] = useState<string | null>(null);
const [videoInfo, setVideoInfo] = useState<VideoInfo | null>(null);
const [videoInfo, setVideoInfo] = useState<VideoData | null>(null);
const [activeChapters, setActiveChapters] = useState<ActiveChapterList>({
type: "video",
chapters: [],
Expand Down
85 changes: 85 additions & 0 deletions src/api/platforms/invid/invidious.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { parseChapters } from "../../../utils/parseChapters";
import { APIProvider } from "../../types/api";
import { InvidiousInstance } from "../../types/instances";
import { SearchSuggestions, VideoFormat, VideoData } from "../../types/video";
import { InvidiousSearchResult, InvidiousVideo, InvidiousVideoData } from "./types";

export class InvidiousAPIProvider implements APIProvider {
instance: InvidiousInstance;

constructor(
instance: InvidiousInstance,
) {
this.instance = instance;
}

request = async <T>(path: string, opts?: {
query: Record<string, string>;
signal?: AbortSignal;
}) => {
let url = new URL(this.instance.url + "/api/v1/" + path);

for(let [k,v] of Object.entries(opts?.query || {}))
url.searchParams.set(k, v);

let res = await fetch(url, {
signal: opts?.signal,
headers: {
"Content-Type": "application/json; utf-8",
},
});

return await res.json() as T;
}

searchSuggestions = async (query: string, signal?: AbortSignal) => {
let data: { suggestions: string[] } = await this.request("search/suggestions", {
query: { q: query },
signal,
});

return data.suggestions;
};

async search(q: string) {
let data: InvidiousSearchResult[] = await this.request("search", { query: { q } });

return {
key: null,
results: [],
};
}

getVideoInfo = async (id: string) => {
let v: InvidiousVideoData = await this.request(`videos/${id}`);

console.log(v);

return {
id,
title: v.title,
channel: {
id: v.authorId,
title: v.author,
},
chapters: parseChapters(v.descriptionHtml),
description: v.descriptionHtml,
keywords: v.keywords,
likeCount: v.likeCount,
viewCount: v.viewCount,
published: new Date(v.published),

formats: [
...v.formatStreams.map(f => ({
itag: f.itag,
url: f.url,
mimeType: f.type,
fps: f.fps,
width: Number(f.size.split("x")[0]),
height: Number(f.size.split("x")[1]),
bitrate: Number(f.bitrate),
} as VideoFormat)),
],
} as VideoData;
};
};
125 changes: 125 additions & 0 deletions src/api/platforms/invid/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
export interface InvidiousImage {
url: string;
width: number;
height: number;
};

export interface InvidiousThumbnail extends InvidiousImage {
quality: string;
};

export interface InvidiousVideo {
type: "video";
title: string;
videoId: string;

author: string;
authorId: string;
authorUrl: string;
authorVerified: boolean;
authorThumbnails: InvidiousThumbnail[];

videoThumbnails: InvidiousThumbnail[];

description: string;
descriptionHtml: string;

viewCount: number;
viewCountText: string;
lengthSeconds: number;
likeCount: number;
dislikeCount: number;

published: number;
publishedText: string;
keywords: string[];

paid: boolean;
premium: boolean;
isFamilyFriendly: boolean;
allowedRegions: string[];
genre: string;
genreUrl: string;

subCountText: string;
isListed: boolean;
liveNow: boolean;
isPostLiveDvr: boolean;
isUpcoming: boolean;
};

export interface InvidiousVideoData extends InvidiousVideo {
dashUrl: string;
adaptiveFormats: InvidiousAdaptiveFormat[];
formatStreams: InvidiousFormat[];
captions: any[];
recommendedVideos: any[];
};

export interface InvidiousAdaptiveFormat {
itag: string;
url: string;
init: string;
index: string;
bitrate: string;
type: string;
clen: string;
lmt: string;
projectionType: string;
fps: number;
container: string;
encoding: string;
audioQuality: string;
audioSampleRate: number;
audioChannels: number;
}

export interface InvidiousFormat {
url: string;
itag: string;
type: string;
quality: string;
bitrate: string;
fps: number;
container: string;
encoding: string;
resolution: string;
qualityLabel: string;
size: string;
}

export interface InvidiousChannel {
type: "channel";
author: string;
authorId: string;
authorUrl: string;
authorVerified: boolean;
authorThumbnails: InvidiousThumbnail[];
autoGenerated: boolean;
subCount: number;
videoCount: number;
description: string;
descriptionHtml: string;
};

export interface InvidiousPlaylist {
type: "playlist";
title: string;
playlistId: string;
playlistThumbnail: string;
author: string;
authorId: string;
authorUrl: string;
authorVerified: boolean;
videoCount: number;
videos: InvidiousPlaylistEntry[];
};

export interface InvidiousPlaylistEntry {
title: string;
videoId: string;
lengthSeconds: number;
videoThumbnails: InvidiousThumbnail[];
};

export type InvidiousSearchResult = InvidiousVideo | InvidiousPlaylist | InvidiousChannel;
Loading

0 comments on commit 4176a55

Please sign in to comment.