Skip to content

Repository files navigation

Unspool app icon

Unspool

A native macOS app for finding and downloading attachments from Telegram chats without losing the filenames Telegram supplied.

MIT License macOS 26 or later Swift 6 TDLib integration Buy Me a Coffee

Interface · Features · Quick start · Documentation

Unspool browses a selected Telegram chat, scans the requested part of its message history, and presents every attachment format exposed by Telegram in a compact file table. It uses the official TDLib client library and runs as a sandboxed SwiftUI application.

Important

Unspool is currently a source-only development build. There is no signed, notarized, or App Store release yet.

Unspool is an independent project and is not affiliated with, maintained by, or endorsed by Telegram.

Interface

These screenshots come from Unspool's isolated preview fixtures. Every chat, filename, count, credential fragment, and destination shown below is synthetic; the capture process never opens a personal Telegram session.

Unspool Browse view showing the synthetic Audio Archive chat, extension badges, selected FLAC files, and the download action

Unspool Browse view with the Audio category and filter token active, showing only synthetic FLAC attachments Unspool Settings showing synthetic Telegram status, history range, destination, concurrency, and appearance controls
Filter the active chat Control scanning and downloads

Unspool setup showing empty Telegram API fields and the pending account and download-folder steps

Features

Browse without format assumptions

  • Browse main and archived Telegram chats with lazily loaded chat avatars.
  • Scan the latest 25, 50, 100, 250, or 500 messages, or continue through the complete available history.
  • Find documents, music, audio, video, images, archives, lyrics, and arbitrary file extensions exposed by TDLib.
  • Keep browse state isolated per chat and message range.
  • Search by filename and combine sender, category, extension, size, date, and sort controls.
  • Save reusable global or per-chat filter presets without sending filter data anywhere.

Preserve Telegram filenames

  • Use Telegram's original filename whenever Telegram supplies one.
  • Never rebuild music filenames from artist, title, caption, or media tags.
  • Use a neutral deterministic fallback only when Telegram provides no filename.
  • Display a consistent extension badge such as FLAC, LRC, PNG, MOV, or FILE.

Download safely

  • Download between one and six files concurrently.
  • Pause, resume, cancel, and retry download work.
  • Restore an interrupted batch after relaunch.
  • Checkpoint every terminal file result before scheduling more work, so a crash cannot silently discard completed outcomes.
  • Save into a user-selected security-scoped folder, optionally grouped into per-chat subfolders.
  • Preflight destination capacity, unsafe filenames, and existing files before starting a batch.
  • Default conflicts to Skip. Replace and Save a Copy require an explicit user choice; ordinary downloads never overwrite or silently rename a file.
  • Keep a local download timeline and avoid downloading the same Telegram file twice unless the user explicitly chooses Download Again.
  • Preview completed local files with system Quick Look and export an explicit JSON or CSV history manifest to a user-selected location.

Feel native on macOS

  • SwiftUI interface with Browse, Downloads, and Settings destinations.
  • Standard Command-click, Shift-click, Command-A, and Escape selection behavior.
  • System, Light, and Dark appearances.
  • VoiceOver labels, keyboard navigation, Reduce Motion, Reduce Transparency, and Increase Contrast support.
  • Finder reveal actions for the destination and completed downloads.

Quick start

Requirements

  • Apple silicon Mac
  • macOS 26 or later
  • Xcode 27 or later with a compatible macOS SDK
  • Homebrew
  • A Telegram account and an API ID/API hash created at my.telegram.org/apps

Build from source

git clone https://github.com/QenTerra/unspool.git
cd unspool
brew bundle
xcodegen generate --spec project.yml
open Unspool.xcodeproj

Before building, provide a locally built universal TDLib XCFramework at Vendor/TDLib/TDLib.xcframework. The generated binary is intentionally not committed. Use the pinned revision under Vendor/TDLib with TDLib's official build instructions.

In Xcode, select the Unspool scheme and run the app.

Connect Telegram

  1. Enter the API ID and API hash issued for your application by Telegram.
  2. Complete the account authorization steps requested by Telegram.
  3. Choose a writable download folder.
  4. Select a chat and a history range.
  5. Select attachments, review the preflight summary, and start the download.

API credentials are stored in the macOS Keychain. Login codes and two-step verification passwords are submitted to Telegram through TDLib and are not written to Unspool's persistent stores. See the Privacy Policy for the complete data map.

How downloading works

  1. AttachmentHistoryService requests Telegram history page by page.
  2. TDLib media objects are normalized into attachment records while preserving Telegram filename provenance.
  3. Filters and selection operate only on the active chat.
  4. A preflight checks destination access, available capacity, previous downloads, and filename conflicts.
  5. DownloadCoordinator downloads through TDLib with bounded concurrency.
  6. DestinationAccess atomically places each completed file into the selected folder using the conflict action chosen by the user.

The complete flow and concurrency boundaries are documented in Architecture.

Permissions and privacy

Capability Why Unspool needs it
Outgoing network access Authorize the account and request chats, messages, and files from Telegram through TDLib
User-selected file access Write downloads only to the folder selected by the user
App sandbox Keep application data and filesystem access inside macOS security boundaries
Keychain Store the Telegram API ID and API hash on this Mac

Unspool has no analytics, advertising SDK, crash-reporting service, developer-operated backend, or remote-code system. Telegram necessarily processes account and chat requests made through its service. Review PRIVACY.md, TERMS_OF_USE.md, and Telegram's own terms before using the app.

Development

project.yml is the source of truth for the generated Xcode project.

brew bundle
xcodegen generate --spec project.yml
swiftformat Unspool UnspoolTests UnspoolUITests --lint
swiftlint lint --config .swiftlint.yml
xcodebuild -project Unspool.xcodeproj -scheme Unspool test
xcodebuild -project Unspool.xcodeproj -scheme Unspool build-for-testing

These commands:

  • regenerate Unspool.xcodeproj;
  • run SwiftFormat and SwiftLint in validation mode;
  • run the unit test suite;
  • compile the UI test suite and Debug app.

If multiple Xcode installations are present, select one for the current shell with a standard path such as:

export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"

The commands do not change the global xcode-select setting.

Project structure

Unspool/
  App/                       application state and intents
  DesignSystem/              Soft Graphite tokens and components
  Domain/                    attachments, filters, selection, download models
  Features/                  Browse, Downloads, Settings, Setup, shared views
  Infrastructure/
    Downloads/               preflight, placement, scheduling
    Persistence/             local JSON stores
    Security/                Keychain credential storage
    TDLib/                   Telegram client and mapping boundary
  PreviewSupport/            synthetic UI fixtures
TDLibBridge/                 C++ bridge to TDLib's JSON C interface
UnspoolTests/                unit and integration-style tests with fakes
UnspoolUITests/              macOS UI tests
Vendor/TDLib/                pinned metadata and license texts

For setup details, dependency pinning, and common failures, use the technical documents below instead of guessing at generated paths.

Current limitations

  • There is no prebuilt signed distribution.
  • Apple silicon is the validated development target. The project expects a universal TDLib artifact, but Intel application execution is not a release gate yet.
  • Complete-history scans depend on chat size, Telegram availability, network conditions, and rate limits.
  • Telegram can omit an original filename for some media.
  • Real-account acceptance still requires manual checks for long histories, music sent as FLAC, Unicode filenames, connection loss, insufficient disk space, relaunch during a batch, and macOS accessibility modes.

Documentation

Support

Unspool is created and maintained by QenTerra. If it saves you time, you can buy me a coffee.

Bug reports and focused pull requests are welcome. Read CONTRIBUTING.md before opening one and use SECURITY.md for private vulnerability reports.

License

Unspool source code and first-party documentation are available under the MIT License. TDLib, OpenSSL, Apple frameworks, and development tools remain subject to their own licenses. See Third-party notices and Dependencies.

About

Native macOS Telegram attachment browser and downloader.

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Contributors

Languages