From dc9d17ec74a2443609afa1a987a796ab272d84a8 Mon Sep 17 00:00:00 2001 From: Guus van Meerveld Date: Wed, 13 Mar 2024 15:01:28 +0100 Subject: [PATCH] trending: limited thumbnails to 1 per video --- .prettierrc.json | 18 +---- .vscode/settings.json | 3 + package.json | 1 + src/app/(trending)/Trending.tsx | 62 ++++++----------- src/app/(trending)/VideoCard.tsx | 50 ++++++++++++++ src/client/adapters/invidious/transformer.ts | 38 ++++++----- .../adapters/invidious/typings/thumbnail.ts | 14 +++- src/client/adapters/piped/transformer.ts | 2 +- src/client/typings/thumbnail.ts | 3 - src/client/typings/trending.ts | 4 +- yarn.lock | 67 +++++++++++++++++-- 11 files changed, 174 insertions(+), 88 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 src/app/(trending)/VideoCard.tsx delete mode 100644 src/client/typings/thumbnail.ts diff --git a/.prettierrc.json b/.prettierrc.json index 6a32fd0..84fb09c 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -5,21 +5,5 @@ "printWidth": 80, "arrowParens": "always", "importOrderSeparation": true, - "importOrder": [ - "^next.*", - "^react$", - "^react.*", - "^axios.*", - "^@emotion/.*", - "^@mui/material/.*", - "^@mui/.*", - "^@src/.*", - "^@models/.*", - "^@interfaces/.*", - "^@utils/.*", - "^@components/.*", - ".*sass$", - ".*css$", - "^@svg/.*" - ] + "importOrder": ["^next./", "^@nextui-org/."] } diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6ea2e9f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "prettier.configPath": ".prettierrc.json" +} \ No newline at end of file diff --git a/package.json b/package.json index 879393a..4aa8d27 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ }, "devDependencies": { "@tanstack/react-query-devtools": "^5.27.8", + "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/next-pwa": "^5.6.9", "@types/node": "^20", "@types/react": "^18", diff --git a/src/app/(trending)/Trending.tsx b/src/app/(trending)/Trending.tsx index 066ea95..2147ece 100644 --- a/src/app/(trending)/Trending.tsx +++ b/src/app/(trending)/Trending.tsx @@ -3,18 +3,17 @@ import { Component } from "@/typings/component"; import { useClient } from "@/hooks/useClient"; import { useQuery } from "@tanstack/react-query"; -import { Card, CardFooter, CardBody } from "@nextui-org/card"; -import { Image } from "@nextui-org/image"; + import { Button } from "@nextui-org/button"; import { CircularProgress } from "@nextui-org/progress"; -import { Divider } from "@nextui-org/divider"; -import Link from "next/link"; -import formatNumber from "@/utils/formatNumbers"; + +import { Spacer } from "@nextui-org/spacer"; +import { VideoCard } from "./VideoCard"; export const Trending: Component = ({}) => { const client = useClient(); - const { isLoading, error, data } = useQuery({ + const { isLoading, error, refetch, data } = useQuery({ queryKey: ["trending"], queryFn: () => client.getTrending("NL") }); @@ -26,45 +25,24 @@ export const Trending: Component = ({}) => { )} + {error && ( +
+
+

+ An error occurred loading the trending page +

+

{error.toString()}

+ + +
+
+ )} {data && (
{data.map((video) => ( - - - - {video.title} -

- 20:41 -

-
- - -
-

- {video.title} -

-
-

- {video.author.name} -

-

- {video.uploaded.toLocaleDateString()} -

- -

- Views: {formatNumber(video.views)} -

-
-
-
-
- + ))}
)} diff --git a/src/app/(trending)/VideoCard.tsx b/src/app/(trending)/VideoCard.tsx new file mode 100644 index 0000000..8e4d021 --- /dev/null +++ b/src/app/(trending)/VideoCard.tsx @@ -0,0 +1,50 @@ +import { TrendingVideo } from "@/client/typings/trending"; +import { Component } from "@/typings/component"; +import { Card, CardFooter, CardBody } from "@nextui-org/card"; +import { Image } from "@nextui-org/image"; +import { Divider } from "@nextui-org/divider"; +import Link from "next/link"; +import formatNumber from "@/utils/formatNumbers"; + +export const VideoCard: Component<{ data: TrendingVideo }> = ({ + data: video +}) => { + return ( + + + + {video.title} +

+ {video.duration} +

+
+ + +
+

+ {video.title} +

+
+

+ {video.author.name} +

+

+ {video.uploaded.toLocaleDateString()} +

+ +

+ Views: {formatNumber(video.views)} +

+
+
+
+
+ + ); +}; diff --git a/src/client/adapters/invidious/transformer.ts b/src/client/adapters/invidious/transformer.ts index 3d7f5f9..4bf506b 100644 --- a/src/client/adapters/invidious/transformer.ts +++ b/src/client/adapters/invidious/transformer.ts @@ -1,23 +1,31 @@ import { TrendingVideo } from "@/client/typings/trending"; -import { Thumbnail } from "@/client/typings/thumbnail"; import InvidiousTrending from "./typings/trending"; -import InvidiousThumbnail from "./typings/thumbnail"; export default class Transformer { - public static thumbnails(data: InvidiousThumbnail[]): Thumbnail[] { - return data.map((thumbnail) => ({ url: thumbnail.url })); - } - public static trending(data: InvidiousTrending[]): TrendingVideo[] { - return data.map((video) => ({ - author: { id: video.authorId, name: video.author }, - duration: video.lengthSeconds * 1000, - id: video.videoId, - title: video.title, - thumbnails: Transformer.thumbnails(video.videoThumbnails), - uploaded: new Date(video.published * 1000 ?? 0), - views: video.viewCount - })); + return data.map((video) => { + const thumbnail = video.videoThumbnails.find( + (thumbnail) => + thumbnail.quality == "default" || + thumbnail.quality == "medium" || + thumbnail.quality == "middle" + ); + + if (thumbnail === undefined) + throw new Error( + `Invidious: Missing thumbnail for video with id ${video.videoId}` + ); + + return { + author: { id: video.authorId, name: video.author }, + duration: video.lengthSeconds * 1000, + id: video.videoId, + title: video.title, + thumbnail: thumbnail.url, + uploaded: new Date(video.published * 1000 ?? 0), + views: video.viewCount + }; + }); } } diff --git a/src/client/adapters/invidious/typings/thumbnail.ts b/src/client/adapters/invidious/typings/thumbnail.ts index bb08c89..730a49d 100644 --- a/src/client/adapters/invidious/typings/thumbnail.ts +++ b/src/client/adapters/invidious/typings/thumbnail.ts @@ -1,7 +1,19 @@ import z from "zod"; +const qualityTypes = [ + "maxres", + "maxresdefault", + "sddefault", + "high", + "medium", + "default", + "start", + "middle", + "end" +] as const; + export const ThumbnailModel = z.object({ - quality: z.string(), + quality: z.enum(qualityTypes), url: z.string().url(), width: z.number(), height: z.number() diff --git a/src/client/adapters/piped/transformer.ts b/src/client/adapters/piped/transformer.ts index 833a492..88a2cc3 100644 --- a/src/client/adapters/piped/transformer.ts +++ b/src/client/adapters/piped/transformer.ts @@ -26,7 +26,7 @@ export default class Transformer { views: video.views, id: videoId, uploaded: new Date(video.uploaded), - thumbnails: [{ url: video.thumbnail }], + thumbnail: video.thumbnail, title: video.title, author: { id: channelId, name: video.uploaderName } }; diff --git a/src/client/typings/thumbnail.ts b/src/client/typings/thumbnail.ts deleted file mode 100644 index 0867598..0000000 --- a/src/client/typings/thumbnail.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface Thumbnail { - url: string; -} diff --git a/src/client/typings/trending.ts b/src/client/typings/trending.ts index 8085205..c9ba2f6 100644 --- a/src/client/typings/trending.ts +++ b/src/client/typings/trending.ts @@ -1,8 +1,6 @@ -import { Thumbnail } from "./thumbnail"; - export interface TrendingVideo { title: string; - thumbnails: Thumbnail[]; + thumbnail: string; id: string; author: { name: string; diff --git a/yarn.lock b/yarn.lock index 6387f29..0542599 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,7 +29,7 @@ jsonpointer "^5.0.0" leven "^3.1.0" -"@babel/code-frame@^7.10.4", "@babel/code-frame@^7.23.5": +"@babel/code-frame@^7.10.4", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5": version "7.23.5" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== @@ -63,7 +63,16 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.23.6": +"@babel/generator@7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" + integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== + dependencies: + "@babel/types" "^7.17.0" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/generator@^7.23.0", "@babel/generator@^7.23.6": version "7.23.6" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== @@ -245,7 +254,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== -"@babel/helper-validator-identifier@^7.22.20": +"@babel/helper-validator-identifier@^7.16.7", "@babel/helper-validator-identifier@^7.22.20": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== @@ -282,7 +291,7 @@ chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/parser@^7.24.0": +"@babel/parser@^7.20.5", "@babel/parser@^7.23.0", "@babel/parser@^7.24.0": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.0.tgz#26a3d1ff49031c53a97d03b604375f028746a9ac" integrity sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg== @@ -947,6 +956,22 @@ "@babel/parser" "^7.24.0" "@babel/types" "^7.24.0" +"@babel/traverse@7.23.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" + integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.23.0" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.0" + "@babel/types" "^7.23.0" + debug "^4.1.0" + globals "^11.1.0" + "@babel/traverse@^7.24.0": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.0.tgz#4a408fbf364ff73135c714a2ab46a5eab2831b1e" @@ -963,7 +988,15 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.24.0", "@babel/types@^7.4.4": +"@babel/types@7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" + integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@babel/types@^7.17.0", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.24.0", "@babel/types@^7.4.4": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== @@ -2955,6 +2988,18 @@ dependencies: "@tanstack/query-core" "5.27.5" +"@trivago/prettier-plugin-sort-imports@^4.3.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.3.0.tgz#725f411646b3942193a37041c84e0b2116339789" + integrity sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ== + dependencies: + "@babel/generator" "7.17.7" + "@babel/parser" "^7.20.5" + "@babel/traverse" "7.23.2" + "@babel/types" "7.17.0" + javascript-natural-sort "0.7.1" + lodash "^4.17.21" + "@types/estree@0.0.39": version "0.0.39" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" @@ -4804,6 +4849,11 @@ jake@^10.8.5: filelist "^1.0.4" minimatch "^3.1.2" +javascript-natural-sort@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59" + integrity sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw== + jest-worker@^26.2.1: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" @@ -5032,7 +5082,7 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== -lodash@^4.17.20: +lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -5932,6 +5982,11 @@ source-map-support@~0.5.20: buffer-from "^1.0.0" source-map "^0.6.0" +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + source-map@^0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"