From fc2c6df2bae7c57e6b97560e8ba20f5a8eff930a Mon Sep 17 00:00:00 2001 From: Mathijs de Bruin Date: Fri, 2 Sep 2022 21:51:18 +0100 Subject: [PATCH 1/3] Don't use IPFS' default port for frontend dev! --- vite.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vite.config.js b/vite.config.js index 40106418..47e9e929 100644 --- a/vite.config.js +++ b/vite.config.js @@ -8,7 +8,7 @@ import createVuePlugin from "@vitejs/plugin-vue"; export default defineConfig({ plugins: [createVuePlugin(), vuetify()], server: { - port: 8080, + port: 8082, }, resolve: { alias: { From fcd374f1f2b8567ba1e8649b117506d2750e643a Mon Sep 17 00:00:00 2001 From: Mathijs de Bruin Date: Fri, 2 Sep 2022 21:51:00 +0100 Subject: [PATCH 2/3] Thumbnails for images (list, detail) and videos (list). * Configuration for relevant variables. * Separate thumbnail components wrapping v-img. * Use dweb.link as default IPFS gateway and our own gateway for thumbnails. * Auto scale thumbnails to container size. * Failure indicator for unavailable thumbnails/images. --- README.md | 16 ++-- package-lock.json | 31 ++++++++ package.json | 2 + .../detailViewComponents/ImageDetail.vue | 19 ++++- .../searchViewComponents/ImageList.vue | 21 +++-- .../searchViewComponents/VideoList.vue | 22 +++++- src/helpers/nyats/vuetify-img-cid.vue | 76 +++++++++++++++++++ src/helpers/resourceURL.js | 9 +-- 8 files changed, 168 insertions(+), 28 deletions(-) create mode 100644 src/helpers/nyats/vuetify-img-cid.vue diff --git a/README.md b/README.md index e2584a20..d29dc439 100644 --- a/README.md +++ b/README.md @@ -49,14 +49,14 @@ Developers: you will likely want to run `npm run serve` in one terminal and `npm Ops will want to use `npm run build`, `npm run test` or `npm run test:coverage`, `npm run prettier:check` -## NSFW api +## Configuration -This build uses an API to check nsfw content. +The following environment variables may be used to configure the frontend. -The default API endpoint to is: https://api.ipfs-search.com/nsfw/ -. This can be overridden by injecting environment variable `VITE_NSFW_API` +### Variables -The API call should be: ``, so e.g. - -`https://api.ipfs-search.com/nsfw/QmSZzv7ux1LGwpehVcCMQ9ec945X6qE4qyjKDhCVwY25iw` -https://api.ipfs-search.com/v1/nsfw/classify/ +- `VITE_IPFS_GATEWAY`: Gateway for URL generation. Default: `https://dweb.link` +- `VITE_NSFW_API`: Endpoint for [nsfw-server](https://github.com/ipfs-search/nsfw-server). Default: `https://api.ipfs-search.com/v1/nsfw/classify/` +- `VITE_NYATS_API`: Endpoint for [nyats](https://github.com/ipfs-search/nyats) (Not Yet Another Thumbnail Server) API. Default: `https://api.ipfs-search.com/v1/thumbnail/` +- `VITE_NYATS_IPFS_GATEWAY`: Gateway for nyats. Default: `https://gw.dwebsearch.com` +- `VITE_NYATS_IPNS_ROOT`: Root for thumbnails over IPNS. Default: `/ipns/12D3KooWPVobDRG9Mdmact3ejSe6UAFP8cevmw35HHR1ZDwCozSo/` diff --git a/package-lock.json b/package-lock.json index ca2307fa..fde061be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "masonry-layout": "^4.2.2", "mime": "^3.0.0", "moment": "^2.29.4", + "nyats-client": "^0.2.0-alpha.2", "pretty-bytes": "^6.0.0", "regenerator-runtime": "^0.13.9", "ts-node": "^10.8.0", @@ -49,6 +50,7 @@ "prettier": "2.7.1", "sass": "^1.53.0", "typescript": "^4.7.3", + "url-join": "^5.0.0", "vite": "^3.0.2", "vite-plugin-vuetify": "^1.0.0-alpha.11", "vitest": "^0.13.1" @@ -3419,6 +3421,14 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, + "node_modules/nyats-client": { + "version": "0.2.0-alpha.2", + "resolved": "https://registry.npmjs.org/nyats-client/-/nyats-client-0.2.0-alpha.2.tgz", + "integrity": "sha512-ctNWNCxmU5d6wiWqXbAIXWiR8/OQ+sp6Ir6vXTpsz7ymsCvVis3M8AzCiRE/V/flY/2dU4jQGiTz6Z6CiPVBEQ==", + "dependencies": { + "url-join": "^5.0.0" + } + }, "node_modules/object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", @@ -4398,6 +4408,14 @@ "querystring": "0.2.0" } }, + "node_modules/url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/url/node_modules/punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", @@ -7389,6 +7407,14 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, + "nyats-client": { + "version": "0.2.0-alpha.2", + "resolved": "https://registry.npmjs.org/nyats-client/-/nyats-client-0.2.0-alpha.2.tgz", + "integrity": "sha512-ctNWNCxmU5d6wiWqXbAIXWiR8/OQ+sp6Ir6vXTpsz7ymsCvVis3M8AzCiRE/V/flY/2dU4jQGiTz6Z6CiPVBEQ==", + "requires": { + "url-join": "^5.0.0" + } + }, "object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", @@ -8061,6 +8087,11 @@ } } }, + "url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==" + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index de31fbfe..5c5d4fa1 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "masonry-layout": "^4.2.2", "mime": "^3.0.0", "moment": "^2.29.4", + "nyats-client": "^0.2.0-alpha.2", "pretty-bytes": "^6.0.0", "regenerator-runtime": "^0.13.9", "ts-node": "^10.8.0", @@ -57,6 +58,7 @@ "prettier": "2.7.1", "sass": "^1.53.0", "typescript": "^4.7.3", + "url-join": "^5.0.0", "vite": "^3.0.2", "vite-plugin-vuetify": "^1.0.0-alpha.11", "vitest": "^0.13.1" diff --git a/src/components/detailViewComponents/ImageDetail.vue b/src/components/detailViewComponents/ImageDetail.vue index c300df4d..fa57320c 100644 --- a/src/components/detailViewComponents/ImageDetail.vue +++ b/src/components/detailViewComponents/ImageDetail.vue @@ -1,22 +1,26 @@ + + + - + diff --git a/src/components/searchViewComponents/ImageList.vue b/src/components/searchViewComponents/ImageList.vue index b4b05f58..bb27f8a6 100644 --- a/src/components/searchViewComponents/ImageList.vue +++ b/src/components/searchViewComponents/ImageList.vue @@ -2,18 +2,17 @@ import NsfwTooltip from "@/components/shared/nsfwTooltip.vue"; import ListBase from "./BaseList.vue"; import HoverCard from "./subcomponents/HoverCard.vue"; -import { useFileListComposable, imports } from "@/composables/useFileListComposable"; +import { useFileListComposable } from "@/composables/useFileListComposable"; import { useBlurExplicit } from "@/composables/BlurExplicitImagesComposable"; import { Types } from "@/helpers/typeHelper"; import { useDisplay } from "vuetify"; +import { mdiRobotDead } from "@mdi/js"; +import NyatsImg from "@/helpers/nyats/vuetify-img-cid.vue"; const fileType = Types.images; const { xs, smAndDown, mdAndDown } = useDisplay(); const { slicedHits } = useFileListComposable({ fileType }); - -const { getResourceURL } = imports; - const { blurExplicit } = useBlurExplicit(); @@ -30,8 +29,9 @@ const { blurExplicit } = useBlurExplicit(); lg="2" > - + + + - + diff --git a/src/components/searchViewComponents/VideoList.vue b/src/components/searchViewComponents/VideoList.vue index 8b76a234..f8112687 100644 --- a/src/components/searchViewComponents/VideoList.vue +++ b/src/components/searchViewComponents/VideoList.vue @@ -6,7 +6,8 @@ import CardContent from "@/components/searchViewComponents/subcomponents/generic import MediaCenterIcon from "@/components/searchViewComponents/subcomponents/MediaCenterIcon.vue"; import { mdiVideo } from "@mdi/js"; import { Types } from "@/helpers/typeHelper"; -import { picsum } from "@/helpers/picsum"; +import { mdiRobotDead, mdiTimerSand } from "@mdi/js"; +import NyatsImg from "@/helpers/nyats/vuetify-img-cid.vue"; const fileType = Types.video; @@ -19,15 +20,28 @@ const { slicedHits } = useFileListComposable({ fileType }); - - + + + + + diff --git a/src/helpers/nyats/vuetify-img-cid.vue b/src/helpers/nyats/vuetify-img-cid.vue new file mode 100644 index 00000000..1a0ba9df --- /dev/null +++ b/src/helpers/nyats/vuetify-img-cid.vue @@ -0,0 +1,76 @@ + + + diff --git a/src/helpers/resourceURL.js b/src/helpers/resourceURL.js index 5a79356e..f8054bf5 100644 --- a/src/helpers/resourceURL.js +++ b/src/helpers/resourceURL.js @@ -1,7 +1,6 @@ -const gatewayURL = "https://gateway.ipfs.io"; +const gatewayURL = import.meta.env.VITE_IPFS_GATEWAY || "https://dweb.link"; -function getResourceURL(hash) { - return `${gatewayURL}/ipfs/${hash}`; +export default function getResourceURL(hash) { + const resourcePath = `/ipfs/${hash}`; + return new URL(resourcePath, gatewayURL).toString(); } - -export default getResourceURL; From c4c66556ff41c144ddc3266014c55622aa0e719e Mon Sep 17 00:00:00 2001 From: Mathijs de Bruin Date: Thu, 22 Sep 2022 18:24:24 +0100 Subject: [PATCH 3/3] INFINITE SCROLLING FOR VIDEOS. YES. Also, closes #249. --- .../searchViewComponents/VideoList.vue | 41 +++++++++++-------- src/composables/useFileListComposable.js | 4 +- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/components/searchViewComponents/VideoList.vue b/src/components/searchViewComponents/VideoList.vue index f8112687..e32cc593 100644 --- a/src/components/searchViewComponents/VideoList.vue +++ b/src/components/searchViewComponents/VideoList.vue @@ -2,6 +2,7 @@ import ListBase from "./BaseList.vue"; import HoverCard from "./subcomponents/HoverCard.vue"; import { useFileListComposable } from "@/composables/useFileListComposable"; +import { useBlurExplicit } from "@/composables/BlurExplicitImagesComposable"; import CardContent from "@/components/searchViewComponents/subcomponents/genericCardContent.vue"; import MediaCenterIcon from "@/components/searchViewComponents/subcomponents/MediaCenterIcon.vue"; import { mdiVideo } from "@mdi/js"; @@ -12,27 +13,34 @@ import NyatsImg from "@/helpers/nyats/vuetify-img-cid.vue"; const fileType = Types.video; const { slicedHits } = useFileListComposable({ fileType }); +const { blurExplicit } = useBlurExplicit(); + + - - - - - - + + + diff --git a/src/composables/useFileListComposable.js b/src/composables/useFileListComposable.js index df9fe007..3c08decd 100644 --- a/src/composables/useFileListComposable.js +++ b/src/composables/useFileListComposable.js @@ -23,7 +23,9 @@ export const useFileListComposable = ({ fileType }) => { return [Types.all, undefined].includes(route.query.type); }); - const infinite = computed(() => route.query.type === Types.images); + const infinite = computed( + () => route.query.type === Types.images || route.query.type === Types.video + ); const loadedPages = computed(() => Math.ceil(store.getters[`results/${fileType}/hits`].length / batchSize)