context-attachment-manager
Codex and Claude Code plugin (works in Claude Desktop): choose which past images go to the model with your next message. Unchecked images become placeholders, the conversation goes on, and requests st
翻译准备中
Universal download manager for Emby, Plex & Jellyfin. Grab movies, TV shows, music, and entire libraries directly from the browser with 10+ export formats, built-in concurrent downloads, JDownloader integration, and in-app updates.
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗A powerful browser userscript that turns any Emby, Plex, or Jellyfin media server into a direct download hub. Grab movies, TV shows, music, photos, and entire libraries — straight from the browser with zero extra software. Transfer server-to-server directly into your own NAS, or use built-in concurrent downloads, JDownloader integration, wget/curl script generation, QR codes, and 10+ export formats.
If PulseGrab saves you time, consider supporting development:
Latest Release: PulseGrab.user.js
Smoother updates and a Send to My Server that never looks stuck.
Everything that was quietly broken now works, plus Plex search.
name.part and renamed when done, a pause resumes where it stopped, and an existing file is never overwritten (the new copy becomes "Name (1)"). Other browsers keep the old behaviour and warn before files over 2 GB.Server-to-server transfers and search results.
Guided setup, and a destination picker that knows your libraries.
chmod, no config editing and no restart afterwards. Works on Unraid, Synology, Debian, a Pi, a VPS.Filmes from memory, and no more guessing that a library called Séries lives at /media/Series.Anime => Anime Series sends anything matching "Anime" there. Content type is corrected automatically against your discovered libraries, so with an Anime Filmes/Anime Series pair a single rule routes films and episodes to the right half.Send to My Server — server-to-server transfers. Pull media from someone else's Emby/Plex/Jellyfin straight into your own NAS. The files never pass through your browser or your computer: PulseGrab hands the link list to a downloader on your box, which fetches the media itself at full server speed. Close the tab, shut the laptop — the transfer keeps running.
Two transports, chosen in Settings → My Server:
| MyJDownloader (default) | aria2 | |
|---|---|---|
| Server setup | Install JDownloader, sign in | Container + hook script |
| Open ports / firewall | None | RPC port on your LAN |
| Works away from home | Yes | LAN or VPN only |
| Partial-file handling | Automatic (.part files) | Staging folder + move hook |
| Live progress in PulseGrab | In JDownloader / my.jdownloader.org | Full in-page panel |
| Links leave your network | Via JD's encrypted relay | Never |
destinationFolder places each season and movie exactly where it belongs. Your password is never stored — only the two SHA-256 secrets derived from it, which can't be reversed back into it. Sessions that lapse are re-established transparently.api_key= / X-Plex-Token=), so they're self-contained and need no header forwarding.TV Shows/<Series>/<Season>/…, Movies/<Title> (<Year>)/…, Music/<Artist>/<Album>/… — already Emby-shaped and ready to scan..pulsegrab-incoming/ staging folder (media servers skip dot-prefixed directories), and a shipped on-download-complete hook moves each file into place the instant it finishes. Because staging lives inside the library dataset, the move is an atomic rename..srt/.ass tracks are queued alongside the video and land in the same folder, matching what the built-in manager does. (dlExternalSubtitles is on by default, so skipping them would have silently dropped subs for most users.)<your-server> can't reach — this transfer runs server-to-server, not through this browser" instead of 400 silent failures. Expired session tokens and loopback-only media server addresses are detected and named explicitly too.Full audit pass across Emby, Plex, and Jellyfin — bug fixes, correctness, and polish.
http://localhost:9666, which resolves to IPv6 ::1 first on macOS, but JDownloader's FlashGot server binds IPv4 127.0.0.1 only, so it was never reached. Now tries 127.0.0.1 first with a localhost fallback and caches the host that answers. Also fixed auto-detect writing the wrong setting key (enableJDownloader vs jdownloaderEnabled), which meant detecting JD never actually armed the send path./web/.TotalRecordCount, scanning stopped after the first page and silently dropped items. Now keeps paging while full pages are returned.\d+) and matched the id= inside serverId=/parentId=; both fixed so GUID-based servers resolve the right item.userId fallback — resolves UserId from additional ApiClient fields and stored credentials to avoid the unscoped /Items/{id} 404 on remote/non-admin sessions.try { braces); .sh/.bat renamers now sort files by JDownloader's numeric order instead of grouping by extension; URLs and paths in all wget/curl/PowerShell/Python output are properly quoted/escaped.@require (page CSP previously blocked them); download history is corruption-safe and capped; notifications are click-to-dismiss and screen-reader announced; Season 0 (Specials) is no longer mislabeled as Season 01.SCRIPT_VERSION: if the cached "available" version is no longer newer than what's installed, the cache is cleared and treated as "no update."userId in show/season ID async fallback — v1.0.7's new resolver called getItemInfo without a userId, so it hit the unscoped /Items/{id} endpoint which 404s on Emby Connect / non-admin user contexts. Now passes userId from getServerAndToken() so the fallback uses /Users/{userId}/Items/{id}, matching the rest of the codebase.app.emby.media — parseIdsFromPage() extracted the show ID from a div.itemBackdrop element's CSS style attribute. On the Emby cloud client (and other layouts that don't render the backdrop with the parent show's image URL), no match → "Could not detect show/season IDs" error when clicking Get Links on a TV show page. Added an async fallback that uses the URL id= + Items API to resolve showId / seasonId from Type (Series / Season / Episode) — works regardless of DOM rendering.SCRIPT_VERSION was hardcoded to '1.0.2' and never bumped on releases, so the About dialog and console log message kept showing 1.0.2 regardless of what was actually installed. Now derived dynamically from GM_info.script.version (the @version metadata header), so the metadata header is the single source of truth.@updateURL and @downloadURL now point to a single stable filename PulseGrab.user.js instead of a per-version URL. Previous releases hardcoded their own filename, so each version bump silently broke auto-update for older installs (404). With v1.0.5 onward, version bumps no longer affect the update path..js to your downloads folder and opening it manually.@connect list — removed release-assets.githubusercontent.com and objects.githubusercontent.com since the in-app updater no longer hits the GitHub release-asset CDN.@connect release-assets.githubusercontent.com and @connect objects.githubusercontent.com. The GitHub Releases asset API redirects to those hosts, and userscript managers were blocking the redirect, so clicking Install Update failed with a "Refused to connect / not whitelisted URL" error.@connect localhost and @connect 127.0.0.1 to the userscript header. Userscript managers were blocking GM_xmlhttpRequest calls to http://localhost:9666/flashgot, breaking the "Send to JDownloader" action.MusicArtist items were not expanded into their tracks.IncludeItemTypes=Audio filtering.SCRIPT_VERSION instead of a hardcoded string.app.plex.tv home page by discovering servers via the plex.tv/api/v2/resources API with a server picker dialog for multi-server accounts.detectPageTypePlex() returning unknown for empty/missing hash on app.plex.tv.artist is now correctly mapped to music).processFunction() execution that was doubling all API calls.originalItems undefined ReferenceError in bypass button handler.processQueue() undefined — corrected to startNextDownload().gmFetch().json() crash on non-JSON responses with try/catch wrapper.parallelFetch deadlock on rejected tasks by using .finally() for cleanup.searchInput event listener in Download Manager._plexPartKey.MediaType (was Video, now correctly Photo).@grant GM_deleteValue and @grant GM_listValues declarations.episodes argument to showConfirmDialog in Plex processShow path.return null guard in EXTRACT_SUBTITLES for Plex subs without _plexStreamKey._embyGrabLargeFolderConfirmed to _pulseGrabLargeFolderConfirmed.fetchAllLibraries() Emby branch to use apiPrefix() consistently./library/parts/ endpoints./emby/ path segment).emby_dl_*) to PulseGrab (pulse_dl_*) keys.Detailed Setup: Quick Start Guide
| Server | Status | Auth Method |
|---|---|---|
| Emby | Full support | API key from page context |
| Plex | Full support | Token captured via fetch/XHR/WebSocket interception |
| Jellyfin | Full support | API key from page context (no /emby/ prefix) |
PulseGrab auto-detects which server you're using and adapts its API calls, URL construction, theme colors, and UI accordingly.
Pull media from any server you have access to straight into your own NAS — the files never pass through your browser or computer. Via MyJDownloader there is nothing to configure on your server at all: no open ports, no firewall rules, and it works from anywhere. Power users can point PulseGrab at an aria2 daemon instead for a fully local transfer with live in-page progress. Either way files arrive already foldered for Emby/Jellyfin/Plex, external subtitles included, and your library never sees a half-finished episode. Close the tab; the transfer keeps running.
| Method | Description |
|---|---|
| Send to My Server | Server-to-server transfer straight into your own NAS via aria2 — bytes never touch your browser or computer |
| Built-in Manager | Concurrent in-browser downloads with pause, resume, retry, and progress tracking |
| JDownloader | One-click send to a running JD2 instance via local API socket |
| wget / curl Scripts | Generate ready-to-run terminal scripts (.bat, .command, .sh) with correct filenames |
| aria2 | Export as aria2 input file for accelerated multi-connection downloads |
| Clipboard | Copy all URLs in your chosen format |
| QR Code | Scan links on mobile for cross-device transfers |
Send a batch of download links via mailto: |
Plain URLs, M3U8 playlist, JSON, HTML, CSV, XML, wget script, curl script, aria2 input, JDownloader package
The built-in browser downloader provides a complete download experience:
Ctrl+D open manager, Ctrl+H toggle history, Ctrl+S open settings, Esc close panels| Section | Key Options |
|---|---|
| General Basics | Button position, default output format, batch size, concurrent downloads (1–5), auto-confirm, rate limiting, debug logging |
| Appearance | Accent theme (Auto / Emby / Plex / Jellyfin / Ocean), dark mode, compact view |
| Filters & History | Download history tracking, skip-downloaded, exclude extras, quality preset floor (Any / 720p / 1080p / 4K+), file-size min/max thresholds |
| My Server | Guided Setup wizard; transfer method (MyJDownloader / aria2); MyJD email, password, device picker, destination folder with Browse; aria2 address, RPC port, secret, HTTPS toggle, library path, connections per file, live panel toggle, connection test, generated compose/hook snippets |
| Naming Templates | Filename macros; connect your own server for library discovery; per-type library folders with Browse; folder-per-film toggle; pinned folders; sorting rules; ask-before-each-transfer toggle |
| JDownloader | Enable/disable local API socket, auto-detect, custom host, custom port |
| Naming Templates | Customizable episode and movie filename macros with substitution tokens |
| Subtitles | External subtitle downloads, language selection grid |
| Updates | Auto-check toggle, check interval, manual check button |
PulseGrab automatically checks for new versions via the GitHub Releases API:
PulseGrab/
├── README.md # This file
├── assets/
│ └── pulsegrab_logo.png # Project logo
├── releases/
│ ├── PulseGrab.user.js # Stable URL — always serves the latest release
│ ├── PulseGrab v1.0.4.js # Per-version archive (kept for legacy install URLs)
│ └── EmbyGrab v1.0.1.js # Legacy Emby-only version
├── guides/
│ ├── PULSEGRAB-QUICK-START.md # Installation & first-use guide
│ ├── JDOWNLOADER-SETUP-GUIDE.md # JDownloader 2 integration setup
│ ├── COLLECTION-404-FIX.md # Troubleshooting collection errors
│ └── WGET-CURL-DOWNLOAD-GUIDE.md # Terminal download scripts guide
└── .gitignore
my.jdownloader.org).That's it — no ports, no config files. Now on any Emby/Plex/Jellyfin server you have access to: Get Links → Send to My Server.
One-time setup on the destination box (example: TrueNAS running Emby):
/downloads).PUID/PGID to the user Emby runs as (568:568 on TrueNAS) so Emby can read the files./config/pulsegrab-move.sh, chmod +x it, and add on-download-complete=/config/pulsegrab-move.sh to /config/aria2.conf.Then, from any Emby/Plex/Jellyfin server you have access to: click Get Links, then Send to My Server. Files transfer directly from that server to yours, arriving correctly foldered in your library. You can close the browser.
The destination needs its own route to the source. The transfer does not go through your browser, so a media server that only your laptop can reach (VPN-only, or a LAN address your NAS can't see) won't work. PulseGrab probes one file first and tells you explicitly if this is the problem.
app.plex.tv (the main Plex home page)Found a bug or want a feature?
PulseGrab is a tool for managing downloads from media servers you have authorized access to. The developers are not responsible for any misuse. Users are solely responsible for ensuring they have the legal right to download any content. Use responsibly and in accordance with your server's terms of service.
MIT License — free to use, modify, and distribute.
Enjoy seamless media server downloads with PulseGrab!
1080p, BluRay, x264) so Dune.2021.1080p.BluRay.mkv is recognised as Dune (2021), and it tells you what the existing copy is called.Authorization header rather than the deprecated api_key query parameter, so it won't break when that is removed.host:port typed without a scheme now tries HTTP before HTTPS instead of assuming TLS; the aria2 connection test detects and corrects a wrong HTTPS setting; failed setup checks no longer overwrite a working configuration; and the mover script now lives in /config/script/, because the aria2 image resets permissions on /config/* at every start and was silently stripping its execute bit.<source>auto-file-renaming=false so a re-queue never litters S01E01.1.mkv next to the real file, and one connection per source server by default so you don't hammer a box you don't own.truenas.local, 192.168.1.50:6800, http://nas/, IPv6 literals), and the generated compose/hook snippets are properly quoted, so secrets containing : or # and library paths containing spaces don't corrupt them. Items with no resolvable download URL are counted and reported instead of failing opaquely.127.0.0.1/localhost is now a JDownloader Host setting, so the JDownloader2 app on a NAS works too. Note that JDownloader binds its FlashGot listener to loopback by default; the remote instance needs ExternInterfaceLocalhostOnly set to false in Advanced Settings first.@connect * for user-configured server addresses — Tampermonkey asks once per host and offers "Always allow all domains".