ChBysk commited on
Commit
82e88b6
·
verified ·
1 Parent(s): 61b6204

Upload folder using huggingface_hub

Browse files
src/routes/api/download-zip.ts CHANGED
@@ -24,6 +24,7 @@ const PostSchema = z.object({
24
  const BodySchema = z.object({
25
  siteName: z.string().default("grabber"),
26
  posts: z.array(PostSchema).min(1).max(200),
 
27
  });
28
 
29
  function sanitize(s: string) {
@@ -38,7 +39,7 @@ function humanSize(n?: number): string {
38
  return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;
39
  }
40
 
41
- function buildMarkdown(post: z.infer<typeof PostSchema>): string {
42
  const dims = post.width && post.height ? `${post.width} x ${post.height}` : "";
43
  const rows: [string, string][] = [
44
  ["Source", post.source ?? ""],
@@ -56,7 +57,8 @@ function buildMarkdown(post: z.infer<typeof PostSchema>): string {
56
  ];
57
 
58
  const meta = rows.map(([k, v]) => `- **${k}:** ${v}`).join("\n");
59
- const tags = post.tags.length ? post.tags.join(" ") : "";
 
60
  let raw = "{}";
61
  if (post.rawJson) {
62
  try {
@@ -99,6 +101,7 @@ export const Route = createFileRoute("/api/download-zip")({
99
  const files: Record<string, Uint8Array> = {};
100
  const errors: string[] = [];
101
  const siteName = sanitize(body.siteName);
 
102
 
103
  await Promise.all(
104
  body.posts.map(async (post) => {
@@ -106,11 +109,14 @@ export const Route = createFileRoute("/api/download-zip")({
106
  const extSafe = sanitize(post.ext || "jpg");
107
  const base = `${siteName}_${idSafe}`;
108
 
 
 
 
109
  // tags .txt — same basename as the image
110
- files[`${base}.txt`] = strToU8(post.tags.join(" "));
111
 
112
  // per-post markdown metadata
113
- files[`${idSafe}.md`] = strToU8(buildMarkdown(post));
114
 
115
  // fetch the image itself
116
  try {
 
24
  const BodySchema = z.object({
25
  siteName: z.string().default("grabber"),
26
  posts: z.array(PostSchema).min(1).max(200),
27
+ excludeTags: z.array(z.string()).default([]),
28
  });
29
 
30
  function sanitize(s: string) {
 
39
  return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;
40
  }
41
 
42
+ function buildMarkdown(post: z.infer<typeof PostSchema>, excludeSet: Set<string>): string {
43
  const dims = post.width && post.height ? `${post.width} x ${post.height}` : "";
44
  const rows: [string, string][] = [
45
  ["Source", post.source ?? ""],
 
57
  ];
58
 
59
  const meta = rows.map(([k, v]) => `- **${k}:** ${v}`).join("\n");
60
+ const filteredTags = post.tags.filter((t) => !excludeSet.has(t.toLowerCase()));
61
+ const tags = filteredTags.length ? filteredTags.join(" ") : "";
62
  let raw = "{}";
63
  if (post.rawJson) {
64
  try {
 
101
  const files: Record<string, Uint8Array> = {};
102
  const errors: string[] = [];
103
  const siteName = sanitize(body.siteName);
104
+ const excludeSet = new Set((body.excludeTags || []).map((t) => t.toLowerCase()));
105
 
106
  await Promise.all(
107
  body.posts.map(async (post) => {
 
109
  const extSafe = sanitize(post.ext || "jpg");
110
  const base = `${siteName}_${idSafe}`;
111
 
112
+ // Filter out tags that user specified to be missing
113
+ const filteredTags = post.tags.filter((t) => !excludeSet.has(t.toLowerCase()));
114
+
115
  // tags .txt — same basename as the image
116
+ files[`${base}.txt`] = strToU8(filteredTags.join(" "));
117
 
118
  // per-post markdown metadata
119
+ files[`${idSafe}.md`] = strToU8(buildMarkdown(post, excludeSet));
120
 
121
  // fetch the image itself
122
  try {
src/routes/index.tsx CHANGED
@@ -47,6 +47,7 @@ function Grabber() {
47
  const [addOpen, setAddOpen] = useState(false);
48
  const [lightbox, setLightbox] = useState<NormalizedPost | null>(null);
49
  const [downloading, setDownloading] = useState(false);
 
50
 
51
  const site = useMemo(() => sites.find((s) => s.id === siteId) ?? sites[0], [sites, siteId]);
52
 
@@ -90,6 +91,10 @@ function Grabber() {
90
  body: JSON.stringify({
91
  siteName: site.id,
92
  posts: chosen,
 
 
 
 
93
  }),
94
  });
95
  if (!res.ok) {
@@ -193,6 +198,12 @@ function Grabber() {
193
  {selected.size === posts.length && posts.length > 0 ? "Deselect all" : "Select all"}
194
  </Button>
195
  <span className="text-sm text-muted-foreground">selected: {selected.size}</span>
 
 
 
 
 
 
196
  <Button onClick={downloadZip} disabled={!selected.size || downloading}>
197
  {downloading ? (
198
  <Loader2 className="w-4 h-4 mr-1 animate-spin" />
 
47
  const [addOpen, setAddOpen] = useState(false);
48
  const [lightbox, setLightbox] = useState<NormalizedPost | null>(null);
49
  const [downloading, setDownloading] = useState(false);
50
+ const [excludeTags, setExcludeTags] = useState("");
51
 
52
  const site = useMemo(() => sites.find((s) => s.id === siteId) ?? sites[0], [sites, siteId]);
53
 
 
91
  body: JSON.stringify({
92
  siteName: site.id,
93
  posts: chosen,
94
+ excludeTags: excludeTags
95
+ .split(/\s+|,/)
96
+ .map((t) => t.trim().toLowerCase())
97
+ .filter(Boolean),
98
  }),
99
  });
100
  if (!res.ok) {
 
198
  {selected.size === posts.length && posts.length > 0 ? "Deselect all" : "Select all"}
199
  </Button>
200
  <span className="text-sm text-muted-foreground">selected: {selected.size}</span>
201
+ <Input
202
+ placeholder="Exclude tags from ZIP (e.g. fluffy, safety)"
203
+ value={excludeTags}
204
+ onChange={(e) => setExcludeTags(e.target.value)}
205
+ className="w-64 max-w-xs"
206
+ />
207
  <Button onClick={downloadZip} disabled={!selected.size || downloading}>
208
  {downloading ? (
209
  <Loader2 className="w-4 h-4 mr-1 animate-spin" />