ipa-dlp 0.3.0__py3-none-any.whl
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.
- ipa_dlp-0.3.0.dist-info/METADATA +414 -0
- ipa_dlp-0.3.0.dist-info/RECORD +6 -0
- ipa_dlp-0.3.0.dist-info/WHEEL +4 -0
- ipa_dlp-0.3.0.dist-info/entry_points.txt +3 -0
- ipa_dlp-0.3.0.dist-info/licenses/LICENSE +21 -0
- ipa_dlp.py +4064 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ipa-dlp
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Fetch, decrypt, and inspect personalized App Store IPAs.
|
|
5
|
+
Author: Benjamin Liou
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
|
|
10
|
+
# ipa-dlp
|
|
11
|
+
|
|
12
|
+
A cross-platform CLI and Python library for fetching, decrypting, and
|
|
13
|
+
extracting App Store IPAs and Mach-O binaries (powered by
|
|
14
|
+
[ipatool](https://github.com/majd/ipatool) and
|
|
15
|
+
[UnfairPlay](https://github.com/DrWhax/unfairplay)). It turns this:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
ipatool auth login ...
|
|
19
|
+
ipatool download ...
|
|
20
|
+
unfairplay setup ...
|
|
21
|
+
unfairplay decrypt ...
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
into this:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
ipa-dlp get spotify@9.1.88
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
It prompts for your Apple ID in the terminal (including 2FA) by default;
|
|
31
|
+
`--gui` switches to native macOS dialogs. On an Apple Silicon Mac it installs
|
|
32
|
+
pinned copies of both tools, recovers the reusable FairPlay model on first use
|
|
33
|
+
with one admin prompt, downloads the requested app version, decrypts it,
|
|
34
|
+
strips the App Store account data, and verifies the plaintext before reporting
|
|
35
|
+
success. On macOS Intel, Linux, and Windows, search, version history,
|
|
36
|
+
`get --encrypted`, and local extraction work; FairPlay decryption requires an
|
|
37
|
+
Apple Silicon Mac.
|
|
38
|
+
|
|
39
|
+
## Requirements
|
|
40
|
+
|
|
41
|
+
- Python 3.9+
|
|
42
|
+
- macOS, Linux, or Windows for search, `get -F`, `get --encrypted`, and local
|
|
43
|
+
extraction (`ipatool` is downloaded automatically for your platform)
|
|
44
|
+
- An Apple Silicon Mac for FairPlay decryption (`get` without `--encrypted`,
|
|
45
|
+
`decrypt`, `setup --seed`), plus admin rights for the one-time model recovery
|
|
46
|
+
|
|
47
|
+
## Platform support
|
|
48
|
+
|
|
49
|
+
| Capability | macOS arm64 | macOS Intel | Linux | Windows |
|
|
50
|
+
| --- | --- | --- | --- | --- |
|
|
51
|
+
| Search, `get -F`, `get --encrypted` | yes | yes | yes | yes |
|
|
52
|
+
| `extract` / `load_macho` on decrypted inputs | yes | yes | yes | yes |
|
|
53
|
+
| `get` (decrypt), `decrypt`, `setup --seed` | yes | no | no | no |
|
|
54
|
+
|
|
55
|
+
Linux amd64/arm64 and Windows amd64/arm64 are covered by ipatool's official
|
|
56
|
+
release builds. `--gui` is macOS-only; the other platforms use terminal
|
|
57
|
+
prompts.
|
|
58
|
+
|
|
59
|
+
## Install
|
|
60
|
+
|
|
61
|
+
### Homebrew (macOS, recommended)
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
brew tap ipakit/ipa-dlp
|
|
65
|
+
brew install ipa-dlp
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
If Homebrew complains that the tap is untrusted (some Homebrew 7 builds gate
|
|
69
|
+
third-party taps), run `brew trust ipakit/ipa-dlp` and retry.
|
|
70
|
+
|
|
71
|
+
Then:
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
ipa-dlp setup
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### From source (macOS)
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
git clone https://github.com/ipakit/ipa-dlp.git
|
|
81
|
+
cd ipa-dlp
|
|
82
|
+
./install.sh
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
This installs the `ipa-dlp` entrypoint and its `ipa_dlp.py` module into
|
|
86
|
+
`~/.local/bin/`, registers that directory in the Python user site-packages
|
|
87
|
+
(`ipa_dlp.pth`) so `import ipa_dlp` works from any script, then runs
|
|
88
|
+
`ipa-dlp setup`. No `sudo` is needed; the first decryption asks for admin
|
|
89
|
+
once.
|
|
90
|
+
|
|
91
|
+
If `~/.local/bin` is not on your `PATH`:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
./install.sh --add-path
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
or call the full path.
|
|
98
|
+
|
|
99
|
+
### pip / pipx (any OS)
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
pipx install ipa-dlp
|
|
103
|
+
# or
|
|
104
|
+
python3 -m pip install ipa-dlp
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
On Linux and Windows this is the supported install path; `install.sh` is
|
|
108
|
+
macOS-only. `ipatool` is fetched for your OS/architecture on first use.
|
|
109
|
+
|
|
110
|
+
## Use
|
|
111
|
+
|
|
112
|
+
### CLI
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
ipa-dlp setup
|
|
116
|
+
ipa-dlp get spotify
|
|
117
|
+
ipa-dlp get spotify@9.1.88
|
|
118
|
+
ipa-dlp get spotify -v 9.1.88
|
|
119
|
+
ipa-dlp get spotify --version 9.1.88
|
|
120
|
+
ipa-dlp get com.spotify.client --version 9.1.88
|
|
121
|
+
ipa-dlp get 324684580 --version 9.1.88
|
|
122
|
+
ipa-dlp get spotify --version 9.1.88 -o ~/Desktop/Spotify.ipa
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
To download the raw FairPlay-encrypted IPA without decrypting (supported on
|
|
126
|
+
any OS):
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
ipa-dlp get spotify --encrypted
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
On macOS Intel, Linux, and Windows, a plain `ipa-dlp get` exits with a clear
|
|
133
|
+
message; `--encrypted` is the supported download path there. `-F` and
|
|
134
|
+
`extract` work normally. The encrypted IPA still contains `SC_Info`
|
|
135
|
+
licenses and account metadata, so treat it like `--keep-account-data`.
|
|
136
|
+
|
|
137
|
+
The final path is printed on stdout; progress and diagnostics go to stderr.
|
|
138
|
+
The default output is:
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
~/Downloads/Spotify-9.1.88.ipa
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Account data is stripped by default: `SC_Info` licenses are removed and the
|
|
145
|
+
Apple ID/purchaser fields are scrubbed from `iTunesMetadata.plist`.
|
|
146
|
+
ipa-dlp checks the decryption report and the output archive
|
|
147
|
+
before printing `account data stripped: yes`; if either check fails,
|
|
148
|
+
it deletes the output and exits with an error.
|
|
149
|
+
|
|
150
|
+
Use `--keep-account-data` if you need the licenses for further analysis, and
|
|
151
|
+
`--full` to keep the extra artifacts:
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
ipa-dlp get spotify --version 9.1.88 --keep-account-data
|
|
155
|
+
ipa-dlp get spotify --version 9.1.88 --full
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`--full` also keeps:
|
|
159
|
+
|
|
160
|
+
```text
|
|
161
|
+
Spotify-9.1.88.encrypted.ipa
|
|
162
|
+
Spotify-9.1.88.report.json
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
For `ipa-dlp decrypt`, `--full` keeps the report; the encrypted input
|
|
166
|
+
already exists where you put it.
|
|
167
|
+
|
|
168
|
+
### Extracting the executable
|
|
169
|
+
|
|
170
|
+
`--extract-binary` also writes the app's arm64 Mach-O executable next to the
|
|
171
|
+
decrypted IPA, ready for a disassembler or symbol dumper:
|
|
172
|
+
|
|
173
|
+
```sh
|
|
174
|
+
ipa-dlp get spotify --version 9.1.88 --extract-binary
|
|
175
|
+
ipa-dlp decrypt /path/to/App.ipa --extract-binary
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```text
|
|
179
|
+
~/Downloads/Spotify-9.1.88.ipa
|
|
180
|
+
~/Downloads/Spotify-9.1.88.bin
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The slice is read from the decrypted archive, so it is already FairPlay-free.
|
|
184
|
+
Universal ("fat") executables are reduced to the arm64 slice (falling back to
|
|
185
|
+
x86_64), written with mode `0755`, and the `.bin` path is what gets printed on
|
|
186
|
+
stdout. The IPA is still written; pass `--force` to replace an existing `.bin`.
|
|
187
|
+
|
|
188
|
+
### Extracting from an existing IPA, .app, or binary
|
|
189
|
+
|
|
190
|
+
`ipa-dlp extract` works on files you already have and does not need an App
|
|
191
|
+
Store account:
|
|
192
|
+
|
|
193
|
+
```sh
|
|
194
|
+
ipa-dlp extract ~/Downloads/Spotify-9.1.88.ipa # -> Spotify-9.1.88.bin
|
|
195
|
+
ipa-dlp extract ~/Applications/MyApp.app -o MyApp.bin
|
|
196
|
+
ipa-dlp extract ./SomeBinary -o SomeBinary.arm64
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
For an IPA it reads `CFBundleExecutable`, checks the Mach-O encryption command,
|
|
200
|
+
and extracts directly when the payload is already decrypted. If `cryptid` is
|
|
201
|
+
non-zero, the command requires `SC_Info`, decrypts through UnfairPlay into a
|
|
202
|
+
temporary directory on an Apple Silicon Mac (the usual model/admin rules
|
|
203
|
+
apply), and extracts from that copy. A `.app` or raw Mach-O that is still encrypted cannot be decrypted
|
|
204
|
+
in place; it is extracted with a warning. `-o` templates and `--exec` work as
|
|
205
|
+
described below.
|
|
206
|
+
|
|
207
|
+
`extract` accepts `--json` like the other commands.
|
|
208
|
+
|
|
209
|
+
### Output templates and hooks
|
|
210
|
+
|
|
211
|
+
`-o` on `get`, `decrypt`, and `extract`, plus `--exec` on all three, accept
|
|
212
|
+
tokens expanded from the app's `Info.plist`:
|
|
213
|
+
|
|
214
|
+
| Token | Value |
|
|
215
|
+
| --- | --- |
|
|
216
|
+
| `%(name)s` | app display name |
|
|
217
|
+
| `%(bundle_id)s` | bundle identifier |
|
|
218
|
+
| `%(version)s` | `CFBundleShortVersionString` |
|
|
219
|
+
| `%(build)s` | `CFBundleVersion` |
|
|
220
|
+
| `%(external_id)s` | Apple external version ID, when known |
|
|
221
|
+
|
|
222
|
+
```sh
|
|
223
|
+
ipa-dlp get spotify --version 9.1.88 \
|
|
224
|
+
-o '~/Research/spotify/%(version)s-%(build)s.ipa'
|
|
225
|
+
|
|
226
|
+
ipa-dlp get spotify --version 9.1.88 --extract-binary \
|
|
227
|
+
--exec 'cp "{}" ~/Research/spotify/current.bin'
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`--exec` runs after the artifacts are written. `{}` is replaced with the final
|
|
231
|
+
artifact path — the `.bin` when `--extract-binary` is set, otherwise the
|
|
232
|
+
`.ipa` — and the command runs through the shell. Expansion uses Python
|
|
233
|
+
`%`-formatting, so write `%%` for a literal `%`. A failing hook exits non-zero
|
|
234
|
+
after the artifacts are kept.
|
|
235
|
+
|
|
236
|
+
For `extract`, tokens are read from an IPA or `.app`; a raw Mach-O only has
|
|
237
|
+
`%(name)s` (its filename stem). `%(external_id)s` is empty for `decrypt` and
|
|
238
|
+
`extract` because the input's version ID is not resolved.
|
|
239
|
+
|
|
240
|
+
### JSON output
|
|
241
|
+
|
|
242
|
+
`--json` prints a JSON object on stdout and keeps all progress and
|
|
243
|
+
diagnostics on stderr, so a pipeline can parse it without stripping noise:
|
|
244
|
+
|
|
245
|
+
```sh
|
|
246
|
+
ipa-dlp --json get spotify --version 9.1.88 > result.json
|
|
247
|
+
ipa-dlp --json get spotify --list-versions --limit 5
|
|
248
|
+
ipa-dlp --json status
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Results carry `ok`, `command`, the resolved app, `external_id`, the
|
|
252
|
+
`artifact` path, `ipa`/`binary`/`encrypted_ipa` paths where relevant,
|
|
253
|
+
`encrypted`, `verified`, and `account_data_stripped`. `--list-versions` returns a `versions` array. A
|
|
254
|
+
failure still prints one object, `{"ok": false, "error": "..."}`, and
|
|
255
|
+
exits non-zero. With `--exec`, the hook's stdout is redirected to stderr so
|
|
256
|
+
the object stays alone on stdout.
|
|
257
|
+
|
|
258
|
+
### Library API
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
from ipa_dlp import download, decrypt, extract_binary, load_macho
|
|
262
|
+
|
|
263
|
+
ipa = download("spotify", version="9.1.88") # -> Path (decrypted IPA)
|
|
264
|
+
raw = download("spotify", encrypted=True) # -> Path (encrypted IPA)
|
|
265
|
+
ipa = decrypt("/path/to/App.ipa", output="App.ipa")
|
|
266
|
+
bin_path = extract_binary(ipa) # -> Path (<base>.bin)
|
|
267
|
+
data = load_macho("spotify", version="9.1.88") # -> bytes (arm64 slice)
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Each function returns its result instead of printing it. Pass `exec_hook=` or
|
|
271
|
+
`reveal=True` only when the side effects are wanted.
|
|
272
|
+
|
|
273
|
+
Other commands:
|
|
274
|
+
|
|
275
|
+
```sh
|
|
276
|
+
ipa-dlp status
|
|
277
|
+
ipa-dlp decrypt /path/to/App.ipa # Apple Silicon Mac
|
|
278
|
+
ipa-dlp extract /path/to/App.ipa
|
|
279
|
+
ipa-dlp setup --update # reinstall pinned ipatool (and UnfairPlay on Mac)
|
|
280
|
+
ipa-dlp setup --reauth # force a new Apple ID login
|
|
281
|
+
ipa-dlp setup --seed spotify # Apple Silicon Mac: create the model now
|
|
282
|
+
ipa-dlp setup --seed spotify --version 9.1.88
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Version selection
|
|
286
|
+
|
|
287
|
+
`--version` matches the IPA's `CFBundleShortVersionString`. ipa-dlp
|
|
288
|
+
maps it to Apple's external version identifier by asking the App Store for
|
|
289
|
+
metadata, newest versions first, and caches the mapping in
|
|
290
|
+
`~/Library/Caches/ipa-dlp/versions/`. If the App Store will not serve a version to
|
|
291
|
+
your account, you get an error; `--external-version-id` lets you bypass the
|
|
292
|
+
lookup once you know the ID.
|
|
293
|
+
|
|
294
|
+
The version can be given as `--version 9.1.88` (or `-v`), as a second
|
|
295
|
+
positional (`ipa-dlp get spotify 9.1.88`), or appended to the query
|
|
296
|
+
(`ipa-dlp get spotify@9.1.88`). The `@` form also works with `load_macho`.
|
|
297
|
+
|
|
298
|
+
### Version history
|
|
299
|
+
|
|
300
|
+
`--list-versions` (`-F`) prints the App Store's version history for an app,
|
|
301
|
+
newest first, without downloading anything:
|
|
302
|
+
|
|
303
|
+
```sh
|
|
304
|
+
ipa-dlp get spotify --list-versions # newest 15
|
|
305
|
+
ipa-dlp get spotify -F --limit 100 # newest 100
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
The table goes to stdout:
|
|
309
|
+
|
|
310
|
+
```text
|
|
311
|
+
EXTERNAL_ID VERSION RELEASE_DATE
|
|
312
|
+
871294812 9.1.88 2026-03-14
|
|
313
|
+
870912300 9.1.86 2026-03-07
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Metadata for versions that were not resolved before is fetched in parallel and
|
|
317
|
+
stored in the same version cache used by `--version`, so later runs are
|
|
318
|
+
instant. Pipe an `EXTERNAL_ID` into `--external-version-id` to download a
|
|
319
|
+
version that is no longer listed.
|
|
320
|
+
|
|
321
|
+
### Licenses and paid apps
|
|
322
|
+
|
|
323
|
+
Free apps are licensed automatically when needed. For a paid app, buy it in the
|
|
324
|
+
App Store first; downloading an owned paid app works without extra flags.
|
|
325
|
+
`--purchase` asks Apple to obtain a missing license, which can charge your
|
|
326
|
+
account, so ipa-dlp asks for confirmation before using it on a paid app.
|
|
327
|
+
|
|
328
|
+
```sh
|
|
329
|
+
ipa-dlp get some-paid-app --purchase
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## On first run
|
|
333
|
+
|
|
334
|
+
1. Pinned `ipatool 2.7.0` (and `UnfairPlay 0.2.0` on Apple Silicon Macs)
|
|
335
|
+
releases are downloaded and SHA-256 verified into
|
|
336
|
+
`~/.local/share/ipa-dlp/bin/`.
|
|
337
|
+
2. You are prompted for your Apple ID and password in the terminal. On macOS
|
|
338
|
+
and Linux the password is fed to `ipatool` over a PTY, not as a
|
|
339
|
+
command-line argument; on Windows ipatool's `--password` flag is used for
|
|
340
|
+
that login (visible in the process list while it runs). ipa-dlp does not
|
|
341
|
+
store the password. If Apple asks for a 2FA
|
|
342
|
+
code, you are prompted for it. Pass `--gui` (macOS) to use native dialogs.
|
|
343
|
+
3. `setup` checks the App Store session and reports the signed-in account.
|
|
344
|
+
4. On an Apple Silicon Mac, the first `get` downloads the IPA, unpacks its app
|
|
345
|
+
bundle, and `UnfairPlay` recovers the enrollment model. You are asked for
|
|
346
|
+
your login password once (in the terminal by default, or in a macOS dialog
|
|
347
|
+
with `--gui`). The model is saved under
|
|
348
|
+
`~/Library/Application Support/unfairplay/models` and reused for later IPAs
|
|
349
|
+
from the same enrollment/account.
|
|
350
|
+
5. The IPA is decrypted, account data is stripped, and the output is checked
|
|
351
|
+
against its pre-encryption page hashes before success is reported.
|
|
352
|
+
|
|
353
|
+
On macOS Intel, Linux, and Windows, steps 4-5 do not apply; use
|
|
354
|
+
`ipa-dlp get --encrypted` to keep the raw IPA. Later `get` calls on a Mac do
|
|
355
|
+
not need the admin password.
|
|
356
|
+
|
|
357
|
+
## Important limitations
|
|
358
|
+
|
|
359
|
+
- **Decryption requires an Apple Silicon Mac.** UnfairPlay depends on
|
|
360
|
+
macOS's FairPlay services, so `get` without `--encrypted`, `decrypt`, and
|
|
361
|
+
`setup --seed` are unavailable on Intel Macs, Linux, and Windows. Those
|
|
362
|
+
platforms can still search, list versions, download with `--encrypted`,
|
|
363
|
+
and extract already-decrypted binaries.
|
|
364
|
+
- **`--encrypted` output is still personalized.** It keeps `SC_Info`
|
|
365
|
+
licenses and account metadata, so treat it like `--keep-account-data`.
|
|
366
|
+
- **UnfairPlay is build-sensitive.** It may fail closed after a macOS update if
|
|
367
|
+
Apple changes the FairPlay state or `fairplayd`. ipa-dlp reports the error.
|
|
368
|
+
- **The model is tied to the Mac's enrollment and Apple ID.** If you sign in to
|
|
369
|
+
a different account, use `ipa-dlp setup --reauth`; a different enrollment
|
|
370
|
+
needs its own model.
|
|
371
|
+
- **Only "store-owned" apps are supported.** If the account cannot obtain the app/version, the download fails.
|
|
372
|
+
- **No App Store password is stored.** `ipatool` stores its own session token in
|
|
373
|
+
the system credential store (the macOS Keychain on Mac). Revoke it with
|
|
374
|
+
`ipatool auth revoke` if needed.
|
|
375
|
+
|
|
376
|
+
## Privacy and legal use
|
|
377
|
+
|
|
378
|
+
Use this only with apps and accounts you lawfully control, and follow Apple's
|
|
379
|
+
terms. Decrypting an app does not grant redistribution rights. Do not share
|
|
380
|
+
personalized or decrypted IPAs. The default output is stripped, but
|
|
381
|
+
`--keep-account-data` and `--encrypted` output still contain your account
|
|
382
|
+
licenses and metadata.
|
|
383
|
+
|
|
384
|
+
The model file is private. Keep it on encrypted storage and never share it.
|
|
385
|
+
|
|
386
|
+
## Development / testing
|
|
387
|
+
|
|
388
|
+
Environment overrides:
|
|
389
|
+
|
|
390
|
+
```sh
|
|
391
|
+
IPADLP_IPATOOL=/path/to/ipatool
|
|
392
|
+
IPADLP_UNFAIRPLAY=/path/to/unfairplay
|
|
393
|
+
IPADLP_BIN_DIR=/tmp/ipa-dlp-bin
|
|
394
|
+
IPADLP_CACHE_DIR=/tmp/ipa-dlp-cache
|
|
395
|
+
IPADLP_DATA_DIR=/tmp/ipa-dlp-data
|
|
396
|
+
UNFAIRPLAY_MODEL_DIR=/tmp/unfairplay-models
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Terminal prompts are the default, which works over SSH and in scripts. Pass
|
|
400
|
+
`--gui` (macOS only) to use native dialogs instead.
|
|
401
|
+
|
|
402
|
+
Useful checks:
|
|
403
|
+
|
|
404
|
+
```sh
|
|
405
|
+
python3 -m py_compile ipa_dlp.py ipa-dlp
|
|
406
|
+
ipa-dlp status
|
|
407
|
+
ipa-dlp --json status
|
|
408
|
+
ipa-dlp get spotify --version 9.1.88 --dry-run
|
|
409
|
+
python3 -m build # wheel + sdist (needs flit_core)
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
See [RELEASING.md](RELEASING.md) for the automated tag → PyPI → Homebrew
|
|
413
|
+
pipeline and the one-time repository secrets.
|
|
414
|
+
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
ipa_dlp.py,sha256=lVw6BWIqXHDLW3mbOe9VMo621Yfqf3KxuqSSRdtVk0Q,133048
|
|
2
|
+
ipa_dlp-0.3.0.dist-info/entry_points.txt,sha256=VAPH_fMh-ePQ2oNt2Lm1FdQVI1IkeA6pErt3Q6puUYA,40
|
|
3
|
+
ipa_dlp-0.3.0.dist-info/licenses/LICENSE,sha256=HSWVgCD2xJ6_tP1cjGKoFQSKdKGyRifZ69nduZVXVtc,1070
|
|
4
|
+
ipa_dlp-0.3.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
5
|
+
ipa_dlp-0.3.0.dist-info/METADATA,sha256=X_9RMkZgITJFIGE3kzS9belXh-7Xz4Fmo2DhKnUrYI0,14421
|
|
6
|
+
ipa_dlp-0.3.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Benjamin Liou
|
|
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.
|