applepodbar 0.1.0__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.
- applepodbar-0.1.0/LICENSE +21 -0
- applepodbar-0.1.0/PKG-INFO +144 -0
- applepodbar-0.1.0/README.md +124 -0
- applepodbar-0.1.0/pyproject.toml +44 -0
- applepodbar-0.1.0/pyproject.toml.orig +41 -0
- applepodbar-0.1.0/src/applepodbar/__init__.py +1 -0
- applepodbar-0.1.0/src/applepodbar/__main__.py +6 -0
- applepodbar-0.1.0/src/applepodbar/amp_client.py +430 -0
- applepodbar-0.1.0/src/applepodbar/app.py +1107 -0
- applepodbar-0.1.0/src/applepodbar/catalog.py +269 -0
- applepodbar-0.1.0/src/applepodbar/credentials.py +98 -0
- applepodbar-0.1.0/src/applepodbar/local_library.py +75 -0
- applepodbar-0.1.0/src/applepodbar/login.py +101 -0
- applepodbar-0.1.0/src/applepodbar/models.py +160 -0
- applepodbar-0.1.0/src/applepodbar/playback.py +361 -0
- applepodbar-0.1.0/src/applepodbar/positions.py +100 -0
- applepodbar-0.1.0/src/applepodbar/rss_client.py +148 -0
- applepodbar-0.1.0/src/applepodbar/settings.py +227 -0
- applepodbar-0.1.0/src/applepodbar/tokens.py +127 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Christopher Patti
|
|
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,144 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: applepodbar
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A command-line TUI podcast player for Apple Podcasts
|
|
5
|
+
Author: Christopher Patti
|
|
6
|
+
Author-email: Christopher Patti <feoh@feoh.org>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: cyclopts>=4.0
|
|
10
|
+
Requires-Dist: feedparser>=6.0.11
|
|
11
|
+
Requires-Dist: httpx>=0.28.1
|
|
12
|
+
Requires-Dist: platformdirs>=4.10.0
|
|
13
|
+
Requires-Dist: textual>=8.2.7
|
|
14
|
+
Requires-Dist: textual-image>=0.8
|
|
15
|
+
Requires-Dist: keyring>=25.0 ; extra == 'login'
|
|
16
|
+
Requires-Dist: playwright>=1.49.0 ; extra == 'login'
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Provides-Extra: login
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# applepodbar
|
|
22
|
+
|
|
23
|
+
A keyboard-driven terminal podcast player for [Apple
|
|
24
|
+
Podcasts](https://podcasts.apple.com), built with Python and
|
|
25
|
+
[Textual](https://textual.textualize.io/).
|
|
26
|
+
|
|
27
|
+
> [!IMPORTANT]
|
|
28
|
+
> applepodbar is an independent, early-stage project and is not affiliated with
|
|
29
|
+
> or endorsed by Apple. It uses the undocumented AMP API that backs the
|
|
30
|
+
> podcasts.apple.com web player, so Apple can change or withdraw it without
|
|
31
|
+
> notice. No DRM bypass is implemented — applepodbar plays only the plain audio
|
|
32
|
+
> URLs the web player itself receives.
|
|
33
|
+
|
|
34
|
+
## Status
|
|
35
|
+
|
|
36
|
+
Early. Home charts, genre/editorial browse, search, show detail, and free-episode
|
|
37
|
+
playback are wired to the AMP catalog. Playwright login is available as an
|
|
38
|
+
optional extra. If Apple's web token cannot be found, search and playback fall
|
|
39
|
+
back to iTunes Search and publisher RSS. Signed-in Library, Up Next, and
|
|
40
|
+
cross-device playback-position sync, and follow/save actions are now wired.
|
|
41
|
+
Paid FairPlay content remains out of scope; see [`docs/SPEC.md`](docs/SPEC.md).
|
|
42
|
+
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+

|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- Browse and search the Apple Podcasts catalog; play free episodes through `mpv`
|
|
50
|
+
- Signed-in Library, Up Next, follows/saves, and cross-device position sync
|
|
51
|
+
- Zero-auth iTunes Search + RSS fallback with local follows and resume positions
|
|
52
|
+
- Paid FairPlay episodes are listed but not playable
|
|
53
|
+
|
|
54
|
+
## Requirements
|
|
55
|
+
|
|
56
|
+
- Python 3.12+
|
|
57
|
+
- [`uv`](https://docs.astral.sh/uv/)
|
|
58
|
+
- [`mpv`](https://mpv.io/) on `PATH` (needed for playback; browsing works
|
|
59
|
+
without it)
|
|
60
|
+
- An Apple account, only for the signed-in features
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
uv tool install applepodbar
|
|
66
|
+
applepodbar
|
|
67
|
+
|
|
68
|
+
# With sign-in support (Library, Up Next, position sync):
|
|
69
|
+
uv tool install 'applepodbar[login]' --with-executables-from playwright
|
|
70
|
+
playwright install chromium
|
|
71
|
+
applepodbar login
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Installation for development
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
git clone git@github.com:feoh/applepodbar.git
|
|
78
|
+
cd applepodbar
|
|
79
|
+
uv sync
|
|
80
|
+
uv run applepodbar
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Signing in
|
|
84
|
+
|
|
85
|
+
Catalog browsing, search, and playback of free episodes need no sign-in at all.
|
|
86
|
+
|
|
87
|
+
Library, Up Next, and position sync need a per-user token. applepodbar captures
|
|
88
|
+
it once by opening a real browser window for you to sign in to Apple yourself —
|
|
89
|
+
**it never sees or stores your Apple ID password.** This needs the optional
|
|
90
|
+
`login` extra:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
uv sync --extra login
|
|
94
|
+
uv run playwright install chromium
|
|
95
|
+
uv run applepodbar login
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Configuration
|
|
99
|
+
|
|
100
|
+
Configuration lives in the platform-standard user config directory:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
<config_dir>/applepodbar/
|
|
104
|
+
config.toml storefront and playback preferences
|
|
105
|
+
tokens.json cached developer JWT, written user-only (mode 600)
|
|
106
|
+
local_library.json local follows and RSS resume positions (mode 600)
|
|
107
|
+
OS keyring media-user-token and browser session cookies
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Set `[general] catalog_backend = "rss"` in `config.toml` to avoid the private
|
|
111
|
+
API altogether. In RSS mode, press `a` on a show to follow it locally; `l`
|
|
112
|
+
lists locally followed shows. Resume positions stay on this device.
|
|
113
|
+
|
|
114
|
+
Linux keyring support requires an unlocked Secret Service backend. No account
|
|
115
|
+
password is handled by applepodbar.
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
uv run pytest -q
|
|
121
|
+
uv run ruff check src tests
|
|
122
|
+
uv run ruff format --check src tests
|
|
123
|
+
uv run mypy src/applepodbar tests
|
|
124
|
+
uv run pyright
|
|
125
|
+
uvx prek run --all-files
|
|
126
|
+
uv build
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Releasing
|
|
130
|
+
|
|
131
|
+
Publishing a GitHub release runs `.github/workflows/publish.yml`, which re-runs
|
|
132
|
+
the checks, builds, and uploads to PyPI through trusted publishing (no API
|
|
133
|
+
token). The release tag must be `v` plus the `pyproject.toml` version:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
uv version --bump patch # or minor / major
|
|
137
|
+
git commit -am "Release v$(uv version --short)"
|
|
138
|
+
git push
|
|
139
|
+
gh release create "v$(uv version --short)" --generate-notes
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# applepodbar
|
|
2
|
+
|
|
3
|
+
A keyboard-driven terminal podcast player for [Apple
|
|
4
|
+
Podcasts](https://podcasts.apple.com), built with Python and
|
|
5
|
+
[Textual](https://textual.textualize.io/).
|
|
6
|
+
|
|
7
|
+
> [!IMPORTANT]
|
|
8
|
+
> applepodbar is an independent, early-stage project and is not affiliated with
|
|
9
|
+
> or endorsed by Apple. It uses the undocumented AMP API that backs the
|
|
10
|
+
> podcasts.apple.com web player, so Apple can change or withdraw it without
|
|
11
|
+
> notice. No DRM bypass is implemented — applepodbar plays only the plain audio
|
|
12
|
+
> URLs the web player itself receives.
|
|
13
|
+
|
|
14
|
+
## Status
|
|
15
|
+
|
|
16
|
+
Early. Home charts, genre/editorial browse, search, show detail, and free-episode
|
|
17
|
+
playback are wired to the AMP catalog. Playwright login is available as an
|
|
18
|
+
optional extra. If Apple's web token cannot be found, search and playback fall
|
|
19
|
+
back to iTunes Search and publisher RSS. Signed-in Library, Up Next, and
|
|
20
|
+
cross-device playback-position sync, and follow/save actions are now wired.
|
|
21
|
+
Paid FairPlay content remains out of scope; see [`docs/SPEC.md`](docs/SPEC.md).
|
|
22
|
+
|
|
23
|
+

|
|
24
|
+
|
|
25
|
+

|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- Browse and search the Apple Podcasts catalog; play free episodes through `mpv`
|
|
30
|
+
- Signed-in Library, Up Next, follows/saves, and cross-device position sync
|
|
31
|
+
- Zero-auth iTunes Search + RSS fallback with local follows and resume positions
|
|
32
|
+
- Paid FairPlay episodes are listed but not playable
|
|
33
|
+
|
|
34
|
+
## Requirements
|
|
35
|
+
|
|
36
|
+
- Python 3.12+
|
|
37
|
+
- [`uv`](https://docs.astral.sh/uv/)
|
|
38
|
+
- [`mpv`](https://mpv.io/) on `PATH` (needed for playback; browsing works
|
|
39
|
+
without it)
|
|
40
|
+
- An Apple account, only for the signed-in features
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
uv tool install applepodbar
|
|
46
|
+
applepodbar
|
|
47
|
+
|
|
48
|
+
# With sign-in support (Library, Up Next, position sync):
|
|
49
|
+
uv tool install 'applepodbar[login]' --with-executables-from playwright
|
|
50
|
+
playwright install chromium
|
|
51
|
+
applepodbar login
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Installation for development
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
git clone git@github.com:feoh/applepodbar.git
|
|
58
|
+
cd applepodbar
|
|
59
|
+
uv sync
|
|
60
|
+
uv run applepodbar
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Signing in
|
|
64
|
+
|
|
65
|
+
Catalog browsing, search, and playback of free episodes need no sign-in at all.
|
|
66
|
+
|
|
67
|
+
Library, Up Next, and position sync need a per-user token. applepodbar captures
|
|
68
|
+
it once by opening a real browser window for you to sign in to Apple yourself —
|
|
69
|
+
**it never sees or stores your Apple ID password.** This needs the optional
|
|
70
|
+
`login` extra:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
uv sync --extra login
|
|
74
|
+
uv run playwright install chromium
|
|
75
|
+
uv run applepodbar login
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Configuration
|
|
79
|
+
|
|
80
|
+
Configuration lives in the platform-standard user config directory:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
<config_dir>/applepodbar/
|
|
84
|
+
config.toml storefront and playback preferences
|
|
85
|
+
tokens.json cached developer JWT, written user-only (mode 600)
|
|
86
|
+
local_library.json local follows and RSS resume positions (mode 600)
|
|
87
|
+
OS keyring media-user-token and browser session cookies
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Set `[general] catalog_backend = "rss"` in `config.toml` to avoid the private
|
|
91
|
+
API altogether. In RSS mode, press `a` on a show to follow it locally; `l`
|
|
92
|
+
lists locally followed shows. Resume positions stay on this device.
|
|
93
|
+
|
|
94
|
+
Linux keyring support requires an unlocked Secret Service backend. No account
|
|
95
|
+
password is handled by applepodbar.
|
|
96
|
+
|
|
97
|
+
## Development
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
uv run pytest -q
|
|
101
|
+
uv run ruff check src tests
|
|
102
|
+
uv run ruff format --check src tests
|
|
103
|
+
uv run mypy src/applepodbar tests
|
|
104
|
+
uv run pyright
|
|
105
|
+
uvx prek run --all-files
|
|
106
|
+
uv build
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Releasing
|
|
110
|
+
|
|
111
|
+
Publishing a GitHub release runs `.github/workflows/publish.yml`, which re-runs
|
|
112
|
+
the checks, builds, and uploads to PyPI through trusted publishing (no API
|
|
113
|
+
token). The release tag must be `v` plus the `pyproject.toml` version:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
uv version --bump patch # or minor / major
|
|
117
|
+
git commit -am "Release v$(uv version --short)"
|
|
118
|
+
git push
|
|
119
|
+
gh release create "v$(uv version --short)" --generate-notes
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "applepodbar"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A command-line TUI podcast player for Apple Podcasts"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.12"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"cyclopts>=4.0",
|
|
11
|
+
"feedparser>=6.0.11",
|
|
12
|
+
"httpx>=0.28.1",
|
|
13
|
+
"platformdirs>=4.10.0",
|
|
14
|
+
"textual>=8.2.7",
|
|
15
|
+
"textual-image>=0.8",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[[project.authors]]
|
|
19
|
+
name = "Christopher Patti"
|
|
20
|
+
email = "feoh@feoh.org"
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
login = [
|
|
24
|
+
"keyring>=25.0",
|
|
25
|
+
"playwright>=1.49.0",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.scripts]
|
|
29
|
+
applepodbar = "applepodbar.app:main"
|
|
30
|
+
|
|
31
|
+
[build-system]
|
|
32
|
+
requires = ["uv_build>=0.9.18,<0.10.0"]
|
|
33
|
+
build-backend = "uv_build"
|
|
34
|
+
|
|
35
|
+
[tool.uv.build-backend]
|
|
36
|
+
source-exclude = [".ruff_cache"]
|
|
37
|
+
|
|
38
|
+
[dependency-groups]
|
|
39
|
+
dev = [
|
|
40
|
+
"mypy>=2.1.0",
|
|
41
|
+
"pyright>=1.1.400",
|
|
42
|
+
"pytest>=9.0.3",
|
|
43
|
+
"ruff>=0.15.16",
|
|
44
|
+
]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "applepodbar"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A command-line TUI podcast player for Apple Podcasts"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [{ name = "Christopher Patti", email = "feoh@feoh.org" }]
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"cyclopts>=4.0",
|
|
12
|
+
"feedparser>=6.0.11",
|
|
13
|
+
"httpx>=0.28.1",
|
|
14
|
+
"platformdirs>=4.10.0",
|
|
15
|
+
"textual>=8.2.7",
|
|
16
|
+
"textual-image>=0.8",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
login = [
|
|
21
|
+
"keyring>=25.0",
|
|
22
|
+
"playwright>=1.49.0",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.scripts]
|
|
26
|
+
applepodbar = "applepodbar.app:main"
|
|
27
|
+
|
|
28
|
+
[build-system]
|
|
29
|
+
requires = ["uv_build>=0.9.18,<0.10.0"]
|
|
30
|
+
build-backend = "uv_build"
|
|
31
|
+
|
|
32
|
+
[tool.uv.build-backend]
|
|
33
|
+
source-exclude = [".ruff_cache"]
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
dev = [
|
|
37
|
+
"mypy>=2.1.0",
|
|
38
|
+
"pyright>=1.1.400",
|
|
39
|
+
"pytest>=9.0.3",
|
|
40
|
+
"ruff>=0.15.16",
|
|
41
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""applepodbar package."""
|