Upload 11 files
Browse files- .gitattributes +1 -0
- AGENTS.md +10 -0
- Dockerfile +20 -0
- README.md +61 -0
- _gitdownloads_grabberintanstack.rar +3 -0
- bun.lock +0 -0
- bunfig.toml +7 -0
- components.json +22 -0
- eslint.config.js +40 -0
- package.json +89 -0
- tsconfig.json +27 -0
- vite.config.ts +15 -0
.gitattributes
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
_gitdownloads_grabberintanstack.rar filter=lfs diff=lfs merge=lfs -text
|
AGENTS.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!-- LOVABLE:BEGIN -->
|
| 2 |
+
> [!IMPORTANT]
|
| 3 |
+
> This project is connected to [Lovable](https://lovable.dev). Avoid rewriting
|
| 4 |
+
> published git history — force pushing, or rebasing/amending/squashing commits
|
| 5 |
+
> that are already pushed — as it rewrites history on Lovable's side and the
|
| 6 |
+
> user will likely lose their project history.
|
| 7 |
+
>
|
| 8 |
+
> Commits you push to the connected branch sync back to Lovable and show up in
|
| 9 |
+
> the editor, so keep the branch in a working state.
|
| 10 |
+
<!-- LOVABLE:END -->
|
Dockerfile
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Build stage
|
| 2 |
+
FROM node:22-slim AS build
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
RUN corepack enable && npm install -g bun@1.3.3
|
| 5 |
+
COPY package.json bun.lock ./
|
| 6 |
+
RUN bun install --frozen-lockfile
|
| 7 |
+
COPY . .
|
| 8 |
+
# Build with the Node server preset so the output runs in a plain Docker container
|
| 9 |
+
ENV NITRO_PRESET=node-server
|
| 10 |
+
RUN bun run build
|
| 11 |
+
|
| 12 |
+
# Runtime stage
|
| 13 |
+
FROM node:22-slim AS runtime
|
| 14 |
+
WORKDIR /app
|
| 15 |
+
ENV NODE_ENV=production \
|
| 16 |
+
PORT=7860 \
|
| 17 |
+
HOST=0.0.0.0
|
| 18 |
+
COPY --from=build /app/.output ./.output
|
| 19 |
+
EXPOSE 7860
|
| 20 |
+
CMD ["node", ".output/server/index.mjs"]
|
README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Imageboard Grabber
|
| 3 |
+
emoji: 🖼️
|
| 4 |
+
colorFrom: indigo
|
| 5 |
+
colorTo: purple
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
+
pinned: false
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
# Imageboard Grabber
|
| 12 |
+
|
| 13 |
+
Booru-style imageboard grabber (inspired by Bionus/Grabber): tag search, thumbnail grid, multi-select, server-side batch ZIP download. Ships with **e621** preconfigured and a **schema-based "Add site" panel** for Danbooru/Gelbooru/Safebooru/etc.
|
| 14 |
+
|
| 15 |
+
## Run locally with Docker
|
| 16 |
+
|
| 17 |
+
```bash
|
| 18 |
+
docker build -t grabber .
|
| 19 |
+
docker run --rm -p 7860:7860 grabber
|
| 20 |
+
```
|
| 21 |
+
|
| 22 |
+
Then open http://localhost:7860.
|
| 23 |
+
|
| 24 |
+
## Deploy to Hugging Face Spaces
|
| 25 |
+
|
| 26 |
+
1. Push this repo to GitHub (Lovable → GitHub sync, or `git push`).
|
| 27 |
+
2. Create a new Space on Hugging Face → **SDK: Docker**.
|
| 28 |
+
3. Link the GitHub repo (or add the Space as a remote and push).
|
| 29 |
+
|
| 30 |
+
The frontmatter above tells HF Spaces to build the `Dockerfile` and serve on port `7860`.
|
| 31 |
+
|
| 32 |
+
## Adding a custom site
|
| 33 |
+
|
| 34 |
+
Click **+ Add site** and paste the site's API schema:
|
| 35 |
+
|
| 36 |
+
- **Base URL / Search Path** — e.g. `https://danbooru.donmai.us` + `/posts.json`
|
| 37 |
+
- **Param names** for tags / page / limit
|
| 38 |
+
- **JSON path** to the posts array (empty = root)
|
| 39 |
+
- **Field mappings** (dotted paths) for `id`, `previewUrl`, `fileUrl`, `ext`, `tags`, `source`, `rating`, `score`
|
| 40 |
+
|
| 41 |
+
Example (Danbooru):
|
| 42 |
+
|
| 43 |
+
```
|
| 44 |
+
baseUrl: https://danbooru.donmai.us
|
| 45 |
+
searchPath: /posts.json
|
| 46 |
+
postsPath: (empty)
|
| 47 |
+
fields.id: id
|
| 48 |
+
fields.previewUrl: preview_file_url
|
| 49 |
+
fields.fileUrl: file_url
|
| 50 |
+
fields.ext: file_ext
|
| 51 |
+
fields.tags: tag_string_general
|
| 52 |
+
fields.source: source
|
| 53 |
+
fields.rating: rating
|
| 54 |
+
fields.score: score
|
| 55 |
+
```
|
| 56 |
+
|
| 57 |
+
## Tech
|
| 58 |
+
|
| 59 |
+
- TanStack Start (React 19, Vite 7) + Tailwind v4 + shadcn/ui
|
| 60 |
+
- Server-side image fetching and streaming ZIP via `fflate`
|
| 61 |
+
- Node server build via nitro `node-server` preset
|
_gitdownloads_grabberintanstack.rar
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b3bd20f9e6477a94eebd4ef44a7b7b7a34cb085b67dfea3c5948e640e40a7edd
|
| 3 |
+
size 429029
|
bun.lock
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
bunfig.toml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[install]
|
| 2 |
+
saveTextLockfile = true
|
| 3 |
+
# 24h supply-chain guard: skip package versions published less than a day ago.
|
| 4 |
+
minimumReleaseAge = 86400
|
| 5 |
+
# Each entry bypasses the 24h guard for one package — confirm with the user
|
| 6 |
+
# before adding any.
|
| 7 |
+
minimumReleaseAgeExcludes = ["@lovable.dev/vite-tanstack-config", "@lovable.dev/mcp-js", "@lovable.dev/vite-plugin-dev-server-bridge", "@lovable.dev/vite-plugin-hmr-gate", "@lovable.dev/email-js", "@lovable.dev/webhooks-js"]
|
components.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"$schema": "https://ui.shadcn.com/schema.json",
|
| 3 |
+
"style": "new-york",
|
| 4 |
+
"rsc": false,
|
| 5 |
+
"tsx": true,
|
| 6 |
+
"tailwind": {
|
| 7 |
+
"css": "src/styles.css",
|
| 8 |
+
"baseColor": "slate",
|
| 9 |
+
"cssVariables": true,
|
| 10 |
+
"prefix": ""
|
| 11 |
+
},
|
| 12 |
+
"iconLibrary": "lucide",
|
| 13 |
+
"rtl": false,
|
| 14 |
+
"aliases": {
|
| 15 |
+
"components": "@/components",
|
| 16 |
+
"utils": "@/lib/utils",
|
| 17 |
+
"ui": "@/components/ui",
|
| 18 |
+
"lib": "@/lib",
|
| 19 |
+
"hooks": "@/hooks"
|
| 20 |
+
},
|
| 21 |
+
"registries": {}
|
| 22 |
+
}
|
eslint.config.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import js from "@eslint/js";
|
| 2 |
+
import eslintPluginPrettier from "eslint-plugin-prettier/recommended";
|
| 3 |
+
import globals from "globals";
|
| 4 |
+
import reactHooks from "eslint-plugin-react-hooks";
|
| 5 |
+
import reactRefresh from "eslint-plugin-react-refresh";
|
| 6 |
+
import tseslint from "typescript-eslint";
|
| 7 |
+
|
| 8 |
+
export default tseslint.config(
|
| 9 |
+
{ ignores: ["dist", ".output", ".vinxi"] },
|
| 10 |
+
{
|
| 11 |
+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
| 12 |
+
files: ["**/*.{ts,tsx}"],
|
| 13 |
+
languageOptions: {
|
| 14 |
+
ecmaVersion: 2020,
|
| 15 |
+
globals: globals.browser,
|
| 16 |
+
},
|
| 17 |
+
plugins: {
|
| 18 |
+
"react-hooks": reactHooks,
|
| 19 |
+
"react-refresh": reactRefresh,
|
| 20 |
+
},
|
| 21 |
+
rules: {
|
| 22 |
+
...reactHooks.configs.recommended.rules,
|
| 23 |
+
"no-restricted-imports": [
|
| 24 |
+
"error",
|
| 25 |
+
{
|
| 26 |
+
paths: [
|
| 27 |
+
{
|
| 28 |
+
name: "server-only",
|
| 29 |
+
message:
|
| 30 |
+
"TanStack Start does not use the Next.js `server-only` package. Rename the module to `*.server.ts` or mark it with `@tanstack/react-start/server-only`.",
|
| 31 |
+
},
|
| 32 |
+
],
|
| 33 |
+
},
|
| 34 |
+
],
|
| 35 |
+
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
|
| 36 |
+
"@typescript-eslint/no-unused-vars": "off",
|
| 37 |
+
},
|
| 38 |
+
},
|
| 39 |
+
eslintPluginPrettier,
|
| 40 |
+
);
|
package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "tanstack_start_ts",
|
| 3 |
+
"private": true,
|
| 4 |
+
"sideEffects": false,
|
| 5 |
+
"type": "module",
|
| 6 |
+
"scripts": {
|
| 7 |
+
"dev": "vite dev",
|
| 8 |
+
"build": "vite build",
|
| 9 |
+
"build:dev": "vite build --mode development",
|
| 10 |
+
"preview": "vite preview",
|
| 11 |
+
"start": "node .output/server/index.mjs",
|
| 12 |
+
"lint": "eslint .",
|
| 13 |
+
"format": "prettier --write ."
|
| 14 |
+
},
|
| 15 |
+
"dependencies": {
|
| 16 |
+
"@hookform/resolvers": "^5.2.2",
|
| 17 |
+
"@radix-ui/react-accordion": "^1.2.12",
|
| 18 |
+
"@radix-ui/react-alert-dialog": "^1.1.15",
|
| 19 |
+
"@radix-ui/react-aspect-ratio": "^1.1.8",
|
| 20 |
+
"@radix-ui/react-avatar": "^1.1.11",
|
| 21 |
+
"@radix-ui/react-checkbox": "^1.3.3",
|
| 22 |
+
"@radix-ui/react-collapsible": "^1.1.12",
|
| 23 |
+
"@radix-ui/react-context-menu": "^2.2.16",
|
| 24 |
+
"@radix-ui/react-dialog": "^1.1.15",
|
| 25 |
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
| 26 |
+
"@radix-ui/react-hover-card": "^1.1.15",
|
| 27 |
+
"@radix-ui/react-label": "^2.1.8",
|
| 28 |
+
"@radix-ui/react-menubar": "^1.1.16",
|
| 29 |
+
"@radix-ui/react-navigation-menu": "^1.2.14",
|
| 30 |
+
"@radix-ui/react-popover": "^1.1.15",
|
| 31 |
+
"@radix-ui/react-progress": "^1.1.8",
|
| 32 |
+
"@radix-ui/react-radio-group": "^1.3.8",
|
| 33 |
+
"@radix-ui/react-scroll-area": "^1.2.10",
|
| 34 |
+
"@radix-ui/react-select": "^2.2.6",
|
| 35 |
+
"@radix-ui/react-separator": "^1.1.8",
|
| 36 |
+
"@radix-ui/react-slider": "^1.3.6",
|
| 37 |
+
"@radix-ui/react-slot": "^1.2.4",
|
| 38 |
+
"@radix-ui/react-switch": "^1.2.6",
|
| 39 |
+
"@radix-ui/react-tabs": "^1.1.13",
|
| 40 |
+
"@radix-ui/react-toggle": "^1.1.10",
|
| 41 |
+
"@radix-ui/react-toggle-group": "^1.1.11",
|
| 42 |
+
"@radix-ui/react-tooltip": "^1.2.8",
|
| 43 |
+
"@tailwindcss/vite": "^4.2.1",
|
| 44 |
+
"@tanstack/react-query": "^5.101.1",
|
| 45 |
+
"@tanstack/react-router": "^1.170.16",
|
| 46 |
+
"@tanstack/react-start": "^1.168.26",
|
| 47 |
+
"@tanstack/router-plugin": "^1.168.18",
|
| 48 |
+
"class-variance-authority": "^0.7.1",
|
| 49 |
+
"clsx": "^2.1.1",
|
| 50 |
+
"cmdk": "^1.1.1",
|
| 51 |
+
"date-fns": "^4.1.0",
|
| 52 |
+
"embla-carousel-react": "^8.6.0",
|
| 53 |
+
"fflate": "^0.8.3",
|
| 54 |
+
"input-otp": "^1.4.2",
|
| 55 |
+
"lucide-react": "^0.575.0",
|
| 56 |
+
"react": "^19.2.0",
|
| 57 |
+
"react-day-picker": "^9.14.0",
|
| 58 |
+
"react-dom": "^19.2.0",
|
| 59 |
+
"react-hook-form": "^7.71.2",
|
| 60 |
+
"react-resizable-panels": "^4.6.5",
|
| 61 |
+
"recharts": "^2.15.4",
|
| 62 |
+
"sonner": "^2.0.7",
|
| 63 |
+
"tailwind-merge": "^3.5.0",
|
| 64 |
+
"tailwindcss": "^4.2.1",
|
| 65 |
+
"tw-animate-css": "^1.3.4",
|
| 66 |
+
"vaul": "^1.1.2",
|
| 67 |
+
"vite-tsconfig-paths": "^6.0.2",
|
| 68 |
+
"zod": "^4.4.3"
|
| 69 |
+
},
|
| 70 |
+
"devDependencies": {
|
| 71 |
+
"@eslint/js": "^9.32.0",
|
| 72 |
+
"@lovable.dev/vite-tanstack-config": "2.7.6",
|
| 73 |
+
"@types/node": "^22.16.5",
|
| 74 |
+
"@types/react": "^19.2.0",
|
| 75 |
+
"@types/react-dom": "^19.2.0",
|
| 76 |
+
"@vitejs/plugin-react": "^5.2.0",
|
| 77 |
+
"eslint": "^9.32.0",
|
| 78 |
+
"eslint-config-prettier": "^10.1.1",
|
| 79 |
+
"eslint-plugin-prettier": "^5.2.6",
|
| 80 |
+
"eslint-plugin-react-hooks": "^5.2.0",
|
| 81 |
+
"eslint-plugin-react-refresh": "^0.4.20",
|
| 82 |
+
"globals": "^15.15.0",
|
| 83 |
+
"nitro": "3.0.260603-beta",
|
| 84 |
+
"prettier": "^3.7.3",
|
| 85 |
+
"typescript": "^5.8.3",
|
| 86 |
+
"typescript-eslint": "^8.56.1",
|
| 87 |
+
"vite": "^8.0.16"
|
| 88 |
+
}
|
| 89 |
+
}
|
tsconfig.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"include": ["src/**/*.ts", "src/**/*.tsx", "vite.config.ts", "eslint.config.js"],
|
| 3 |
+
"compilerOptions": {
|
| 4 |
+
"target": "ES2022",
|
| 5 |
+
"jsx": "react-jsx",
|
| 6 |
+
"module": "ESNext",
|
| 7 |
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
| 8 |
+
"types": ["vite/client"],
|
| 9 |
+
|
| 10 |
+
/* Bundler mode */
|
| 11 |
+
"moduleResolution": "Bundler",
|
| 12 |
+
"allowImportingTsExtensions": true,
|
| 13 |
+
"verbatimModuleSyntax": false,
|
| 14 |
+
"noEmit": true,
|
| 15 |
+
|
| 16 |
+
/* Linting */
|
| 17 |
+
"skipLibCheck": true,
|
| 18 |
+
"strict": true,
|
| 19 |
+
"noUnusedLocals": false,
|
| 20 |
+
"noUnusedParameters": false,
|
| 21 |
+
"noFallthroughCasesInSwitch": true,
|
| 22 |
+
"noUncheckedSideEffectImports": true,
|
| 23 |
+
"paths": {
|
| 24 |
+
"@/*": ["./src/*"]
|
| 25 |
+
}
|
| 26 |
+
}
|
| 27 |
+
}
|
vite.config.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// @lovable.dev/vite-tanstack-config already includes the following — do NOT add them manually
|
| 2 |
+
// or the app will break with duplicate plugins:
|
| 3 |
+
// - TanStack devtools (dev-only, first), tanstackStart, viteReact, tailwindcss, tsConfigPaths,
|
| 4 |
+
// nitro (build-only using cloudflare as a default target), VITE_* env injection, @ path alias,
|
| 5 |
+
// React/TanStack dedupe, error logger plugins, and sandbox detection (port/host/strictPort).
|
| 6 |
+
// You can pass additional config via defineConfig({ vite: { ... }, etc... }) if needed.
|
| 7 |
+
import { defineConfig } from "@lovable.dev/vite-tanstack-config";
|
| 8 |
+
|
| 9 |
+
export default defineConfig({
|
| 10 |
+
tanstackStart: {
|
| 11 |
+
// Redirect TanStack Start's bundled server entry to src/server.ts (our SSR error wrapper).
|
| 12 |
+
// nitro/vite builds from this
|
| 13 |
+
server: { entry: "server" },
|
| 14 |
+
},
|
| 15 |
+
});
|