Add per-kind stats, GIF hover playback, and static gif previews

This commit is contained in:
Fisto
2026-09-16 13:36:51 +02:00
parent 612b2504dc
commit 0081224954
13 changed files with 189 additions and 57 deletions
+3
View File
@@ -125,6 +125,9 @@ Previews run after every walk:
- Embeds without a thumbnail in Discord's data (fxtwitter, vxReddit, ...) are resolved first:
provider oEmbed/fxtwitter API, then the page's `og:image`/`twitter:image` (512 KiB read cap,
10 s timeout, one attempt).
- Animated GIF previews are stored as a static first frame (`ffmpeg`, 480px WebP); the original
animated GIF URL stays in `preview_url` for hover playback. Tenor embeds without a thumbnail are
resolved through Tenor's oEmbed.
- One attempt per row, no retries; a failure marks `preview_error` and never fails the scrape.
- Stored by hash in `thumbs/<sha256>.<ext>`, where the extension follows the response type
(`preview_ext`, default webp); `preview_hash` and `preview_bytes` land on the row, and the
+4 -3
View File
@@ -159,9 +159,10 @@ that deletion is irreversible. The delete button is disabled for a 5 second coun
for a fresh signed URL, so expired CDN links still play. Embed `videoUrl`s (gifv/Tenor mp4s) are
stored as `play_url` and used directly. The full link is a separate button that opens the
original page with the warning. Length comes from Discord's attachment duration and, for
downloads, an ffprobe probe. The status row reads
`(Images/Videos) | Downloaded A/B | Cached C/B (excl Downl) | Loaded L/B`, where B is the total
for the active filters. A scrape strip shows live progress with Stop.
downloads, an ffprobe probe. GIF tiles carry a translucent **GIF** label top-left; the cached
preview is a static frame and the animated GIF plays while hovering. The status row reads
`(Images/Videos) | Downloaded I/V | Cached I/V | Loaded I/V` — image counts include GIFs, and
each slot is the count for the active filters. A scrape strip shows live progress with Stop.
**New scrape…** (rightmost) opens a popup with Server and Group chat trees (servers expand to
channels; each row has Links and Download). Every scrape button asks for confirmation; the
dialog takes optional From/To dates and a **Check Message Count** button (Discord search total,
+1 -1
View File
@@ -265,7 +265,7 @@ replaceable.
| GET | `/api/media/scrapes` | none | Every scrape with state and counters |
| GET | `/api/media/status` | none | Slopbot connection state and the scrape list |
| GET | `/api/media/authors` | none | Distinct posters across every scrape, with counts |
| GET | `/api/media/stats` | same filters as `/api/media` | Counts: `total`, `downloaded`, `cached`, `notDownloaded` |
| GET | `/api/media/stats` | same filters as `/api/media` | Counts per kind (`image`, `gif`, `video`, `audio`), each with `total`, `downloaded`, `cached`, `notDownloaded` |
| GET | `/api/media/storage` | none | Usage against the limit, per-kind sizes, `nearLimit`; marks old scrapes when over |
| POST | `/api/media/scrape` | `channelId`, `guildId?`, `mode?`, `backend?`, `confirm?`, `downloadDir?`, `after?`, `before?` | Start a media scrape. `backend` is `auto` (default), `slopbot`, or `puppet`; `downloadDir` is an absolute path for downloaded files (previews stay local); `after`/`before` are ISO dates bounding the walk. Near the limit: `409` with code `MEDIA_LIMIT` unless `confirm: true` |
| POST | `/api/media/count` | `channelId`, `guildId?`, `after?`, `before?` | Discord search total for the channel or range. Returns `{ count }` or `{ count: null, reason }` (slopbot guild channels only) |