instagram-dl 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. instagram_dl-0.0.1/.github/workflows/docs.yml +46 -0
  2. instagram_dl-0.0.1/.github/workflows/lint.yml +33 -0
  3. instagram_dl-0.0.1/.github/workflows/tests.yml +22 -0
  4. instagram_dl-0.0.1/.gitignore +16 -0
  5. instagram_dl-0.0.1/CHANGELOG.md +31 -0
  6. instagram_dl-0.0.1/CONTRIBUTING.md +94 -0
  7. instagram_dl-0.0.1/LICENSE +21 -0
  8. instagram_dl-0.0.1/PKG-INFO +207 -0
  9. instagram_dl-0.0.1/README.md +141 -0
  10. instagram_dl-0.0.1/docs/architecture.md +94 -0
  11. instagram_dl-0.0.1/docs/backends.md +84 -0
  12. instagram_dl-0.0.1/docs/basic-usage.md +130 -0
  13. instagram_dl-0.0.1/docs/changelog.md +1 -0
  14. instagram_dl-0.0.1/docs/cli-reference.md +152 -0
  15. instagram_dl-0.0.1/docs/contributing.md +1 -0
  16. instagram_dl-0.0.1/docs/index.md +46 -0
  17. instagram_dl-0.0.1/docs/installation.md +73 -0
  18. instagram_dl-0.0.1/docs/python-api.md +161 -0
  19. instagram_dl-0.0.1/docs/troubleshooting.md +134 -0
  20. instagram_dl-0.0.1/insta_dl/__init__.py +1 -0
  21. instagram_dl-0.0.1/insta_dl/__main__.py +6 -0
  22. instagram_dl-0.0.1/insta_dl/backend.py +49 -0
  23. instagram_dl-0.0.1/insta_dl/backends/__init__.py +14 -0
  24. instagram_dl-0.0.1/insta_dl/backends/_hiker_map.py +159 -0
  25. instagram_dl-0.0.1/insta_dl/backends/aiograpi_backend.py +66 -0
  26. instagram_dl-0.0.1/insta_dl/backends/hiker.py +236 -0
  27. instagram_dl-0.0.1/insta_dl/cli.py +120 -0
  28. instagram_dl-0.0.1/insta_dl/downloader.py +195 -0
  29. instagram_dl-0.0.1/insta_dl/exceptions.py +22 -0
  30. instagram_dl-0.0.1/insta_dl/filestore.py +71 -0
  31. instagram_dl-0.0.1/insta_dl/latest_stamps.py +44 -0
  32. instagram_dl-0.0.1/insta_dl/models.py +80 -0
  33. instagram_dl-0.0.1/mkdocs.yml +67 -0
  34. instagram_dl-0.0.1/pyproject.toml +125 -0
  35. instagram_dl-0.0.1/tests/__init__.py +0 -0
  36. instagram_dl-0.0.1/tests/test_cli.py +128 -0
  37. instagram_dl-0.0.1/tests/test_cli_run.py +140 -0
  38. instagram_dl-0.0.1/tests/test_downloader.py +57 -0
  39. instagram_dl-0.0.1/tests/test_downloader_integration.py +237 -0
  40. instagram_dl-0.0.1/tests/test_edges.py +114 -0
  41. instagram_dl-0.0.1/tests/test_filestore.py +106 -0
  42. instagram_dl-0.0.1/tests/test_hardening.py +294 -0
  43. instagram_dl-0.0.1/tests/test_hiker_backend.py +76 -0
  44. instagram_dl-0.0.1/tests/test_hiker_backend_http.py +294 -0
  45. instagram_dl-0.0.1/tests/test_hiker_map.py +183 -0
  46. instagram_dl-0.0.1/tests/test_latest_stamps.py +58 -0
@@ -0,0 +1,46 @@
1
+ name: docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "docs/**"
8
+ - "mkdocs.yml"
9
+ - "README.md"
10
+ - "CONTRIBUTING.md"
11
+ - "CHANGELOG.md"
12
+ - ".github/workflows/docs.yml"
13
+ workflow_dispatch:
14
+
15
+ permissions:
16
+ contents: read
17
+ pages: write
18
+ id-token: write
19
+
20
+ concurrency:
21
+ group: docs-deploy
22
+ cancel-in-progress: false
23
+
24
+ jobs:
25
+ build:
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - uses: actions/setup-python@v5
30
+ with:
31
+ python-version: "3.12"
32
+ cache: pip
33
+ - run: pip install -e '.[docs]'
34
+ - run: mkdocs build --strict --site-dir _site
35
+ - uses: actions/upload-pages-artifact@v3
36
+ with:
37
+ path: _site
38
+
39
+ deploy:
40
+ needs: build
41
+ runs-on: ubuntu-latest
42
+ environment:
43
+ name: github-pages
44
+ steps:
45
+ - id: deployment
46
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,33 @@
1
+ name: lint
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ ruff:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: "3.12"
20
+ cache: pip
21
+ - run: pip install -e '.[lint]'
22
+ - run: ruff check insta_dl tests
23
+
24
+ mypy:
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+ - uses: actions/setup-python@v5
29
+ with:
30
+ python-version: "3.12"
31
+ cache: pip
32
+ - run: pip install -e '.[lint]'
33
+ - run: mypy insta_dl
@@ -0,0 +1,22 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: "3.12"
20
+ cache: pip
21
+ - run: pip install -e '.[dev]'
22
+ - run: pytest --cov=insta_dl --cov-report=term-missing --cov-fail-under=90
@@ -0,0 +1,16 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ _site/
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+ .coverage
12
+ htmlcov/
13
+ .DS_Store
14
+ .claude/
15
+ .context/
16
+ CLAUDE.md
@@ -0,0 +1,31 @@
1
+ # Changelog
2
+
3
+ All notable changes to insta-dl. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows [SemVer](https://semver.org/spec/v2.0.0.html).
4
+
5
+ ## [0.0.1] — 2026-04-24
6
+
7
+ ### Added
8
+
9
+ - Initial async-first skeleton with pluggable backend interface (`InstagramBackend` ABC).
10
+ - HikerAPI backend (`HikerBackend`) with cursor pagination, dict→DTO mapping, and streaming downloads via `httpx.AsyncClient`.
11
+ - `Downloader` facade orchestrating profile/post/hashtag/stories/highlights/comments downloads with consistent file layout.
12
+ - CLI accepting profile names, `#hashtag`, `post:SHORTCODE`, and full `instagram.com/p/...`, `/reel/`, `/tv/` URLs (case-insensitive, anchored regex against host spoofing).
13
+ - Sidecar JSON metadata per post; optional `--comments` sidecar streamed to disk.
14
+ - `--fast-update` + `--latest-stamps` for incremental archive updates (INI-backed state).
15
+ - `safe_component()` path sanitizer applied to every user-controlled component (username, owner, hashtag, highlight title, post code).
16
+ - Hardening: HTTPS-only allowlist for CDN downloads (`*.cdninstagram.com`, `*.fbcdn.net`), manual redirect loop with cap, signed-token strip from sidecar URLs, `.part` files with UUID suffixes, configurable max-download size (default 500 MB), Windows reserved-name and bidi/zero-width character handling.
17
+ - Test suite: 198 pytest cases at 95% coverage. `httpx.MockTransport` used for CDN, fake hikerapi client for upstream.
18
+ - MkDocs Material documentation site at `docs/`.
19
+
20
+ ### Stubbed
21
+
22
+ - `AiograpiBackend` — interface defined, methods raise `NotImplementedError` pending an upstream sync.
23
+ - `--post-filter` — parsed but ignored; planned implementation uses AST-restricted compile (no raw `eval`).
24
+
25
+ ### Known limitations
26
+
27
+ - No retry/backoff on 429 / 5xx / connection reset (relies on hikerapi defaults).
28
+ - No support for `:feed`, `:saved`, or DMs (account-bound, blocked on aiograpi).
29
+ - Comments sidecar is a single JSON array — fine for posts with thousands of comments, may want JSONL for hundreds of thousands.
30
+
31
+ [0.0.1]: https://github.com/subzeroid/insta-dl/releases/tag/v0.0.1
@@ -0,0 +1,94 @@
1
+ # Contributing to insta-dl
2
+
3
+ Thanks for considering a contribution. This document covers the dev workflow.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ git clone git@github.com:subzeroid/insta-dl.git
9
+ cd insta-dl
10
+ python -m venv .venv && source .venv/bin/activate
11
+ pip install -e '.[dev]'
12
+ ```
13
+
14
+ Python 3.11+ required (we use `dataclass(slots=True)`, `X | Y` unions, `datetime.fromisoformat` with `Z`).
15
+
16
+ ## Running tests
17
+
18
+ ```bash
19
+ pytest # all tests
20
+ pytest -k hiker # subset
21
+ pytest --cov=insta_dl --cov-report=term-missing # with coverage
22
+ ```
23
+
24
+ The suite is fully offline — no real HikerAPI or Instagram calls. Network is mocked via `httpx.MockTransport` and a fake hikerapi client.
25
+
26
+ Coverage targets: keep pure-logic modules at 100% (`models`, `filestore`, `latest_stamps`, `exceptions`). Everything else: 90%+ where reasonable. Don't write tests for `__main__.py`.
27
+
28
+ ## Project layout
29
+
30
+ ```
31
+ insta_dl/
32
+ cli.py # argparse + target dispatch
33
+ downloader.py # Downloader facade (orchestrates files, mtime, fast-update)
34
+ backend.py # InstagramBackend ABC — async iterators
35
+ models.py # DTOs (Profile, Post, StoryItem, Highlight, Comment)
36
+ filestore.py # safe_component, post_filename, mtime
37
+ latest_stamps.py # INI state for --fast-update
38
+ exceptions.py # error hierarchy
39
+ backends/
40
+ hiker.py # HikerAPI adapter (httpx + AsyncClient)
41
+ _hiker_map.py # raw dict → DTO mappers
42
+ aiograpi_backend.py # aiograpi adapter (stub; in progress)
43
+ tests/
44
+ test_*.py # pytest, asyncio mode = auto
45
+ docs/
46
+ *.md # MkDocs Material site
47
+ ```
48
+
49
+ ## Adding a backend
50
+
51
+ 1. Implement `insta_dl.backend.InstagramBackend` in `insta_dl/backends/<name>.py`. All methods are `async`; iterators are `AsyncIterator[...]`.
52
+ 2. Map raw responses to DTOs in `insta_dl/backends/_<name>_map.py`. Don't fabricate missing fields — raise `ValueError` so the caller can decide to skip.
53
+ 3. Implement `download_resource(url, dest)` with:
54
+ - host allowlist (`*.cdninstagram.com`, `*.fbcdn.net`)
55
+ - https-only scheme check
56
+ - manual redirect loop with limit
57
+ - `.part` file with `uuid.uuid4().hex` suffix → `os.replace` on success, `unlink` on failure
58
+ - byte budget against `_max_bytes`
59
+ See `HikerBackend.download_resource` for the reference.
60
+ 4. Register in `insta_dl/backends/__init__.py:make_backend`.
61
+ 5. Add tests in `tests/test_<name>_backend.py` using `httpx.MockTransport` for the CDN and a fake client for the upstream API.
62
+
63
+ The `Downloader` facade and DTOs are backend-agnostic — never let backend-specific types leak past the adapter layer.
64
+
65
+ ## Code style
66
+
67
+ - No emojis in code or docs (unless the user asked for them).
68
+ - No comments unless the *why* is non-obvious. Code should self-document via naming.
69
+ - Default to writing nothing speculative (no helpers for hypothetical future requirements).
70
+ - `from __future__ import annotations` everywhere — keeps annotations lazy and string-based.
71
+ - Lazy imports for heavy backend dependencies (`hikerapi`, `aiograpi`) — top-level import of a backend module must succeed without the upstream library installed.
72
+
73
+ ## Documentation
74
+
75
+ The MkDocs site lives in `docs/`. To preview locally:
76
+
77
+ ```bash
78
+ pip install -e '.[docs]'
79
+ mkdocs serve
80
+ ```
81
+
82
+ Then open <http://localhost:8000>. The site auto-deploys to GitHub Pages on push to `main` via `.github/workflows/docs.yml`.
83
+
84
+ ## Pull requests
85
+
86
+ - Branch from `main`, rebase before opening the PR.
87
+ - One logical change per PR.
88
+ - All tests must pass; coverage shouldn't drop more than 1%.
89
+ - Update `CHANGELOG.md` under "Unreleased".
90
+ - For new CLI flags or backend methods, update `docs/cli-reference.md` and `docs/backends.md`.
91
+
92
+ ## Security
93
+
94
+ If you find a vulnerability (path traversal, SSRF bypass, signed-token leak, etc.), please open a private security advisory on GitHub rather than a public issue.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 subzeroid
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,207 @@
1
+ Metadata-Version: 2.4
2
+ Name: instagram-dl
3
+ Version: 0.0.1
4
+ Summary: Async Instagram downloader CLI — profiles, posts, reels, stories, highlights, hashtags, comments. Pluggable backends (HikerAPI / aiograpi).
5
+ Project-URL: Homepage, https://subzeroid.github.io/insta-dl/
6
+ Project-URL: Documentation, https://subzeroid.github.io/insta-dl/
7
+ Project-URL: Repository, https://github.com/subzeroid/insta-dl
8
+ Project-URL: Issues, https://github.com/subzeroid/insta-dl/issues
9
+ Project-URL: Changelog, https://github.com/subzeroid/insta-dl/blob/main/CHANGELOG.md
10
+ Author: subzeroid
11
+ License: MIT License
12
+
13
+ Copyright (c) 2026 subzeroid
14
+
15
+ Permission is hereby granted, free of charge, to any person obtaining a copy
16
+ of this software and associated documentation files (the "Software"), to deal
17
+ in the Software without restriction, including without limitation the rights
18
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
+ copies of the Software, and to permit persons to whom the Software is
20
+ furnished to do so, subject to the following conditions:
21
+
22
+ The above copyright notice and this permission notice shall be included in all
23
+ copies or substantial portions of the Software.
24
+
25
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
+ SOFTWARE.
32
+ License-File: LICENSE
33
+ Keywords: aiograpi,async,cli,downloader,hikerapi,instagram,instagram-downloader,instagram-scraper,osint
34
+ Classifier: Development Status :: 3 - Alpha
35
+ Classifier: Environment :: Console
36
+ Classifier: Intended Audience :: Developers
37
+ Classifier: Intended Audience :: End Users/Desktop
38
+ Classifier: License :: OSI Approved :: MIT License
39
+ Classifier: Operating System :: OS Independent
40
+ Classifier: Programming Language :: Python
41
+ Classifier: Programming Language :: Python :: 3
42
+ Classifier: Programming Language :: Python :: 3 :: Only
43
+ Classifier: Programming Language :: Python :: 3.11
44
+ Classifier: Programming Language :: Python :: 3.12
45
+ Classifier: Programming Language :: Python :: 3.13
46
+ Classifier: Topic :: Internet
47
+ Classifier: Topic :: Multimedia :: Graphics
48
+ Classifier: Topic :: Multimedia :: Video
49
+ Classifier: Topic :: Utilities
50
+ Classifier: Typing :: Typed
51
+ Requires-Python: >=3.11
52
+ Requires-Dist: aiograpi
53
+ Requires-Dist: hikerapi
54
+ Provides-Extra: dev
55
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
56
+ Requires-Dist: pytest-cov>=5; extra == 'dev'
57
+ Requires-Dist: pytest>=8; extra == 'dev'
58
+ Provides-Extra: docs
59
+ Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
60
+ Requires-Dist: mkdocs>=1.6; extra == 'docs'
61
+ Requires-Dist: pymdown-extensions>=10; extra == 'docs'
62
+ Provides-Extra: lint
63
+ Requires-Dist: mypy>=1.11; extra == 'lint'
64
+ Requires-Dist: ruff>=0.6; extra == 'lint'
65
+ Description-Content-Type: text/markdown
66
+
67
+ # insta-dl
68
+
69
+ [![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
70
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
71
+ [![Status: alpha](https://img.shields.io/badge/status-alpha-orange.svg)]()
72
+ [![Tests](https://img.shields.io/badge/tests-198%20passing-success.svg)]()
73
+ [![Coverage](https://img.shields.io/badge/coverage-95%25-success.svg)]()
74
+
75
+ Async command-line downloader for Instagram. Profiles, posts, reels, stories, highlights, hashtags, and comments — saved to disk with the original timestamps preserved.
76
+
77
+ ```bash
78
+ pip install instagram-dl # installs the `insta-dl` command
79
+
80
+ export HIKERAPI_TOKEN=your_token
81
+ insta-dl instagram
82
+ ```
83
+
84
+ **insta-dl**
85
+
86
+ - downloads **profiles, hashtags, single posts, reels, stories, highlights, and comments**,
87
+ - preserves the **original `taken_at` timestamp** as file mtime so Photos/Finder sort correctly,
88
+ - writes a **JSON metadata sidecar** next to every post (caption, like count, location, owner),
89
+ - supports **incremental updates** with `--fast-update` and `--latest-stamps`,
90
+ - accepts profile names, `#hashtag`, post shortcodes, and full `instagram.com` URLs,
91
+ - ships **two interchangeable backends**: a paid commercial API (HikerAPI, no Instagram session, no ban risk) and an open-source private-API library (aiograpi, your own login).
92
+
93
+ ```text
94
+ insta-dl [--backend hiker|aiograpi]
95
+ [--dest DIR] [--fast-update] [--latest-stamps FILE]
96
+ [--stories] [--highlights] [--comments]
97
+ profile | "#hashtag" | post:SHORTCODE | https://instagram.com/...
98
+ ```
99
+
100
+ 📖 **[Full documentation](https://subzeroid.github.io/insta-dl/)** — installation, CLI reference, backends comparison, Python API, troubleshooting.
101
+
102
+ ## How to download an Instagram profile
103
+
104
+ ```bash
105
+ export HIKERAPI_TOKEN=$(cat ~/.config/hikerapi-token)
106
+ insta-dl --dest ./out instagram
107
+ ```
108
+
109
+ This grabs every post, names files `2026-04-21_16-04-15_DXZlTiKEpxw.mp4`, and writes a metadata sidecar next to each.
110
+
111
+ ## How to keep a local archive in sync
112
+
113
+ ```bash
114
+ insta-dl --fast-update --latest-stamps ./stamps.ini --dest ./out instagram
115
+ ```
116
+
117
+ `--fast-update` stops at the first post that's already on disk; `--latest-stamps` records the newest `taken_at` per profile so even a deleted local copy can be resumed.
118
+
119
+ ## How to download a single post or reel
120
+
121
+ ```bash
122
+ insta-dl post:DXZlTiKEpxw
123
+ insta-dl https://www.instagram.com/p/DXZlTiKEpxw/
124
+ insta-dl https://www.instagram.com/reel/DXZlTiKEpxw/
125
+ ```
126
+
127
+ ## How to download a hashtag
128
+
129
+ ```bash
130
+ insta-dl '#sunset' --dest ./out
131
+ ```
132
+
133
+ Pulls the recent feed for the tag into `./out/#sunset/`.
134
+
135
+ ## How to grab stories and highlights
136
+
137
+ ```bash
138
+ insta-dl --stories --highlights --dest ./out instagram
139
+ ```
140
+
141
+ Stories and highlights land under `<dest>/<username>/stories/` and `<dest>/<username>/highlights/<id>_<title>/`.
142
+
143
+ ## How to save comments alongside posts
144
+
145
+ ```bash
146
+ insta-dl --comments --dest ./out instagram
147
+ ```
148
+
149
+ Each post gets a `..._comments.json` sidecar streamed to disk.
150
+
151
+ ## Backends
152
+
153
+ Pick the one that matches how you want to authenticate.
154
+
155
+ | | **hiker** (default) | **aiograpi** *(in development)* |
156
+ |---|---|---|
157
+ | Auth | API token | Instagram login + 2FA |
158
+ | Cost | Paid per request, [**100 free requests**](https://hikerapi.com/p/18j4ib4j) to start | Free |
159
+ | Account ban risk | None — no Instagram session involved | Real, mitigated by session reuse |
160
+ | Stability vs. Instagram changes | High (managed proxy) | Brittle |
161
+ | Private profiles | What HikerAPI exposes | Anything your account can see |
162
+
163
+ Switch with `--backend`:
164
+
165
+ ```bash
166
+ insta-dl --backend hiker --hiker-token TOKEN instagram
167
+ insta-dl --backend aiograpi --login USER --password PASS --session ./session.json instagram
168
+ ```
169
+
170
+ Detailed comparison and auth setup: see the [backends documentation](https://subzeroid.github.io/insta-dl/backends/).
171
+
172
+ ## Output layout
173
+
174
+ ```
175
+ <dest>/<username>/
176
+ 2026-04-21_16-04-15_DXZlTiKEpxw.mp4
177
+ 2026-04-21_16-04-15_DXZlTiKEpxw.json # metadata sidecar
178
+ 2026-04-21_16-04-15_DXZlTiKEpxw_comments.json # with --comments
179
+ stories/
180
+ 2026-04-21_18-30-00_178290.jpg # with --stories
181
+ highlights/
182
+ 17991_Travel/ # with --highlights
183
+ 2025-10-12_19-20-30_4011.jpg
184
+ ```
185
+
186
+ Hashtag downloads land under `<dest>/#<tag>/`; single-post downloads use the post owner's username (or `owner_pk` fallback).
187
+
188
+ ## Status
189
+
190
+ This is **alpha**. The hiker backend is functional end-to-end (197 tests, 95% coverage). The aiograpi backend is stubbed pending an upstream sync. CLI flags and output layout are stable; Python API may still shift.
191
+
192
+ What's not yet implemented:
193
+
194
+ - private profiles requiring login (waiting on aiograpi)
195
+ - `:feed` and `:saved` (account-bound, blocked on aiograpi)
196
+ - post-filter expressions (planned: AST-restricted eval)
197
+ - automatic retry/backoff on 429/5xx
198
+
199
+ See the [changelog](CHANGELOG.md) for what landed when, and [contributing](CONTRIBUTING.md) for how to help.
200
+
201
+ ## Contributing
202
+
203
+ Bug reports, fixes, and backend implementations welcome. Start with [CONTRIBUTING.md](CONTRIBUTING.md). Tests: `pip install -e .[dev] && pytest`.
204
+
205
+ ## Disclaimer
206
+
207
+ insta-dl is not affiliated with, authorized, maintained, or endorsed by Instagram or Meta. Use at your own risk and respect the rights of content creators. Licensed under [MIT](LICENSE).
@@ -0,0 +1,141 @@
1
+ # insta-dl
2
+
3
+ [![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
5
+ [![Status: alpha](https://img.shields.io/badge/status-alpha-orange.svg)]()
6
+ [![Tests](https://img.shields.io/badge/tests-198%20passing-success.svg)]()
7
+ [![Coverage](https://img.shields.io/badge/coverage-95%25-success.svg)]()
8
+
9
+ Async command-line downloader for Instagram. Profiles, posts, reels, stories, highlights, hashtags, and comments — saved to disk with the original timestamps preserved.
10
+
11
+ ```bash
12
+ pip install instagram-dl # installs the `insta-dl` command
13
+
14
+ export HIKERAPI_TOKEN=your_token
15
+ insta-dl instagram
16
+ ```
17
+
18
+ **insta-dl**
19
+
20
+ - downloads **profiles, hashtags, single posts, reels, stories, highlights, and comments**,
21
+ - preserves the **original `taken_at` timestamp** as file mtime so Photos/Finder sort correctly,
22
+ - writes a **JSON metadata sidecar** next to every post (caption, like count, location, owner),
23
+ - supports **incremental updates** with `--fast-update` and `--latest-stamps`,
24
+ - accepts profile names, `#hashtag`, post shortcodes, and full `instagram.com` URLs,
25
+ - ships **two interchangeable backends**: a paid commercial API (HikerAPI, no Instagram session, no ban risk) and an open-source private-API library (aiograpi, your own login).
26
+
27
+ ```text
28
+ insta-dl [--backend hiker|aiograpi]
29
+ [--dest DIR] [--fast-update] [--latest-stamps FILE]
30
+ [--stories] [--highlights] [--comments]
31
+ profile | "#hashtag" | post:SHORTCODE | https://instagram.com/...
32
+ ```
33
+
34
+ 📖 **[Full documentation](https://subzeroid.github.io/insta-dl/)** — installation, CLI reference, backends comparison, Python API, troubleshooting.
35
+
36
+ ## How to download an Instagram profile
37
+
38
+ ```bash
39
+ export HIKERAPI_TOKEN=$(cat ~/.config/hikerapi-token)
40
+ insta-dl --dest ./out instagram
41
+ ```
42
+
43
+ This grabs every post, names files `2026-04-21_16-04-15_DXZlTiKEpxw.mp4`, and writes a metadata sidecar next to each.
44
+
45
+ ## How to keep a local archive in sync
46
+
47
+ ```bash
48
+ insta-dl --fast-update --latest-stamps ./stamps.ini --dest ./out instagram
49
+ ```
50
+
51
+ `--fast-update` stops at the first post that's already on disk; `--latest-stamps` records the newest `taken_at` per profile so even a deleted local copy can be resumed.
52
+
53
+ ## How to download a single post or reel
54
+
55
+ ```bash
56
+ insta-dl post:DXZlTiKEpxw
57
+ insta-dl https://www.instagram.com/p/DXZlTiKEpxw/
58
+ insta-dl https://www.instagram.com/reel/DXZlTiKEpxw/
59
+ ```
60
+
61
+ ## How to download a hashtag
62
+
63
+ ```bash
64
+ insta-dl '#sunset' --dest ./out
65
+ ```
66
+
67
+ Pulls the recent feed for the tag into `./out/#sunset/`.
68
+
69
+ ## How to grab stories and highlights
70
+
71
+ ```bash
72
+ insta-dl --stories --highlights --dest ./out instagram
73
+ ```
74
+
75
+ Stories and highlights land under `<dest>/<username>/stories/` and `<dest>/<username>/highlights/<id>_<title>/`.
76
+
77
+ ## How to save comments alongside posts
78
+
79
+ ```bash
80
+ insta-dl --comments --dest ./out instagram
81
+ ```
82
+
83
+ Each post gets a `..._comments.json` sidecar streamed to disk.
84
+
85
+ ## Backends
86
+
87
+ Pick the one that matches how you want to authenticate.
88
+
89
+ | | **hiker** (default) | **aiograpi** *(in development)* |
90
+ |---|---|---|
91
+ | Auth | API token | Instagram login + 2FA |
92
+ | Cost | Paid per request, [**100 free requests**](https://hikerapi.com/p/18j4ib4j) to start | Free |
93
+ | Account ban risk | None — no Instagram session involved | Real, mitigated by session reuse |
94
+ | Stability vs. Instagram changes | High (managed proxy) | Brittle |
95
+ | Private profiles | What HikerAPI exposes | Anything your account can see |
96
+
97
+ Switch with `--backend`:
98
+
99
+ ```bash
100
+ insta-dl --backend hiker --hiker-token TOKEN instagram
101
+ insta-dl --backend aiograpi --login USER --password PASS --session ./session.json instagram
102
+ ```
103
+
104
+ Detailed comparison and auth setup: see the [backends documentation](https://subzeroid.github.io/insta-dl/backends/).
105
+
106
+ ## Output layout
107
+
108
+ ```
109
+ <dest>/<username>/
110
+ 2026-04-21_16-04-15_DXZlTiKEpxw.mp4
111
+ 2026-04-21_16-04-15_DXZlTiKEpxw.json # metadata sidecar
112
+ 2026-04-21_16-04-15_DXZlTiKEpxw_comments.json # with --comments
113
+ stories/
114
+ 2026-04-21_18-30-00_178290.jpg # with --stories
115
+ highlights/
116
+ 17991_Travel/ # with --highlights
117
+ 2025-10-12_19-20-30_4011.jpg
118
+ ```
119
+
120
+ Hashtag downloads land under `<dest>/#<tag>/`; single-post downloads use the post owner's username (or `owner_pk` fallback).
121
+
122
+ ## Status
123
+
124
+ This is **alpha**. The hiker backend is functional end-to-end (197 tests, 95% coverage). The aiograpi backend is stubbed pending an upstream sync. CLI flags and output layout are stable; Python API may still shift.
125
+
126
+ What's not yet implemented:
127
+
128
+ - private profiles requiring login (waiting on aiograpi)
129
+ - `:feed` and `:saved` (account-bound, blocked on aiograpi)
130
+ - post-filter expressions (planned: AST-restricted eval)
131
+ - automatic retry/backoff on 429/5xx
132
+
133
+ See the [changelog](CHANGELOG.md) for what landed when, and [contributing](CONTRIBUTING.md) for how to help.
134
+
135
+ ## Contributing
136
+
137
+ Bug reports, fixes, and backend implementations welcome. Start with [CONTRIBUTING.md](CONTRIBUTING.md). Tests: `pip install -e .[dev] && pytest`.
138
+
139
+ ## Disclaimer
140
+
141
+ insta-dl is not affiliated with, authorized, maintained, or endorsed by Instagram or Meta. Use at your own risk and respect the rights of content creators. Licensed under [MIT](LICENSE).