@@ -52,19 +74,33 @@ export const Search: Component = () => {
)}
- {results.length != 0 &&
- results.map((result) => {
- switch (result.type) {
- case "channel":
- return
;
+ {data?.pages.map((page, i) => {
+ return (
+
+ {page.items.map((result) => {
+ switch (result.type) {
+ case "channel":
+ return ;
+
+ case "video":
+ return ;
+
+ case "playlist":
+ return ;
+ }
+ })}
+
+ );
+ })}
- case "video":
- return
;
+
- case "playlist":
- return
;
- }
- })}
+ {/* {!isFetching && !isFetchingNextPage && !error && (
+
+ )} */}
>
diff --git a/src/app/results/Video.tsx b/src/app/results/Video.tsx
index 9667559..daba460 100644
--- a/src/app/results/Video.tsx
+++ b/src/app/results/Video.tsx
@@ -12,17 +12,13 @@ import formatUploadedTime from "@/utils/formatUploadedTime";
import { Link } from "@nextui-org/link";
import NextLink from "next/link";
import formatDuration from "@/utils/formatDuration";
+import { videoSize } from "@/utils/videoSize";
export const Video: Component<{ data: VideoProps }> = ({ data }) => {
const url = `/watch?v=${data.id}`;
const channelUrl = `/channel/${data.author.id}`;
- const videoSize = 200;
- const aspectRatio = 16 / 9;
-
- const [width, height] = useMemo(() => {
- return [videoSize * aspectRatio, videoSize];
- }, [videoSize]);
+ const [width, height] = videoSize([16, 9], 30);
return (
@@ -65,6 +61,7 @@ export const Video: Component<{ data: VideoProps }> = ({ data }) => {
height={64}
src={data.author.avatar}
alt={data.author.name}
+ className="rounded-full"
as={NextImage}
unoptimized
/>
diff --git a/src/client/adapters/invidious/index.ts b/src/client/adapters/invidious/index.ts
index 66722d4..f222836 100644
--- a/src/client/adapters/invidious/index.ts
+++ b/src/client/adapters/invidious/index.ts
@@ -96,10 +96,14 @@ const adapter: Adapter = {
return getSearchSuggestions(url, query).then(Transformer.suggestions);
},
async getSearch(query, options) {
- return getSearch(url, query, {
- page: options?.page,
+ const page = options?.pageParam ? parseInt(options.pageParam) : 1;
+
+ const items = await getSearch(url, query, {
+ page: page,
type: options?.type
}).then(Transformer.search);
+
+ return { items: items, nextCursor: (page + 1).toString() };
}
};
}
diff --git a/src/client/adapters/invidious/transformer.ts b/src/client/adapters/invidious/transformer.ts
index d4a389c..10579ee 100644
--- a/src/client/adapters/invidious/transformer.ts
+++ b/src/client/adapters/invidious/transformer.ts
@@ -3,7 +3,7 @@ import { Suggestions } from "@/client/typings/search/suggestions";
import {
ChannelResult,
PlaylistResult,
- SearchResults,
+ SearchItems,
VideoResult
} from "@/client/typings/search";
@@ -56,7 +56,7 @@ export default class Transformer {
return data.suggestions;
}
- public static search(data: InvidiousSearch): SearchResults {
+ public static search(data: InvidiousSearch): SearchItems {
return data.map((result) => {
switch (result.type) {
case "video":
diff --git a/src/client/adapters/piped/index.ts b/src/client/adapters/piped/index.ts
index c1c77cb..48e4755 100644
--- a/src/client/adapters/piped/index.ts
+++ b/src/client/adapters/piped/index.ts
@@ -115,9 +115,10 @@ const adapter: Adapter = {
break;
}
- return getSearch(url, query, { filter: filter }).then(
- Transformer.search
- );
+ return getSearch(url, query, {
+ filter: filter,
+ nextpage: options?.pageParam
+ }).then(Transformer.search);
}
};
}
diff --git a/src/client/adapters/piped/transformer.ts b/src/client/adapters/piped/transformer.ts
index 90870db..f171d6a 100644
--- a/src/client/adapters/piped/transformer.ts
+++ b/src/client/adapters/piped/transformer.ts
@@ -45,7 +45,7 @@ export default class Transformer {
}
public static search(data: PipedSearch): SearchResults {
- return data.items.map((result) => {
+ const items = data.items.map((result) => {
switch (result.type) {
case "stream":
const video: VideoResult = {
@@ -92,5 +92,7 @@ export default class Transformer {
return playlist;
}
});
+
+ return { items, nextCursor: data.nextpage };
}
}
diff --git a/src/client/adapters/piped/typings/search/index.ts b/src/client/adapters/piped/typings/search/index.ts
index d865450..cbdee41 100644
--- a/src/client/adapters/piped/typings/search/index.ts
+++ b/src/client/adapters/piped/typings/search/index.ts
@@ -35,7 +35,7 @@ export const SearchModel = z.object({
.union([VideoResultModel, ChannelResultModel, PlaylistResultModel])
.array(),
nextpage: z.string(),
- suggestion: z.string(),
+ suggestion: z.string().nullable(),
corrected: z.boolean()
});
diff --git a/src/client/index.ts b/src/client/index.ts
index 2bb6b79..0199339 100644
--- a/src/client/index.ts
+++ b/src/client/index.ts
@@ -68,8 +68,11 @@ export default class Client {
): Promise {
const adapter = this.getBestAdapter();
+ const pageParam =
+ options?.pageParam?.length === 0 ? undefined : options?.pageParam;
+
return await adapter.getSearch(query, {
- page: options?.page ?? 1,
+ pageParam: pageParam,
type: options?.type ?? "all"
});
}
diff --git a/src/client/typings/search/index.ts b/src/client/typings/search/index.ts
index 52c729f..1c4f3cb 100644
--- a/src/client/typings/search/index.ts
+++ b/src/client/typings/search/index.ts
@@ -30,4 +30,9 @@ export interface PlaylistResult {
}[];
}
-export type SearchResults = (VideoResult | ChannelResult | PlaylistResult)[];
+export type SearchItems = (VideoResult | ChannelResult | PlaylistResult)[];
+
+export interface SearchResults {
+ items: SearchItems;
+ nextCursor: string;
+}
diff --git a/src/client/typings/search/options.ts b/src/client/typings/search/options.ts
index eb0f25d..f1ce007 100644
--- a/src/client/typings/search/options.ts
+++ b/src/client/typings/search/options.ts
@@ -1,5 +1,5 @@
export interface SearchOptions {
- page?: number;
+ pageParam?: string;
type?: SearchType;
}
diff --git a/src/components/Search.tsx b/src/components/Search.tsx
index 34bbefe..5bd1255 100644
--- a/src/components/Search.tsx
+++ b/src/components/Search.tsx
@@ -4,15 +4,15 @@ import { useClient } from "@/hooks/useClient";
import { Component } from "@/typings/component";
import { Autocomplete, AutocompleteItem } from "@nextui-org/autocomplete";
import { useQuery } from "@tanstack/react-query";
-import { FormEventHandler, useCallback, useMemo, useState } from "react";
+import { useCallback, useMemo, useState } from "react";
import { useDebounce } from "use-debounce";
import { FiSearch as SearchIcon } from "react-icons/fi";
import { useRouter } from "next/navigation";
-export const Search: Component<{ initialQueryValue?: string }> = ({
- initialQueryValue
-}) => {
+export const Search: Component<{
+ initialQueryValue?: string;
+}> = ({ initialQueryValue }) => {
const client = useClient();
const [searchQuery, setSearchQuery] = useState(initialQueryValue ?? "");
@@ -70,7 +70,7 @@ export const Search: Component<{ initialQueryValue?: string }> = ({
required
type="text"
label="Search"
- variant="bordered"
+ variant="flat"
placeholder="Search for videos"
>
{(suggestion) => (
diff --git a/src/components/Video.tsx b/src/components/Video.tsx
index 1d1ac40..d08d458 100644
--- a/src/components/Video.tsx
+++ b/src/components/Video.tsx
@@ -12,18 +12,13 @@ import { Tooltip } from "@nextui-org/tooltip";
import { ContextMenuItem } from "@/typings/contextMenu";
import NextImage from "next/image";
-import { useMemo } from "react";
+import { videoSize } from "@/utils/videoSize";
export const Video: Component<{ data: VideoProps }> = ({ data }) => {
const url = `/watch?v=${data.id}`;
const channelUrl = `/channel/${data.author.id}`;
- const videoSize = 400;
- const aspectRatio = 16 / 9;
-
- const [width, height] = useMemo(() => {
- return [videoSize * aspectRatio, videoSize];
- }, [videoSize]);
+ const [width, height] = videoSize([16, 9], 40);
const menuItems: ContextMenuItem[] = [
{ title: "Go to video", key: "gotoVideo", href: url },
@@ -69,7 +64,7 @@ export const Video: Component<{ data: VideoProps }> = ({ data }) => {
width={width}
unoptimized
alt={data.title}
- className="object-contain aspect-video"
+ className="object-contain aspect"
src={data.thumbnail}
/>
diff --git a/src/hooks/useClient.ts b/src/hooks/useClient.ts
index ce4efd2..d58e913 100644
--- a/src/hooks/useClient.ts
+++ b/src/hooks/useClient.ts
@@ -7,8 +7,8 @@ export const useClient = () => {
const [client] = useState(
() =>
new Client([
- { baseUrl: "https://invidious.drgns.space", type: ApiType.Invidious }
- // { baseUrl: "https://pipedapi.kavin.rocks", type: ApiType.Piped }
+ // { baseUrl: "https://invidious.drgns.space", type: ApiType.Invidious }
+ { baseUrl: "https://pipedapi.kavin.rocks", type: ApiType.Piped }
])
);
diff --git a/src/utils/videoSize.ts b/src/utils/videoSize.ts
new file mode 100644
index 0000000..7cece18
--- /dev/null
+++ b/src/utils/videoSize.ts
@@ -0,0 +1,6 @@
+export const videoSize = (
+ aspectRatio: [number, number],
+ size: number
+): [number, number] => {
+ return [aspectRatio[0] * size, aspectRatio[1] * size];
+};
diff --git a/yarn.lock b/yarn.lock
index ec2f04a..322be98 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5680,6 +5680,11 @@ react@^18:
dependencies:
loose-envify "^1.1.0"
+reactjs-visibility@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/reactjs-visibility/-/reactjs-visibility-0.1.4.tgz#843a50cf8c156109fb9ebf855ad60f86b699f10d"
+ integrity sha512-r2NZUFt8kXcay3/oIC+iiP8I/woTWTtQ7CW/Q2aBfJtHertGTN2Qpg68scJpSA7oP4r3nVtXtUOffHJMuICbMQ==
+
read-cache@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"